Skip to content

Commit 95add0e

Browse files
committed
test(matcher): cover multi-value matching and missing-key regressions
1 parent 1acb8ab commit 95add0e

1 file changed

Lines changed: 93 additions & 12 deletions

File tree

matcher_test.go

Lines changed: 93 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,34 @@ func TestQueryMatcher_Match(t *testing.T) {
4747
url: "/path",
4848
want: false,
4949
},
50+
{
51+
name: "match second value of multi-value",
52+
key: "foo",
53+
value: "b",
54+
url: "/path?foo=a&foo=b",
55+
want: true,
56+
},
57+
{
58+
name: "no match across multi-value",
59+
key: "foo",
60+
value: "c",
61+
url: "/path?foo=a&foo=b",
62+
want: false,
63+
},
64+
{
65+
name: "no match empty value with missing key",
66+
key: "foo",
67+
value: "",
68+
url: "/path",
69+
want: false,
70+
},
71+
{
72+
name: "match empty value with present empty value",
73+
key: "foo",
74+
value: "",
75+
url: "/path?foo=",
76+
want: true,
77+
},
5078
}
5179

5280
for _, tc := range cases {
@@ -129,6 +157,27 @@ func TestQueryRegexpMatcher_Match(t *testing.T) {
129157
url: "/path?other=123",
130158
want: false,
131159
},
160+
{
161+
name: "match second value of multi-value",
162+
key: "id",
163+
pattern: `^\d+$`,
164+
url: "/path?id=abc&id=123",
165+
want: true,
166+
},
167+
{
168+
name: "no match across multi-value",
169+
key: "id",
170+
pattern: `^\d+$`,
171+
url: "/path?id=abc&id=def",
172+
want: false,
173+
},
174+
{
175+
name: "no match permissive regex with missing key",
176+
key: "id",
177+
pattern: `^.*$`,
178+
url: "/path",
179+
want: false,
180+
},
132181
}
133182

134183
for _, tc := range cases {
@@ -187,28 +236,28 @@ func TestHeaderMatcher_Match(t *testing.T) {
187236
name string
188237
headerKey string
189238
value string
190-
headers map[string]string
239+
headers map[string][]string
191240
want bool
192241
}{
193242
{
194243
name: "match header",
195244
headerKey: "Content-Type",
196245
value: "application/json",
197-
headers: map[string]string{"Content-Type": "application/json"},
246+
headers: map[string][]string{"Content-Type": {"application/json"}},
198247
want: true,
199248
},
200249
{
201250
name: "no match different value",
202251
headerKey: "Content-Type",
203252
value: "application/json",
204-
headers: map[string]string{"Content-Type": "text/plain"},
253+
headers: map[string][]string{"Content-Type": {"text/plain"}},
205254
want: false,
206255
},
207256
{
208257
name: "no match missing header",
209258
headerKey: "Content-Type",
210259
value: "application/json",
211-
headers: map[string]string{"Accept": "application/json"},
260+
headers: map[string][]string{"Accept": {"application/json"}},
212261
want: false,
213262
},
214263
{
@@ -218,14 +267,30 @@ func TestHeaderMatcher_Match(t *testing.T) {
218267
headers: nil,
219268
want: false,
220269
},
270+
{
271+
name: "match second value of multi-value",
272+
headerKey: "Content-Type",
273+
value: "application/json",
274+
headers: map[string][]string{"Content-Type": {"text/plain", "application/json"}},
275+
want: true,
276+
},
277+
{
278+
name: "no match across multi-value",
279+
headerKey: "Content-Type",
280+
value: "application/json",
281+
headers: map[string][]string{"Content-Type": {"text/plain", "text/html"}},
282+
want: false,
283+
},
221284
}
222285

223286
for _, tc := range cases {
224287
t.Run(tc.name, func(t *testing.T) {
225288
m := HeaderMatcher{canonicalKey: http.CanonicalHeaderKey(tc.headerKey), value: tc.value}
226289
req := httptest.NewRequest(http.MethodGet, "/path", nil)
227-
for k, v := range tc.headers {
228-
req.Header.Set(k, v)
290+
for k, vs := range tc.headers {
291+
for _, v := range vs {
292+
req.Header.Add(k, v)
293+
}
229294
}
230295
w := httptest.NewRecorder()
231296
c := NewTestContextOnly(w, req)
@@ -279,28 +344,42 @@ func TestHeaderRegexpMatcher_Match(t *testing.T) {
279344
name string
280345
headerKey string
281346
pattern string
282-
headers map[string]string
347+
headers map[string][]string
283348
want bool
284349
}{
285350
{
286351
name: "match regex",
287352
headerKey: "Content-Type",
288353
pattern: `^application/.*`,
289-
headers: map[string]string{"Content-Type": "application/json"},
354+
headers: map[string][]string{"Content-Type": {"application/json"}},
290355
want: true,
291356
},
292357
{
293358
name: "no match regex",
294359
headerKey: "Content-Type",
295360
pattern: `^application/.*`,
296-
headers: map[string]string{"Content-Type": "text/plain"},
361+
headers: map[string][]string{"Content-Type": {"text/plain"}},
297362
want: false,
298363
},
299364
{
300365
name: "missing header",
301366
headerKey: "Content-Type",
302367
pattern: `^application/.*`,
303-
headers: map[string]string{"Accept": "application/json"},
368+
headers: map[string][]string{"Accept": {"application/json"}},
369+
want: false,
370+
},
371+
{
372+
name: "match second value of multi-value",
373+
headerKey: "Content-Type",
374+
pattern: `^application/.*`,
375+
headers: map[string][]string{"Content-Type": {"text/plain", "application/json"}},
376+
want: true,
377+
},
378+
{
379+
name: "no match across multi-value",
380+
headerKey: "Content-Type",
381+
pattern: `^application/.*`,
382+
headers: map[string][]string{"Content-Type": {"text/plain", "text/html"}},
304383
want: false,
305384
},
306385
}
@@ -309,8 +388,10 @@ func TestHeaderRegexpMatcher_Match(t *testing.T) {
309388
t.Run(tc.name, func(t *testing.T) {
310389
m := HeaderRegexpMatcher{canonicalKey: http.CanonicalHeaderKey(tc.headerKey), regex: regexp.MustCompile(tc.pattern)}
311390
req := httptest.NewRequest(http.MethodGet, "/path", nil)
312-
for k, v := range tc.headers {
313-
req.Header.Set(k, v)
391+
for k, vs := range tc.headers {
392+
for _, v := range vs {
393+
req.Header.Add(k, v)
394+
}
314395
}
315396
w := httptest.NewRecorder()
316397
c := NewTestContextOnly(w, req)

0 commit comments

Comments
 (0)