OLD | NEW |
1 // Copyright 2016 The LUCI Authors. All rights reserved. | 1 // Copyright 2016 The LUCI Authors. All rights reserved. |
2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
4 | 4 |
5 package cloud | 5 package cloud |
6 | 6 |
7 import ( | 7 import ( |
8 "crypto/rand" | 8 "crypto/rand" |
9 "encoding/hex" | 9 "encoding/hex" |
10 "fmt" | 10 "fmt" |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 testTime := ds.RoundTime(time.Date(2016, 1, 1, 0, 0, 0, 0, time.
UTC)) | 82 testTime := ds.RoundTime(time.Date(2016, 1, 1, 0, 0, 0, 0, time.
UTC)) |
83 _ = testTime | 83 _ = testTime |
84 | 84 |
85 c = Use(c, client) | 85 c = Use(c, client) |
86 | 86 |
87 Convey(`Supports namespaces`, func() { | 87 Convey(`Supports namespaces`, func() { |
88 namespaces := []string{"foo", "bar", "baz"} | 88 namespaces := []string{"foo", "bar", "baz"} |
89 | 89 |
90 // Clear all used entities from all namespaces. | 90 // Clear all used entities from all namespaces. |
91 for _, ns := range namespaces { | 91 for _, ns := range namespaces { |
92 » » » » nsCtx := info.Get(c).MustNamespace(ns) | 92 » » » » nsCtx := info.MustNamespace(c, ns) |
93 » » » » di := ds.Get(nsCtx) | |
94 | 93 |
95 keys := make([]*ds.Key, len(namespaces)) | 94 keys := make([]*ds.Key, len(namespaces)) |
96 for i := range keys { | 95 for i := range keys { |
97 » » » » » keys[i] = di.MakeKey("Test", i+1) | 96 » » » » » keys[i] = ds.MakeKey(nsCtx, "Test", i+1) |
98 } | 97 } |
99 » » » » So(errors.Filter(di.DeleteMulti(keys), ds.ErrNoS
uchEntity), ShouldBeNil) | 98 » » » » So(errors.Filter(ds.Delete(nsCtx, keys), ds.ErrN
oSuchEntity), ShouldBeNil) |
100 } | 99 } |
101 | 100 |
102 // Put one entity per namespace. | 101 // Put one entity per namespace. |
103 for i, ns := range namespaces { | 102 for i, ns := range namespaces { |
104 » » » » nsCtx := info.Get(c).MustNamespace(ns) | 103 » » » » nsCtx := info.MustNamespace(c, ns) |
105 | 104 |
106 pmap := ds.PropertyMap{"$kind": mkp("Test"), "$i
d": mkp(i + 1), "Value": mkp(i)} | 105 pmap := ds.PropertyMap{"$kind": mkp("Test"), "$i
d": mkp(i + 1), "Value": mkp(i)} |
107 » » » » So(ds.Get(nsCtx).Put(pmap), ShouldBeNil) | 106 » » » » So(ds.Put(nsCtx, pmap), ShouldBeNil) |
108 } | 107 } |
109 | 108 |
110 // Make sure that entity only exists in that namespace. | 109 // Make sure that entity only exists in that namespace. |
111 for _, ns := range namespaces { | 110 for _, ns := range namespaces { |
112 » » » » nsCtx := info.Get(c).MustNamespace(ns) | 111 » » » » nsCtx := info.MustNamespace(c, ns) |
113 | 112 |
114 for i := range namespaces { | 113 for i := range namespaces { |
115 pmap := ds.PropertyMap{"$kind": mkp("Tes
t"), "$id": mkp(i + 1)} | 114 pmap := ds.PropertyMap{"$kind": mkp("Tes
t"), "$id": mkp(i + 1)} |
116 » » » » » err := ds.Get(nsCtx).Get(pmap) | 115 » » » » » err := ds.Get(nsCtx, pmap) |
117 | 116 |
118 if namespaces[i] == ns { | 117 if namespaces[i] == ns { |
119 So(err, ShouldBeNil) | 118 So(err, ShouldBeNil) |
120 } else { | 119 } else { |
121 So(err, ShouldEqual, ds.ErrNoSuc
hEntity) | 120 So(err, ShouldEqual, ds.ErrNoSuc
hEntity) |
122 } | 121 } |
123 } | 122 } |
124 } | 123 } |
125 }) | 124 }) |
126 | 125 |
127 Convey(`In a clean random testing namespace`, func() { | 126 Convey(`In a clean random testing namespace`, func() { |
128 // Enter a namespace for this round of tests. | 127 // Enter a namespace for this round of tests. |
129 randNamespace := make([]byte, 32) | 128 randNamespace := make([]byte, 32) |
130 if _, err := rand.Read(randNamespace); err != nil { | 129 if _, err := rand.Read(randNamespace); err != nil { |
131 panic(err) | 130 panic(err) |
132 } | 131 } |
133 » » » c = info.Get(c).MustNamespace(fmt.Sprintf("testing-%s",
hex.EncodeToString(randNamespace))) | 132 » » » c = info.MustNamespace(c, fmt.Sprintf("testing-%s", hex.
EncodeToString(randNamespace))) |
134 » » » di := ds.Get(c) | |
135 | 133 |
136 // Execute a kindless query to clear the namespace. | 134 // Execute a kindless query to clear the namespace. |
137 q := ds.NewQuery("").KeysOnly(true) | 135 q := ds.NewQuery("").KeysOnly(true) |
138 var allKeys []*ds.Key | 136 var allKeys []*ds.Key |
139 » » » So(di.GetAll(q, &allKeys), ShouldBeNil) | 137 » » » So(ds.GetAll(c, q, &allKeys), ShouldBeNil) |
140 » » » So(di.DeleteMulti(allKeys), ShouldBeNil) | 138 » » » So(ds.Delete(c, allKeys), ShouldBeNil) |
141 | 139 |
142 Convey(`Can allocate an ID range`, func() { | 140 Convey(`Can allocate an ID range`, func() { |
143 var keys []*ds.Key | 141 var keys []*ds.Key |
144 » » » » keys = append(keys, di.NewIncompleteKeys(10, "Ba
r", di.MakeKey("Foo", 12))...) | 142 » » » » keys = append(keys, ds.NewIncompleteKeys(c, 10,
"Bar", ds.MakeKey(c, "Foo", 12))...) |
145 » » » » keys = append(keys, di.NewIncompleteKeys(10, "Ba
z", di.MakeKey("Foo", 12))...) | 143 » » » » keys = append(keys, ds.NewIncompleteKeys(c, 10,
"Baz", ds.MakeKey(c, "Foo", 12))...) |
146 | 144 |
147 seen := map[string]struct{}{} | 145 seen := map[string]struct{}{} |
148 » » » » So(di.AllocateIDs(keys), ShouldBeNil) | 146 » » » » So(ds.AllocateIDs(c, keys), ShouldBeNil) |
149 for _, k := range keys { | 147 for _, k := range keys { |
150 So(k.IsIncomplete(), ShouldBeFalse) | 148 So(k.IsIncomplete(), ShouldBeFalse) |
151 seen[k.String()] = struct{}{} | 149 seen[k.String()] = struct{}{} |
152 } | 150 } |
153 | 151 |
154 » » » » So(di.AllocateIDs(keys), ShouldBeNil) | 152 » » » » So(ds.AllocateIDs(c, keys), ShouldBeNil) |
155 for _, k := range keys { | 153 for _, k := range keys { |
156 So(k.IsIncomplete(), ShouldBeFalse) | 154 So(k.IsIncomplete(), ShouldBeFalse) |
157 | 155 |
158 _, ok := seen[k.String()] | 156 _, ok := seen[k.String()] |
159 So(ok, ShouldBeFalse) | 157 So(ok, ShouldBeFalse) |
160 } | 158 } |
161 }) | 159 }) |
162 | 160 |
163 Convey(`Can get, put, and delete entities`, func() { | 161 Convey(`Can get, put, and delete entities`, func() { |
164 // Put: "foo", "bar", "baz". | 162 // Put: "foo", "bar", "baz". |
165 put := []ds.PropertyMap{ | 163 put := []ds.PropertyMap{ |
166 {"$kind": mkp("test"), "$id": mkp("foo")
, "Value": mkp(1337)}, | 164 {"$kind": mkp("test"), "$id": mkp("foo")
, "Value": mkp(1337)}, |
167 {"$kind": mkp("test"), "$id": mkp("bar")
, "Value": mkp(42)}, | 165 {"$kind": mkp("test"), "$id": mkp("bar")
, "Value": mkp(42)}, |
168 {"$kind": mkp("test"), "$id": mkp("baz")
, "Value": mkp(0xd065)}, | 166 {"$kind": mkp("test"), "$id": mkp("baz")
, "Value": mkp(0xd065)}, |
169 } | 167 } |
170 » » » » So(di.PutMulti(put), ShouldBeNil) | 168 » » » » So(ds.Put(c, put), ShouldBeNil) |
171 delete(put[0], "$key") | 169 delete(put[0], "$key") |
172 delete(put[1], "$key") | 170 delete(put[1], "$key") |
173 delete(put[2], "$key") | 171 delete(put[2], "$key") |
174 | 172 |
175 // Delete: "bar". | 173 // Delete: "bar". |
176 » » » » So(di.Delete(di.MakeKey("test", "bar")), ShouldB
eNil) | 174 » » » » So(ds.Delete(c, ds.MakeKey(c, "test", "bar")), S
houldBeNil) |
177 | 175 |
178 // Get: "foo", "bar", "baz" | 176 // Get: "foo", "bar", "baz" |
179 get := []ds.PropertyMap{ | 177 get := []ds.PropertyMap{ |
180 {"$kind": mkp("test"), "$id": mkp("foo")
}, | 178 {"$kind": mkp("test"), "$id": mkp("foo")
}, |
181 {"$kind": mkp("test"), "$id": mkp("bar")
}, | 179 {"$kind": mkp("test"), "$id": mkp("bar")
}, |
182 {"$kind": mkp("test"), "$id": mkp("baz")
}, | 180 {"$kind": mkp("test"), "$id": mkp("baz")
}, |
183 } | 181 } |
184 | 182 |
185 » » » » err := di.GetMulti(get) | 183 » » » » err := ds.Get(c, get) |
186 So(err, ShouldHaveSameTypeAs, errors.MultiError(
nil)) | 184 So(err, ShouldHaveSameTypeAs, errors.MultiError(
nil)) |
187 | 185 |
188 merr := err.(errors.MultiError) | 186 merr := err.(errors.MultiError) |
189 So(len(merr), ShouldEqual, 3) | 187 So(len(merr), ShouldEqual, 3) |
190 So(merr[0], ShouldBeNil) | 188 So(merr[0], ShouldBeNil) |
191 So(merr[1], ShouldEqual, ds.ErrNoSuchEntity) | 189 So(merr[1], ShouldEqual, ds.ErrNoSuchEntity) |
192 So(merr[2], ShouldBeNil) | 190 So(merr[2], ShouldBeNil) |
193 | 191 |
194 // put[1] will not be retrieved (delete) | 192 // put[1] will not be retrieved (delete) |
195 put[1] = get[1] | 193 put[1] = get[1] |
196 So(get, ShouldResemble, put) | 194 So(get, ShouldResemble, put) |
197 }) | 195 }) |
198 | 196 |
199 Convey(`Can put and get all supported entity fields.`, f
unc() { | 197 Convey(`Can put and get all supported entity fields.`, f
unc() { |
200 put := ds.PropertyMap{ | 198 put := ds.PropertyMap{ |
201 "$id": mkpNI("foo"), | 199 "$id": mkpNI("foo"), |
202 "$kind": mkpNI("FooType"), | 200 "$kind": mkpNI("FooType"), |
203 | 201 |
204 "Number": mkp(1337), | 202 "Number": mkp(1337), |
205 "String": mkpNI("hello"), | 203 "String": mkpNI("hello"), |
206 "Bytes": mkp([]byte("world")), | 204 "Bytes": mkp([]byte("world")), |
207 "Time": mkp(testTime), | 205 "Time": mkp(testTime), |
208 "Float": mkpNI(3.14), | 206 "Float": mkpNI(3.14), |
209 » » » » » "Key": mkp(di.MakeKey("Parent", "P
arentID", "Child", 1337)), | 207 » » » » » "Key": mkp(ds.MakeKey(c, "Parent",
"ParentID", "Child", 1337)), |
210 "Null": mkp(nil), | 208 "Null": mkp(nil), |
211 "NullSlice": mkp(nil, nil), | 209 "NullSlice": mkp(nil, nil), |
212 | 210 |
213 "ComplexSlice": mkp(1337, "string", []by
te("bytes"), testTime, float32(3.14), | 211 "ComplexSlice": mkp(1337, "string", []by
te("bytes"), testTime, float32(3.14), |
214 » » » » » » float64(2.71), true, nil, di.Mak
eKey("SomeKey", "SomeID")), | 212 » » » » » » float64(2.71), true, nil, ds.Mak
eKey(c, "SomeKey", "SomeID")), |
215 | 213 |
216 "Single": mkp("single"), | 214 "Single": mkp("single"), |
217 "SingleSlice": mkProperties(true, true,
"single"), // Force a single "multi" value. | 215 "SingleSlice": mkProperties(true, true,
"single"), // Force a single "multi" value. |
218 "EmptySlice": ds.PropertySlice(nil), | 216 "EmptySlice": ds.PropertySlice(nil), |
219 } | 217 } |
220 » » » » So(di.Put(put), ShouldBeNil) | 218 » » » » So(ds.Put(c, put), ShouldBeNil) |
221 delete(put, "$key") | 219 delete(put, "$key") |
222 | 220 |
223 get := ds.PropertyMap{ | 221 get := ds.PropertyMap{ |
224 "$id": mkpNI("foo"), | 222 "$id": mkpNI("foo"), |
225 "$kind": mkpNI("FooType"), | 223 "$kind": mkpNI("FooType"), |
226 } | 224 } |
227 » » » » So(di.Get(get), ShouldBeNil) | 225 » » » » So(ds.Get(c, get), ShouldBeNil) |
228 So(get, ShouldResemble, put) | 226 So(get, ShouldResemble, put) |
229 }) | 227 }) |
230 | 228 |
231 Convey(`With several entities installed`, func() { | 229 Convey(`With several entities installed`, func() { |
232 » » » » So(di.PutMulti([]ds.PropertyMap{ | 230 » » » » So(ds.Put(c, []ds.PropertyMap{ |
233 {"$kind": mkp("Test"), "$id": mkp("foo")
, "FooBar": mkp(true)}, | 231 {"$kind": mkp("Test"), "$id": mkp("foo")
, "FooBar": mkp(true)}, |
234 {"$kind": mkp("Test"), "$id": mkp("bar")
, "FooBar": mkp(true)}, | 232 {"$kind": mkp("Test"), "$id": mkp("bar")
, "FooBar": mkp(true)}, |
235 {"$kind": mkp("Test"), "$id": mkp("baz")
}, | 233 {"$kind": mkp("Test"), "$id": mkp("baz")
}, |
236 {"$kind": mkp("Test"), "$id": mkp("qux")
}, | 234 {"$kind": mkp("Test"), "$id": mkp("qux")
}, |
237 }), ShouldBeNil) | 235 }), ShouldBeNil) |
238 | 236 |
239 q := ds.NewQuery("Test") | 237 q := ds.NewQuery("Test") |
240 | 238 |
241 Convey(`Can query for entities with FooBar == tr
ue.`, func() { | 239 Convey(`Can query for entities with FooBar == tr
ue.`, func() { |
242 var results []ds.PropertyMap | 240 var results []ds.PropertyMap |
243 q = q.Eq("FooBar", true) | 241 q = q.Eq("FooBar", true) |
244 » » » » » So(di.GetAll(q, &results), ShouldBeNil) | 242 » » » » » So(ds.GetAll(c, q, &results), ShouldBeNi
l) |
245 | 243 |
246 So(results, ShouldResemble, []ds.Propert
yMap{ | 244 So(results, ShouldResemble, []ds.Propert
yMap{ |
247 » » » » » » {"$key": mkpNI(di.MakeKey("Test"
, "bar")), "FooBar": mkp(true)}, | 245 » » » » » » {"$key": mkpNI(ds.MakeKey(c, "Te
st", "bar")), "FooBar": mkp(true)}, |
248 » » » » » » {"$key": mkpNI(di.MakeKey("Test"
, "foo")), "FooBar": mkp(true)}, | 246 » » » » » » {"$key": mkpNI(ds.MakeKey(c, "Te
st", "foo")), "FooBar": mkp(true)}, |
249 }) | 247 }) |
250 }) | 248 }) |
251 | 249 |
252 Convey(`Can query for entities whose __key__ > "
baz".`, func() { | 250 Convey(`Can query for entities whose __key__ > "
baz".`, func() { |
253 var results []ds.PropertyMap | 251 var results []ds.PropertyMap |
254 » » » » » q = q.Gt("__key__", di.MakeKey("Test", "
baz")) | 252 » » » » » q = q.Gt("__key__", ds.MakeKey(c, "Test"
, "baz")) |
255 » » » » » So(di.GetAll(q, &results), ShouldBeNil) | 253 » » » » » So(ds.GetAll(c, q, &results), ShouldBeNi
l) |
256 | 254 |
257 So(results, ShouldResemble, []ds.Propert
yMap{ | 255 So(results, ShouldResemble, []ds.Propert
yMap{ |
258 » » » » » » {"$key": mkpNI(di.MakeKey("Test"
, "foo")), "FooBar": mkp(true)}, | 256 » » » » » » {"$key": mkpNI(ds.MakeKey(c, "Te
st", "foo")), "FooBar": mkp(true)}, |
259 » » » » » » {"$key": mkpNI(di.MakeKey("Test"
, "qux"))}, | 257 » » » » » » {"$key": mkpNI(ds.MakeKey(c, "Te
st", "qux"))}, |
260 }) | 258 }) |
261 }) | 259 }) |
262 | 260 |
263 Convey(`Can transactionally get and put.`, func(
) { | 261 Convey(`Can transactionally get and put.`, func(
) { |
264 » » » » » err := di.RunInTransaction(func(c contex
t.Context) error { | 262 » » » » » err := ds.RunInTransaction(c, func(c con
text.Context) error { |
265 » » » » » » di := ds.Get(c) | |
266 | |
267 pmap := ds.PropertyMap{"$kind":
mkp("Test"), "$id": mkp("qux")} | 263 pmap := ds.PropertyMap{"$kind":
mkp("Test"), "$id": mkp("qux")} |
268 » » » » » » if err := di.Get(pmap); err != n
il { | 264 » » » » » » if err := ds.Get(c, pmap); err !
= nil { |
269 return err | 265 return err |
270 } | 266 } |
271 | 267 |
272 pmap["ExtraField"] = mkp("Presen
t!") | 268 pmap["ExtraField"] = mkp("Presen
t!") |
273 » » » » » » return di.Put(pmap) | 269 » » » » » » return ds.Put(c, pmap) |
274 }, nil) | 270 }, nil) |
275 So(err, ShouldBeNil) | 271 So(err, ShouldBeNil) |
276 | 272 |
277 pmap := ds.PropertyMap{"$kind": mkp("Tes
t"), "$id": mkp("qux")} | 273 pmap := ds.PropertyMap{"$kind": mkp("Tes
t"), "$id": mkp("qux")} |
278 » » » » » err = di.RunInTransaction(func(c context
.Context) error { | 274 » » » » » err = ds.RunInTransaction(c, func(c cont
ext.Context) error { |
279 » » » » » » return ds.Get(c).Get(pmap) | 275 » » » » » » return ds.Get(c, pmap) |
280 }, nil) | 276 }, nil) |
281 So(err, ShouldBeNil) | 277 So(err, ShouldBeNil) |
282 So(pmap, ShouldResemble, ds.PropertyMap{
"$kind": mkp("Test"), "$id": mkp("qux"), "ExtraField": mkp("Present!")}) | 278 So(pmap, ShouldResemble, ds.PropertyMap{
"$kind": mkp("Test"), "$id": mkp("qux"), "ExtraField": mkp("Present!")}) |
283 }) | 279 }) |
284 | 280 |
285 Convey(`Can fail in a transaction with no effect
.`, func() { | 281 Convey(`Can fail in a transaction with no effect
.`, func() { |
286 testError := errors.New("test error") | 282 testError := errors.New("test error") |
287 | 283 |
288 » » » » » err := di.RunInTransaction(func(c contex
t.Context) error { | 284 » » » » » noTxnPM := ds.PropertyMap{"$kind": mkp("
Test"), "$id": mkp("no txn")} |
289 » » » » » » di := ds.Get(c) | 285 » » » » » err := ds.RunInTransaction(c, func(c con
text.Context) error { |
| 286 » » » » » » So(ds.CurrentTransaction(c), Sho
uldNotBeNil) |
290 | 287 |
291 pmap := ds.PropertyMap{"$kind":
mkp("Test"), "$id": mkp("quux")} | 288 pmap := ds.PropertyMap{"$kind":
mkp("Test"), "$id": mkp("quux")} |
292 » » » » » » if err := di.Put(pmap); err != n
il { | 289 » » » » » » if err := ds.Put(c, pmap); err !
= nil { |
| 290 » » » » » » » return err |
| 291 » » » » » » } |
| 292 |
| 293 » » » » » » // Put an entity outside of the
transaction so we can confirm that |
| 294 » » » » » » // it was added even when the tr
ansaction fails. |
| 295 » » » » » » if err := ds.Put(ds.WithoutTrans
action(c), noTxnPM); err != nil { |
293 return err | 296 return err |
294 } | 297 } |
295 return testError | 298 return testError |
296 }, nil) | 299 }, nil) |
297 So(err, ShouldEqual, testError) | 300 So(err, ShouldEqual, testError) |
298 | 301 |
| 302 // Confirm that noTxnPM was added. |
| 303 So(ds.CurrentTransaction(c), ShouldBeNil
) |
| 304 So(ds.Get(c, noTxnPM), ShouldBeNil) |
| 305 |
299 pmap := ds.PropertyMap{"$kind": mkp("Tes
t"), "$id": mkp("quux")} | 306 pmap := ds.PropertyMap{"$kind": mkp("Tes
t"), "$id": mkp("quux")} |
300 » » » » » err = di.RunInTransaction(func(c context
.Context) error { | 307 » » » » » err = ds.RunInTransaction(c, func(c cont
ext.Context) error { |
301 » » » » » » return ds.Get(c).Get(pmap) | 308 » » » » » » return ds.Get(c, pmap) |
302 }, nil) | 309 }, nil) |
303 So(err, ShouldEqual, ds.ErrNoSuchEntity) | 310 So(err, ShouldEqual, ds.ErrNoSuchEntity) |
304 }) | 311 }) |
305 }) | 312 }) |
306 }) | 313 }) |
307 }) | 314 }) |
308 } | 315 } |
OLD | NEW |