diff --git a/internal/server/scanner.go b/internal/server/scanner.go index c1580440..e3cae7b1 100644 --- a/internal/server/scanner.go +++ b/internal/server/scanner.go @@ -342,7 +342,7 @@ func (sw *scanWriter) testObject(id string, o geojson.Object, fields []float64, if !ignoreGlobMatch { match, kg := sw.globMatch(id, o) if !match { - return true, kg, fieldVals + return false, kg, fieldVals } } nf, ok := sw.fieldMatch(fields, o) diff --git a/internal/server/search.go b/internal/server/search.go index 9315d77a..9cc12615 100644 --- a/internal/server/search.go +++ b/internal/server/search.go @@ -413,7 +413,7 @@ func (server *Server) nearestNeighbors( if server.hasExpired(s.key, id) { return true } - ok, keepGoing, _ := sw.testObject(id, o, fields, true) + ok, keepGoing, _ := sw.testObject(id, o, fields, false) if !ok { return true } diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 00000000..7640e54a --- /dev/null +++ b/tests/README.md @@ -0,0 +1,33 @@ +## Tile38 Integation Testing + +- Uses Redis protocol +- The Tile38 data is flushed before every `DoBatch` + +A basic test operation looks something like: + +```go +func keys_SET_test(mc *mockServer) error { + return mc.DoBatch([][]interface{}{ + {"SET", "fleet", "truck1", "POINT", 33.0001, -112.0001}, {"OK"}, + {"GET", "fleet", "truck1", "POINT"}, {"[33.0001 -112.0001]"}, + } +} +``` + +Using a custom function: + +```go +func keys_MATCH_test(mc *mockServer) error { + return mc.DoBatch([][]interface{}{ + {"SET", "fleet", "truck1", "POINT", 33.0001, -112.0001}, { + func(v interface{}) (resp, expect interface{}) { + // v is the value as strings or slices of strings + // test will pass as long as `resp` and `expect` are the same. + return v, "OK" + }, + }, + } +} +``` + + diff --git a/tests/keys_search_test.go b/tests/keys_search_test.go index f0767656..2552f387 100644 --- a/tests/keys_search_test.go +++ b/tests/keys_search_test.go @@ -1,6 +1,8 @@ package tests import ( + "fmt" + "sort" "testing" ) @@ -15,6 +17,7 @@ func subTestSearch(t *testing.T, mc *mockServer) { runStep(t, mc, "INTERSECTS_CURSOR", keys_INTERSECTS_CURSOR_test) runStep(t, mc, "SCAN_CURSOR", keys_SCAN_CURSOR_test) runStep(t, mc, "SEARCH_CURSOR", keys_SEARCH_CURSOR_test) + runStep(t, mc, "MATCH", keys_MATCH_test) } func keys_KNN_test(mc *mockServer) error { @@ -34,7 +37,7 @@ func keys_KNN_test(mc *mockServer) error { func keys_KNN_cursor_test(mc *mockServer) error { return mc.DoBatch([][]interface{}{ {"SET", "mykey", "1", "FIELD", "foo", 5.5, "POINT", 5, 5}, {"OK"}, - {"SET", "mykey", "2", "FIELD", "foo", 19.19, "POINT",19, 19}, {"OK"}, + {"SET", "mykey", "2", "FIELD", "foo", 19.19, "POINT", 19, 19}, {"OK"}, {"SET", "mykey", "3", "FIELD", "foo", 12.19, "POINT", 12, 19}, {"OK"}, {"SET", "mykey", "4", "FIELD", "foo", -5.5, "POINT", -5, 5}, {"OK"}, {"SET", "mykey", "5", "FIELD", "foo", 13.21, "POINT", 33, 21}, {"OK"}, @@ -118,7 +121,7 @@ func keys_WITHIN_CURSOR_test(mc *mockServer) error { {"SET", "mykey", "point2", "FIELD", "foo", 2, "POINT", 37.7335, -122.44121}, {"OK"}, {"SET", "mykey", "line3", "FIELD", "foo", 3, "OBJECT", `{"type":"LineString","coordinates":[[-122.4408378,37.7341129],[-122.4408378,37.733]]}`}, {"OK"}, {"SET", "mykey", "poly4", "FIELD", "foo", 4, "OBJECT", `{"type":"Polygon","coordinates":[[[-122.4408378,37.7341129],[-122.4408378,37.733],[-122.44,37.733],[-122.44,37.7341129],[-122.4408378,37.7341129]]]}`}, {"OK"}, - {"SET", "mykey", "multipoly5","FIELD", "foo", 5, "OBJECT", `{"type":"MultiPolygon","coordinates":[[[[-122.4408378,37.7341129],[-122.4408378,37.733],[-122.44,37.733],[-122.44,37.7341129],[-122.4408378,37.7341129]]],[[[-122.44091033935547,37.731981251280985],[-122.43994474411011,37.731981251280985],[-122.43994474411011,37.73254976045042],[-122.44091033935547,37.73254976045042],[-122.44091033935547,37.731981251280985]]]]}`}, {"OK"}, + {"SET", "mykey", "multipoly5", "FIELD", "foo", 5, "OBJECT", `{"type":"MultiPolygon","coordinates":[[[[-122.4408378,37.7341129],[-122.4408378,37.733],[-122.44,37.733],[-122.44,37.7341129],[-122.4408378,37.7341129]]],[[[-122.44091033935547,37.731981251280985],[-122.43994474411011,37.731981251280985],[-122.43994474411011,37.73254976045042],[-122.44091033935547,37.73254976045042],[-122.44091033935547,37.731981251280985]]]]}`}, {"OK"}, {"SET", "mykey", "point6", "FIELD", "foo", 6, "POINT", -5, 5}, {"OK"}, {"SET", "mykey", "point7", "FIELD", "foo", 7, "POINT", 33, 21}, {"OK"}, {"SET", "mykey", "poly8", "FIELD", "foo", 8, "OBJECT", `{"type":"Polygon","coordinates":[[[-122.4408378,37.7341129],[-122.4408378,37.733],[-122.44,37.733],[-122.44,37.7341129],[-122.4408378,37.7341129]],[[-122.44060993194579,37.73345766902749],[-122.44044363498686,37.73345766902749],[-122.44044363498686,37.73355524732416],[-122.44060993194579,37.73355524732416],[-122.44060993194579,37.73345766902749]],[[-122.44060724973677,37.7336888869566],[-122.4402102828026,37.7336888869566],[-122.4402102828026,37.7339752567853],[-122.44060724973677,37.7339752567853],[-122.44060724973677,37.7336888869566]]]}`}, {"OK"}, @@ -302,3 +305,63 @@ func keys_SEARCH_CURSOR_test(mc *mockServer) error { {"SEARCH", "mykey", "LIMIT", 3, "DESC", "IDS"}, {"[3 [id9 id8 id7]]"}, }) } + +func keys_MATCH_test(mc *mockServer) error { + return mc.DoBatch([][]interface{}{ + {"SET", "fleet", "truck1", "POINT", "33.0001", "-112.0001"}, {"OK"}, + {"SET", "fleet", "truck2", "POINT", "33.0002", "-112.0002"}, {"OK"}, + {"SET", "fleet", "luck1", "POINT", "33.0003", "-112.0003"}, {"OK"}, + {"SET", "fleet", "luck2", "POINT", "33.0004", "-112.0004"}, {"OK"}, + + {"SCAN", "fleet", "IDS"}, {"[0 [luck1 luck2 truck1 truck2]]"}, + {"SCAN", "fleet", "MATCH", "*", "IDS"}, {"[0 [luck1 luck2 truck1 truck2]]"}, + {"SCAN", "fleet", "MATCH", "truck*", "IDS"}, {"[0 [truck1 truck2]]"}, + {"SCAN", "fleet", "MATCH", "luck*", "IDS"}, {"[0 [luck1 luck2]]"}, + {"SCAN", "fleet", "MATCH", "*2", "IDS"}, {"[0 [luck2 truck2]]"}, + {"SCAN", "fleet", "MATCH", "*2*", "IDS"}, {"[0 [luck2 truck2]]"}, + {"SCAN", "fleet", "MATCH", "*u*", "IDS"}, {"[0 [luck1 luck2 truck1 truck2]]"}, + + {"NEARBY", "fleet", "IDS", "POINT", 33.00005, -112.00005, 100000}, { + match("[0 [luck1 luck2 truck1 truck2]]"), + }, + {"NEARBY", "fleet", "MATCH", "*", "IDS", "POINT", 33.00005, -112.00005, 100000}, { + match("[0 [luck1 luck2 truck1 truck2]]"), + }, + {"NEARBY", "fleet", "MATCH", "t*", "IDS", "POINT", 33.00005, -112.00005, 100000}, { + match("[0 [truck1 truck2]]"), + }, + {"NEARBY", "fleet", "MATCH", "t*2", "IDS", "POINT", 33.00005, -112.00005, 100000}, { + match("[0 [truck2]]"), + }, + {"NEARBY", "fleet", "MATCH", "*2", "IDS", "POINT", 33.00005, -112.00005, 100000}, { + match("[0 [luck2 truck2]]"), + }, + + {"INTERSECTS", "fleet", "IDS", "BOUNDS", 33, -113, 34, -112}, { + match("[0 [luck1 luck2 truck1 truck2]]"), + }, + {"INTERSECTS", "fleet", "MATCH", "*", "IDS", "BOUNDS", 33, -113, 34, -112}, { + match("[0 [luck1 luck2 truck1 truck2]]"), + }, + {"INTERSECTS", "fleet", "MATCH", "t*", "IDS", "BOUNDS", 33, -113, 34, -112}, { + match("[0 [truck1 truck2]]"), + }, + {"INTERSECTS", "fleet", "MATCH", "t*2", "IDS", "BOUNDS", 33, -113, 34, -112}, { + match("[0 [truck2]]"), + }, + {"INTERSECTS", "fleet", "MATCH", "*2", "IDS", "BOUNDS", 33, -113, 34, -112}, { + match("[0 [luck2 truck2]]"), + }, + }) +} + +// match sorts the response and compares to the expected input +func match(expectIn string) func(org, v interface{}) (resp, expect interface{}) { + return func(v, org interface{}) (resp, expect interface{}) { + sort.Slice(org.([]interface{})[1], func(i, j int) bool { + return org.([]interface{})[1].([]interface{})[i].(string) < + org.([]interface{})[1].([]interface{})[j].(string) + }) + return fmt.Sprintf("%v", org), expectIn + } +} diff --git a/tests/mock_test.go b/tests/mock_test.go index 53929d78..f4f5f2d6 100644 --- a/tests/mock_test.go +++ b/tests/mock_test.go @@ -226,11 +226,23 @@ func (mc *mockServer) DoExpect(expect interface{}, commandName string, args ...i resp = string([]byte(b)) } } - if fn, ok := expect.(func(v, org interface{}) (resp, expect interface{})); ok { - resp, expect = fn(resp, oresp) - } - if fn, ok := expect.(func(v interface{}) (resp, expect interface{})); ok { - resp, expect = fn(resp) + err = func() (err error) { + defer func() { + v := recover() + if v != nil { + err = fmt.Errorf("panic '%v'", v) + } + }() + if fn, ok := expect.(func(v, org interface{}) (resp, expect interface{})); ok { + resp, expect = fn(resp, oresp) + } + if fn, ok := expect.(func(v interface{}) (resp, expect interface{})); ok { + resp, expect = fn(resp) + } + return nil + }() + if err != nil { + return err } if fmt.Sprintf("%v", resp) != fmt.Sprintf("%v", expect) { return fmt.Errorf("expected '%v', got '%v'", expect, resp) diff --git a/tests/tests.go b/tests/tests.go deleted file mode 100644 index ca8701d2..00000000 --- a/tests/tests.go +++ /dev/null @@ -1 +0,0 @@ -package tests