mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
	
	
		
			168 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Go
		
	
	
	
		
		
			
		
	
	
			168 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Go
		
	
	
	
|  | package elasticsearch | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"fmt" | ||
|  | 	"os" | ||
|  | 	"path/filepath" | ||
|  | 	"regexp" | ||
|  | 	"strings" | ||
|  | 	"testing" | ||
|  | 
 | ||
|  | 	"github.com/grafana/grafana-plugin-sdk-go/experimental" | ||
|  | 	"github.com/stretchr/testify/require" | ||
|  | ) | ||
|  | 
 | ||
|  | // these snapshot-tests test the whole request-response flow:
 | ||
|  | // the inputs:
 | ||
|  | // - the backend.DataQuery query
 | ||
|  | // - the elastic-response json
 | ||
|  | // the snapshot verifies:
 | ||
|  | // - the elastic-request json
 | ||
|  | // - the dataframe result
 | ||
|  | 
 | ||
|  | // a regex that matches the request-snapshot-filenames, and extracts the name of the test
 | ||
|  | var requestRe = regexp.MustCompile(`^(.*)\.request\.line\d+\.json$`) | ||
|  | 
 | ||
|  | // the "elastic request" is often in multiple json-snapshot-files,
 | ||
|  | // so we have to find them on disk, so we have to look at every file in
 | ||
|  | // the folder.
 | ||
|  | func findRequestSnapshots(t *testing.T, folder string) map[string][]string { | ||
|  | 	allTestSnapshotFiles, err := os.ReadDir(folder) | ||
|  | 	require.NoError(t, err) | ||
|  | 
 | ||
|  | 	snapshots := make(map[string][]string) | ||
|  | 
 | ||
|  | 	for _, file := range allTestSnapshotFiles { | ||
|  | 		fileName := file.Name() | ||
|  | 		match := requestRe.FindStringSubmatch(fileName) | ||
|  | 		if len(match) == 2 { | ||
|  | 			testName := match[1] | ||
|  | 			files := append(snapshots[testName], filepath.Join(folder, fileName)) | ||
|  | 			snapshots[testName] = files | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return snapshots | ||
|  | } | ||
|  | 
 | ||
|  | // a regex that matches the response-snapshot-filenames, and extracts the name of the test
 | ||
|  | var responseRe = regexp.MustCompile(`^([^\.]+)\.[^\.]+.golden.jsonc$`) | ||
|  | 
 | ||
|  | func findResponseSnapshotCounts(t *testing.T, folder string) map[string]int { | ||
|  | 	allTestSnapshotFiles, err := os.ReadDir(folder) | ||
|  | 	require.NoError(t, err) | ||
|  | 
 | ||
|  | 	snapshots := make(map[string]int) | ||
|  | 
 | ||
|  | 	for _, file := range allTestSnapshotFiles { | ||
|  | 		fileName := file.Name() | ||
|  | 		match := responseRe.FindStringSubmatch(fileName) | ||
|  | 		if len(match) == 2 { | ||
|  | 			testName := match[1] | ||
|  | 			snapshots[testName] = snapshots[testName] + 1 | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return snapshots | ||
|  | } | ||
|  | 
 | ||
|  | func TestRequestSnapshots(t *testing.T) { | ||
|  | 	tt := []struct { | ||
|  | 		name string | ||
|  | 		path string | ||
|  | 	}{ | ||
|  | 		{name: "simple metric test", path: "metric_simple"}, | ||
|  | 		{name: "complex metric test", path: "metric_complex"}, | ||
|  | 		{name: "multi metric test", path: "metric_multi"}, | ||
|  | 	} | ||
|  | 
 | ||
|  | 	queryHeader := []byte(` | ||
|  | 	{ | ||
|  | 		"ignore_unavailable": true, | ||
|  | 		"index": "testdb-2022.11.14", | ||
|  | 		"search_type": "query_then_fetch" | ||
|  | 	} | ||
|  | 	`) | ||
|  | 
 | ||
|  | 	requestSnapshots := findRequestSnapshots(t, "testdata_request") | ||
|  | 
 | ||
|  | 	for _, test := range tt { | ||
|  | 		t.Run(test.name, func(t *testing.T) { | ||
|  | 			responseBytes := []byte(`{"responses":[]}`) | ||
|  | 
 | ||
|  | 			queriesFileName := filepath.Join("testdata_request", test.path+".queries.json") | ||
|  | 			queriesBytes, err := os.ReadFile(filepath.Clean(queriesFileName)) | ||
|  | 			require.NoError(t, err) | ||
|  | 
 | ||
|  | 			var requestLines [][]byte | ||
|  | 
 | ||
|  | 			for _, fileName := range requestSnapshots[test.path] { | ||
|  | 				bytes, err := os.ReadFile(filepath.Clean(fileName)) | ||
|  | 				require.NoError(t, err) | ||
|  | 				requestLines = append(requestLines, bytes) | ||
|  | 			} | ||
|  | 
 | ||
|  | 			require.True(t, len(requestLines) > 0, "requestLines must not be empty") | ||
|  | 
 | ||
|  | 			result, err := queryDataTest(queriesBytes, responseBytes) | ||
|  | 			require.NoError(t, err) | ||
|  | 
 | ||
|  | 			reqLines := strings.Split(strings.TrimSpace(string(result.requestBytes)), "\n") | ||
|  | 			require.Len(t, reqLines, len(requestLines)*2) | ||
|  | 
 | ||
|  | 			for i, expectedRequestLine := range requestLines { | ||
|  | 				actualRequestHeaderLine := reqLines[2*i] | ||
|  | 				actualRequestLine := reqLines[2*i+1] | ||
|  | 				require.JSONEq(t, string(queryHeader), actualRequestHeaderLine, fmt.Sprintf("invalid request-header at index: %v", i)) | ||
|  | 				require.JSONEq(t, string(expectedRequestLine), actualRequestLine, fmt.Sprintf("invalid request at index: %v", i)) | ||
|  | 			} | ||
|  | 		}) | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | func TestResponseSnapshots(t *testing.T) { | ||
|  | 	tt := []struct { | ||
|  | 		name string | ||
|  | 		path string | ||
|  | 	}{ | ||
|  | 		{name: "simple metric test", path: "metric_simple"}, | ||
|  | 		{name: "complex metric test", path: "metric_complex"}, | ||
|  | 		{name: "multi metric test", path: "metric_multi"}, | ||
|  | 	} | ||
|  | 
 | ||
|  | 	snapshotCount := findResponseSnapshotCounts(t, "testdata_response") | ||
|  | 
 | ||
|  | 	for _, test := range tt { | ||
|  | 		t.Run(test.name, func(t *testing.T) { | ||
|  | 			responseFileName := filepath.Join("testdata_response", test.path+".response.json") | ||
|  | 			responseBytes, err := os.ReadFile(filepath.Clean(responseFileName)) | ||
|  | 			require.NoError(t, err) | ||
|  | 
 | ||
|  | 			queriesFileName := filepath.Join("testdata_response", test.path+".queries.json") | ||
|  | 			queriesBytes, err := os.ReadFile(filepath.Clean(queriesFileName)) | ||
|  | 			require.NoError(t, err) | ||
|  | 
 | ||
|  | 			result, err := queryDataTest(queriesBytes, responseBytes) | ||
|  | 			require.NoError(t, err) | ||
|  | 
 | ||
|  | 			// first we need to test that the number of items in `result.response.Responses`,
 | ||
|  | 			// is exactly the same as the count of our response snapshot files
 | ||
|  | 			// (this is so that we avoid situations where we provide more snapshot-files than
 | ||
|  | 			// what is returned)
 | ||
|  | 
 | ||
|  | 			expectedResponseCount := snapshotCount[test.path] | ||
|  | 			require.True(t, expectedResponseCount > 0, "response snapshots not found") | ||
|  | 
 | ||
|  | 			require.Len(t, result.response.Responses, expectedResponseCount) | ||
|  | 
 | ||
|  | 			for refId, dataRes := range result.response.Responses { | ||
|  | 				goldenFileName := fmt.Sprintf("%v.%v.golden", test.path, refId) | ||
|  | 				// we make a copy of the variable to avoid this linter-warning:
 | ||
|  | 				// "G601: Implicit memory aliasing in for loop."
 | ||
|  | 				dataResCopy := dataRes | ||
|  | 				experimental.CheckGoldenJSONResponse(t, "testdata_response", goldenFileName, &dataResCopy, false) | ||
|  | 			} | ||
|  | 		}) | ||
|  | 	} | ||
|  | } |