| 
									
										
										
										
											2024-03-12 00:22:33 +08:00
										 |  |  | package promlib | 
					
						
							| 
									
										
										
										
											2023-04-27 21:43:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2023-08-28 20:53:50 +08:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2023-04-27 21:43:54 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2023-08-28 20:53:50 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2023-04-27 21:43:54 +08:00
										 |  |  | 	"testing" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/grafana/grafana-plugin-sdk-go/backend" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana-plugin-sdk-go/backend/datasource" | 
					
						
							| 
									
										
										
										
											2024-03-12 00:22:33 +08:00
										 |  |  | 	sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" | 
					
						
							| 
									
										
										
										
											2023-04-27 21:43:54 +08:00
										 |  |  | 	"github.com/stretchr/testify/assert" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type healthCheckProvider[T http.RoundTripper] struct { | 
					
						
							| 
									
										
										
										
											2024-03-12 00:22:33 +08:00
										 |  |  | 	sdkhttpclient.Provider | 
					
						
							| 
									
										
										
										
											2023-04-27 21:43:54 +08:00
										 |  |  | 	RoundTripper *T | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type healthCheckSuccessRoundTripper struct { | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-03-12 00:22:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 21:43:54 +08:00
										 |  |  | type healthCheckFailRoundTripper struct { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (rt *healthCheckSuccessRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { | 
					
						
							|  |  |  | 	return &http.Response{ | 
					
						
							| 
									
										
										
										
											2023-08-28 20:53:50 +08:00
										 |  |  | 		Status:     "200", | 
					
						
							|  |  |  | 		StatusCode: 200, | 
					
						
							|  |  |  | 		Header:     nil, | 
					
						
							|  |  |  | 		Body: io.NopCloser(strings.NewReader(`{ | 
					
						
							|  |  |  | 			"status": "success", | 
					
						
							|  |  |  | 			"data": { | 
					
						
							|  |  |  | 				"resultType": "scalar", | 
					
						
							|  |  |  | 				"result": [ | 
					
						
							|  |  |  | 					1692969348.331, | 
					
						
							| 
									
										
										
										
											2024-03-26 00:32:56 +08:00
										 |  |  | 					"3" | 
					
						
							| 
									
										
										
										
											2023-08-28 20:53:50 +08:00
										 |  |  | 				] | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}`)), | 
					
						
							| 
									
										
										
										
											2023-04-27 21:43:54 +08:00
										 |  |  | 		ContentLength: 0, | 
					
						
							|  |  |  | 		Request:       req, | 
					
						
							|  |  |  | 	}, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (rt *healthCheckFailRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { | 
					
						
							|  |  |  | 	return &http.Response{ | 
					
						
							|  |  |  | 		Status:        "400", | 
					
						
							|  |  |  | 		StatusCode:    400, | 
					
						
							|  |  |  | 		Header:        nil, | 
					
						
							|  |  |  | 		Body:          nil, | 
					
						
							|  |  |  | 		ContentLength: 0, | 
					
						
							|  |  |  | 		Request:       req, | 
					
						
							|  |  |  | 	}, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-12 00:22:33 +08:00
										 |  |  | func (provider *healthCheckProvider[T]) New(opts ...sdkhttpclient.Options) (*http.Client, error) { | 
					
						
							| 
									
										
										
										
											2023-04-27 21:43:54 +08:00
										 |  |  | 	client := &http.Client{} | 
					
						
							|  |  |  | 	provider.RoundTripper = new(T) | 
					
						
							|  |  |  | 	client.Transport = *provider.RoundTripper | 
					
						
							|  |  |  | 	return client, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-12 00:22:33 +08:00
										 |  |  | func (provider *healthCheckProvider[T]) GetTransport(opts ...sdkhttpclient.Options) (http.RoundTripper, error) { | 
					
						
							| 
									
										
										
										
											2023-04-27 21:43:54 +08:00
										 |  |  | 	return *new(T), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-12 00:22:33 +08:00
										 |  |  | func getMockProvider[T http.RoundTripper]() *sdkhttpclient.Provider { | 
					
						
							| 
									
										
										
										
											2023-10-23 22:40:43 +08:00
										 |  |  | 	p := &healthCheckProvider[T]{ | 
					
						
							| 
									
										
										
										
											2023-04-27 21:43:54 +08:00
										 |  |  | 		RoundTripper: new(T), | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-03-12 00:22:33 +08:00
										 |  |  | 	anotherFN := func(o sdkhttpclient.Options, next http.RoundTripper) http.RoundTripper { | 
					
						
							| 
									
										
										
										
											2023-10-23 22:40:43 +08:00
										 |  |  | 		return *p.RoundTripper | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-03-12 00:22:33 +08:00
										 |  |  | 	fn := sdkhttpclient.MiddlewareFunc(anotherFN) | 
					
						
							|  |  |  | 	mid := sdkhttpclient.NamedMiddlewareFunc("mock", fn) | 
					
						
							|  |  |  | 	return sdkhttpclient.NewProvider(sdkhttpclient.ProviderOptions{Middlewares: []sdkhttpclient.Middleware{mid}}) | 
					
						
							| 
									
										
										
										
											2023-04-27 21:43:54 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func Test_healthcheck(t *testing.T) { | 
					
						
							|  |  |  | 	t.Run("should do a successful health check", func(t *testing.T) { | 
					
						
							|  |  |  | 		httpProvider := getMockProvider[*healthCheckSuccessRoundTripper]() | 
					
						
							| 
									
										
										
										
											2024-03-15 20:37:29 +08:00
										 |  |  | 		logger := backend.NewLoggerWith("logger", "test") | 
					
						
							| 
									
										
										
										
											2023-04-27 21:43:54 +08:00
										 |  |  | 		s := &Service{ | 
					
						
							| 
									
										
										
										
											2024-03-15 20:37:29 +08:00
										 |  |  | 			im:     datasource.NewInstanceManager(newInstanceSettings(httpProvider, logger, mockExtendClientOpts)), | 
					
						
							|  |  |  | 			logger: logger, | 
					
						
							| 
									
										
										
										
											2023-04-27 21:43:54 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		req := &backend.CheckHealthRequest{ | 
					
						
							|  |  |  | 			PluginContext: getPluginContext(), | 
					
						
							|  |  |  | 			Headers:       nil, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		res, err := s.CheckHealth(context.Background(), req) | 
					
						
							|  |  |  | 		assert.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, backend.HealthStatusOk, res.Status) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("should return an error for an unsuccessful health check", func(t *testing.T) { | 
					
						
							|  |  |  | 		httpProvider := getMockProvider[*healthCheckFailRoundTripper]() | 
					
						
							| 
									
										
										
										
											2024-03-15 20:37:29 +08:00
										 |  |  | 		logger := backend.NewLoggerWith("logger", "test") | 
					
						
							| 
									
										
										
										
											2023-04-27 21:43:54 +08:00
										 |  |  | 		s := &Service{ | 
					
						
							| 
									
										
										
										
											2024-03-15 20:37:29 +08:00
										 |  |  | 			im:     datasource.NewInstanceManager(newInstanceSettings(httpProvider, logger, mockExtendClientOpts)), | 
					
						
							|  |  |  | 			logger: logger, | 
					
						
							| 
									
										
										
										
											2023-04-27 21:43:54 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		req := &backend.CheckHealthRequest{ | 
					
						
							|  |  |  | 			PluginContext: getPluginContext(), | 
					
						
							|  |  |  | 			Headers:       nil, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		res, err := s.CheckHealth(context.Background(), req) | 
					
						
							|  |  |  | 		assert.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, backend.HealthStatusError, res.Status) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func getPluginContext() backend.PluginContext { | 
					
						
							|  |  |  | 	return backend.PluginContext{ | 
					
						
							|  |  |  | 		OrgID:                      0, | 
					
						
							|  |  |  | 		PluginID:                   "prometheus", | 
					
						
							|  |  |  | 		User:                       nil, | 
					
						
							|  |  |  | 		AppInstanceSettings:        nil, | 
					
						
							|  |  |  | 		DataSourceInstanceSettings: getPromInstanceSettings(), | 
					
						
							| 
									
										
										
										
											2025-04-12 06:11:19 +08:00
										 |  |  | 		GrafanaConfig:              backend.NewGrafanaCfg(map[string]string{"concurrent_query_count": "10"}), | 
					
						
							| 
									
										
										
										
											2023-04-27 21:43:54 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-04-12 06:11:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 21:43:54 +08:00
										 |  |  | func getPromInstanceSettings() *backend.DataSourceInstanceSettings { | 
					
						
							|  |  |  | 	return &backend.DataSourceInstanceSettings{ | 
					
						
							|  |  |  | 		ID:                      0, | 
					
						
							|  |  |  | 		UID:                     "", | 
					
						
							|  |  |  | 		Type:                    "prometheus", | 
					
						
							|  |  |  | 		Name:                    "test-prometheus", | 
					
						
							|  |  |  | 		URL:                     "http://promurl:9090", | 
					
						
							|  |  |  | 		User:                    "", | 
					
						
							|  |  |  | 		Database:                "", | 
					
						
							|  |  |  | 		BasicAuthEnabled:        true, | 
					
						
							|  |  |  | 		BasicAuthUser:           "admin", | 
					
						
							|  |  |  | 		JSONData:                []byte("{}"), | 
					
						
							|  |  |  | 		DecryptedSecureJSONData: map[string]string{}, | 
					
						
							|  |  |  | 		Updated:                 time.Time{}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |