| 
									
										
										
										
											2021-08-09 22:07:54 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2022-02-09 20:44:38 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2022-02-09 20:44:38 +08:00
										 |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"net/http/httptest" | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2021-08-09 22:07:54 +08:00
										 |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-06 23:44:22 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/log/logtest" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 	"github.com/stretchr/testify/assert" | 
					
						
							|  |  |  | 	"github.com/stretchr/testify/require" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-09 20:44:38 +08:00
										 |  |  | 	"github.com/grafana/grafana-plugin-sdk-go/backend" | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/log" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/models" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/plugins" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							| 
									
										
										
										
											2021-08-09 22:07:54 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | func Test_GetPluginAssets(t *testing.T) { | 
					
						
							|  |  |  | 	pluginID := "test-plugin" | 
					
						
							|  |  |  | 	pluginDir := "." | 
					
						
							|  |  |  | 	tmpFile, err := ioutil.TempFile(pluginDir, "") | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2021-12-08 01:15:53 +08:00
										 |  |  | 	tmpFileInParentDir, err := ioutil.TempFile("..", "") | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 	t.Cleanup(func() { | 
					
						
							|  |  |  | 		err := os.RemoveAll(tmpFile.Name()) | 
					
						
							|  |  |  | 		assert.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2021-12-08 01:15:53 +08:00
										 |  |  | 		err = os.RemoveAll(tmpFileInParentDir.Name()) | 
					
						
							|  |  |  | 		assert.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 	expectedBody := "Plugin test" | 
					
						
							|  |  |  | 	_, err = tmpFile.WriteString(expectedBody) | 
					
						
							|  |  |  | 	assert.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2021-08-09 22:07:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 	requestedFile := filepath.Clean(tmpFile.Name()) | 
					
						
							| 
									
										
										
										
											2021-08-09 22:07:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 	t.Run("Given a request for an existing plugin file that is listed as a signature covered file", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-17 19:04:22 +08:00
										 |  |  | 		p := plugins.PluginDTO{ | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | 			JSONData: plugins.JSONData{ | 
					
						
							|  |  |  | 				ID: pluginID, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 			PluginDir: pluginDir, | 
					
						
							|  |  |  | 			SignedFiles: map[string]struct{}{ | 
					
						
							|  |  |  | 				requestedFile: {}, | 
					
						
							| 
									
										
										
										
											2021-08-09 22:07:54 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-11-17 19:04:22 +08:00
										 |  |  | 		service := &fakePluginStore{ | 
					
						
							|  |  |  | 			plugins: map[string]plugins.PluginDTO{ | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 				pluginID: p, | 
					
						
							| 
									
										
										
										
											2021-08-09 22:07:54 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-05-06 23:44:22 +08:00
										 |  |  | 		l := &logtest.Fake{} | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		url := fmt.Sprintf("/public/plugins/%s/%s", pluginID, requestedFile) | 
					
						
							|  |  |  | 		pluginAssetScenario(t, "When calling GET on", url, "/public/plugins/:pluginId/*", service, l, | 
					
						
							|  |  |  | 			func(sc *scenarioContext) { | 
					
						
							|  |  |  | 				callGetPluginAsset(sc) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				require.Equal(t, 200, sc.resp.Code) | 
					
						
							|  |  |  | 				assert.Equal(t, expectedBody, sc.resp.Body.String()) | 
					
						
							| 
									
										
										
										
											2022-05-06 23:44:22 +08:00
										 |  |  | 				assert.Zero(t, l.WarnLogs.Calls) | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-08 01:15:53 +08:00
										 |  |  | 	t.Run("Given a request for a relative path", func(t *testing.T) { | 
					
						
							|  |  |  | 		p := plugins.PluginDTO{ | 
					
						
							|  |  |  | 			JSONData: plugins.JSONData{ | 
					
						
							|  |  |  | 				ID: pluginID, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			PluginDir: pluginDir, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		service := &fakePluginStore{ | 
					
						
							|  |  |  | 			plugins: map[string]plugins.PluginDTO{ | 
					
						
							|  |  |  | 				pluginID: p, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-05-06 23:44:22 +08:00
										 |  |  | 		l := &logtest.Fake{} | 
					
						
							| 
									
										
										
										
											2021-12-08 01:15:53 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		url := fmt.Sprintf("/public/plugins/%s/%s", pluginID, tmpFileInParentDir.Name()) | 
					
						
							|  |  |  | 		pluginAssetScenario(t, "When calling GET on", url, "/public/plugins/:pluginId/*", service, l, | 
					
						
							|  |  |  | 			func(sc *scenarioContext) { | 
					
						
							|  |  |  | 				callGetPluginAsset(sc) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				require.Equal(t, 404, sc.resp.Code) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 	t.Run("Given a request for an existing plugin file that is not listed as a signature covered file", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-17 19:04:22 +08:00
										 |  |  | 		p := plugins.PluginDTO{ | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | 			JSONData: plugins.JSONData{ | 
					
						
							|  |  |  | 				ID: pluginID, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 			PluginDir: pluginDir, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-11-17 19:04:22 +08:00
										 |  |  | 		service := &fakePluginStore{ | 
					
						
							|  |  |  | 			plugins: map[string]plugins.PluginDTO{ | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 				pluginID: p, | 
					
						
							| 
									
										
										
										
											2021-08-09 22:07:54 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-05-06 23:44:22 +08:00
										 |  |  | 		l := &logtest.Fake{} | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		url := fmt.Sprintf("/public/plugins/%s/%s", pluginID, requestedFile) | 
					
						
							|  |  |  | 		pluginAssetScenario(t, "When calling GET on", url, "/public/plugins/:pluginId/*", service, l, | 
					
						
							|  |  |  | 			func(sc *scenarioContext) { | 
					
						
							|  |  |  | 				callGetPluginAsset(sc) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				require.Equal(t, 200, sc.resp.Code) | 
					
						
							|  |  |  | 				assert.Equal(t, expectedBody, sc.resp.Body.String()) | 
					
						
							| 
									
										
										
										
											2022-05-06 23:44:22 +08:00
										 |  |  | 				assert.Zero(t, l.WarnLogs.Calls) | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("Given a request for an non-existing plugin file", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-17 19:04:22 +08:00
										 |  |  | 		p := plugins.PluginDTO{ | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | 			JSONData: plugins.JSONData{ | 
					
						
							|  |  |  | 				ID: pluginID, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 			PluginDir: pluginDir, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-11-17 19:04:22 +08:00
										 |  |  | 		service := &fakePluginStore{ | 
					
						
							|  |  |  | 			plugins: map[string]plugins.PluginDTO{ | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 				pluginID: p, | 
					
						
							| 
									
										
										
										
											2021-08-09 22:07:54 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-05-06 23:44:22 +08:00
										 |  |  | 		l := &logtest.Fake{} | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		requestedFile := "nonExistent" | 
					
						
							|  |  |  | 		url := fmt.Sprintf("/public/plugins/%s/%s", pluginID, requestedFile) | 
					
						
							|  |  |  | 		pluginAssetScenario(t, "When calling GET on", url, "/public/plugins/:pluginId/*", service, l, | 
					
						
							|  |  |  | 			func(sc *scenarioContext) { | 
					
						
							|  |  |  | 				callGetPluginAsset(sc) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var respJson map[string]interface{} | 
					
						
							|  |  |  | 				err := json.NewDecoder(sc.resp.Body).Decode(&respJson) | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 				require.Equal(t, 404, sc.resp.Code) | 
					
						
							|  |  |  | 				assert.Equal(t, "Plugin file not found", respJson["message"]) | 
					
						
							| 
									
										
										
										
											2022-05-06 23:44:22 +08:00
										 |  |  | 				assert.Zero(t, l.WarnLogs.Calls) | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("Given a request for an non-existing plugin", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-17 19:04:22 +08:00
										 |  |  | 		service := &fakePluginStore{ | 
					
						
							|  |  |  | 			plugins: map[string]plugins.PluginDTO{}, | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-05-06 23:44:22 +08:00
										 |  |  | 		l := &logtest.Fake{} | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		requestedFile := "nonExistent" | 
					
						
							|  |  |  | 		url := fmt.Sprintf("/public/plugins/%s/%s", pluginID, requestedFile) | 
					
						
							|  |  |  | 		pluginAssetScenario(t, "When calling GET on", url, "/public/plugins/:pluginId/*", service, l, | 
					
						
							|  |  |  | 			func(sc *scenarioContext) { | 
					
						
							|  |  |  | 				callGetPluginAsset(sc) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var respJson map[string]interface{} | 
					
						
							|  |  |  | 				err := json.NewDecoder(sc.resp.Body).Decode(&respJson) | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 				assert.Equal(t, 404, sc.resp.Code) | 
					
						
							|  |  |  | 				assert.Equal(t, "Plugin not found", respJson["message"]) | 
					
						
							| 
									
										
										
										
											2022-05-06 23:44:22 +08:00
										 |  |  | 				assert.Zero(t, l.WarnLogs.Calls) | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("Given a request for a core plugin's file", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-17 19:04:22 +08:00
										 |  |  | 		service := &fakePluginStore{ | 
					
						
							|  |  |  | 			plugins: map[string]plugins.PluginDTO{ | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 				pluginID: { | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | 					Class: plugins.Core, | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2021-08-09 22:07:54 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-05-06 23:44:22 +08:00
										 |  |  | 		l := &logtest.Fake{} | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		url := fmt.Sprintf("/public/plugins/%s/%s", pluginID, requestedFile) | 
					
						
							|  |  |  | 		pluginAssetScenario(t, "When calling GET on", url, "/public/plugins/:pluginId/*", service, l, | 
					
						
							|  |  |  | 			func(sc *scenarioContext) { | 
					
						
							|  |  |  | 				callGetPluginAsset(sc) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				require.Equal(t, 200, sc.resp.Code) | 
					
						
							|  |  |  | 				assert.Equal(t, expectedBody, sc.resp.Body.String()) | 
					
						
							| 
									
										
										
										
											2022-05-06 23:44:22 +08:00
										 |  |  | 				assert.Zero(t, l.WarnLogs.Calls) | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-09 20:44:38 +08:00
										 |  |  | func TestMakePluginResourceRequest(t *testing.T) { | 
					
						
							|  |  |  | 	pluginClient := &fakePluginClient{} | 
					
						
							|  |  |  | 	hs := HTTPServer{ | 
					
						
							|  |  |  | 		Cfg:          setting.NewCfg(), | 
					
						
							|  |  |  | 		log:          log.New(), | 
					
						
							|  |  |  | 		pluginClient: pluginClient, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	req := httptest.NewRequest(http.MethodGet, "/", nil) | 
					
						
							|  |  |  | 	resp := httptest.NewRecorder() | 
					
						
							|  |  |  | 	pCtx := backend.PluginContext{} | 
					
						
							|  |  |  | 	err := hs.makePluginResourceRequest(resp, req, pCtx) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		if resp.Flushed { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	require.Equal(t, "sandbox", resp.Header().Get("Content-Security-Policy")) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | func callGetPluginAsset(sc *scenarioContext) { | 
					
						
							|  |  |  | 	sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | func pluginAssetScenario(t *testing.T, desc string, url string, urlPattern string, pluginStore plugins.Store, | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 	logger log.Logger, fn scenarioFunc) { | 
					
						
							|  |  |  | 	t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) { | 
					
						
							|  |  |  | 		hs := HTTPServer{ | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | 			Cfg:         setting.NewCfg(), | 
					
						
							|  |  |  | 			pluginStore: pluginStore, | 
					
						
							|  |  |  | 			log:         logger, | 
					
						
							| 
									
										
										
										
											2021-09-08 14:49:05 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		sc := setupScenarioContext(t, url) | 
					
						
							|  |  |  | 		sc.defaultHandler = func(c *models.ReqContext) { | 
					
						
							|  |  |  | 			sc.context = c | 
					
						
							|  |  |  | 			hs.getPluginAssets(c) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		sc.m.Get(urlPattern, sc.defaultHandler) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		fn(sc) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-09 20:44:38 +08:00
										 |  |  | type fakePluginClient struct { | 
					
						
							|  |  |  | 	plugins.Client | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	req *backend.CallResourceRequest | 
					
						
							| 
									
										
										
										
											2022-05-04 00:02:20 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	backend.QueryDataHandlerFunc | 
					
						
							| 
									
										
										
										
											2022-02-09 20:44:38 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-04 00:02:20 +08:00
										 |  |  | func (c *fakePluginClient) CallResource(_ context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { | 
					
						
							| 
									
										
										
										
											2022-02-09 20:44:38 +08:00
										 |  |  | 	c.req = req | 
					
						
							|  |  |  | 	bytes, err := json.Marshal(map[string]interface{}{ | 
					
						
							|  |  |  | 		"message": "hello", | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return sender.Send(&backend.CallResourceResponse{ | 
					
						
							|  |  |  | 		Status:  http.StatusOK, | 
					
						
							|  |  |  | 		Headers: make(map[string][]string), | 
					
						
							|  |  |  | 		Body:    bytes, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-05-04 00:02:20 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func (c *fakePluginClient) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { | 
					
						
							|  |  |  | 	if c.QueryDataHandlerFunc != nil { | 
					
						
							|  |  |  | 		return c.QueryDataHandlerFunc.QueryData(ctx, req) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return backend.NewQueryDataResponse(), nil | 
					
						
							|  |  |  | } |