github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/logcli/client/file_test.go (about) 1 package client 2 3 import ( 4 "bytes" 5 "errors" 6 "io" 7 "sort" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/grafana/loki/pkg/loghttp" 13 "github.com/grafana/loki/pkg/logproto" 14 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 ) 18 19 func TestFileClient_QueryRangeLogQueries(t *testing.T) { 20 input := []string{ 21 `level=info event="loki started" caller=main.go ts=1625995076`, 22 `level=info event="runtime loader started" caller=main.go ts=1625995077`, 23 `level=error event="unable to read rules directory" file="/tmp/rules" caller=rules.go ts=1625995090`, 24 `level=error event="failed to apply wal" error="/tmp/wal/ corrupted" caller=wal.go ts=1625996090`, 25 `level=info event="loki ready" caller=main.go ts=1625996095`, 26 } 27 28 reversed := make([]string, len(input)) 29 copy(reversed, input) 30 sort.Slice(reversed, func(i, j int) bool { 31 return i > j 32 }) 33 34 now := time.Now() 35 36 cases := []struct { 37 name string 38 limit int 39 start, end time.Time 40 direction logproto.Direction 41 step, interval time.Duration 42 expectedStatus loghttp.QueryStatus 43 expected []string 44 }{ 45 { 46 name: "return-all-logs-backward", 47 limit: 10, // more than input 48 start: now.Add(-1 * time.Hour), 49 end: now, 50 direction: logproto.BACKWARD, 51 step: 0, // let client decide based on start and end 52 interval: 0, 53 expectedStatus: loghttp.QueryStatusSuccess, 54 expected: reversed, 55 }, 56 { 57 name: "return-all-logs-forward", 58 limit: 10, // more than input 59 start: now.Add(-1 * time.Hour), 60 end: now, 61 direction: logproto.FORWARD, 62 step: 0, // let the client decide based on start and end 63 interval: 0, 64 expectedStatus: loghttp.QueryStatusSuccess, 65 expected: input, 66 }, 67 } 68 69 for _, c := range cases { 70 t.Run(c.name, func(t *testing.T) { 71 client := NewFileClient(io.NopCloser(strings.NewReader(strings.Join(input, "\n")))) 72 resp, err := client.QueryRange( 73 `{foo="bar"}`, // label matcher doesn't matter. 74 c.limit, 75 c.start, 76 c.end, 77 c.direction, 78 c.step, 79 c.interval, 80 true, 81 ) 82 83 require.NoError(t, err) 84 require.Equal(t, loghttp.QueryStatusSuccess, resp.Status) 85 assert.Equal(t, string(resp.Data.ResultType), loghttp.ResultTypeStream) 86 assertStreams(t, resp.Data.Result, c.expected) 87 }) 88 } 89 } 90 91 func TestFileClient_Query(t *testing.T) { 92 input := []string{ 93 `level=info event="loki started" caller=main.go ts=1625995076`, 94 `level=info event="runtime loader started" caller=main.go ts=1625995077`, 95 `level=error event="unable to read rules directory" file="/tmp/rules" caller=rules.go ts=1625995090`, 96 `level=error event="failed to apply wal" error="/tmp/wal/ corrupted" caller=wal.go ts=1625996090`, 97 `level=info event="loki ready" caller=main.go ts=1625996095`, 98 } 99 100 reversed := make([]string, len(input)) 101 copy(reversed, input) 102 sort.Slice(reversed, func(i, j int) bool { 103 return i > j 104 }) 105 106 now := time.Now() 107 108 cases := []struct { 109 name string 110 limit int 111 ts time.Time 112 direction logproto.Direction 113 expectedStatus loghttp.QueryStatus 114 expected []string 115 }{ 116 { 117 name: "return-all-logs-backward", 118 limit: 10, // more than input 119 ts: now.Add(-1 * time.Hour), 120 direction: logproto.BACKWARD, 121 expectedStatus: loghttp.QueryStatusSuccess, 122 expected: reversed, 123 }, 124 { 125 name: "return-all-logs-forward", 126 limit: 10, // more than input 127 ts: now.Add(-1 * time.Hour), 128 direction: logproto.FORWARD, 129 expectedStatus: loghttp.QueryStatusSuccess, 130 expected: input, 131 }, 132 } 133 134 for _, c := range cases { 135 t.Run(c.name, func(t *testing.T) { 136 client := NewFileClient(io.NopCloser(strings.NewReader(strings.Join(input, "\n")))) 137 resp, err := client.Query( 138 `{foo="bar"}`, // label matcher doesn't matter. 139 c.limit, 140 c.ts, 141 c.direction, 142 true, 143 ) 144 145 require.NoError(t, err) 146 require.Equal(t, loghttp.QueryStatusSuccess, resp.Status) 147 assert.Equal(t, string(resp.Data.ResultType), loghttp.ResultTypeStream) 148 assertStreams(t, resp.Data.Result, c.expected) 149 }) 150 } 151 } 152 153 func TestFileClient_ListLabelNames(t *testing.T) { 154 c := newEmptyClient(t) 155 values, err := c.ListLabelNames(true, time.Now(), time.Now()) 156 require.NoError(t, err) 157 assert.Equal(t, &loghttp.LabelResponse{ 158 Data: []string{defaultLabelKey}, 159 Status: loghttp.QueryStatusSuccess, 160 }, values) 161 } 162 163 func TestFileClient_ListLabelValues(t *testing.T) { 164 c := newEmptyClient(t) 165 values, err := c.ListLabelValues(defaultLabelKey, true, time.Now(), time.Now()) 166 require.NoError(t, err) 167 assert.Equal(t, &loghttp.LabelResponse{ 168 Data: []string{defaultLabelValue}, 169 Status: loghttp.QueryStatusSuccess, 170 }, values) 171 172 } 173 174 func TestFileClient_Series(t *testing.T) { 175 c := newEmptyClient(t) 176 got, err := c.Series(nil, time.Now(), time.Now(), true) 177 require.NoError(t, err) 178 179 exp := &loghttp.SeriesResponse{ 180 Data: []loghttp.LabelSet{ 181 {defaultLabelKey: defaultLabelValue}, 182 }, 183 Status: loghttp.QueryStatusSuccess, 184 } 185 186 assert.Equal(t, exp, got) 187 } 188 189 func TestFileClient_LiveTail(t *testing.T) { 190 c := newEmptyClient(t) 191 x, err := c.LiveTailQueryConn("", time.Second, 0, time.Now(), true) 192 require.Error(t, err) 193 require.Nil(t, x) 194 assert.True(t, errors.Is(err, ErrNotSupported)) 195 } 196 197 func TestFileClient_GetOrgID(t *testing.T) { 198 c := newEmptyClient(t) 199 assert.Equal(t, defaultOrgID, c.GetOrgID()) 200 } 201 202 func newEmptyClient(t *testing.T) *FileClient { 203 t.Helper() 204 return NewFileClient(io.NopCloser(&bytes.Buffer{})) 205 } 206 207 func assertStreams(t *testing.T, result loghttp.ResultValue, logLines []string) { 208 t.Helper() 209 210 streams, ok := result.(loghttp.Streams) 211 require.True(t, ok, "response type should be `loghttp.Streams`") 212 213 require.Len(t, streams, 1, "there should be only one stream for FileClient") 214 215 got := streams[0] 216 sort.Slice(got.Entries, func(i, j int) bool { 217 return got.Entries[i].Timestamp.UnixNano() < got.Entries[j].Timestamp.UnixNano() 218 }) 219 require.Equal(t, len(got.Entries), len(logLines)) 220 for i, entry := range got.Entries { 221 assert.Equal(t, entry.Line, logLines[i]) 222 } 223 }