github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/util/marshal/legacy/marshal_test.go (about)

     1  package marshal
     2  
     3  import (
     4  	"bytes"
     5  	"log"
     6  	"testing"
     7  	"time"
     8  
     9  	json "github.com/json-iterator/go"
    10  	"github.com/stretchr/testify/require"
    11  
    12  	loghttp "github.com/grafana/loki/pkg/loghttp/legacy"
    13  	"github.com/grafana/loki/pkg/logproto"
    14  	"github.com/grafana/loki/pkg/logqlmodel"
    15  )
    16  
    17  // covers responses from /api/prom/query
    18  var queryTests = []struct {
    19  	actual   logqlmodel.Streams
    20  	expected string
    21  }{
    22  	{
    23  		logqlmodel.Streams{
    24  			logproto.Stream{
    25  				Entries: []logproto.Entry{
    26  					{
    27  						Timestamp: mustParse(time.RFC3339Nano, "2019-09-13T18:32:22.380001319Z"),
    28  						Line:      "super line",
    29  					},
    30  				},
    31  				Labels: `{test="test"}`,
    32  			},
    33  		},
    34  		`{
    35  			"streams":[
    36  				{
    37  					"labels":"{test=\"test\"}",
    38  					"entries":[
    39  						{
    40  							"ts": "2019-09-13T18:32:22.380001319Z",
    41  							"line": "super line"
    42  						}
    43  					]
    44  				}
    45  			],
    46  			"stats" : {
    47  				"ingester" : {
    48  					"store": {
    49  						"chunksDownloadTime": 0,
    50  						"totalChunksRef": 0,
    51  						"totalChunksDownloaded": 0,
    52  						"chunk" :{
    53  							"compressedBytes": 0,
    54  							"decompressedBytes": 0,
    55  							"decompressedLines": 0,
    56  							"headChunkBytes": 0,
    57  							"headChunkLines": 0,
    58  							"totalDuplicates": 0
    59  						}
    60  					},
    61  					"totalBatches": 0,
    62  					"totalChunksMatched": 0,
    63  					"totalLinesSent": 0,
    64  					"totalReached": 0
    65  				},
    66  				"querier": {
    67  					"store": {
    68  						"chunksDownloadTime": 0,
    69  						"totalChunksRef": 0,
    70  						"totalChunksDownloaded": 0,
    71  						"chunk" :{
    72  							"compressedBytes": 0,
    73  							"decompressedBytes": 0,
    74  							"decompressedLines": 0,
    75  							"headChunkBytes": 0,
    76  							"headChunkLines": 0,
    77  							"totalDuplicates": 0
    78  						}
    79  					}
    80  				},
    81  				"cache": {
    82  					"chunk": {
    83  						"entriesFound": 0,
    84  						"entriesRequested": 0,
    85  						"entriesStored": 0,
    86  						"bytesReceived": 0,
    87  						"bytesSent": 0,
    88  						"requests": 0
    89  					},
    90  					"index": {
    91  						"entriesFound": 0,
    92  						"entriesRequested": 0,
    93  						"entriesStored": 0,
    94  						"bytesReceived": 0,
    95  						"bytesSent": 0,
    96  						"requests": 0
    97  					},
    98  					"result": {
    99  						"entriesFound": 0,
   100  						"entriesRequested": 0,
   101  						"entriesStored": 0,
   102  						"bytesReceived": 0,
   103  						"bytesSent": 0,
   104  						"requests": 0
   105  					}
   106  				},
   107  				"summary": {
   108  					"bytesProcessedPerSecond": 0,
   109  					"execTime": 0,
   110  					"linesProcessedPerSecond": 0,
   111  					"queueTime": 0,
   112  					"subqueries": 0,
   113  					"totalBytesProcessed":0,
   114                                          "totalEntriesReturned":0,
   115  					"totalLinesProcessed":0
   116  				}
   117  			}
   118  		}`,
   119  	},
   120  }
   121  
   122  // covers responses from /api/prom/label and /api/prom/label/{name}/values
   123  var labelTests = []struct {
   124  	actual   logproto.LabelResponse
   125  	expected string
   126  }{
   127  	{
   128  		logproto.LabelResponse{
   129  			Values: []string{
   130  				"label1",
   131  				"test",
   132  				"value",
   133  			},
   134  		},
   135  		`{"values": ["label1", "test", "value"]}`,
   136  	},
   137  }
   138  
   139  // covers responses from /api/prom/tail and /api/prom/tail
   140  var tailTests = []struct {
   141  	actual   loghttp.TailResponse
   142  	expected string
   143  }{
   144  	{
   145  		loghttp.TailResponse{
   146  			Streams: []logproto.Stream{
   147  				{
   148  					Entries: []logproto.Entry{
   149  						{
   150  							Timestamp: mustParse(time.RFC3339Nano, "2019-09-13T18:32:22.380001319Z"),
   151  							Line:      "super line",
   152  						},
   153  					},
   154  					Labels: "{test=\"test\"}",
   155  				},
   156  			},
   157  			DroppedEntries: []loghttp.DroppedEntry{
   158  				{
   159  					Timestamp: mustParse(time.RFC3339Nano, "2019-09-13T18:32:22.380001319Z"),
   160  					Labels:    "{test=\"test\"}",
   161  				},
   162  			},
   163  		},
   164  		`{
   165  			"streams": [
   166  				{
   167  					"labels": "{test=\"test\"}",
   168  					"entries": [
   169  						{
   170  							"ts": "2019-09-13T18:32:22.380001319Z",
   171  							"line": "super line"
   172  						}
   173  					]
   174  				}
   175  			],
   176  			"dropped_entries": [
   177  				{
   178  					"Timestamp": "2019-09-13T18:32:22.380001319Z",
   179  					"Labels": "{test=\"test\"}"
   180  				}
   181  			]
   182  		}`,
   183  	},
   184  }
   185  
   186  func Test_WriteQueryResponseJSON(t *testing.T) {
   187  	for i, queryTest := range queryTests {
   188  		var b bytes.Buffer
   189  		err := WriteQueryResponseJSON(logqlmodel.Result{Data: queryTest.actual}, &b)
   190  		require.NoError(t, err)
   191  
   192  		testJSONBytesEqual(t, []byte(queryTest.expected), b.Bytes(), "Query Test %d failed", i)
   193  	}
   194  }
   195  
   196  func Test_WriteLabelResponseJSON(t *testing.T) {
   197  	for i, labelTest := range labelTests {
   198  		var b bytes.Buffer
   199  		err := WriteLabelResponseJSON(labelTest.actual, &b)
   200  		require.NoError(t, err)
   201  
   202  		testJSONBytesEqual(t, []byte(labelTest.expected), b.Bytes(), "Label Test %d failed", i)
   203  	}
   204  }
   205  
   206  func Test_MarshalTailResponse(t *testing.T) {
   207  	for i, tailTest := range tailTests {
   208  		// marshal model object
   209  		bytes, err := json.Marshal(tailTest.actual)
   210  		require.NoError(t, err)
   211  
   212  		testJSONBytesEqual(t, []byte(tailTest.expected), bytes, "Tail Test %d failed", i)
   213  	}
   214  }
   215  
   216  func Test_QueryResponseMarshalLoop(t *testing.T) {
   217  	for i, queryTest := range queryTests {
   218  		var r map[string]interface{}
   219  
   220  		err := json.Unmarshal([]byte(queryTest.expected), &r)
   221  		require.NoError(t, err)
   222  
   223  		jsonOut, err := json.Marshal(r)
   224  		require.NoError(t, err)
   225  
   226  		testJSONBytesEqual(t, []byte(queryTest.expected), jsonOut, "Query Marshal Loop %d failed", i)
   227  	}
   228  }
   229  
   230  func Test_LabelResponseMarshalLoop(t *testing.T) {
   231  	for i, labelTest := range labelTests {
   232  		var r loghttp.LabelResponse
   233  
   234  		err := json.Unmarshal([]byte(labelTest.expected), &r)
   235  		require.NoError(t, err)
   236  
   237  		jsonOut, err := json.Marshal(r)
   238  		require.NoError(t, err)
   239  
   240  		testJSONBytesEqual(t, []byte(labelTest.expected), jsonOut, "Label Marshal Loop %d failed", i)
   241  	}
   242  }
   243  
   244  func Test_TailResponseMarshalLoop(t *testing.T) {
   245  	for i, tailTest := range tailTests {
   246  		var r loghttp.TailResponse
   247  
   248  		err := json.Unmarshal([]byte(tailTest.expected), &r)
   249  		require.NoError(t, err)
   250  
   251  		jsonOut, err := json.Marshal(r)
   252  		require.NoError(t, err)
   253  
   254  		testJSONBytesEqual(t, []byte(tailTest.expected), jsonOut, "Tail Marshal Loop %d failed", i)
   255  	}
   256  }
   257  
   258  func testJSONBytesEqual(t *testing.T, expected []byte, actual []byte, msg string, args ...interface{}) {
   259  	var expectedValue map[string]interface{}
   260  	err := json.Unmarshal(expected, &expectedValue)
   261  	require.NoError(t, err)
   262  
   263  	var actualValue map[string]interface{}
   264  	err = json.Unmarshal(actual, &actualValue)
   265  	require.NoError(t, err)
   266  
   267  	require.Equalf(t, expectedValue, actualValue, msg, args)
   268  }
   269  
   270  func mustParse(l string, t string) time.Time {
   271  	ret, err := time.Parse(l, t)
   272  	if err != nil {
   273  		log.Fatalf("Failed to parse %s", t)
   274  	}
   275  
   276  	return ret
   277  }