Refactor query tests

This commit refactors the query package tests to use the
standard library testing package instead of goconvey. Goconvey
is now completely removed from the repository.
This commit is contained in:
Ben Johnson 2015-08-19 10:09:18 -06:00
parent ad0b37d0f1
commit 894ae3598f
6 changed files with 715 additions and 591 deletions

View file

@ -14,11 +14,6 @@
"version": "master",
"type": "git"
},
"goconvey": {
"repo": "github.com/smartystreets/goconvey",
"version": "master",
"type": "git"
},
"gocql": {
"repo": "github.com/gocql/gocql",
"version": "f8fb76bb772442ea938e4be46ab1666e542411a5",

View file

@ -7,7 +7,6 @@ import (
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func TestStorage(t *testing.T) {

View file

@ -1,213 +1,279 @@
package query
package query_test
import (
"reflect"
"testing"
. "github.com/smartystreets/goconvey/convey"
"github.com/davecgh/go-spew/spew"
"github.com/umbel/pilosa/query"
)
func TestLexer(t *testing.T) {
Convey("Basic lexical analysis", t, func() {
var tokens []Token
var err error
tokens, err = Lex("get(10)")
So(err, ShouldBeNil)
So(len(tokens), ShouldEqual, 4)
So(tokens, ShouldResemble, []Token{
{"get", TYPE_FUNC},
{"(", TYPE_LP},
{"10", TYPE_VALUE},
{")", TYPE_RP},
})
tokens, err = Lex("get(id=10)")
So(err, ShouldBeNil)
So(tokens, ShouldResemble, []Token{
{"get", TYPE_FUNC},
{"(", TYPE_LP},
{"id", TYPE_KEYWORD},
{"=", TYPE_EQUALS},
{"10", TYPE_VALUE},
{")", TYPE_RP},
})
tokens, err = Lex("get(id=10, frame=brand)")
So(err, ShouldBeNil)
So(tokens, ShouldResemble, []Token{
{"get", TYPE_FUNC},
{"(", TYPE_LP},
{"id", TYPE_KEYWORD},
{"=", TYPE_EQUALS},
{"10", TYPE_VALUE},
{",", TYPE_COMMA},
{"frame", TYPE_KEYWORD},
{"=", TYPE_EQUALS},
{"brand", TYPE_VALUE},
{")", TYPE_RP},
})
tokens, err = Lex("union(get(10))")
So(err, ShouldBeNil)
So(tokens, ShouldResemble, []Token{
{"union", TYPE_FUNC},
{"(", TYPE_LP},
{"get", TYPE_FUNC},
{"(", TYPE_LP},
{"10", TYPE_VALUE},
{")", TYPE_RP},
{")", TYPE_RP},
})
tokens, err = Lex("intersect(get(10), get(11), get(12))")
So(err, ShouldBeNil)
So(tokens, ShouldResemble, []Token{
{"intersect", TYPE_FUNC},
{"(", TYPE_LP},
{"get", TYPE_FUNC},
{"(", TYPE_LP},
{"10", TYPE_VALUE},
{")", TYPE_RP},
{",", TYPE_COMMA},
{"get", TYPE_FUNC},
{"(", TYPE_LP},
{"11", TYPE_VALUE},
{")", TYPE_RP},
{",", TYPE_COMMA},
{"get", TYPE_FUNC},
{"(", TYPE_LP},
{"12", TYPE_VALUE},
{")", TYPE_RP},
{")", TYPE_RP},
})
tokens, err = Lex("intersect(get(10), get(11), concat(get(12),get(14)))")
So(err, ShouldBeNil)
So(tokens, ShouldResemble, []Token{
{"intersect", TYPE_FUNC},
{"(", TYPE_LP},
{"get", TYPE_FUNC},
{"(", TYPE_LP},
{"10", TYPE_VALUE},
{")", TYPE_RP},
{",", TYPE_COMMA},
{"get", TYPE_FUNC},
{"(", TYPE_LP},
{"11", TYPE_VALUE},
{")", TYPE_RP},
{",", TYPE_COMMA},
{"concat", TYPE_FUNC},
{"(", TYPE_LP},
{"get", TYPE_FUNC},
{"(", TYPE_LP},
{"12", TYPE_VALUE},
{")", TYPE_RP},
{",", TYPE_COMMA},
{"get", TYPE_FUNC},
{"(", TYPE_LP},
{"14", TYPE_VALUE},
{")", TYPE_RP},
{")", TYPE_RP},
{")", TYPE_RP},
})
tokens, err = Lex("concat(get(1, brand),get(2))")
So(err, ShouldBeNil)
So(tokens, ShouldResemble, []Token{
{"concat", TYPE_FUNC},
{"(", TYPE_LP},
{"get", TYPE_FUNC},
{"(", TYPE_LP},
{"1", TYPE_VALUE},
{",", TYPE_COMMA},
{"brand", TYPE_VALUE},
{")", TYPE_RP},
{",", TYPE_COMMA},
{"get", TYPE_FUNC},
{"(", TYPE_LP},
{"2", TYPE_VALUE},
{")", TYPE_RP},
{")", TYPE_RP},
})
tokens, err = Lex("set(1, 987)")
So(err, ShouldBeNil)
So(tokens, ShouldResemble, []Token{
{"set", TYPE_FUNC},
{"(", TYPE_LP},
{"1", TYPE_VALUE},
{",", TYPE_COMMA},
{"987", TYPE_VALUE},
{")", TYPE_RP},
})
tokens, err = Lex("set(1, general, 987)")
So(err, ShouldBeNil)
So(tokens, ShouldResemble, []Token{
{"set", TYPE_FUNC},
{"(", TYPE_LP},
{"1", TYPE_VALUE},
{",", TYPE_COMMA},
{"general", TYPE_VALUE},
{",", TYPE_COMMA},
{"987", TYPE_VALUE},
{")", TYPE_RP},
})
tokens, err = Lex("top-n(get(10), 8)")
So(tokens, ShouldResemble, []Token{
Token{"top-n", TYPE_FUNC},
Token{"(", TYPE_LP},
Token{"get", TYPE_FUNC},
Token{"(", TYPE_LP},
Token{"10", TYPE_VALUE},
Token{")", TYPE_RP},
Token{",", TYPE_COMMA},
Token{"8", TYPE_VALUE},
Token{")", TYPE_RP},
})
tokens, err = Lex("top-n(get(10, general), [1,2,3])")
So(tokens, ShouldResemble, []Token{
Token{"top-n", TYPE_FUNC},
Token{"(", TYPE_LP},
Token{"get", TYPE_FUNC},
Token{"(", TYPE_LP},
Token{"10", TYPE_VALUE},
Token{",", TYPE_COMMA},
Token{"general", TYPE_VALUE},
Token{")", TYPE_RP},
Token{",", TYPE_COMMA},
Token{"[", TYPE_LB},
Token{"1", TYPE_VALUE},
Token{",", TYPE_COMMA},
Token{"2", TYPE_VALUE},
Token{",", TYPE_COMMA},
Token{"3", TYPE_VALUE},
Token{"]", TYPE_RB},
Token{")", TYPE_RP},
})
tokens, err = Lex("plugin(get(10, general), [get(11, general)])")
So(tokens, ShouldResemble, []Token{
Token{"plugin", TYPE_FUNC},
Token{"(", TYPE_LP},
Token{"get", TYPE_FUNC},
Token{"(", TYPE_LP},
Token{"10", TYPE_VALUE},
Token{",", TYPE_COMMA},
Token{"general", TYPE_VALUE},
Token{")", TYPE_RP},
Token{",", TYPE_COMMA},
Token{"[", TYPE_LB},
Token{"get", TYPE_FUNC},
Token{"(", TYPE_LP},
Token{"11", TYPE_VALUE},
Token{",", TYPE_COMMA},
Token{"general", TYPE_VALUE},
Token{")", TYPE_RP},
Token{"]", TYPE_RB},
Token{")", TYPE_RP},
})
})
// Ensure a simple function and value can be lexed.
func TestLexer_Lex_FuncValue(t *testing.T) {
if tokens, err := query.Lex("get(10)"); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(tokens, []query.Token{
{"get", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"10", query.TYPE_VALUE},
{")", query.TYPE_RP},
}) {
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
}
}
// Ensure a simple function, keyword, & value can be lexed.
func TestLexer_Lex_FuncKeywordValue(t *testing.T) {
if tokens, err := query.Lex("get(id=10)"); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(tokens, []query.Token{
{"get", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"id", query.TYPE_KEYWORD},
{"=", query.TYPE_EQUALS},
{"10", query.TYPE_VALUE},
{")", query.TYPE_RP},
}) {
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
}
}
// Ensure a more complex function can be lexed.
func TestLexer_Lex_FuncComplex(t *testing.T) {
if tokens, err := query.Lex("get(id=10, frame=brand)"); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(tokens, []query.Token{
{"get", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"id", query.TYPE_KEYWORD},
{"=", query.TYPE_EQUALS},
{"10", query.TYPE_VALUE},
{",", query.TYPE_COMMA},
{"frame", query.TYPE_KEYWORD},
{"=", query.TYPE_EQUALS},
{"brand", query.TYPE_VALUE},
{")", query.TYPE_RP},
}) {
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
}
}
// Ensure that nested functions can be lexed.
func TestLexer_Lex_FuncNested(t *testing.T) {
if tokens, err := query.Lex("union(get(10))"); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(tokens, []query.Token{
{"union", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"get", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"10", query.TYPE_VALUE},
{")", query.TYPE_RP},
{")", query.TYPE_RP},
}) {
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
}
}
// Ensure that a list of nested functions can be lexed.
func TestLexer_Lex_FuncNestedList(t *testing.T) {
if tokens, err := query.Lex("intersect(get(10), get(11), get(12))"); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(tokens, []query.Token{
{"intersect", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"get", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"10", query.TYPE_VALUE},
{")", query.TYPE_RP},
{",", query.TYPE_COMMA},
{"get", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"11", query.TYPE_VALUE},
{")", query.TYPE_RP},
{",", query.TYPE_COMMA},
{"get", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"12", query.TYPE_VALUE},
{")", query.TYPE_RP},
{")", query.TYPE_RP},
}) {
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
}
}
// Ensure that complex nested functions can be lexed.
func TestLexer_Lex_FuncNestedComplex(t *testing.T) {
if tokens, err := query.Lex("intersect(get(10), get(11), concat(get(12),get(14)))"); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(tokens, []query.Token{
{"intersect", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"get", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"10", query.TYPE_VALUE},
{")", query.TYPE_RP},
{",", query.TYPE_COMMA},
{"get", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"11", query.TYPE_VALUE},
{")", query.TYPE_RP},
{",", query.TYPE_COMMA},
{"concat", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"get", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"12", query.TYPE_VALUE},
{")", query.TYPE_RP},
{",", query.TYPE_COMMA},
{"get", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"14", query.TYPE_VALUE},
{")", query.TYPE_RP},
{")", query.TYPE_RP},
{")", query.TYPE_RP},
}) {
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
}
}
// Ensure that complex nested functions can be lexed.
func TestLexer_Lex_FuncNestedComplex2(t *testing.T) {
if tokens, err := query.Lex("concat(get(1, brand),get(2))"); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(tokens, []query.Token{
{"concat", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"get", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"1", query.TYPE_VALUE},
{",", query.TYPE_COMMA},
{"brand", query.TYPE_VALUE},
{")", query.TYPE_RP},
{",", query.TYPE_COMMA},
{"get", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"2", query.TYPE_VALUE},
{")", query.TYPE_RP},
{")", query.TYPE_RP},
}) {
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
}
}
// Ensure that a set function can be lexed.
func TestLexer_Lex_Set1(t *testing.T) {
if tokens, err := query.Lex("set(1, 987)"); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(tokens, []query.Token{
{"set", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"1", query.TYPE_VALUE},
{",", query.TYPE_COMMA},
{"987", query.TYPE_VALUE},
{")", query.TYPE_RP},
}) {
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
}
}
// Ensure that a set function can be lexed.
func TestLexer_Lex_Set2(t *testing.T) {
if tokens, err := query.Lex("set(1, general, 987)"); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(tokens, []query.Token{
{"set", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"1", query.TYPE_VALUE},
{",", query.TYPE_COMMA},
{"general", query.TYPE_VALUE},
{",", query.TYPE_COMMA},
{"987", query.TYPE_VALUE},
{")", query.TYPE_RP},
}) {
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
}
}
// Ensure that a TopN function can be lexed.
func TestLexer_Lex_TopN1(t *testing.T) {
if tokens, err := query.Lex("top-n(get(10), 8)"); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(tokens, []query.Token{
{"top-n", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"get", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"10", query.TYPE_VALUE},
{")", query.TYPE_RP},
{",", query.TYPE_COMMA},
{"8", query.TYPE_VALUE},
{")", query.TYPE_RP},
}) {
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
}
}
// Ensure that a TopN function can be lexed.
func TestLexer_Lex_TopN2(t *testing.T) {
if tokens, err := query.Lex("top-n(get(10, general), [1,2,3])"); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(tokens, []query.Token{
{"top-n", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"get", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"10", query.TYPE_VALUE},
{",", query.TYPE_COMMA},
{"general", query.TYPE_VALUE},
{")", query.TYPE_RP},
{",", query.TYPE_COMMA},
{"[", query.TYPE_LB},
{"1", query.TYPE_VALUE},
{",", query.TYPE_COMMA},
{"2", query.TYPE_VALUE},
{",", query.TYPE_COMMA},
{"3", query.TYPE_VALUE},
{"]", query.TYPE_RB},
{")", query.TYPE_RP},
}) {
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
}
}
// Ensure that a plugin function can be lexed.
func TestLexer_Lex_Plugin(t *testing.T) {
if tokens, err := query.Lex("plugin(get(10, general), [get(11, general)])"); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(tokens, []query.Token{
{"plugin", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"get", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"10", query.TYPE_VALUE},
{",", query.TYPE_COMMA},
{"general", query.TYPE_VALUE},
{")", query.TYPE_RP},
{",", query.TYPE_COMMA},
{"[", query.TYPE_LB},
{"get", query.TYPE_FUNC},
{"(", query.TYPE_LP},
{"11", query.TYPE_VALUE},
{",", query.TYPE_COMMA},
{"general", query.TYPE_VALUE},
{")", query.TYPE_RP},
{"]", query.TYPE_RB},
{")", query.TYPE_RP},
}) {
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
}
}
// MustLex lexes s and returns a set of tokens. Panic on error.
func MustLex(s string) []query.Token {
a, err := query.Lex(s)
if err != nil {
panic(err)
}
return a
}

View file

@ -1,127 +1,157 @@
package query
package query_test
import (
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
. "github.com/smartystreets/goconvey/convey"
"github.com/umbel/pilosa/query"
)
func TestQueryParser(t *testing.T) {
Convey("Basic parse - get()", t, func() {
tokens, err := Lex("get(10)")
So(err, ShouldBeNil)
query, err := Parse(tokens)
So(err, ShouldBeNil)
So(query.Operation, ShouldEqual, "get")
So(query.Args, ShouldResemble, map[string]interface{}{"id": uint64(10), "frame": "general"})
})
Convey("Basic parse - clear()", t, func() {
tokens, err := Lex("clear(10, general, 0, 20)")
So(err, ShouldBeNil)
query, err := Parse(tokens)
So(err, ShouldBeNil)
spew.Dump(query)
So(query.Operation, ShouldEqual, "clear")
So(query.Args, ShouldResemble, map[string]interface{}{"id": uint64(10), "frame": "general", "filter": uint64(0), "profile_id": uint64(20)})
})
Convey("Basic parse - set()", t, func() {
tokens, err := Lex("set(10, general, 0, 20)")
So(err, ShouldBeNil)
query, err := Parse(tokens)
So(err, ShouldBeNil)
So(query.Operation, ShouldEqual, "set")
So(query.Args, ShouldResemble, map[string]interface{}{"id": uint64(10), "frame": "general", "filter": uint64(0), "profile_id": uint64(20)})
})
Convey("Basic nested query parse", t, func() {
tokens, err := Lex("union(get(10,general), get(11,brand), get(12))")
So(err, ShouldBeNil)
query, err := Parse(tokens)
So(err, ShouldBeNil)
So(query.Operation, ShouldEqual, "union")
So(len(query.Subqueries), ShouldEqual, 3)
So(query.Subqueries[0].Operation, ShouldEqual, "get")
So(query.Subqueries[0].Args, ShouldResemble, map[string]interface{}{"id": uint64(10), "frame": "general"})
So(query.Subqueries[1].Operation, ShouldEqual, "get")
So(query.Subqueries[1].Args, ShouldResemble, map[string]interface{}{"id": uint64(11), "frame": "brand"})
So(query.Subqueries[2].Operation, ShouldEqual, "get")
So(query.Subqueries[2].Args, ShouldResemble, map[string]interface{}{"id": uint64(12), "frame": "general"})
})
Convey("Keyword args", t, func() {
tokens, err := Lex("get(id=10)")
So(err, ShouldBeNil)
query, err := Parse(tokens)
So(err, ShouldBeNil)
So(query.Operation, ShouldEqual, "get")
So(query.Args, ShouldResemble, map[string]interface{}{"id": uint64(10), "frame": "general"})
})
Convey("Keyword args - multiple", t, func() {
tokens, err := Lex("get(id=10, frame=brands)")
So(err, ShouldBeNil)
query, err := Parse(tokens)
So(err, ShouldBeNil)
So(query.Operation, ShouldEqual, "get")
So(query.Args, ShouldResemble, map[string]interface{}{"id": uint64(10), "frame": "brands"})
})
Convey("Lists", t, func() {
tokens, err := Lex("top-n(get(10, general), [1,2,3], 50)")
So(err, ShouldBeNil)
query, err := Parse(tokens)
So(err, ShouldBeNil)
So(query.Operation, ShouldEqual, "top-n")
So(query.Args, ShouldResemble, map[string]interface{}{"ids": []uint64{1, 2, 3}, "n": 50})
So(len(query.Subqueries), ShouldEqual, 1)
So(query.Subqueries[0].Operation, ShouldEqual, "get")
So(query.Subqueries[0].Args, ShouldResemble, map[string]interface{}{"id": uint64(10), "frame": "general"})
})
Convey("Bracketed Lists", t, func() {
tokens, err := Lex("plugin(get(99), [get(10), get(11)])")
So(err, ShouldBeNil)
query, err := Parse(tokens)
So(err, ShouldBeNil)
spew.Dump("*********************************************")
spew.Dump(query)
spew.Dump("*********************************************")
})
Convey("Lists", t, func() {
tokens, err := Lex("wat(50)")
_, err = Parse(tokens)
So(err, ShouldBeNil)
})
Convey("Recall", t, func() {
tokens, err := Lex("recall(12345,1,12345,2,12345,3)")
q, err := Parse(tokens)
spew.Dump(q)
So(err, ShouldBeNil)
})
Convey("all() query parse", t, func() {
tokens, err := Lex("top-n(all(), general, 30)")
So(err, ShouldBeNil)
query, err := Parse(tokens)
So(err, ShouldBeNil)
So(query.Operation, ShouldEqual, "top-n")
So(len(query.Subqueries), ShouldEqual, 1)
So(query.Subqueries[0].Operation, ShouldEqual, "all")
So(query.Subqueries[0].Args, ShouldResemble, map[string]interface{}{})
})
// Ensure the parser can parse a get() query.
func TestParser_Parse_Get(t *testing.T) {
if q, err := query.Parse(MustLex("get(10)")); err != nil {
t.Fatal(err)
} else if q.Operation != "get" {
t.Fatalf("unexpected operation: %q", q.Operation)
} else if !reflect.DeepEqual(q.Args, map[string]interface{}{
"id": uint64(10),
"frame": "general",
}) {
t.Fatalf("unexpected args:\n\n%s", spew.Sprint(q.Args))
}
}
// Ensure the parser can parse a get() query with a keyword.
func TestParser_Parse_Get_Keyword(t *testing.T) {
if q, err := query.Parse(MustLex("get(id=10)")); err != nil {
t.Fatal(err)
} else if q.Operation != "get" {
t.Fatalf("unexpected operation: %q", q.Operation)
} else if !reflect.DeepEqual(q.Args, map[string]interface{}{"id": uint64(10), "frame": "general"}) {
t.Fatalf("unexpected args:\n\n%s", spew.Sprint(q.Args))
}
}
// Ensure the parser can parse a get() query with a keyword.
func TestParser_Parse_Get_MultiKeyword(t *testing.T) {
if q, err := query.Parse(MustLex("get(id=10, frame=brands)")); err != nil {
t.Fatal(err)
} else if q.Operation != "get" {
t.Fatalf("unexpected operation: %q", q.Operation)
} else if !reflect.DeepEqual(q.Args, map[string]interface{}{"id": uint64(10), "frame": "brands"}) {
t.Fatalf("unexpected args:\n\n%s", spew.Sprint(q.Args))
}
}
// Ensure the parser can parse a clear() query.
func TestParser_Parse_Clear(t *testing.T) {
if q, err := query.Parse(MustLex("clear(10, general, 0, 20)")); err != nil {
t.Fatal(err)
} else if q.Operation != "clear" {
t.Fatalf("unexpected operation: %q", q.Operation)
} else if !reflect.DeepEqual(q.Args, map[string]interface{}{
"id": uint64(10),
"frame": "general",
"filter": uint64(0),
"profile_id": uint64(20),
}) {
t.Fatalf("unexpected args:\n\n%s", spew.Sprint(q.Args))
}
}
// Ensure the parser can parse a set() query.
func TestParser_Parse_Set(t *testing.T) {
if q, err := query.Parse(MustLex("set(10, general, 0, 20)")); err != nil {
t.Fatal(err)
} else if q.Operation != "set" {
t.Fatalf("unexpected operation: %q", q.Operation)
} else if !reflect.DeepEqual(q.Args, map[string]interface{}{
"id": uint64(10),
"frame": "general",
"filter": uint64(0),
"profile_id": uint64(20),
}) {
t.Fatalf("unexpected args:\n\n%s", spew.Sprint(q.Args))
}
}
// Ensure the parser can parse a nested query.
func TestParser_Parse_Nested(t *testing.T) {
q, err := query.Parse(MustLex("union(get(10,general), get(11,brand), get(12))"))
if err != nil {
t.Fatal(err)
} else if q.Operation != "union" {
t.Fatalf("unexpected operation: %q", q.Operation)
} else if len(q.Subqueries) != 3 {
t.Fatalf("unexpected subquery count: %d", len(q.Subqueries))
}
if sq := q.Subqueries[0]; sq.Operation != "get" {
t.Fatalf("unexpected subquery(0) operation: %q", sq.Operation)
} else if !reflect.DeepEqual(sq.Args, map[string]interface{}{"id": uint64(10), "frame": "general"}) {
t.Fatalf("unexpected subquery(0) args:\n\n%s", spew.Sprint(q.Args))
}
if sq := q.Subqueries[1]; sq.Operation != "get" {
t.Fatalf("unexpected subquery(1) operation: %q", sq.Operation)
} else if !reflect.DeepEqual(sq.Args, map[string]interface{}{"id": uint64(11), "frame": "brand"}) {
t.Fatalf("unexpected subquery(1) args:\n\n%s", spew.Sprint(sq.Args))
}
if sq := q.Subqueries[2]; sq.Operation != "get" {
t.Fatalf("unexpected subquery(2) operation: %q", sq.Operation)
} else if !reflect.DeepEqual(sq.Args, map[string]interface{}{"id": uint64(12), "frame": "general"}) {
t.Fatalf("unexpected subquery(2) args:\n\n%s", spew.Sprint(sq.Args))
}
}
// Ensure the parser can parse a query with lists.
func TestParser_Parse_Lists(t *testing.T) {
q, err := query.Parse(MustLex("top-n(get(10, general), [1,2,3], 50)"))
if err != nil {
t.Fatal(err)
} else if q.Operation != "top-n" {
t.Fatalf("unexpected operation: %q", q.Operation)
} else if !reflect.DeepEqual(q.Args, map[string]interface{}{"ids": []uint64{1, 2, 3}, "n": 50}) {
t.Fatalf("unexpected args:\n\n%s", spew.Sprint(q.Args))
}
if sq := q.Subqueries[0]; sq.Operation != "get" {
t.Fatalf("unexpected subquery(0) operation: %q", sq.Operation)
} else if !reflect.DeepEqual(sq.Args, map[string]interface{}{"id": uint64(10), "frame": "general"}) {
t.Fatalf("unexpected subquery(0) args:\n\n%s", spew.Sprint(q.Args))
}
}
// Ensure the parser can parse "all()".
func TestParser_Parse_All(t *testing.T) {
q, err := query.Parse(MustLex("top-n(all(), general, 30)"))
if err != nil {
t.Fatal(err)
} else if q.Operation != "top-n" {
t.Fatalf("unexpected operation: %q", q.Operation)
}
if sq := q.Subqueries[0]; sq.Operation != "all" {
t.Fatalf("unexpected subquery(0) operation: %q", sq.Operation)
}
}
// Ensure the parser can parse bracketed lists.
func TestParser_Parse_Lists_Bracketed(t *testing.T) {
q, err := query.Parse(MustLex("plugin(get(99), [get(10), get(11)])"))
if err != nil {
t.Fatalf("expected error")
}
spew.Dump(q)
}
// Ensure the parser can parse a recall query.
func TestParser_Parse_Recall(t *testing.T) {
q, err := query.Parse(MustLex("recall(12345,1,12345,2,12345,3)"))
if err != nil {
t.Fatal(err)
}
spew.Dump(q)
}

View file

@ -1,253 +1,283 @@
package query
package query_test
import (
"log"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
. "github.com/smartystreets/goconvey/convey"
"github.com/umbel/pilosa/db"
"github.com/umbel/pilosa/query"
"github.com/umbel/pilosa/util"
)
func basic_database() (*db.Database, *db.Fragment) {
// create an empty database
cluster := db.NewCluster()
database := cluster.GetOrCreateDatabase("main")
frame := database.GetOrCreateFrame("default")
// Ensure the query planner can plan a "get" query.
func TestQueryPlanner_Plan_Get(t *testing.T) {
q, err := query.QueryForPQL("get(10,default)")
if err != nil {
t.Fatal(err)
}
slice1 := database.GetOrCreateSlice(0)
fragment_id1 := util.Id()
fragment1 := database.GetOrCreateFragment(frame, slice1, fragment_id1)
process_id1 := util.RandomUUID()
process1 := db.NewProcess(&process_id1)
process1.SetHost("----192.1.1.0----")
fragment1.SetProcess(process1)
d, frag1 := NewDefaultDB()
planner := query.QueryPlanner{Database: d, Query: q}
slice2 := database.GetOrCreateSlice(1)
fragment_id2 := util.Id()
fragment2 := database.GetOrCreateFragment(frame, slice2, fragment_id2)
process_id2 := util.RandomUUID()
process2 := db.NewProcess(&process_id2)
process2.SetHost("----192.1.1.1----")
fragment2.SetProcess(process2)
return database, fragment1
id := util.RandomUUID()
plan, err := planner.Plan(q, &id, frag1.GetLocation())
if err != nil {
t.Fatal(err)
}
if n := len(*plan); n != 3 {
t.Fatalf("unexpected plan length: %d", n)
}
if step := (*plan)[0].(query.GetQueryStep); step.Operation != "get" {
t.Fatalf("unexpected step(0) operation: %s", step.Operation)
} else if step.Slice != 0 {
t.Fatalf("unexpected step(0) slice: %d", step.Slice)
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{10, "default", 0}) {
t.Fatalf("unexpected step(0) bitmap: %s", spew.Sprint(step.Bitmap))
}
if step := (*plan)[1].(query.GetQueryStep); step.Operation != "get" {
t.Fatalf("unexpected step(1) operation: %s", step.Operation)
} else if step.Slice != 1 {
t.Fatalf("unexpected step(1) slice: %d", step.Slice)
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{10, "default", 0}) {
t.Fatalf("unexpected step(1) bitmap: %s", spew.Sprint(step.Bitmap))
}
if step := (*plan)[2].(query.CatQueryStep); step.Operation != "cat" {
t.Fatalf("unexpected step(2) operation: %s", step.Operation)
} else if !reflect.DeepEqual(step.Inputs, []*util.GUID{
(*plan)[0].(query.GetQueryStep).Id,
(*plan)[1].(query.GetQueryStep).Id,
}) {
t.Fatalf("unexpected step(2) inputs: %s", spew.Sprint(step.Inputs))
}
}
func TestQueryPlanner(t *testing.T) {
Convey("Union query plan", t, func() {
// Ensure the query planner can plan a "set" query.
func TestQueryPlanner_Plan_Set(t *testing.T) {
q, err := query.QueryForPQL("set(10, default, 0, 100)")
if err != nil {
t.Fatal(err)
}
id1 := util.RandomUUID()
query1 := Query{Id: &id1, Operation: "get", Args: map[string]interface{}{"id": uint64(10), "frame": "default"}}
d, frag1 := NewDefaultDB()
planner := query.QueryPlanner{Database: d, Query: q}
id2 := util.RandomUUID()
query2 := Query{Id: &id2, Operation: "get", Args: map[string]interface{}{"id": uint64(20), "frame": "default"}}
id := util.RandomUUID()
plan, err := planner.Plan(q, &id, frag1.GetLocation())
if err != nil {
t.Fatal(err)
}
id3 := util.RandomUUID()
query := Query{Id: &id3, Operation: "union", Subqueries: []Query{query1, query2}}
database, fragment1 := basic_database()
qplanner := QueryPlanner{Database: database, Query: &query}
destination := fragment1.GetLocation()
id := util.RandomUUID()
log.Println(id)
qpp, err := qplanner.Plan(&query, &id, destination)
So(err, ShouldEqual, nil)
qp := *qpp
So(len(qp), ShouldEqual, 7)
So(qp[0].(GetQueryStep).Operation, ShouldEqual, "get")
So(qp[0].(GetQueryStep).Slice, ShouldEqual, 0)
So(*(qp[0].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
So(qp[1].(GetQueryStep).Operation, ShouldEqual, "get")
So(qp[1].(GetQueryStep).Slice, ShouldEqual, 0)
So(*(qp[1].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{20, "default", 0})
So(qp[2].(UnionQueryStep).Operation, ShouldEqual, "union")
So(qp[2].(UnionQueryStep).Inputs, ShouldResemble, []*util.GUID{
qp[0].(GetQueryStep).Id,
qp[1].(GetQueryStep).Id,
})
So(qp[3].(GetQueryStep).Operation, ShouldEqual, "get")
So(qp[3].(GetQueryStep).Slice, ShouldEqual, 1)
So(*(qp[3].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
So(qp[4].(GetQueryStep).Operation, ShouldEqual, "get")
So(qp[4].(GetQueryStep).Slice, ShouldEqual, 1)
So(*(qp[4].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{20, "default", 0})
So(qp[5].(UnionQueryStep).Operation, ShouldEqual, "union")
So(qp[5].(UnionQueryStep).Inputs, ShouldResemble, []*util.GUID{
qp[3].(GetQueryStep).Id,
qp[4].(GetQueryStep).Id,
})
So(qp[6].(CatQueryStep).Operation, ShouldEqual, "cat")
So(qp[6].(CatQueryStep).Inputs, ShouldResemble, []*util.GUID{
qp[2].(UnionQueryStep).Id,
qp[5].(UnionQueryStep).Id,
})
})
Convey("Get query plan - including parsing", t, func() {
query, err := QueryForPQL("get(10,default)")
So(err, ShouldEqual, nil)
database, fragment1 := basic_database()
qplanner := QueryPlanner{Database: database, Query: query}
destination := fragment1.GetLocation()
id := util.RandomUUID()
qpp, err := qplanner.Plan(query, &id, destination)
So(err, ShouldEqual, nil)
qp := *qpp
So(len(qp), ShouldEqual, 3)
So(qp[0].(GetQueryStep).Operation, ShouldEqual, "get")
So(qp[0].(GetQueryStep).Slice, ShouldEqual, 0)
So(*(qp[0].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
So(qp[1].(GetQueryStep).Operation, ShouldEqual, "get")
So(qp[1].(GetQueryStep).Slice, ShouldEqual, 1)
So(*(qp[1].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
So(qp[2].(CatQueryStep).Operation, ShouldEqual, "cat")
So(qp[2].(CatQueryStep).Inputs, ShouldResemble, []*util.GUID{
qp[0].(GetQueryStep).Id,
qp[1].(GetQueryStep).Id,
})
})
Convey("Union query plan - including parsing", t, func() {
query, err := QueryForPQL("union(get(10, default), get(20, default))")
So(err, ShouldEqual, nil)
database, fragment1 := basic_database()
qplanner := QueryPlanner{Database: database, Query: query}
destination := fragment1.GetLocation()
id := util.RandomUUID()
qpp, err := qplanner.Plan(query, &id, destination)
So(err, ShouldEqual, nil)
qp := *qpp
So(len(qp), ShouldEqual, 7)
So(qp[0].(GetQueryStep).Operation, ShouldEqual, "get")
So(qp[0].(GetQueryStep).Slice, ShouldEqual, 0)
So(*(qp[0].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
So(qp[1].(GetQueryStep).Operation, ShouldEqual, "get")
So(qp[1].(GetQueryStep).Slice, ShouldEqual, 0)
So(*(qp[1].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{20, "default", 0})
So(qp[2].(UnionQueryStep).Operation, ShouldEqual, "union")
So(qp[2].(UnionQueryStep).Inputs, ShouldResemble, []*util.GUID{
qp[0].(GetQueryStep).Id,
qp[1].(GetQueryStep).Id,
})
So(qp[3].(GetQueryStep).Operation, ShouldEqual, "get")
So(qp[3].(GetQueryStep).Slice, ShouldEqual, 1)
So(*(qp[3].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
So(qp[4].(GetQueryStep).Operation, ShouldEqual, "get")
So(qp[4].(GetQueryStep).Slice, ShouldEqual, 1)
So(*(qp[4].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{20, "default", 0})
So(qp[5].(UnionQueryStep).Operation, ShouldEqual, "union")
So(qp[5].(UnionQueryStep).Inputs, ShouldResemble, []*util.GUID{
qp[3].(GetQueryStep).Id,
qp[4].(GetQueryStep).Id,
})
So(qp[6].(CatQueryStep).Operation, ShouldEqual, "cat")
So(qp[6].(CatQueryStep).Inputs, ShouldResemble, []*util.GUID{
qp[2].(UnionQueryStep).Id,
qp[5].(UnionQueryStep).Id,
})
})
Convey("Set query plan - including parsing", t, func() {
query, err := QueryForPQL("set(10, default, 0, 100)")
So(err, ShouldEqual, nil)
database, fragment1 := basic_database()
qplanner := QueryPlanner{Database: database, Query: query}
destination := fragment1.GetLocation()
id := util.RandomUUID()
qpp, err := qplanner.Plan(query, &id, destination)
So(err, ShouldEqual, nil)
qp := *qpp
So(len(qp), ShouldEqual, 1)
So(qp[0].(SetQueryStep).Operation, ShouldEqual, "set")
So(qp[0].(SetQueryStep).ProfileId, ShouldEqual, 100)
So(*(qp[0].(SetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
})
Convey("Top-n query plan - including parsing", t, func() {
query, err := QueryForPQL("top-n(get(10, default), default, 50,[1,2,3])")
So(err, ShouldEqual, nil)
database, fragment1 := basic_database()
qplanner := QueryPlanner{Database: database, Query: query}
destination := fragment1.GetLocation()
id := util.RandomUUID()
qpp, err := qplanner.Plan(query, &id, destination)
So(err, ShouldEqual, nil)
qp := *qpp
So(err, ShouldEqual, nil)
So(len(qp), ShouldEqual, 5)
So(qp[0].(GetQueryStep).Operation, ShouldEqual, "get")
So(*(qp[0].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
So(qp[1].(*TopNQueryStep).Operation, ShouldEqual, "top-n")
So(qp[1].(*TopNQueryStep).Input, ShouldEqual, qp[0].(GetQueryStep).Id)
So(qp[1].(*TopNQueryStep).N, ShouldEqual, 50)
So(qp[1].(*TopNQueryStep).Filters, ShouldResemble, []uint64{1, 2, 3})
So(qp[2].(GetQueryStep).Operation, ShouldEqual, "get")
So(*(qp[2].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
So(qp[3].(*TopNQueryStep).Operation, ShouldEqual, "top-n")
So(qp[3].(*TopNQueryStep).Input, ShouldEqual, qp[2].(GetQueryStep).Id)
So(qp[3].(*TopNQueryStep).N, ShouldEqual, 50)
})
Convey("All query plan - including parsing", t, func() {
query, err := QueryForPQL("top-n(all(), default, 50, [1,2,3])")
So(err, ShouldEqual, nil)
database, fragment1 := basic_database()
qplanner := QueryPlanner{Database: database, Query: query}
destination := fragment1.GetLocation()
id := util.RandomUUID()
qpp, err := qplanner.Plan(query, &id, destination)
So(err, ShouldEqual, nil)
qp := *qpp
So(err, ShouldEqual, nil)
So(len(qp), ShouldEqual, 3)
So(qp[0].(*TopNQueryStep).Operation, ShouldEqual, "top-n")
So(qp[0].(*TopNQueryStep).Input, ShouldEqual, nil)
So(qp[0].(*TopNQueryStep).N, ShouldEqual, 50)
So(qp[0].(*TopNQueryStep).Filters, ShouldResemble, []uint64{1, 2, 3})
})
Convey("Get query plan - including parsing", t, func() {
_, err := QueryForPQL("count()")
So(err, ShouldNotEqual, nil)
_, err = QueryForPQL("count(intersect())")
So(err, ShouldNotEqual, nil)
_, err = QueryForPQL("count(get(10, default))")
So(err, ShouldEqual, nil)
_, err = QueryForPQL("count(union())")
So(err, ShouldNotEqual, nil)
})
Convey("Stash including parsing", t, func() {
qp, err := QueryForPQL("stash(union(get(10,default),get(20,default)))")
So(err, ShouldEqual, nil)
database, fragment1 := basic_database()
qplanner := QueryPlanner{Database: database, Query: qp}
destination := fragment1.GetLocation()
id := util.RandomUUID()
qpp, _ := qplanner.Plan(qp, &id, destination)
p := *qpp
So(len(p), ShouldNotEqual, 0)
log.Println(len(p))
spew.Dump(p[0])
})
if n := len(*plan); n != 1 {
t.Fatalf("unexpected plan length: %d", n)
}
if step := (*plan)[0].(query.SetQueryStep); step.Operation != "set" {
t.Fatalf("unexpected step(0) operation: %s", step.Operation)
} else if step.ProfileId != 100 {
t.Fatalf("unexpected step(0) profile id: %d", step.ProfileId)
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{10, "default", 0}) {
t.Fatalf("unexpected step(0) bitmap: %s", spew.Sprint(step.Bitmap))
}
}
// Ensure the query planner can plan a "top-n" query.
func TestQueryPlanner_Plan_TopN(t *testing.T) {
q, err := query.QueryForPQL("top-n(get(10, default), default, 50,[1,2,3])")
if err != nil {
t.Fatal(err)
}
d, frag1 := NewDefaultDB()
planner := query.QueryPlanner{Database: d, Query: q}
id := util.RandomUUID()
plan, err := planner.Plan(q, &id, frag1.GetLocation())
if err != nil {
t.Fatal(err)
}
if n := len(*plan); n != 5 {
t.Fatalf("unexpected plan length: %d", n)
}
if step := (*plan)[0].(query.GetQueryStep); step.Operation != "get" {
t.Fatalf("unexpected step(0) operation: %s", step.Operation)
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{10, "default", 0}) {
t.Fatalf("unexpected step(0) bitmap: %s", spew.Sprint(step.Bitmap))
}
if step := (*plan)[1].(*query.TopNQueryStep); step.Operation != "top-n" {
t.Fatalf("unexpected step(1) operation: %s", step.Operation)
} else if step.Input != (*plan)[0].(query.GetQueryStep).Id {
t.Fatalf("unexpected step(1) input: %d", step.Input)
} else if step.N != 50 {
t.Fatalf("unexpected step(1) n: %d", step.N)
} else if !reflect.DeepEqual(step.Filters, []uint64{1, 2, 3}) {
t.Fatalf("unexpected step(1) filters: %s", spew.Sprint(step.Filters))
}
if step := (*plan)[2].(query.GetQueryStep); step.Operation != "get" {
t.Fatalf("unexpected step(2) operation: %s", step.Operation)
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{10, "default", 0}) {
t.Fatalf("unexpected step(2) bitmap: %s", spew.Sprint(step.Bitmap))
}
if step := (*plan)[3].(*query.TopNQueryStep); step.Operation != "top-n" {
t.Fatalf("unexpected step(3) operation: %s", step.Operation)
} else if step.Input != (*plan)[2].(query.GetQueryStep).Id {
t.Fatalf("unexpected step(3) input: %d", step.Input)
} else if step.N != 50 {
t.Fatalf("unexpected step(3) n: %d", step.N)
}
}
// Ensure the query planner can plan a "top-n" all() query.
func TestQueryPlanner_Plan_TopN_All(t *testing.T) {
q, err := query.QueryForPQL("top-n(all(), default, 50, [1,2,3])")
if err != nil {
t.Fatal(err)
}
d, frag1 := NewDefaultDB()
planner := query.QueryPlanner{Database: d, Query: q}
id := util.RandomUUID()
plan, err := planner.Plan(q, &id, frag1.GetLocation())
if err != nil {
t.Fatal(err)
}
if n := len(*plan); n != 3 {
t.Fatalf("unexpected plan length: %d", n)
}
if step := (*plan)[0].(*query.TopNQueryStep); step.Operation != "top-n" {
t.Fatalf("unexpected step(0) operation: %s", step.Operation)
} else if step.Input != nil {
t.Fatalf("unexpected step(0) input: %v", step.Input)
} else if step.N != 50 {
t.Fatalf("unexpected step(0) n: %d", step.N)
} else if !reflect.DeepEqual(step.Filters, []uint64{1, 2, 3}) {
t.Fatalf("unexpected step(0) filters: %s", spew.Sprint(step.Filters))
}
}
// Ensure the query planner can plan a "union" query.
func TestQueryPlanner_Plan_Union(t *testing.T) {
id1 := util.RandomUUID()
q1 := query.Query{Id: &id1, Operation: "get", Args: map[string]interface{}{"id": uint64(10), "frame": "default"}}
id2 := util.RandomUUID()
q2 := query.Query{Id: &id2, Operation: "get", Args: map[string]interface{}{"id": uint64(20), "frame": "default"}}
id3 := util.RandomUUID()
q := query.Query{Id: &id3, Operation: "union", Subqueries: []query.Query{q1, q2}}
d, frag1 := NewDefaultDB()
planner := query.QueryPlanner{Database: d, Query: &q}
id := util.RandomUUID()
plan, err := planner.Plan(&q, &id, frag1.GetLocation())
if err != nil {
t.Fatal(err)
}
if n := len(*plan); n != 7 {
t.Fatalf("unexpected plan size: %d", n)
}
// First step should be a "get" step.
if step := (*plan)[0].(query.GetQueryStep); step.Operation != "get" {
t.Fatalf("unexpected step(0) operation: %s", step.Operation)
} else if step.Slice != 0 {
t.Fatalf("unexpected step(0) slice: %d", step.Slice)
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{10, "default", 0}) {
t.Fatalf("unexpected step(0) bitmap: %s", spew.Sprint(step.Bitmap))
}
// Second step should also be a "get" step.
if step := (*plan)[1].(query.GetQueryStep); step.Operation != "get" {
t.Fatalf("unexpected step(1) operation: %s", step.Operation)
} else if step.Slice != 0 {
t.Fatalf("unexpected step(1) slice: %d", step.Slice)
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{20, "default", 0}) {
t.Fatalf("unexpected step(1) bitmap: %s", spew.Sprint(step.Bitmap))
}
// Third step should union the first two steps.
if step := (*plan)[2].(query.UnionQueryStep); step.Operation != "union" {
t.Fatalf("unexpected step(2) operation: %s", step.Operation)
} else if !reflect.DeepEqual(step.Inputs, []*util.GUID{
(*plan)[0].(query.GetQueryStep).Id,
(*plan)[1].(query.GetQueryStep).Id,
}) {
t.Fatalf("unexpected step(2) inputs: %s", spew.Sprint(step.Inputs))
}
// Fourth step should be a "get" step.
if step := (*plan)[3].(query.GetQueryStep); step.Operation != "get" {
t.Fatalf("unexpected step(3) operation: %s", step.Operation)
} else if step.Slice != 1 {
t.Fatalf("unexpected step(3) slice: %d", step.Slice)
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{10, "default", 0}) {
t.Fatalf("unexpected step(3) bitmap: %s", spew.Sprint(step.Bitmap))
}
// Fifth step should also be a "get" step.
if step := (*plan)[4].(query.GetQueryStep); step.Operation != "get" {
t.Fatalf("unexpected step(4) operation: %s", step.Operation)
} else if step.Slice != 1 {
t.Fatalf("unexpected step(4) slice: %d", step.Slice)
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{20, "default", 0}) {
t.Fatalf("unexpected step(4) bitmap: %s", spew.Sprint(step.Bitmap))
}
// Sixth step should union the previous two steps.
if step := (*plan)[5].(query.UnionQueryStep); step.Operation != "union" {
t.Fatalf("unexpected step(5) operation: %s", step.Operation)
} else if !reflect.DeepEqual(step.Inputs, []*util.GUID{
(*plan)[3].(query.GetQueryStep).Id,
(*plan)[4].(query.GetQueryStep).Id,
}) {
t.Fatalf("unexpected step(5) inputs: %s", spew.Sprint(step.Inputs))
}
// Final step should concatenate the two union steps.
if step := (*plan)[6].(query.CatQueryStep); step.Operation != "cat" {
t.Fatalf("unexpected step(6) operation: %s", step.Operation)
} else if !reflect.DeepEqual(step.Inputs, []*util.GUID{
(*plan)[2].(query.UnionQueryStep).Id,
(*plan)[5].(query.UnionQueryStep).Id,
}) {
t.Fatalf("unexpected step(6) inputs: %s", spew.Sprint(step.Inputs))
}
}
// NewDefaultDB returns a simple, initialized database and fragment.
func NewDefaultDB() (*db.Database, *db.Fragment) {
// Create an empty database
c := db.NewCluster()
d := c.GetOrCreateDatabase("main")
f := d.GetOrCreateFrame("default")
s1 := d.GetOrCreateSlice(0)
frag1 := d.GetOrCreateFragment(f, s1, util.Id())
pid := util.RandomUUID()
p1 := db.NewProcess(&pid)
p1.SetHost("----192.1.1.0----")
frag1.SetProcess(p1)
s2 := d.GetOrCreateSlice(1)
frag2 := d.GetOrCreateFragment(f, s2, util.Id())
pid = util.RandomUUID()
p2 := db.NewProcess(&pid)
p2.SetHost("----192.1.1.1----")
frag2.SetProcess(p2)
return d, frag1
}

View file

@ -1,32 +1,36 @@
package query
package query_test
import (
"reflect"
"testing"
. "github.com/smartystreets/goconvey/convey"
"github.com/davecgh/go-spew/spew"
"github.com/umbel/pilosa/query"
)
func TestQuery(t *testing.T) {
Convey("Bracketed Lists 1", t, func() {
tokens, err := Lex("plugin(get(88, general), [get(12, general), get(13, general)])")
So(err, ShouldBeNil)
filter, filters := TokensToFilterStrings(tokens)
So(filter, ShouldEqual, "get(88,general)")
So(filters, ShouldResemble, []string{"get(12,general)", "get(13,general)"})
})
Convey("Bracketed Lists 2", t, func() {
tokens, err := Lex("plugin(intersect(get(88, general, [0]), get(77, b.n)), [get(12, general), get(13, general)])")
So(err, ShouldBeNil)
filter, filters := TokensToFilterStrings(tokens)
So(filter, ShouldEqual, "intersect(get(88,general,[0]),get(77,b.n))")
So(filters, ShouldResemble, []string{"get(12,general)", "get(13,general)"})
})
Convey("Bracketed Lists 3", t, func() {
tokens, err := Lex("plugin(intersect(get(88, general, [0]), get(77, b.n)))")
So(err, ShouldBeNil)
filter, filters := TokensToFilterStrings(tokens)
So(filter, ShouldEqual, "intersect(get(88,general,[0]),get(77,b.n))")
var empty []string
So(filters, ShouldResemble, empty)
})
func TestTokensToFilterStrings1(t *testing.T) {
filter, filters := query.TokensToFilterStrings(MustLex("plugin(get(88, general), [get(12, general), get(13, general)])"))
if filter != "get(88,general)" {
t.Fatalf("unexpected filter: %s", filter)
} else if !reflect.DeepEqual(filters, []string{"get(12,general)", "get(13,general)"}) {
t.Fatalf("unexpected filters: %s", spew.Sprint(filters))
}
}
func TestTokensToFilterStrings2(t *testing.T) {
filter, filters := query.TokensToFilterStrings(MustLex("plugin(intersect(get(88, general, [0]), get(77, b.n)), [get(12, general), get(13, general)])"))
if filter != "intersect(get(88,general,[0]),get(77,b.n))" {
t.Fatalf("unexpected filter: %s", filter)
} else if !reflect.DeepEqual(filters, []string{"get(12,general)", "get(13,general)"}) {
t.Fatalf("unexpected filters: %s", spew.Sprint(filters))
}
}
func TestTokensToFilterStrings3(t *testing.T) {
filter, filters := query.TokensToFilterStrings(MustLex("plugin(intersect(get(88, general, [0]), get(77, b.n)))"))
if filter != "intersect(get(88,general,[0]),get(77,b.n))" {
t.Fatalf("unexpected filter: %s", filter)
} else if !reflect.DeepEqual(filters, []string(nil)) {
t.Fatalf("unexpected filters: %s", spew.Sprint(filters))
}
}