| 
									
										
										
										
											2022-03-08 02:33:01 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-18 02:52:22 +08:00
										 |  |  | 	"github.com/grafana/grafana-plugin-sdk-go/backend" | 
					
						
							|  |  |  | 	"github.com/stretchr/testify/require" | 
					
						
							| 
									
										
										
										
											2022-03-08 02:33:01 +08:00
										 |  |  | 	"golang.org/x/oauth2" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/models" | 
					
						
							| 
									
										
										
										
											2022-05-04 00:02:20 +08:00
										 |  |  | 	fakeDatasources "github.com/grafana/grafana/pkg/services/datasources/fakes" | 
					
						
							| 
									
										
										
										
											2022-05-18 02:52:22 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/featuremgmt" | 
					
						
							| 
									
										
										
										
											2022-03-08 02:33:01 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/query" | 
					
						
							| 
									
										
										
										
											2022-05-18 02:52:22 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/web/webtest" | 
					
						
							| 
									
										
										
										
											2022-03-08 02:33:01 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-17 05:17:05 +08:00
										 |  |  | var queryDatasourceInput = `{ | 
					
						
							|  |  |  | "from": "", | 
					
						
							| 
									
										
										
										
											2022-03-08 02:33:01 +08:00
										 |  |  | 		"to": "", | 
					
						
							|  |  |  | 		"queries": [ | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				"datasource": { | 
					
						
							|  |  |  | 					"type": "datasource", | 
					
						
							|  |  |  | 					"uid": "grafana" | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				"queryType": "randomWalk", | 
					
						
							|  |  |  | 				"refId": "A" | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		] | 
					
						
							|  |  |  | 	}` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type fakePluginRequestValidator struct { | 
					
						
							|  |  |  | 	err error | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (rv *fakePluginRequestValidator) Validate(dsURL string, req *http.Request) error { | 
					
						
							|  |  |  | 	return rv.err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type fakeOAuthTokenService struct { | 
					
						
							|  |  |  | 	passThruEnabled bool | 
					
						
							|  |  |  | 	token           *oauth2.Token | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ts *fakeOAuthTokenService) GetCurrentOAuthToken(context.Context, *models.SignedInUser) *oauth2.Token { | 
					
						
							|  |  |  | 	return ts.token | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ts *fakeOAuthTokenService) IsOAuthPassThruEnabled(*models.DataSource) bool { | 
					
						
							|  |  |  | 	return ts.passThruEnabled | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-04 00:02:20 +08:00
										 |  |  | // `/ds/query` endpoint test
 | 
					
						
							|  |  |  | func TestAPIEndpoint_Metrics_QueryMetricsV2(t *testing.T) { | 
					
						
							|  |  |  | 	qds := query.ProvideService( | 
					
						
							|  |  |  | 		nil, | 
					
						
							|  |  |  | 		nil, | 
					
						
							|  |  |  | 		nil, | 
					
						
							|  |  |  | 		&fakePluginRequestValidator{}, | 
					
						
							|  |  |  | 		&fakeDatasources.FakeDataSourceService{}, | 
					
						
							|  |  |  | 		&fakePluginClient{ | 
					
						
							|  |  |  | 			QueryDataHandlerFunc: func(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { | 
					
						
							|  |  |  | 				resp := backend.Responses{ | 
					
						
							|  |  |  | 					"A": backend.DataResponse{ | 
					
						
							|  |  |  | 						Error: fmt.Errorf("query failed"), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return &backend.QueryDataResponse{Responses: resp}, nil | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		&fakeOAuthTokenService{}, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	serverFeatureEnabled := SetupAPITestServer(t, func(hs *HTTPServer) { | 
					
						
							|  |  |  | 		hs.queryDataService = qds | 
					
						
							|  |  |  | 		hs.Features = featuremgmt.WithFeatures(featuremgmt.FlagDatasourceQueryMultiStatus, true) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	serverFeatureDisabled := SetupAPITestServer(t, func(hs *HTTPServer) { | 
					
						
							|  |  |  | 		hs.queryDataService = qds | 
					
						
							|  |  |  | 		hs.Features = featuremgmt.WithFeatures(featuremgmt.FlagDatasourceQueryMultiStatus, false) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("Status code is 400 when data source response has an error and feature toggle is disabled", func(t *testing.T) { | 
					
						
							|  |  |  | 		req := serverFeatureDisabled.NewPostRequest("/api/ds/query", strings.NewReader(queryDatasourceInput)) | 
					
						
							|  |  |  | 		webtest.RequestWithSignedInUser(req, &models.SignedInUser{UserId: 1, OrgId: 1, OrgRole: models.ROLE_VIEWER}) | 
					
						
							|  |  |  | 		resp, err := serverFeatureDisabled.SendJSON(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		require.NoError(t, resp.Body.Close()) | 
					
						
							|  |  |  | 		require.Equal(t, http.StatusBadRequest, resp.StatusCode) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("Status code is 207 when data source response has an error and feature toggle is enabled", func(t *testing.T) { | 
					
						
							|  |  |  | 		req := serverFeatureEnabled.NewPostRequest("/api/ds/query", strings.NewReader(queryDatasourceInput)) | 
					
						
							|  |  |  | 		webtest.RequestWithSignedInUser(req, &models.SignedInUser{UserId: 1, OrgId: 1, OrgRole: models.ROLE_VIEWER}) | 
					
						
							|  |  |  | 		resp, err := serverFeatureEnabled.SendJSON(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		require.NoError(t, resp.Body.Close()) | 
					
						
							|  |  |  | 		require.Equal(t, http.StatusMultiStatus, resp.StatusCode) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } |