| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2024-01-29 17:31:49 +08:00
										 |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 	"path/filepath" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-19 22:56:40 +08:00
										 |  |  | 	"github.com/grafana/grafana-azure-sdk-go/v2/azsettings" | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 	"github.com/grafana/grafana-plugin-sdk-go/backend" | 
					
						
							| 
									
										
										
										
											2023-10-09 20:12:57 +08:00
										 |  |  | 	"github.com/prometheus/client_golang/prometheus" | 
					
						
							| 
									
										
										
										
											2023-01-30 16:18:26 +08:00
										 |  |  | 	"github.com/stretchr/testify/require" | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/infra/db" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/infra/localcache" | 
					
						
							| 
									
										
										
										
											2023-04-28 20:02:27 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/log" | 
					
						
							| 
									
										
										
										
											2023-03-28 17:01:06 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/tracing" | 
					
						
							| 
									
										
										
										
											2023-10-09 20:12:57 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/plugins" | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/plugins/manager/fakes" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/accesscontrol" | 
					
						
							| 
									
										
										
										
											2023-04-13 00:30:33 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/caching" | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 	datasources "github.com/grafana/grafana/pkg/services/datasources/fakes" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/featuremgmt" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/oauthtoken/oauthtokentest" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/pluginsintegration" | 
					
						
							| 
									
										
										
										
											2023-03-27 17:15:37 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginaccesscontrol" | 
					
						
							| 
									
										
										
										
											2024-02-27 19:38:02 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginconfig" | 
					
						
							| 
									
										
										
										
											2023-03-08 00:22:30 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext" | 
					
						
							|  |  |  | 	pluginSettings "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings/service" | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/quota/quotatest" | 
					
						
							| 
									
										
										
										
											2023-06-08 19:59:51 +08:00
										 |  |  | 	fakeSecrets "github.com/grafana/grafana/pkg/services/secrets/fakes" | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/user" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/tsdb/cloudwatch" | 
					
						
							| 
									
										
										
										
											2023-09-22 20:00:40 +08:00
										 |  |  | 	testdatasource "github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource" | 
					
						
							| 
									
										
										
										
											2025-09-08 21:49:49 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/util/testutil" | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/web/webtest" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-29 22:56:24 +08:00
										 |  |  | func TestIntegrationCallResource(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2025-09-08 21:49:49 +08:00
										 |  |  | 	testutil.SkipIntegrationTestInShortMode(t) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 	staticRootPath, err := filepath.Abs("../../public/") | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cfg := setting.NewCfg() | 
					
						
							|  |  |  | 	cfg.StaticRootPath = staticRootPath | 
					
						
							|  |  |  | 	cfg.Azure = &azsettings.AzureSettings{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-26 21:56:50 +08:00
										 |  |  | 	coreRegistry := coreplugin.ProvideCoreRegistry(tracing.InitializeTracerForTest(), nil, &cloudwatch.Service{}, nil, nil, nil, nil, | 
					
						
							| 
									
										
										
										
											2025-01-24 20:37:36 +08:00
										 |  |  | 		nil, nil, nil, nil, testdatasource.ProvideService(), nil, nil, nil, nil, nil, nil, nil, nil) | 
					
						
							| 
									
										
										
										
											2023-07-27 21:29:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-29 17:31:49 +08:00
										 |  |  | 	testCtx := pluginsintegration.CreateIntegrationTestCtx(t, cfg, coreRegistry) | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-29 17:31:49 +08:00
										 |  |  | 	pcp := plugincontext.ProvideService(cfg, localcache.ProvideService(), testCtx.PluginStore, &datasources.FakeCacheService{}, | 
					
						
							| 
									
										
										
										
											2024-02-27 19:38:02 +08:00
										 |  |  | 		&datasources.FakeDataSourceService{}, pluginSettings.ProvideService(db.InitTestDB(t), fakeSecrets.NewFakeSecretsService()), pluginconfig.NewFakePluginRequestConfigProvider()) | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	srv := SetupAPITestServer(t, func(hs *HTTPServer) { | 
					
						
							|  |  |  | 		hs.Cfg = cfg | 
					
						
							| 
									
										
										
										
											2023-06-08 19:59:51 +08:00
										 |  |  | 		hs.pluginContextProvider = pcp | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 		hs.QuotaService = quotatest.New(false, nil) | 
					
						
							| 
									
										
										
										
											2024-01-29 17:31:49 +08:00
										 |  |  | 		hs.pluginStore = testCtx.PluginStore | 
					
						
							|  |  |  | 		hs.pluginClient = testCtx.PluginClient | 
					
						
							| 
									
										
										
										
											2023-04-28 20:02:27 +08:00
										 |  |  | 		hs.log = log.New("test") | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("Test successful response is received for valid request", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2024-01-29 17:31:49 +08:00
										 |  |  | 		req := srv.NewPostRequest("/api/plugins/grafana-testdata-datasource/resources/test", strings.NewReader(`{"test": "true"}`)) | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 		webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{ | 
					
						
							| 
									
										
										
										
											2024-07-03 14:08:57 +08:00
										 |  |  | 			1: accesscontrol.GroupScopesByActionContext(context.Background(), []accesscontrol.Permission{ | 
					
						
							| 
									
										
										
										
											2023-03-27 17:15:37 +08:00
										 |  |  | 				{Action: pluginaccesscontrol.ActionAppAccess, Scope: pluginaccesscontrol.ScopeProvider.GetResourceAllScope()}, | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 			}), | 
					
						
							|  |  |  | 		}}) | 
					
						
							|  |  |  | 		resp, err := srv.SendJSON(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		b, err := io.ReadAll(resp.Body) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 23:46:47 +08:00
										 |  |  | 		var body = make(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 		err = json.Unmarshal(b, &body) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		require.Equal(t, "Hello world from test datasource!", body["message"]) | 
					
						
							|  |  |  | 		require.NoError(t, resp.Body.Close()) | 
					
						
							|  |  |  | 		require.Equal(t, 200, resp.StatusCode) | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2024-01-29 17:31:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("Test successful response is received for valid request with the colon character", func(t *testing.T) { | 
					
						
							|  |  |  | 		req := srv.NewPostRequest("/api/plugins/grafana-testdata-datasource/resources/test-*,*:test-*/_mapping", strings.NewReader(`{"test": "true"}`)) | 
					
						
							|  |  |  | 		webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{ | 
					
						
							| 
									
										
										
										
											2024-07-03 14:08:57 +08:00
										 |  |  | 			1: accesscontrol.GroupScopesByActionContext(context.Background(), []accesscontrol.Permission{ | 
					
						
							| 
									
										
										
										
											2024-01-29 17:31:49 +08:00
										 |  |  | 				{Action: pluginaccesscontrol.ActionAppAccess, Scope: pluginaccesscontrol.ScopeProvider.GetResourceAllScope()}, | 
					
						
							|  |  |  | 			}), | 
					
						
							|  |  |  | 		}}) | 
					
						
							|  |  |  | 		resp, err := srv.SendJSON(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		require.NoError(t, resp.Body.Close()) | 
					
						
							|  |  |  | 		require.Equal(t, 200, resp.StatusCode) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("CallResource plugin resource request is created correctly", func(t *testing.T) { | 
					
						
							|  |  |  | 		type testdataCallResourceTestResponse struct { | 
					
						
							|  |  |  | 			Message string `json:"message"` | 
					
						
							|  |  |  | 			Request struct { | 
					
						
							|  |  |  | 				URL  url.URL | 
					
						
							|  |  |  | 				Body map[string]any `json:"body"` | 
					
						
							|  |  |  | 			} `json:"request"` | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for _, tc := range []struct { | 
					
						
							|  |  |  | 			name string | 
					
						
							|  |  |  | 			url  string | 
					
						
							|  |  |  | 			exp  func(t *testing.T, resp testdataCallResourceTestResponse) | 
					
						
							|  |  |  | 		}{ | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				name: "Simple URL", | 
					
						
							|  |  |  | 				url:  "/api/plugins/grafana-testdata-datasource/resources/test", | 
					
						
							|  |  |  | 				exp: func(t *testing.T, resp testdataCallResourceTestResponse) { | 
					
						
							|  |  |  | 					require.Equal(t, "Hello world from test datasource!", resp.Message) | 
					
						
							|  |  |  | 					require.Equal(t, "/test", resp.Request.URL.Path) | 
					
						
							|  |  |  | 					require.Equal(t, "true", resp.Request.Body["test"]) | 
					
						
							|  |  |  | 					require.Len(t, resp.Request.Body, 1) | 
					
						
							|  |  |  | 					require.Empty(t, resp.Request.URL.RawQuery) | 
					
						
							|  |  |  | 					require.Empty(t, resp.Request.URL.Query()) | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				name: "URL with query params", | 
					
						
							|  |  |  | 				url:  "/api/plugins/grafana-testdata-datasource/resources/test?test=true&a=b", | 
					
						
							|  |  |  | 				exp: func(t *testing.T, resp testdataCallResourceTestResponse) { | 
					
						
							|  |  |  | 					require.Equal(t, "Hello world from test datasource!", resp.Message) | 
					
						
							|  |  |  | 					require.Equal(t, "/test", resp.Request.URL.Path) | 
					
						
							|  |  |  | 					require.Equal(t, "test=true&a=b", resp.Request.URL.RawQuery) | 
					
						
							|  |  |  | 					query := resp.Request.URL.Query() | 
					
						
							|  |  |  | 					require.Equal(t, "true", query.Get("test")) | 
					
						
							|  |  |  | 					require.Equal(t, "b", query.Get("a")) | 
					
						
							|  |  |  | 					require.Len(t, query, 2) | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} { | 
					
						
							|  |  |  | 			t.Run(tc.name, func(t *testing.T) { | 
					
						
							|  |  |  | 				req := srv.NewPostRequest(tc.url, strings.NewReader(`{"test": "true"}`)) | 
					
						
							|  |  |  | 				webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{ | 
					
						
							| 
									
										
										
										
											2024-07-03 14:08:57 +08:00
										 |  |  | 					1: accesscontrol.GroupScopesByActionContext(context.Background(), []accesscontrol.Permission{ | 
					
						
							| 
									
										
										
										
											2024-01-29 17:31:49 +08:00
										 |  |  | 						{Action: pluginaccesscontrol.ActionAppAccess, Scope: pluginaccesscontrol.ScopeProvider.GetResourceAllScope()}, | 
					
						
							|  |  |  | 					}), | 
					
						
							|  |  |  | 				}}) | 
					
						
							|  |  |  | 				resp, err := srv.SendJSON(req) | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var body testdataCallResourceTestResponse | 
					
						
							|  |  |  | 				require.NoError(t, json.NewDecoder(resp.Body).Decode(&body)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				tc.exp(t, body) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				require.NoError(t, resp.Body.Close()) | 
					
						
							|  |  |  | 				require.Equal(t, 200, resp.StatusCode) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-09 20:12:57 +08:00
										 |  |  | 	pluginRegistry := fakes.NewFakePluginRegistry() | 
					
						
							|  |  |  | 	require.NoError(t, pluginRegistry.Add(context.Background(), &plugins.Plugin{ | 
					
						
							|  |  |  | 		JSONData: plugins.JSONData{ | 
					
						
							|  |  |  | 			ID:      "grafana-testdata-datasource", | 
					
						
							|  |  |  | 			Backend: true, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	})) | 
					
						
							| 
									
										
										
										
											2024-04-05 00:22:31 +08:00
										 |  |  | 	middlewares := pluginsintegration.CreateMiddlewares(cfg, &oauthtokentest.Service{}, tracing.InitializeTracerForTest(), &caching.OSSCachingService{}, featuremgmt.WithFeatures(), prometheus.DefaultRegisterer, pluginRegistry) | 
					
						
							| 
									
										
										
										
											2024-09-30 22:33:15 +08:00
										 |  |  | 	pc, err := backend.HandlerFromMiddlewares(&fakes.FakePluginClient{ | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 		CallResourceHandlerFunc: backend.CallResourceHandlerFunc(func(ctx context.Context, | 
					
						
							|  |  |  | 			req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { | 
					
						
							|  |  |  | 			return errors.New("something went wrong") | 
					
						
							|  |  |  | 		}), | 
					
						
							| 
									
										
										
										
											2023-10-09 20:12:57 +08:00
										 |  |  | 	}, middlewares...) | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	srv = SetupAPITestServer(t, func(hs *HTTPServer) { | 
					
						
							|  |  |  | 		hs.Cfg = cfg | 
					
						
							| 
									
										
										
										
											2023-06-08 19:59:51 +08:00
										 |  |  | 		hs.pluginContextProvider = pcp | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 		hs.QuotaService = quotatest.New(false, nil) | 
					
						
							| 
									
										
										
										
											2024-01-29 17:31:49 +08:00
										 |  |  | 		hs.pluginStore = testCtx.PluginStore | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 		hs.pluginClient = pc | 
					
						
							| 
									
										
										
										
											2023-04-28 20:02:27 +08:00
										 |  |  | 		hs.log = log.New("test") | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("Test error is properly propagated to API response", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-09-22 20:00:40 +08:00
										 |  |  | 		req := srv.NewGetRequest("/api/plugins/grafana-testdata-datasource/resources/scenarios") | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 		webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{ | 
					
						
							| 
									
										
										
										
											2024-07-03 14:08:57 +08:00
										 |  |  | 			1: accesscontrol.GroupScopesByActionContext(context.Background(), []accesscontrol.Permission{ | 
					
						
							| 
									
										
										
										
											2023-03-27 17:15:37 +08:00
										 |  |  | 				{Action: pluginaccesscontrol.ActionAppAccess, Scope: pluginaccesscontrol.ScopeProvider.GetResourceAllScope()}, | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 			}), | 
					
						
							|  |  |  | 		}}) | 
					
						
							|  |  |  | 		resp, err := srv.SendJSON(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-17 06:08:19 +08:00
										 |  |  | 		bodyBytes, err := io.ReadAll(resp.Body) | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-17 06:08:19 +08:00
										 |  |  | 		var responseBody struct { | 
					
						
							|  |  |  | 			Message string `json:"message"` | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		err = json.Unmarshal(bodyBytes, &responseBody) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		require.Equal(t, responseBody.Message, "Failed to call resource") | 
					
						
							| 
									
										
										
										
											2023-01-25 18:45:52 +08:00
										 |  |  | 		require.NoError(t, resp.Body.Close()) | 
					
						
							|  |  |  | 		require.Equal(t, 500, resp.StatusCode) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } |