@@ -4,8 +4,10 @@ import (
4
4
"context"
5
5
"fmt"
6
6
"strconv"
7
+ "strings"
7
8
"testing"
8
9
"time"
10
+ "unicode"
9
11
10
12
"github.com/go-kit/log"
11
13
"github.com/prometheus/prometheus/model/labels"
@@ -27,12 +29,14 @@ func TestMultiTenantQuerier_SelectLogs(t *testing.T) {
27
29
for _ ,tc := range []struct {
28
30
desc string
29
31
orgID string
32
+ selector string
30
33
expLabels []string
31
34
expLines []string
32
35
}{
33
36
{
34
37
"two tenants" ,
35
38
"1|2" ,
39
+ `{type="test"}` ,
36
40
[]string {
37
41
`{__tenant_id__="1", type="test"}` ,
38
42
`{__tenant_id__="1", type="test"}` ,
@@ -41,9 +45,30 @@ func TestMultiTenantQuerier_SelectLogs(t *testing.T) {
41
45
},
42
46
[]string {"line 1" ,"line 2" ,"line 1" ,"line 2" },
43
47
},
48
+ {
49
+ "two tenants with selector" ,
50
+ "1|2" ,
51
+ `{type="test", __tenant_id__="1"}` ,
52
+ []string {
53
+ `{__tenant_id__="1", type="test"}` ,
54
+ `{__tenant_id__="1", type="test"}` ,
55
+ },
56
+ []string {"line 1" ,"line 2" ,"line 1" ,"line 2" },
57
+ },
58
+ {
59
+ "two tenants with selector and pipeline filter" ,
60
+ "1|2" ,
61
+ `{type="test", __tenant_id__!="2"} | logfmt | some_lable="foobar"` ,
62
+ []string {
63
+ `{__tenant_id__="1", type="test"}` ,
64
+ `{__tenant_id__="1", type="test"}` ,
65
+ },
66
+ []string {"line 1" ,"line 2" ,"line 1" ,"line 2" },
67
+ },
44
68
{
45
69
"one tenant" ,
46
70
"1" ,
71
+ `{type="test"}` ,
47
72
[]string {
48
73
`{type="test"}` ,
49
74
`{type="test"}` ,
@@ -59,7 +84,7 @@ func TestMultiTenantQuerier_SelectLogs(t *testing.T) {
59
84
60
85
ctx := user .InjectOrgID (context .Background (),tc .orgID )
61
86
params := logql.SelectLogParams {QueryRequest :& logproto.QueryRequest {
62
- Selector :`{type="test"}` ,
87
+ Selector :tc . selector ,
63
88
Direction :logproto .BACKWARD ,
64
89
Limit :0 ,
65
90
Shards :nil ,
@@ -86,11 +111,13 @@ func TestMultiTenantQuerier_SelectSamples(t *testing.T) {
86
111
for _ ,tc := range []struct {
87
112
desc string
88
113
orgID string
114
+ selector string
89
115
expLabels []string
90
116
}{
91
117
{
92
118
"two tenants" ,
93
119
"1|2" ,
120
+ `count_over_time({foo="bar"}[1m]) > 10` ,
94
121
[]string {
95
122
`{__tenant_id__="1", app="foo"}` ,
96
123
`{__tenant_id__="2", app="foo"}` ,
@@ -102,9 +129,21 @@ func TestMultiTenantQuerier_SelectSamples(t *testing.T) {
102
129
`{__tenant_id__="1", app="bar"}` ,
103
130
},
104
131
},
132
+ {
133
+ "two tenants with selector" ,
134
+ "1|2" ,
135
+ `count_over_time({foo="bar", __tenant_id__="1"}[1m]) > 10` ,
136
+ []string {
137
+ `{__tenant_id__="1", app="foo"}` ,
138
+ `{__tenant_id__="1", app="bar"}` ,
139
+ `{__tenant_id__="1", app="foo"}` ,
140
+ `{__tenant_id__="1", app="bar"}` ,
141
+ },
142
+ },
105
143
{
106
144
"one tenant" ,
107
145
"1" ,
146
+ `count_over_time({foo="bar"}[1m]) > 10` ,
108
147
[]string {
109
148
`{app="foo"}` ,
110
149
`{app="bar"}` ,
@@ -120,16 +159,42 @@ func TestMultiTenantQuerier_SelectSamples(t *testing.T) {
120
159
multiTenantQuerier := NewMultiTenantQuerier (querier ,log .NewNopLogger ())
121
160
122
161
ctx := user .InjectOrgID (context .Background (),tc .orgID )
123
- params := logql.SelectSampleParams {}
162
+ params := logql.SelectSampleParams {SampleQueryRequest :& logproto.SampleQueryRequest {
163
+ Selector :tc .selector ,
164
+ }}
124
165
iter ,err := multiTenantQuerier .SelectSamples (ctx ,params )
125
166
require .NoError (t ,err )
126
167
127
- entriesCount := 0
168
+ received := make ([] string , 0 , len ( tc . expLabels ))
128
169
for iter .Next () {
129
- require .Equalf (t ,tc .expLabels [entriesCount ],iter .Labels (),"Entry %d" ,entriesCount )
130
- entriesCount ++
170
+ received = append (received ,iter .Labels ())
131
171
}
132
- require .Equalf (t ,len (tc .expLabels ),entriesCount ,"Expected %d entries but got %d" ,len (tc .expLabels ),entriesCount )
172
+ require .ElementsMatch (t ,tc .expLabels ,received )
173
+ })
174
+ }
175
+ }
176
+
177
+ func TestMultiTenantQuerier_TenantFilter (t * testing.T ) {
178
+ for _ ,tc := range []struct {
179
+ selector string
180
+ expected string
181
+ }{
182
+ {
183
+ `count_over_time({foo="bar", __tenant_id__="1"}[1m]) > 10` ,
184
+ `(count_over_time({foo="bar"}[1m]) > 10)` ,
185
+ },
186
+ {
187
+ `topk(2, count_over_time({app="foo", __tenant_id__="1"}[3m]))` ,
188
+ `topk(2, count_over_time({app="foo"}[3m]))` ,
189
+ },
190
+ } {
191
+ t .Run (tc .selector ,func (t * testing.T ) {
192
+ params := logql.SelectSampleParams {SampleQueryRequest :& logproto.SampleQueryRequest {
193
+ Selector :tc .selector ,
194
+ }}
195
+ _ ,updatedSelector ,err := removeTenantSelector (params , []string {})
196
+ require .NoError (t ,err )
197
+ require .Equal (t ,removeWhiteSpace (tc .expected ),removeWhiteSpace (updatedSelector .String ()))
133
198
})
134
199
}
135
200
}
@@ -355,3 +420,41 @@ func mockSeriesResponse() *logproto.SeriesResponse {
355
420
},
356
421
}
357
422
}
423
+
424
+ func removeWhiteSpace (s string )string {
425
+ return strings .Map (func (r rune )rune {
426
+ if r == ' ' || unicode .IsSpace (r ) {
427
+ return - 1
428
+ }
429
+ return r
430
+ },s )
431
+ }
432
+
433
+ func TestSliceToSet (t * testing.T ) {
434
+ for _ ,tc := range []struct {
435
+ desc string
436
+ slice []string
437
+ expected map [string ]struct {}
438
+ }{
439
+ {
440
+ desc :"empty slice" ,
441
+ slice : []string {},
442
+ expected :map [string ]struct {}{},
443
+ },
444
+ {
445
+ desc :"single element" ,
446
+ slice : []string {"a" },
447
+ expected :map [string ]struct {}{"a" : {}},
448
+ },
449
+ {
450
+ desc :"multiple elements" ,
451
+ slice : []string {"a" ,"b" ,"c" },
452
+ expected :map [string ]struct {}{"a" : {},"b" : {},"c" : {}},
453
+ },
454
+ } {
455
+ t .Run (tc .desc ,func (t * testing.T ) {
456
+ actual := sliceToSet (tc .slice )
457
+ require .Equal (t ,tc .expected ,actual )
458
+ })
459
+ }
460
+ }