OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package memory |
| 6 |
| 7 import ( |
| 8 "math" |
| 9 "testing" |
| 10 |
| 11 dsS "github.com/luci/gae/service/datastore" |
| 12 . "github.com/smartystreets/goconvey/convey" |
| 13 "golang.org/x/net/context" |
| 14 ) |
| 15 |
| 16 const ( |
| 17 MaxUint = ^uint(0) |
| 18 MaxInt = int(MaxUint >> 1) |
| 19 IntIs32Bits = int64(MaxInt) < math.MaxInt64 |
| 20 ) |
| 21 |
| 22 func TestDatastoreQueries(t *testing.T) { |
| 23 Convey("Datastore Query suport", t, func() { |
| 24 c := Use(context.Background()) |
| 25 ds := dsS.Get(c) |
| 26 So(ds, ShouldNotBeNil) |
| 27 |
| 28 Convey("can create good queries", func() { |
| 29 q := ds.NewQuery("Foo").KeysOnly().Limit(10).Offset(39) |
| 30 q = q.Start(queryCursor("kosmik")).End(queryCursor("krab
s")) |
| 31 So(q, ShouldNotBeNil) |
| 32 So(q.(*queryImpl).err, ShouldBeNil) |
| 33 done, err := q.(*queryImpl).valid("", false) |
| 34 So(done, ShouldBeFalse) |
| 35 So(err, ShouldBeNil) |
| 36 }) |
| 37 |
| 38 Convey("ensures orders make sense", func() { |
| 39 q := ds.NewQuery("Cool") |
| 40 q = q.Filter("cat =", 19).Filter("bob =", 10).Order("bob
").Order("bob") |
| 41 |
| 42 Convey("removes dups and equality orders", func() { |
| 43 q = q.Order("wat") |
| 44 qi := q.(*queryImpl) |
| 45 done, err := qi.valid("", false) |
| 46 So(done, ShouldBeFalse) |
| 47 So(err, ShouldBeNil) |
| 48 So(qi.order, ShouldResemble, []dsS.IndexColumn{{
Property: "wat"}}) |
| 49 }) |
| 50 |
| 51 Convey("if we equality-filter on __key__, that's just si
lly", func() { |
| 52 q = q.Order("wat") |
| 53 q := q.Filter("__key__ =", ds.NewKey("Foo", "wat
", 0, nil)) |
| 54 _, err := q.(*queryImpl).valid("", false) |
| 55 So(err.Error(), ShouldContainSubstring, |
| 56 "query equality filter on __key__ is sil
ly") |
| 57 }) |
| 58 |
| 59 }) |
| 60 |
| 61 Convey("inequalities apply immediately", func() { |
| 62 // NOTE: this is (maybe?) a slight divergence from reali
ty, but it's |
| 63 // helpful to retain sanity. It's possible that in real-
appengine, many |
| 64 // inequalities count towards the MaxQueryComponents lim
it (100), where |
| 65 // in this system we will never have more than 2 (an upp
er and lower |
| 66 // bound). |
| 67 }) |
| 68 |
| 69 Convey("can create bad queries", func() { |
| 70 q := ds.NewQuery("Foo") |
| 71 |
| 72 Convey("only one inequality", func() { |
| 73 q = q.Order("bob").Order("wat") |
| 74 q = q.Filter("bob >", 10).Filter("wat <", 29) |
| 75 qi := q.(*queryImpl) |
| 76 _, err := qi.valid("", false) |
| 77 So(err.Error(), ShouldContainSubstring, |
| 78 "inequality filters on multiple properti
es") |
| 79 }) |
| 80 |
| 81 Convey("bad filter ops", func() { |
| 82 q := q.Filter("Bob !", "value") |
| 83 So(q.(*queryImpl).err.Error(), ShouldContainSubs
tring, "invalid operator \"!\"") |
| 84 }) |
| 85 Convey("bad filter", func() { |
| 86 q := q.Filter("Bob", "value") |
| 87 So(q.(*queryImpl).err.Error(), ShouldContainSubs
tring, "invalid filter") |
| 88 }) |
| 89 Convey("bad order", func() { |
| 90 q := q.Order("+Bob") |
| 91 So(q.(*queryImpl).err.Error(), ShouldContainSubs
tring, "invalid order") |
| 92 }) |
| 93 Convey("empty", func() { |
| 94 q := q.Order("") |
| 95 So(q.(*queryImpl).err.Error(), ShouldContainSubs
tring, "empty order") |
| 96 }) |
| 97 Convey("OOB limit", func() { |
| 98 // this is supremely stupid. The SDK uses 'int'
which measn we have to |
| 99 // use it too, but then THEY BOUNDS CHECK IT FOR
32 BITS... *sigh* |
| 100 if !IntIs32Bits { |
| 101 q := q.Limit(MaxInt) |
| 102 So(q.(*queryImpl).err.Error(), ShouldCon
tainSubstring, "query limit overflow") |
| 103 } |
| 104 }) |
| 105 Convey("underflow offset", func() { |
| 106 q := q.Offset(-29) |
| 107 So(q.(*queryImpl).err.Error(), ShouldContainSubs
tring, "negative query offset") |
| 108 }) |
| 109 Convey("OOB offset", func() { |
| 110 if !IntIs32Bits { |
| 111 q := q.Offset(MaxInt) |
| 112 So(q.(*queryImpl).err.Error(), ShouldCon
tainSubstring, "query offset overflow") |
| 113 } |
| 114 }) |
| 115 Convey("Bad cursors", func() { |
| 116 q := q.Start(queryCursor("")).End(queryCursor(""
)) |
| 117 So(q.(*queryImpl).err.Error(), ShouldContainSubs
tring, "invalid cursor") |
| 118 }) |
| 119 Convey("Bad ancestors", func() { |
| 120 q := q.Ancestor(ds.NewKey("Goop", "wat", 10, nil
)) |
| 121 So(q, ShouldNotBeNil) |
| 122 _, err := q.(*queryImpl).valid("", false) |
| 123 So(err, ShouldEqual, dsS.ErrInvalidKey) |
| 124 }) |
| 125 Convey("nil ancestors", func() { |
| 126 _, err := q.Ancestor(nil).(*queryImpl).valid("",
false) |
| 127 So(err.Error(), ShouldContainSubstring, "nil que
ry ancestor") |
| 128 }) |
| 129 Convey("Bad key filters", func() { |
| 130 q := q.Filter("__key__ >", ds.NewKey("Goop", "wa
t", 10, nil)) |
| 131 _, err := q.(*queryImpl).valid("", false) |
| 132 So(err, ShouldEqual, dsS.ErrInvalidKey) |
| 133 }) |
| 134 Convey("non-ancestor queries in a transaction", func() { |
| 135 _, err := q.(*queryImpl).valid("", true) |
| 136 So(err.Error(), ShouldContainSubstring, "Only an
cestor queries") |
| 137 }) |
| 138 Convey("absurd numbers of filters are prohibited", func(
) { |
| 139 q := q.Ancestor(ds.NewKey("thing", "wat", 0, nil
)) |
| 140 for i := 0; i < 100; i++ { |
| 141 q = q.Filter("something =", i) |
| 142 } |
| 143 _, err := q.(*queryImpl).valid("", false) |
| 144 So(err.Error(), ShouldContainSubstring, "query i
s too large") |
| 145 }) |
| 146 Convey("filters for __key__ that aren't keys", func() { |
| 147 q := q.Filter("__key__ > ", 10) |
| 148 _, err := q.(*queryImpl).valid("", false) |
| 149 So(err.Error(), ShouldContainSubstring, "is not
a key") |
| 150 }) |
| 151 Convey("multiple inequalities", func() { |
| 152 q := q.Filter("bob > ", 19).Filter("charlie < ",
20) |
| 153 _, err := q.(*queryImpl).valid("", false) |
| 154 So(err.Error(), ShouldContainSubstring, |
| 155 "inequality filters on multiple properti
es") |
| 156 }) |
| 157 Convey("bad sort orders", func() { |
| 158 q := q.Filter("bob > ", 19).Order("-charlie") |
| 159 _, err := q.(*queryImpl).valid("", false) |
| 160 So(err.Error(), ShouldContainSubstring, "first s
ort order") |
| 161 }) |
| 162 Convey("kindless with non-__key__ filters", func() { |
| 163 q := ds.NewQuery("").Filter("face <", 25.3) |
| 164 _, err := q.(*queryImpl).valid("", false) |
| 165 So(err.Error(), ShouldContainSubstring, |
| 166 "kindless queries can only filter on __k
ey__") |
| 167 }) |
| 168 Convey("kindless with non-__key__ orders", func() { |
| 169 q := ds.NewQuery("").Order("face") |
| 170 _, err := q.(*queryImpl).valid("", false) |
| 171 So(err.Error(), ShouldContainSubstring, |
| 172 "invalid order for kindless query") |
| 173 }) |
| 174 Convey("kindless with decending-__key__ orders", func()
{ |
| 175 q := ds.NewQuery("").Order("-__key__") |
| 176 _, err := q.(*queryImpl).valid("", false) |
| 177 So(err.Error(), ShouldContainSubstring, |
| 178 "invalid order for kindless query") |
| 179 }) |
| 180 }) |
| 181 |
| 182 }) |
| 183 } |
OLD | NEW |