mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
				
	
	
		
			181 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			181 lines
		
	
	
		
			5.9 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
 | |
| 
 | |
| // If you need to adjust the snapshots, go to Line 172 and change
 | |
| // `experimental.CheckGoldenJSONResponse(t, "testdata_response", goldenFileName, &dataResCopy, false)` to `experimental.CheckGoldenJSONResponse(t, "testdata_response", goldenFileName, &dataResCopy, true)`
 | |
| // then run the test once to generate the new snapshots.
 | |
| 
 | |
| // 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"},
 | |
| 		{name: "raw data test", path: "raw_data"},
 | |
| 		{name: "raw document test", path: "raw_document"},
 | |
| 		{name: "logs test", path: "logs"},
 | |
| 	}
 | |
| 
 | |
| 	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"},
 | |
| 		{name: "metric avg test", path: "metric_avg"},
 | |
| 		{name: "metric percentiles test", path: "metric_percentiles"},
 | |
| 		{name: "metric top_metrics test", path: "metric_top_metrics"},
 | |
| 		{name: "metric extended_stats test", path: "metric_extended_stats"},
 | |
| 		{name: "raw data test", path: "raw_data"},
 | |
| 		{name: "logs test", path: "logs"},
 | |
| 	}
 | |
| 
 | |
| 	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, strings.ToLower(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)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 |