blob: b8a0c30f24a7fe2d743528b4d64c33c1148b7b9f [file] [log] [blame]
package query
import (
"fmt"
"net/url"
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"go.skia.org/infra/go/paramtools"
"go.skia.org/infra/go/testutils"
)
func TestValidateKey(t *testing.T) {
testutils.SmallTest(t)
testCases := []struct {
key string
valid bool
reason string
}{
{
key: ",arch=x86,config=565,",
valid: true,
reason: "",
},
{
key: "arch=x86,config=565,",
valid: false,
reason: "No comma at beginning.",
},
{
key: ",arch=x86,config=565",
valid: false,
reason: "No comma at end.",
},
{
key: ",arch=x86,",
valid: true,
reason: "Short is fine.",
},
{
key: "",
valid: false,
reason: "Empty is invalid.",
},
{
key: ",config=565,arch=x86,",
valid: false,
reason: "Unsorted.",
},
{
key: ",config=565,config=8888,",
valid: false,
reason: "Duplicate param names.",
},
{
key: ",arch=x85,config=565,config=8888,",
valid: false,
reason: "Duplicate param names.",
},
{
key: ",arch=x85,archer=x85,",
valid: true,
reason: "Param name prefix of another param name.",
},
{
key: ",,",
valid: false,
reason: "Degenerate case.",
},
}
for _, tc := range testCases {
if got, want := ValidateKey(tc.key), tc.valid; got != want {
t.Errorf("Failed validation for %q. Got %v Want %v. %s", tc.key, got, want, tc.reason)
}
}
}
func TestMakeKey(t *testing.T) {
testutils.SmallTest(t)
testCases := []struct {
m map[string]string
key string
valid bool
reason string
}{
{
m: map[string]string{"arch": "x86", "config": "565"},
key: ",arch=x86,config=565,",
valid: true,
reason: "",
},
{
m: map[string]string{"arch": "x86", "archer": "x86"},
key: ",arch=x86,archer=x86,",
valid: true,
reason: "",
},
{
m: map[string]string{"bad,key": "x86"},
key: "",
valid: false,
reason: "Bad key.",
},
{
m: map[string]string{"key": "bad,value"},
key: "",
valid: false,
reason: "Bad value.",
},
{
m: map[string]string{},
key: "",
valid: false,
reason: "Empty map is invalid.",
},
}
for _, tc := range testCases {
key, err := MakeKey(tc.m)
if tc.valid && err != nil {
t.Errorf("Failed to make key for %#v: %s", tc.m, err)
}
if key != tc.key {
t.Errorf("Failed to make key for %#v. Got %q Want %q. %s", tc.m, key, tc.key, tc.reason)
}
}
}
func TestNew(t *testing.T) {
testutils.SmallTest(t)
q, err := New(url.Values{"config": []string{"565", "8888"}})
assert.NoError(t, err)
assert.Equal(t, 1, len(q.params))
assert.Equal(t, false, q.params[0].isWildCard)
q, err = New(url.Values{"debug": []string{"false"}, "config": []string{"565", "8888"}})
assert.NoError(t, err)
assert.Equal(t, 2, len(q.params))
assert.Equal(t, ",config=", q.params[0].keyMatch)
assert.Equal(t, ",debug=", q.params[1].keyMatch)
assert.Equal(t, false, q.params[0].isWildCard)
assert.Equal(t, false, q.params[1].isWildCard)
assert.Equal(t, false, q.params[0].isNegative)
assert.Equal(t, false, q.params[1].isNegative)
q, err = New(url.Values{"debug": []string{"*"}})
assert.NoError(t, err)
assert.Equal(t, 1, len(q.params))
assert.Equal(t, ",debug=", q.params[0].keyMatch)
assert.Equal(t, true, q.params[0].isWildCard)
assert.Equal(t, false, q.params[0].isNegative)
q, err = New(url.Values{"config": []string{"!565"}})
assert.NoError(t, err)
assert.Equal(t, 1, len(q.params))
assert.Equal(t, ",config=", q.params[0].keyMatch)
assert.Equal(t, false, q.params[0].isWildCard)
assert.Equal(t, true, q.params[0].isNegative)
q, err = New(url.Values{"config": []string{"!565", "!8888"}, "debug": []string{"*"}})
assert.NoError(t, err)
assert.Equal(t, 2, len(q.params))
assert.Equal(t, ",config=", q.params[0].keyMatch)
assert.Equal(t, "565", q.params[0].values[0])
assert.Equal(t, "8888", q.params[0].values[1])
assert.Equal(t, ",debug=", q.params[1].keyMatch)
assert.Equal(t, false, q.params[0].isWildCard)
assert.Equal(t, true, q.params[0].isNegative)
assert.Equal(t, true, q.params[1].isWildCard)
assert.Equal(t, false, q.params[1].isNegative)
q, err = New(url.Values{})
assert.NoError(t, err)
assert.Equal(t, 0, len(q.params))
}
func TestMatches(t *testing.T) {
testutils.SmallTest(t)
testCases := []struct {
key string
query url.Values
matches bool
reason string
}{
{
key: ",arch=x86,config=565,debug=true,",
query: url.Values{},
matches: true,
reason: "Empty query matches everything.",
},
{
key: ",arch=x86,config=565,debug=true,",
query: url.Values{"config": []string{"565"}},
matches: true,
reason: "Simple match",
},
{
key: ",arch=x86,config=565,debug=true,",
query: url.Values{"config": []string{"8888"}},
matches: false,
reason: "Simple miss",
},
{
key: ",arch=x86,config=565,debug=true,",
query: url.Values{"config": []string{"565", "8888"}},
matches: true,
reason: "Simple OR",
},
{
key: ",arch=x86,config=565,debug=true,",
query: url.Values{"config": []string{"8888", "565"}},
matches: true,
reason: "Simple OR 2",
},
{
key: ",arch=x86,config=565,debug=true,",
query: url.Values{"config": []string{"565"}, "debug": []string{"true"}},
matches: true,
reason: "Simple AND",
},
{
key: ",arch=x86,config=565,debug=true,",
query: url.Values{"config": []string{"565"}, "debug": []string{"false"}},
matches: false,
reason: "Simple AND miss",
},
{
key: ",arch=x86,config=565,debug=true,",
query: url.Values{"foo": []string{"bar"}},
matches: false,
reason: "Unknown param",
},
{
key: ",arch=x86,config=565,debug=true,",
query: url.Values{"arch": []string{"*"}},
matches: true,
reason: "Wildcard param value match",
},
{
key: ",arch=x86,config=565,debug=true,",
query: url.Values{"foo": []string{"*"}},
matches: false,
reason: "Wildcard param value missing",
},
{
key: ",arch=x86,config=565,debug=true,",
query: url.Values{"config": []string{"!565"}},
matches: false,
reason: "Negative miss",
},
{
key: ",arch=x86,config=8888,debug=true,",
query: url.Values{"config": []string{"!565"}},
matches: true,
reason: "Negative match",
},
{
key: ",arch=x86,config=8888,debug=true,",
query: url.Values{"config": []string{"!565", "!8888"}},
matches: false,
reason: "Negative multi miss",
},
{
key: ",arch=x86,config=8888,debug=true,",
query: url.Values{"config": []string{"!565"}, "debug": []string{"*"}},
matches: true,
reason: "Negative and wildcard",
},
{
key: ",arch=x86,config=8888,",
query: url.Values{"config": []string{"!565"}, "debug": []string{"*"}},
matches: false,
reason: "Negative and wildcard, miss wildcard.",
},
{
key: ",arch=x86,config=565,debug=true,",
query: url.Values{"config": []string{"!565"}, "debug": []string{"*"}},
matches: false,
reason: "Negative and wildcard, miss negative",
},
{
key: ",arch=x86,config=565,debug=true,",
query: url.Values{},
matches: true,
reason: "Empty query matches everything.",
},
{
key: ",arch=x86,config=565,debug=true,",
query: url.Values{"config": []string{"~5.5"}},
matches: true,
reason: "Regexp match",
},
{
key: ",arch=x86,config=565,debug=true,",
query: url.Values{"config": []string{"~8+"}},
matches: false,
reason: "Regexp match",
},
{
key: ",arch=x86,config=8888,debug=true,",
query: url.Values{"arch": []string{"~^x"}, "config": []string{"!565"}, "debug": []string{"*"}},
matches: true,
reason: "Negative, wildcard, and regexp",
},
{
key: ",arch=x86,config=8888,debug=true,",
query: url.Values{"arch": []string{"~^y.*"}, "config": []string{"!565"}, "debug": []string{"*"}},
matches: false,
reason: "Negative, wildcard, and miss regexp",
},
}
ops := &paramtools.OrderedParamSet{
KeyOrder: []string{"arch", "config", "debug", "foo"},
ParamSet: paramtools.ParamSet{
"config": []string{"8888", "565", "gpu"},
"arch": []string{"x86", "arm"},
"debug": []string{"true", "false"},
"foo": []string{"bar"},
},
}
for _, tc := range testCases {
q, err := New(tc.query)
assert.NoError(t, err)
if got, want := q.Matches(tc.key), tc.matches; got != want {
t.Errorf("Failed matching %q to %#v. Got %v Want %v. %s", tc.key, tc.query, got, want, tc.reason)
}
// Now confirm that the query transformed into a Regexp will give the same answer as Matches().
r, err := q.Regexp(ops)
if err == QueryWillNeverMatch {
assert.False(t, tc.matches)
continue
} else {
assert.NoError(t, err)
}
parsed, err := ParseKey(tc.key)
assert.NoError(t, err)
s, err := ops.EncodeParamsAsString(paramtools.Params(parsed))
assert.NoError(t, err)
assert.Equal(t, tc.matches, r.MatchString(s), fmt.Sprintf("%#v %s %v\n", tc, s, r))
}
}
func TestParseKey(t *testing.T) {
testutils.SmallTest(t)
testCases := []struct {
key string
parsed map[string]string
hasError bool
reason string
}{
{
key: ",arch=x86,config=565,debug=true,",
parsed: map[string]string{
"arch": "x86",
"config": "565",
"debug": "true",
},
hasError: false,
reason: "Simple parse",
},
{
key: ",config=565,arch=x86,",
parsed: map[string]string{},
hasError: true,
reason: "Unsorted",
},
{
key: ",,",
parsed: map[string]string{},
hasError: true,
reason: "Invalid regex",
},
{
key: "x/y",
parsed: map[string]string{},
hasError: true,
reason: "Invalid",
},
{
key: "",
parsed: map[string]string{},
hasError: true,
reason: "Empty string",
},
}
for _, tc := range testCases {
p, err := ParseKey(tc.key)
if got, want := (err != nil), tc.hasError; got != want {
t.Errorf("Failed error status parsing %q, Got %v Want %v. %s", tc.key, got, want, tc.reason)
}
if err != nil {
continue
}
if got, want := p, tc.parsed; !reflect.DeepEqual(got, want) {
t.Errorf("Failed matching parsed values. Got %v Want %v. %s", got, want, tc.reason)
}
}
}
func TestForceValue(t *testing.T) {
testutils.SmallTest(t)
testCases := []struct {
input map[string]string
want map[string]string
}{
{
input: map[string]string{"arch": "x86", "config": "565"},
want: map[string]string{"arch": "x86", "config": "565"},
},
{
input: map[string]string{"arch::this": "x!~@#$%^&*()86"},
want: map[string]string{"arch__this": "x___________86"},
},
{
input: map[string]string{},
want: map[string]string{},
},
}
for _, tc := range testCases {
if got, want := ForceValid(tc.input), tc.want; !reflect.DeepEqual(got, want) {
t.Errorf("Failed to force a map to be valid: Got %#v Want %#v", got, want)
}
}
}