elastic: improve error-messages, first step, tests only (#61847)
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
package elasticsearch
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestErrorAvgMissingField(t *testing.T) {
|
||||
query := []byte(`
|
||||
[
|
||||
{
|
||||
"refId": "A",
|
||||
"metrics": [
|
||||
{ "type": "avg", "id": "1" }
|
||||
],
|
||||
"bucketAggs": [
|
||||
{ "type": "date_histogram", "field": "@timestamp", "id": "2" }
|
||||
]
|
||||
}
|
||||
]
|
||||
`)
|
||||
|
||||
response := []byte(`
|
||||
{
|
||||
"error": {
|
||||
"reason": "Required one of fields [field, script], but none were specified. ",
|
||||
"root_cause": [
|
||||
{
|
||||
"reason": "Required one of fields [field, script], but none were specified. ",
|
||||
"type": "illegal_argument_exception"
|
||||
}
|
||||
],
|
||||
"type": "illegal_argument_exception"
|
||||
},
|
||||
"status": 400
|
||||
}
|
||||
`)
|
||||
|
||||
result, err := queryDataTestWithResponseCode(query, 400, response)
|
||||
require.NoError(t, err)
|
||||
|
||||
// FIXME: we should return the received error message
|
||||
require.Len(t, result.response.Responses, 0)
|
||||
}
|
||||
|
||||
func TestErrorAvgMissingFieldNoDetailedErrors(t *testing.T) {
|
||||
query := []byte(`
|
||||
[
|
||||
{
|
||||
"refId": "A",
|
||||
"metrics": [
|
||||
{ "type": "avg", "id": "1" }
|
||||
],
|
||||
"bucketAggs": [
|
||||
{ "type": "date_histogram", "field": "@timestamp", "id": "2" }
|
||||
]
|
||||
}
|
||||
]
|
||||
`)
|
||||
|
||||
// you can receive such an error if you configure elastic with:
|
||||
// http.detailed_errors.enabled=false
|
||||
response := []byte(`
|
||||
{ "error": "No ElasticsearchException found", "status": 400 }
|
||||
`)
|
||||
|
||||
result, err := queryDataTestWithResponseCode(query, 400, response)
|
||||
require.NoError(t, err)
|
||||
|
||||
// FIXME: we should return the received error message
|
||||
require.Len(t, result.response.Responses, 0)
|
||||
}
|
||||
|
||||
func TestErrorTooManyDateHistogramBuckets(t *testing.T) {
|
||||
query := []byte(`
|
||||
[
|
||||
{
|
||||
"refId": "A",
|
||||
"metrics": [
|
||||
{ "type": "count", "id": "1" }
|
||||
],
|
||||
"bucketAggs": [
|
||||
{ "type": "date_histogram", "field": "@timestamp", "settings": { "interval": "10s" }, "id": "2" }
|
||||
]
|
||||
}
|
||||
]
|
||||
`)
|
||||
|
||||
response := []byte(`
|
||||
{
|
||||
"responses": [
|
||||
{
|
||||
"error": {
|
||||
"caused_by": {
|
||||
"max_buckets": 65536,
|
||||
"reason": "Trying to create too many buckets. Must be less than or equal to: [65536].",
|
||||
"type": "too_many_buckets_exception"
|
||||
},
|
||||
"reason": "",
|
||||
"root_cause": [],
|
||||
"type": "search_phase_execution_exception"
|
||||
},
|
||||
"status": 503
|
||||
}
|
||||
]
|
||||
}
|
||||
`)
|
||||
|
||||
result, err := queryDataTestWithResponseCode(query, 200, response)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, result.response.Responses, 1)
|
||||
|
||||
dataResponse, ok := result.response.Responses["A"]
|
||||
|
||||
require.True(t, ok)
|
||||
require.Len(t, dataResponse.Frames, 0)
|
||||
require.ErrorContains(t, dataResponse.Error, "Trying to create too many buckets. Must be less than or equal to: [65536].")
|
||||
}
|
||||
|
||||
func TestNonElasticError(t *testing.T) {
|
||||
query := []byte(`
|
||||
[
|
||||
{
|
||||
"refId": "A",
|
||||
"metrics": [
|
||||
{ "type": "count", "id": "1" }
|
||||
],
|
||||
"bucketAggs": [
|
||||
{ "type": "date_histogram", "field": "@timestamp", "settings": { "interval": "10s" }, "id": "2" }
|
||||
]
|
||||
}
|
||||
]
|
||||
`)
|
||||
|
||||
// this scenario is about an error-message that does not come directly from elastic,
|
||||
// but from a middleware/proxy server that for example reports that it is forbidden
|
||||
// to access the database for some reason.
|
||||
response := []byte(`Access to the database is forbidden`)
|
||||
|
||||
_, err := queryDataTestWithResponseCode(query, 403, response)
|
||||
// FIXME: we should return something better.
|
||||
// currently it returns the error-message about being unable to decode JSON
|
||||
// it is not 100% clear what we should return to the browser
|
||||
// (and what to debug-log for example), we could return
|
||||
// at least something like "unknown response, http status code 403"
|
||||
require.ErrorContains(t, err, "invalid character")
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
type queryDataTestRoundTripper struct {
|
||||
requestCallback func(req *http.Request) error
|
||||
body []byte
|
||||
statusCode int
|
||||
}
|
||||
|
||||
// we fake the http-request-call. we return a fixed byte-array (defined by the test snapshot),
|
||||
@@ -28,16 +29,16 @@ func (rt *queryDataTestRoundTripper) RoundTrip(req *http.Request) (*http.Respons
|
||||
}
|
||||
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
StatusCode: rt.statusCode,
|
||||
Header: http.Header{},
|
||||
Body: io.NopCloser(bytes.NewReader(rt.body)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// we setup a fake datasource-info
|
||||
func newFlowTestDsInfo(body []byte, reuestCallback func(req *http.Request) error) *es.DatasourceInfo {
|
||||
func newFlowTestDsInfo(body []byte, statusCode int, reuestCallback func(req *http.Request) error) *es.DatasourceInfo {
|
||||
client := http.Client{
|
||||
Transport: &queryDataTestRoundTripper{body: body, requestCallback: reuestCallback},
|
||||
Transport: &queryDataTestRoundTripper{body: body, statusCode: statusCode, requestCallback: reuestCallback},
|
||||
}
|
||||
return &es.DatasourceInfo{
|
||||
ESVersion: semver.MustParse("8.5.0"),
|
||||
@@ -104,7 +105,7 @@ type queryDataTestResult struct {
|
||||
requestBytes []byte
|
||||
}
|
||||
|
||||
func queryDataTest(queriesBytes []byte, responseBytes []byte) (queryDataTestResult, error) {
|
||||
func queryDataTestWithResponseCode(queriesBytes []byte, responseStatusCode int, responseBytes []byte) (queryDataTestResult, error) {
|
||||
queries, err := newFlowTestQueries(queriesBytes)
|
||||
if err != nil {
|
||||
return queryDataTestResult{}, err
|
||||
@@ -113,7 +114,7 @@ func queryDataTest(queriesBytes []byte, responseBytes []byte) (queryDataTestResu
|
||||
requestBytesStored := false
|
||||
var requestBytes []byte
|
||||
|
||||
dsInfo := newFlowTestDsInfo(responseBytes, func(req *http.Request) error {
|
||||
dsInfo := newFlowTestDsInfo(responseBytes, responseStatusCode, func(req *http.Request) error {
|
||||
requestBytes, err = io.ReadAll(req.Body)
|
||||
|
||||
bodyCloseError := req.Body.Close()
|
||||
@@ -144,3 +145,7 @@ func queryDataTest(queriesBytes []byte, responseBytes []byte) (queryDataTestResu
|
||||
requestBytes: requestBytes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func queryDataTest(queriesBytes []byte, responseBytes []byte) (queryDataTestResult, error) {
|
||||
return queryDataTestWithResponseCode(queriesBytes, 200, responseBytes)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user