The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/tsdb/elasticsearch/healthcheck_test.go

152 lines
6.2 KiB

package elasticsearch
import (
"bytes"
"context"
"io"
"net/http"
"testing"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana-plugin-sdk-go/experimental/featuretoggles"
es "github.com/grafana/grafana/pkg/tsdb/elasticsearch/client"
"github.com/stretchr/testify/assert"
)
var mockedCfg = backend.WithGrafanaConfig(context.Background(), backend.NewGrafanaCfg(map[string]string{featuretoggles.EnabledFeatures: "elasticsearchCrossClusterSearch"}))
func Test_Healthcheck_OK(t *testing.T) {
service := GetMockService(http.StatusOK, "200 OK", `{"status":"green"}`, `{"fields":{"timestamp":{"date":{"metadata_field":true}}}}`)
res, _ := service.CheckHealth(context.Background(), &backend.CheckHealthRequest{
PluginContext: backend.PluginContext{},
Headers: nil,
})
assert.Equal(t, backend.HealthStatusOk, res.Status)
assert.Equal(t, "Elasticsearch data source is healthy.", res.Message)
}
func Test_Healthcheck_Timeout(t *testing.T) {
service := GetMockService(http.StatusRequestTimeout, "408 Request Timeout", `{"status":"red"}`, `{"fields":{"timestamp":{"date":{"metadata_field":true}}}}`)
res, _ := service.CheckHealth(context.Background(), &backend.CheckHealthRequest{
PluginContext: backend.PluginContext{},
Headers: nil,
})
assert.Equal(t, backend.HealthStatusError, res.Status)
assert.Equal(t, "Health check failed: Elasticsearch data source is not healthy. Request timed out", res.Message)
}
func Test_Healthcheck_Error(t *testing.T) {
service := GetMockService(http.StatusBadGateway, "502 Bad Gateway", `{"status":"red"}`, `{"fields":{"timestamp":{"date":{"metadata_field":true}}}}`)
res, _ := service.CheckHealth(context.Background(), &backend.CheckHealthRequest{
PluginContext: backend.PluginContext{},
Headers: nil,
})
assert.Equal(t, backend.HealthStatusError, res.Status)
assert.Equal(t, "Health check failed: Elasticsearch data source is not healthy. Status: 502 Bad Gateway", res.Message)
}
func Test_validateIndex_Warning_ErrorValidatingIndex(t *testing.T) {
service := GetMockService(http.StatusOK, "200 OK", `{"status":"green"}`, `{"error":{"reason":"index_not_found"}}`)
res, _ := service.CheckHealth(mockedCfg, &backend.CheckHealthRequest{
PluginContext: backend.PluginContext{},
Headers: nil,
})
assert.Equal(t, backend.HealthStatusOk, res.Status)
assert.Equal(t, "Elasticsearch data source is healthy. Warning: Error validating index: index_not_found", res.Message)
}
func Test_validateIndex_Warning_WrongTimestampType(t *testing.T) {
service := GetMockService(http.StatusOK, "200 OK", `{"status":"green"}`, `{"fields":{"timestamp":{"float":{"metadata_field":true}}}}`)
res, _ := service.CheckHealth(mockedCfg, &backend.CheckHealthRequest{
PluginContext: backend.PluginContext{},
Headers: nil,
})
assert.Equal(t, backend.HealthStatusOk, res.Status)
assert.Equal(t, "Elasticsearch data source is healthy. Warning: Could not find time field 'timestamp' with type date in index", res.Message)
}
func Test_validateIndex_Error_FailedToUnmarshalValidateResponse(t *testing.T) {
service := GetMockService(http.StatusOK, "200 OK", `{"status":"green"}`, `\\\///{"fields":null}"`)
res, _ := service.CheckHealth(mockedCfg, &backend.CheckHealthRequest{
PluginContext: backend.PluginContext{},
Headers: nil,
})
assert.Equal(t, backend.HealthStatusError, res.Status)
assert.Equal(t, "Failed to unmarshal field capabilities response", res.Message)
}
func Test_validateIndex_Success_SuccessValidatingIndex(t *testing.T) {
service := GetMockService(http.StatusOK, "200 OK", `{"status":"green"}`, `{"fields":{"timestamp":{"date":{"metadata_field":true}}}}`)
res, _ := service.CheckHealth(mockedCfg, &backend.CheckHealthRequest{
PluginContext: backend.PluginContext{},
Headers: nil,
})
assert.Equal(t, backend.HealthStatusOk, res.Status)
assert.Equal(t, "Elasticsearch data source is healthy.", res.Message)
}
type FakeRoundTripper struct {
statusCode int
status string
index int
elasticSearchResponse string
fieldCapsResponse string
}
func (fakeRoundTripper *FakeRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
var res *http.Response
if fakeRoundTripper.index == 0 {
if fakeRoundTripper.statusCode == http.StatusOK {
res = &http.Response{
StatusCode: http.StatusOK,
Status: "200 OK",
Body: io.NopCloser(bytes.NewBufferString(fakeRoundTripper.elasticSearchResponse)),
}
} else {
res = &http.Response{
StatusCode: fakeRoundTripper.statusCode,
Status: fakeRoundTripper.status,
Body: io.NopCloser(bytes.NewBufferString(fakeRoundTripper.elasticSearchResponse)),
}
}
fakeRoundTripper.index++
} else {
res = &http.Response{
StatusCode: http.StatusOK,
Status: "200 OK",
Body: io.NopCloser(bytes.NewBufferString(fakeRoundTripper.fieldCapsResponse)),
}
}
return res, nil
}
type FakeInstanceManager struct {
statusCode int
status string
elasticSearchResponse string
fieldCapsResponse string
}
func (fakeInstanceManager *FakeInstanceManager) Get(tx context.Context, pluginContext backend.PluginContext) (instancemgmt.Instance, error) {
httpClient, _ := httpclient.New(httpclient.Options{})
httpClient.Transport = &FakeRoundTripper{statusCode: fakeInstanceManager.statusCode, status: fakeInstanceManager.status, elasticSearchResponse: fakeInstanceManager.elasticSearchResponse, fieldCapsResponse: fakeInstanceManager.fieldCapsResponse, index: 0}
return es.DatasourceInfo{
HTTPClient: httpClient,
ConfiguredFields: es.ConfiguredFields{
TimeField: "timestamp",
},
}, nil
}
func (*FakeInstanceManager) Do(_ context.Context, _ backend.PluginContext, _ instancemgmt.InstanceCallbackFunc) error {
return nil
}
func GetMockService(statusCode int, status string, elasticSearchResponse string, fieldCapsResponse string) *Service {
return &Service{
im: &FakeInstanceManager{statusCode: statusCode, status: status, elasticSearchResponse: elasticSearchResponse, fieldCapsResponse: fieldCapsResponse},
logger: log.New(),
}
}