syncbase: syncQL: add back query_checker_test for offset
Add a check for the correct offset in query_checker_test.go.
Change-Id: Ib525ad95e2070b2c88b6a5ec6bcf0667fe208b19
diff --git a/v23/syncbase/nosql/internal/query/query_checker/query_checker_test.go b/v23/syncbase/nosql/internal/query/query_checker/query_checker_test.go
index 93947b2..ba3b5a3 100644
--- a/v23/syncbase/nosql/internal/query/query_checker/query_checker_test.go
+++ b/v23/syncbase/nosql/internal/query/query_checker/query_checker_test.go
@@ -13,67 +13,15 @@
"v.io/syncbase/v23/syncbase/nosql/internal/query/query_checker"
"v.io/syncbase/v23/syncbase/nosql/internal/query/query_parser"
"v.io/syncbase/v23/syncbase/nosql/query_db"
+ "v.io/syncbase/v23/syncbase/nosql/query_exec"
"v.io/syncbase/v23/syncbase/nosql/syncql"
"v.io/v23"
"v.io/v23/context"
"v.io/v23/verror"
_ "v.io/x/ref/runtime/factories/generic"
"v.io/x/ref/test"
- "strings"
)
-// oneOf represents an expectation that more than one type of error may be
-// returned by the corresponding test.
-type oneOf []interface{}
-
-func (o oneOf) matches(err error) bool {
- for _, e := range o {
- switch e := e.(type) {
- case error:
- if e.Error() == err.Error() {
- return true
- }
- case vErrorContaining:
- vErr, ok := err.(verror.E)
- if !ok {
- continue
- }
- if e.matches(vErr) {
- return true
- }
- }
- }
- return false
-}
-
-// containing represents an expectation that an error will be of the given
-// VError type and will contain the given string.
-type vErrorContaining struct {
- id verror.ID
- message string
-}
-
-func newVErrorContaining(id verror.ID, message string) vErrorContaining {
- return vErrorContaining{
- id: id,
- message: message,
- }
-}
-
-func (v vErrorContaining) matches(err verror.E) bool {
- if err.ID != v.id {
- return false
- }
- if !strings.Contains(err.Error(), v.message) {
- return false
- }
- return true
-}
-
-func (v vErrorContaining) String() string {
- return fmt.Sprintf("VError containing ID=%s, message=%s", v.id, v.message)
-}
-
type mockDB struct {
ctx *context.T
}
@@ -133,7 +81,7 @@
type parseSelectErrorTest struct {
query string
- err interface{}
+ err error
}
func TestQueryChecker(t *testing.T) {
@@ -485,53 +433,18 @@
{"select v from Customer where v.ZipCode is not 94303", syncql.NewErrIsIsNotRequireRhsNil(db.GetContext(), 46)},
{"select v from Customer where v.ZipCode is not true", syncql.NewErrIsIsNotRequireRhsNil(db.GetContext(), 46)},
{"select v from Customer where v.ZipCode is not 943.03", syncql.NewErrIsIsNotRequireRhsNil(db.GetContext(), 46)},
- // TODO(jkline): check offset for the 1.5 tests.
- {"select v from Customer where Type(v) = \"Customer\" and Year(v.InvoiceDate, \"ABC\") = 2015", oneOf([]interface{}{
- // Go1.4
- syncql.NewErrLocationConversionError(db.GetContext(), 74, errors.New("unknown time zone ABC")),
- // Go1.5
- newVErrorContaining(syncql.ErrLocationConversionError.ID, "cannot find ABC in zip file"),
- })},
- {"select v from Customer where Type(v) = \"Customer\" and Month(v.InvoiceDate, \"ABC\") = 2015", oneOf([]interface{} {
- // Go1.4
- syncql.NewErrLocationConversionError(db.GetContext(), 75, errors.New("unknown time zone ABC")),
- // Go1.5
- newVErrorContaining(syncql.ErrLocationConversionError.ID, "cannot find ABC in zip file"),
- })},
- {"select v from Customer where Type(v) = \"Customer\" and Day(v.InvoiceDate, \"ABC\") = 2015", oneOf([]interface{} {
- // Go1.4
- syncql.NewErrLocationConversionError(db.GetContext(), 73, errors.New("unknown time zone ABC")),
- // Go1.5
- newVErrorContaining(syncql.ErrLocationConversionError.ID, "cannot find ABC in zip file"),
- })},
- {"select v from Customer where Type(v) = \"Customer\" and Hour(v.InvoiceDate, \"ABC\") = 2015", oneOf([]interface{} {
- // Go1.4
- syncql.NewErrLocationConversionError(db.GetContext(), 74, errors.New("unknown time zone ABC")),
- // Go1.5
- newVErrorContaining(syncql.ErrLocationConversionError.ID, "cannot find ABC in zip file"),
- })},
- {"select v from Customer where Type(v) = \"Customer\" and Minute(v.InvoiceDate, \"ABC\") = 2015", oneOf([]interface{} {
- // Go1.4
- syncql.NewErrLocationConversionError(db.GetContext(), 76, errors.New("unknown time zone ABC")),
- // Go1.5
- newVErrorContaining(syncql.ErrLocationConversionError.ID, "cannot find ABC in zip file"),
- })},
- {"select v from Customer where Type(v) = \"Customer\" and Second(v.InvoiceDate, \"ABC\") = 2015", oneOf([]interface{} {
- // Go1.4
- syncql.NewErrLocationConversionError(db.GetContext(), 76, errors.New("unknown time zone ABC")),
- // Go1.5
- newVErrorContaining(syncql.ErrLocationConversionError.ID, "cannot find ABC in zip file"),
- })},
+ {"select v from Customer where Type(v) = \"Customer\" and Year(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrLocationConversionError(db.GetContext(), 74, errors.New("unknown time zone ABC"))},
+ {"select v from Customer where Type(v) = \"Customer\" and Month(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrLocationConversionError(db.GetContext(), 75, errors.New("unknown time zone ABC"))},
+ {"select v from Customer where Type(v) = \"Customer\" and Day(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrLocationConversionError(db.GetContext(), 73, errors.New("unknown time zone ABC"))},
+ {"select v from Customer where Type(v) = \"Customer\" and Hour(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrLocationConversionError(db.GetContext(), 74, errors.New("unknown time zone ABC"))},
+ {"select v from Customer where Type(v) = \"Customer\" and Minute(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrLocationConversionError(db.GetContext(), 76, errors.New("unknown time zone ABC"))},
+ {"select v from Customer where Type(v) = \"Customer\" and Second(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrLocationConversionError(db.GetContext(), 76, errors.New("unknown time zone ABC"))},
{"select v from Customer where Type(v) = \"Customer\" and Now(v.InvoiceDate, \"ABC\") = 2015", syncql.NewErrFunctionArgCount(db.GetContext(), 54, "Now", 0, 2)},
{"select v from Customer where Type(v) = \"Customer\" and Lowercase(v.Name, 2) = \"smith\"", syncql.NewErrFunctionArgCount(db.GetContext(), 54, "Lowercase", 1, 2)},
{"select v from Customer where Type(v) = \"Customer\" and Uppercase(v.Name, 2) = \"SMITH\"", syncql.NewErrFunctionArgCount(db.GetContext(), 54, "Uppercase", 1, 2)},
{"select Time() from Customer", syncql.NewErrFunctionArgCount(db.GetContext(), 7, "Time", 2, 0)},
- {"select Year(v.InvoiceDate, \"Foo\") from Customer where Type(v) = \"Invoice\"", oneOf([]interface{}{
- // Go1.4
- syncql.NewErrLocationConversionError(db.GetContext(), 27, errors.New("unknown time zone Foo")),
- // Go1.5
- newVErrorContaining(syncql.ErrLocationConversionError.ID, "cannot find Foo in zip file"),
- })},
+ {"select Year(v.InvoiceDate, \"Foo\") from Customer where Type(v) = \"Invoice\"",
+ syncql.NewErrLocationConversionError(db.GetContext(), 27, errors.New("unknown time zone Foo"))},
{"select K from Customer where Type(v) = \"Invoice\"", syncql.NewErrDidYouMeanLowercaseK(db.GetContext(), 7)},
{"select V from Customer where Type(v) = \"Invoice\"", syncql.NewErrDidYouMeanLowercaseV(db.GetContext(), 7)},
{"select k from Customer where K = \"001\"", syncql.NewErrDidYouMeanLowercaseK(db.GetContext(), 29)},
@@ -545,16 +458,11 @@
t.Errorf("query: %s; unexpected error: got %v, want nil", test.query, syntaxErr)
} else {
err := query_checker.Check(&db, s)
- // Test both that the IDs compare and the text compares (since the offset needs to match).
- switch e := test.err.(type) {
- case error:
- if verror.ErrorID(err) != verror.ErrorID(e) || err.Error() != e.Error() {
- t.Errorf("query: %s; got %v, want %v", test.query, err, test.err)
- }
- case oneOf:
- if !e.matches(err) {
- t.Errorf("query: %s; got %v, want one of %s", test.query, err, e)
- }
+ // Test both that the ID and offset are equal.
+ testErrOff, _ := query_exec.SplitError(test.err)
+ errOff, _ := query_exec.SplitError(err)
+ if verror.ErrorID(test.err) != verror.ErrorID(err) || testErrOff != errOff {
+ t.Errorf("query: %s; got %v, want %v", test.query, err, test.err)
}
}
}
diff --git a/v23/syncbase/nosql/query_exec/error_offset_test.go b/v23/syncbase/nosql/query_exec/error_offset_test.go
new file mode 100644
index 0000000..caff1de
--- /dev/null
+++ b/v23/syncbase/nosql/query_exec/error_offset_test.go
@@ -0,0 +1,66 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package query_exec
+
+import (
+ "errors"
+ "fmt"
+ "testing"
+
+ "v.io/syncbase/v23/syncbase/nosql/query_db"
+ "v.io/syncbase/v23/syncbase/nosql/syncql"
+ "v.io/v23"
+ "v.io/v23/context"
+ _ "v.io/x/ref/runtime/factories/generic"
+ "v.io/x/ref/test"
+)
+
+type mockDB struct {
+ ctx *context.T
+}
+
+func (db *mockDB) GetContext() *context.T {
+ return db.ctx
+}
+
+func init() {
+ var shutdown v23.Shutdown
+ db.ctx, shutdown = test.V23Init()
+ defer shutdown()
+}
+
+func (db *mockDB) GetTable(table string) (query_db.Table, error) {
+ return nil, errors.New(fmt.Sprintf("No such table: %s", table))
+}
+
+var db mockDB
+
+type splitErrorTest struct {
+ err error
+ offset int64
+ errStr string
+}
+
+func TestSplitError(t *testing.T) {
+ basic := []splitErrorTest{
+ {
+ syncql.NewErrInvalidSelectField(db.GetContext(), 7),
+ 7,
+ "Select field must be 'k' or 'v[{.<ident>}...]'.",
+ },
+ {
+ syncql.NewErrTableCantAccess(db.GetContext(), 14, "Bob", errors.New("No such table: Bob")),
+ 14,
+ "Table Bob does not exist (or cannot be accessed): No such table: Bob.",
+ },
+ }
+
+ for _, test := range basic {
+ offset, errStr := SplitError(test.err)
+ if offset != test.offset || errStr != test.errStr {
+ t.Errorf("err: %v; got %d:%s, want %d:%s", test.err, offset, errStr, test.offset, test.errStr)
+ }
+ }
+}
diff --git a/v23/syncbase/nosql/query_exec/exec.go b/v23/syncbase/nosql/query_exec/exec.go
index edff51e..a166839 100644
--- a/v23/syncbase/nosql/query_exec/exec.go
+++ b/v23/syncbase/nosql/query_exec/exec.go
@@ -5,6 +5,8 @@
package query_exec
import (
+ "strconv"
+ "strings"
"v.io/syncbase/v23/syncbase/nosql"
"v.io/syncbase/v23/syncbase/nosql/internal/query"
"v.io/syncbase/v23/syncbase/nosql/query_db"
@@ -16,3 +18,22 @@
func Exec(db query_db.Database, q string) ([]string, nosql.ResultStream, error) {
return query.Exec(db, q)
}
+
+// Split an error message into an offset and the remaining (i.e., rhs of offset) message.
+// The convention for syncql is "<module><optional-rpc>[offset]<remaining-message>".
+// TODO(jkline): find a better place for client utilities (which, in this case, is also
+// used by internal tests).
+func SplitError(err error) (int64, string) {
+ errMsg := err.Error()
+ idx1 := strings.Index(errMsg, "[")
+ idx2 := strings.Index(errMsg, "]")
+ if idx1 == -1 || idx2 == -1 {
+ return 0, errMsg
+ }
+ offsetString := errMsg[idx1+1 : idx2]
+ offset, err := strconv.ParseInt(offsetString, 10, 64)
+ if err != nil {
+ return 0, errMsg
+ }
+ return offset, errMsg[idx2+1:]
+}