Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(359)

Side by Side Diff: service/datastore/datastore_test.go

Issue 2007123002: datastore: Update AllocateIDs to take keys. (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/gae@master
Patch Set: Rebase, comments. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « service/datastore/datastore.go ('k') | service/datastore/finalized_query.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The LUCI Authors. All rights reserved. 1 // Copyright 2015 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 // adapted from github.com/golang/appengine/datastore 5 // adapted from github.com/golang/appengine/datastore
6 6
7 package datastore 7 package datastore
8 8
9 import ( 9 import (
10 "bytes" 10 "bytes"
(...skipping 13 matching lines...) Expand all
24 24
25 func fakeDatastoreFactory(c context.Context, wantTxn bool) RawInterface { 25 func fakeDatastoreFactory(c context.Context, wantTxn bool) RawInterface {
26 i := info.Get(c) 26 i := info.Get(c)
27 fds := fakeDatastore{ 27 fds := fakeDatastore{
28 aid: i.FullyQualifiedAppID(), 28 aid: i.FullyQualifiedAppID(),
29 } 29 }
30 fds.ns, _ = i.GetNamespace() 30 fds.ns, _ = i.GetNamespace()
31 return &fds 31 return &fds
32 } 32 }
33 33
34 var (
35 errFail = errors.New("Individual element fail")
36 errFailAll = errors.New("Operation fail")
37 )
38
34 type fakeDatastore struct { 39 type fakeDatastore struct {
35 RawInterface 40 RawInterface
36 aid string 41 aid string
37 ns string 42 ns string
38 } 43 }
39 44
40 func (f *fakeDatastore) mkKey(elems ...interface{}) *Key { 45 func (f *fakeDatastore) mkKey(elems ...interface{}) *Key {
41 return MakeKey(f.aid, f.ns, elems...) 46 return MakeKey(f.aid, f.ns, elems...)
42 } 47 }
43 48
49 func (f *fakeDatastore) newKey(kind, stringID string, intID int64, parent *Key) *Key {
50 return NewKey(f.aid, f.ns, kind, stringID, intID, parent)
51 }
52
53 func (f *fakeDatastore) AllocateIDs(keys []*Key, cb NewKeyCB) error {
54 if keys[0].Kind() == "FailAll" {
55 return errFailAll
56 }
57 for i, k := range keys {
58 if k.Kind() == "Fail" {
59 cb(nil, errFail)
60 } else {
61 cb(f.newKey(k.Kind(), "", int64(i+1), k.Parent()), nil)
62 }
63 }
64 return nil
65 }
66
44 func (f *fakeDatastore) Run(fq *FinalizedQuery, cb RawRunCB) error { 67 func (f *fakeDatastore) Run(fq *FinalizedQuery, cb RawRunCB) error {
45 lim, _ := fq.Limit() 68 lim, _ := fq.Limit()
46 69
47 cursCB := func() (Cursor, error) { 70 cursCB := func() (Cursor, error) {
48 return fakeCursor("CURSOR"), nil 71 return fakeCursor("CURSOR"), nil
49 } 72 }
50 73
51 for i := int32(0); i < lim; i++ { 74 for i := int32(0); i < lim; i++ {
52 if v, ok := fq.eqFilts["$err_single"]; ok { 75 if v, ok := fq.eqFilts["$err_single"]; ok {
53 idx := fq.eqFilts["$err_single_idx"][0].Value().(int64) 76 idx := fq.eqFilts["$err_single_idx"][0].Value().(int64)
54 if idx == int64(i) { 77 if idx == int64(i) {
55 return errors.New(v[0].Value().(string)) 78 return errors.New(v[0].Value().(string))
56 } 79 }
57 } 80 }
58 k := f.mkKey("Kind", i+1) 81 k := f.mkKey("Kind", i+1)
59 if i == 10 { 82 if i == 10 {
60 k = f.mkKey("Kind", "eleven") 83 k = f.mkKey("Kind", "eleven")
61 } 84 }
62 pm := PropertyMap{"Value": {MkProperty(i)}} 85 pm := PropertyMap{"Value": {MkProperty(i)}}
63 if err := cb(k, pm, cursCB); err != nil { 86 if err := cb(k, pm, cursCB); err != nil {
64 if err == Stop { 87 if err == Stop {
65 err = nil 88 err = nil
66 } 89 }
67 return err 90 return err
68 } 91 }
69 } 92 }
70 return nil 93 return nil
71 } 94 }
72 95
73 var ( 96 func (f *fakeDatastore) PutMulti(keys []*Key, vals []PropertyMap, cb NewKeyCB) e rror {
74 » errFail = errors.New("Individual element fail")
75 » errFailAll = errors.New("Operation fail")
76 )
77
78 func (f *fakeDatastore) PutMulti(keys []*Key, vals []PropertyMap, cb PutMultiCB) error {
79 if keys[0].Kind() == "FailAll" { 97 if keys[0].Kind() == "FailAll" {
80 return errFailAll 98 return errFailAll
81 } 99 }
82 _, assertExtra := vals[0].GetMeta("assertExtra") 100 _, assertExtra := vals[0].GetMeta("assertExtra")
83 for i, k := range keys { 101 for i, k := range keys {
84 err := error(nil) 102 err := error(nil)
85 if k.Kind() == "Fail" { 103 if k.Kind() == "Fail" {
86 err = errFail 104 err = errFail
87 } else { 105 } else {
88 So(vals[i]["Value"], ShouldResemble, []Property{MkProper ty(i)}) 106 So(vals[i]["Value"], ShouldResemble, []Property{MkProper ty(i)})
89 if assertExtra { 107 if assertExtra {
90 So(vals[i]["Extra"], ShouldResemble, []Property{ MkProperty("whoa")}) 108 So(vals[i]["Extra"], ShouldResemble, []Property{ MkProperty("whoa")})
91 } 109 }
92 » » » if k.Incomplete() { 110 » » » if k.IsIncomplete() {
93 k = NewKey(k.AppID(), k.Namespace(), k.Kind(), " ", int64(i+1), k.Parent()) 111 k = NewKey(k.AppID(), k.Namespace(), k.Kind(), " ", int64(i+1), k.Parent())
94 } 112 }
95 } 113 }
96 cb(k, err) 114 cb(k, err)
97 } 115 }
98 return nil 116 return nil
99 } 117 }
100 118
101 const noSuchEntityID = 0xdead 119 const noSuchEntityID = 0xdead
102 120
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after
389 407
390 func TestPopulateKey(t *testing.T) { 408 func TestPopulateKey(t *testing.T) {
391 t.Parallel() 409 t.Parallel()
392 410
393 Convey("Test PopulateKey", t, func() { 411 Convey("Test PopulateKey", t, func() {
394 k := NewKey("app", "namespace", "kind", "", 1337, nil) 412 k := NewKey("app", "namespace", "kind", "", 1337, nil)
395 413
396 Convey("Can set the key of a common struct.", func() { 414 Convey("Can set the key of a common struct.", func() {
397 var cs CommonStruct 415 var cs CommonStruct
398 416
399 » » » PopulateKey(&cs, k) 417 » » » So(PopulateKey(&cs, k), ShouldBeTrue)
400 So(cs.ID, ShouldEqual, 1337) 418 So(cs.ID, ShouldEqual, 1337)
401 }) 419 })
402 420
403 Convey("Will not set the value of a singleton struct.", func() { 421 Convey("Will not set the value of a singleton struct.", func() {
404 var ss SingletonStruct 422 var ss SingletonStruct
405 423
406 » » » PopulateKey(&ss, k) 424 » » » So(PopulateKey(&ss, k), ShouldBeFalse)
407 So(ss.id, ShouldEqual, 0) 425 So(ss.id, ShouldEqual, 0)
408 }) 426 })
409 427
410 Convey("Will panic when setting the key of a bad struct.", func( ) { 428 Convey("Will panic when setting the key of a bad struct.", func( ) {
411 var bs badStruct 429 var bs badStruct
412 430
413 So(func() { PopulateKey(&bs, k) }, ShouldPanic) 431 So(func() { PopulateKey(&bs, k) }, ShouldPanic)
414 }) 432 })
415 433
416 Convey("Will panic when setting the key of a broken PLS struct." , func() { 434 Convey("Will panic when setting the key of a broken PLS struct." , func() {
417 var broken permaBad 435 var broken permaBad
418 436
419 So(func() { PopulateKey(&broken, k) }, ShouldPanic) 437 So(func() { PopulateKey(&broken, k) }, ShouldPanic)
420 }) 438 })
421 }) 439 })
422 } 440 }
423 441
442 func TestAllocateIDs(t *testing.T) {
443 t.Parallel()
444
445 Convey("A testing environment", t, func() {
446 c := info.Set(context.Background(), fakeInfo{})
447 c = SetRawFactory(c, fakeDatastoreFactory)
448 ds := Get(c)
449
450 Convey("Testing AllocateIDs", func() {
451 Convey("Will return nil if no entities are supplied.", f unc() {
452 So(ds.AllocateIDs(), ShouldBeNil)
453 })
454
455 Convey("single struct", func() {
456 cs := CommonStruct{Value: 1}
457 So(ds.AllocateIDs(&cs), ShouldBeNil)
458 So(cs.ID, ShouldEqual, 1)
459 })
460
461 Convey("struct slice", func() {
462 csSlice := []*CommonStruct{{Value: 1}, {Value: 2 }}
463 So(ds.AllocateIDs(csSlice), ShouldBeNil)
464 So(csSlice, ShouldResemble, []*CommonStruct{{ID: 1, Value: 1}, {ID: 2, Value: 2}})
465 })
466
467 Convey("single key will fail", func() {
468 singleKey := ds.MakeKey("FooParent", "BarParent" , "Foo", "Bar")
469 So(func() { ds.AllocateIDs(singleKey) }, ShouldP anicLike,
470 "invalid input type (*datastore.Key): no t a PLS, pointer-to-struct, or slice thereof")
471 })
472
473 Convey("key slice", func() {
474 k0 := ds.MakeKey("Foo", "Bar")
475 k1 := ds.MakeKey("Baz", "Qux")
476 keySlice := []*Key{k0, k1}
477 So(ds.AllocateIDs(keySlice), ShouldBeNil)
478 So(keySlice[0].Equal(ds.MakeKey("Foo", 1)), Shou ldBeTrue)
479 So(keySlice[1].Equal(ds.MakeKey("Baz", 2)), Shou ldBeTrue)
480
481 // The original keys should not have changed.
482 So(k0.Equal(ds.MakeKey("Foo", "Bar")), ShouldBeT rue)
483 So(k1.Equal(ds.MakeKey("Baz", "Qux")), ShouldBeT rue)
484 })
485
486 Convey("fail all key slice", func() {
487 keySlice := []*Key{ds.MakeKey("FailAll", "oops") , ds.MakeKey("Baz", "Qux")}
488 So(ds.AllocateIDs(keySlice), ShouldEqual, errFai lAll)
489 So(keySlice[0].StringID(), ShouldEqual, "oops")
490 So(keySlice[1].StringID(), ShouldEqual, "Qux")
491 })
492
493 Convey("fail key slice", func() {
494 keySlice := []*Key{ds.MakeKey("Fail", "oops"), d s.MakeKey("Baz", "Qux")}
495 So(ds.AllocateIDs(keySlice), ShouldResemble, err ors.MultiError{errFail, nil})
496 So(keySlice[0].StringID(), ShouldEqual, "oops")
497 So(keySlice[1].IntID(), ShouldEqual, 2)
498 })
499
500 Convey("vararg with errors", func() {
501 successSlice := []CommonStruct{{Value: 0}, {Valu e: 1}}
502 failSlice := []FakePLS{{Kind: "Fail"}, {Value: 3 }}
503 emptySlice := []CommonStruct(nil)
504 cs0 := CommonStruct{Value: 4}
505 cs1 := FakePLS{Kind: "Fail", Value: 5}
506 keySlice := []*Key{ds.MakeKey("Foo", "Bar"), ds. MakeKey("Baz", "Qux")}
507 fpls := FakePLS{StringID: "ohai", Value: 6}
508
509 err := ds.AllocateIDs(successSlice, failSlice, e mptySlice, &cs0, &cs1, keySlice, &fpls)
510 So(err, ShouldResemble, errors.MultiError{
511 nil, errors.MultiError{errFail, nil}, ni l, nil, errFail, nil, nil})
512 So(successSlice[0].ID, ShouldEqual, 1)
513 So(successSlice[1].ID, ShouldEqual, 2)
514 So(failSlice[1].IntID, ShouldEqual, 4)
515 So(cs0.ID, ShouldEqual, 5)
516 So(keySlice[0].Equal(ds.MakeKey("Foo", 7)), Shou ldBeTrue)
517 So(keySlice[1].Equal(ds.MakeKey("Baz", 8)), Shou ldBeTrue)
518 So(fpls.IntID, ShouldEqual, 9)
519 })
520 })
521 })
522 }
523
424 func TestPut(t *testing.T) { 524 func TestPut(t *testing.T) {
425 t.Parallel() 525 t.Parallel()
426 526
427 Convey("A testing environment", t, func() { 527 Convey("A testing environment", t, func() {
428 c := info.Set(context.Background(), fakeInfo{}) 528 c := info.Set(context.Background(), fakeInfo{})
429 c = SetRawFactory(c, fakeDatastoreFactory) 529 c = SetRawFactory(c, fakeDatastoreFactory)
430 ds := Get(c) 530 ds := Get(c)
431 531
432 Convey("Testing Put", func() { 532 Convey("Testing Put", func() {
433 Convey("bad", func() { 533 Convey("bad", func() {
434 Convey("static can't serialize", func() { 534 Convey("static can't serialize", func() {
435 bss := []badStruct{{}, {}} 535 bss := []badStruct{{}, {}}
436 So(func() { ds.Put(bss) }, ShouldPanicLi ke, 536 So(func() { ds.Put(bss) }, ShouldPanicLi ke,
437 `field "Compy" has invalid type` ) 537 `field "Compy" has invalid type` )
438 }) 538 })
439 539
440 Convey("static ptr can't serialize", func() { 540 Convey("static ptr can't serialize", func() {
441 bss := []*badStruct{{}, {}} 541 bss := []*badStruct{{}, {}}
442 So(func() { ds.Put(bss) }, ShouldPanicLi ke, 542 So(func() { ds.Put(bss) }, ShouldPanicLi ke,
443 `field "Compy" has invalid type: complex64`) 543 `field "Compy" has invalid type: complex64`)
444 }) 544 })
445 545
446 Convey("static bad type", func() { 546 Convey("static bad type", func() {
447 So(func() { ds.Put(100) }, ShouldPanicLi ke, 547 So(func() { ds.Put(100) }, ShouldPanicLi ke,
448 » » » » » » "invalid input type (int): not a PLS or pointer-to-struct") 548 » » » » » » "invalid input type (int): not a PLS, pointer-to-struct, or slice thereof")
449 }) 549 })
450 550
451 Convey("static bad type (slice of bad type)", fu nc() { 551 Convey("static bad type (slice of bad type)", fu nc() {
452 So(func() { ds.Put([]int{}) }, ShouldPan icLike, 552 So(func() { ds.Put([]int{}) }, ShouldPan icLike,
453 » » » » » » "invalid input type ([]int): not a PLS or pointer-to-struct") 553 » » » » » » "invalid input type ([]int): not a PLS, pointer-to-struct, or slice thereof")
454 }) 554 })
455 555
456 Convey("dynamic can't serialize", func() { 556 Convey("dynamic can't serialize", func() {
457 fplss := []FakePLS{{failSave: true}, {}} 557 fplss := []FakePLS{{failSave: true}, {}}
458 So(ds.Put(fplss), ShouldErrLike, "FakePL S.Save") 558 So(ds.Put(fplss), ShouldErrLike, "FakePL S.Save")
459 }) 559 })
460 560
461 Convey("can't get keys", func() { 561 Convey("can't get keys", func() {
462 fplss := []FakePLS{{failGetMeta: true}, {}} 562 fplss := []FakePLS{{failGetMeta: true}, {}}
463 So(ds.Put(fplss), ShouldErrLike, "unable to extract $kind") 563 So(ds.Put(fplss), ShouldErrLike, "unable to extract $kind")
464 }) 564 })
465 565
466 Convey("get single error for RPC failure", func( ) { 566 Convey("get single error for RPC failure", func( ) {
467 fplss := []FakePLS{{Kind: "FailAll"}, {} } 567 fplss := []FakePLS{{Kind: "FailAll"}, {} }
468 So(ds.Put(fplss), ShouldEqual, errFailAl l) 568 So(ds.Put(fplss), ShouldEqual, errFailAl l)
469 }) 569 })
470 570
471 Convey("get multi error for individual failures" , func() { 571 Convey("get multi error for individual failures" , func() {
472 fplss := []FakePLS{{}, {Kind: "Fail"}} 572 fplss := []FakePLS{{}, {Kind: "Fail"}}
473 So(ds.Put(fplss), ShouldResemble, errors .MultiError{nil, errFail}) 573 So(ds.Put(fplss), ShouldResemble, errors .MultiError{nil, errFail})
474 }) 574 })
475 575
476 Convey("get with *Key is an error", func() { 576 Convey("get with *Key is an error", func() {
477 So(func() { ds.Get(&Key{}) }, ShouldPani cLike, 577 So(func() { ds.Get(&Key{}) }, ShouldPani cLike,
478 » » » » » » "invalid input type (*datastore. Key): not user datatype") 578 » » » » » » "invalid input type (*datastore. Key): not a PLS, pointer-to-struct, or slice thereof")
479 }) 579 })
480 580
481 Convey("struct with no $kind is an error", func( ) { 581 Convey("struct with no $kind is an error", func( ) {
482 s := MGSWithNoKind{} 582 s := MGSWithNoKind{}
483 So(ds.Put(&s), ShouldErrLike, "unable to extract $kind") 583 So(ds.Put(&s), ShouldErrLike, "unable to extract $kind")
484 }) 584 })
485 585
486 Convey("struct with invalid but non-nil key is a n error", func() { 586 Convey("struct with invalid but non-nil key is a n error", func() {
487 type BadParent struct { 587 type BadParent struct {
488 ID int64 `gae:"$id"` 588 ID int64 `gae:"$id"`
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after
878 }) 978 })
879 979
880 Convey("get with nil is an error", func() { 980 Convey("get with nil is an error", func() {
881 So(func() { ds.Get(nil) }, ShouldPanicLi ke, 981 So(func() { ds.Get(nil) }, ShouldPanicLi ke,
882 "cannot use nil as single argume nt") 982 "cannot use nil as single argume nt")
883 }) 983 })
884 984
885 Convey("get with ptr-to-nonstruct is an error", func() { 985 Convey("get with ptr-to-nonstruct is an error", func() {
886 val := 100 986 val := 100
887 So(func() { ds.Get(&val) }, ShouldPanicL ike, 987 So(func() { ds.Get(&val) }, ShouldPanicL ike,
888 » » » » » » "invalid input type (*int): not a PLS or pointer-to-struct") 988 » » » » » » "invalid input type (*int): not a PLS, pointer-to-struct, or slice thereof")
889 }) 989 })
890 990
891 Convey("failure to save metadata is no problem t hough", func() { 991 Convey("failure to save metadata is no problem t hough", func() {
892 // It just won't save the key 992 // It just won't save the key
893 cs := &FakePLS{IntID: 10, failSetMeta: t rue} 993 cs := &FakePLS{IntID: 10, failSetMeta: t rue}
894 So(ds.Get(cs), ShouldBeNil) 994 So(ds.Get(cs), ShouldBeNil)
895 }) 995 })
896 996
897 Convey("vararg with errors", func() { 997 Convey("vararg with errors", func() {
898 successSlice := []CommonStruct{{ID: 1}, {ID: 2}} 998 successSlice := []CommonStruct{{ID: 1}, {ID: 2}}
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after
1308 data, ok := d.data[k.String()] 1408 data, ok := d.data[k.String()]
1309 if ok { 1409 if ok {
1310 cb(data, nil) 1410 cb(data, nil)
1311 } else { 1411 } else {
1312 cb(nil, ErrNoSuchEntity) 1412 cb(nil, ErrNoSuchEntity)
1313 } 1413 }
1314 } 1414 }
1315 return nil 1415 return nil
1316 } 1416 }
1317 1417
1318 func (d *fixedDataDatastore) PutMulti(keys []*Key, vals []PropertyMap, cb PutMul tiCB) error { 1418 func (d *fixedDataDatastore) PutMulti(keys []*Key, vals []PropertyMap, cb NewKey CB) error {
1319 if d.data == nil { 1419 if d.data == nil {
1320 d.data = make(map[string]PropertyMap, len(keys)) 1420 d.data = make(map[string]PropertyMap, len(keys))
1321 } 1421 }
1322 for i, k := range keys { 1422 for i, k := range keys {
1323 » » if k.Incomplete() { 1423 » » if k.IsIncomplete() {
1324 panic("key is incomplete, don't do that.") 1424 panic("key is incomplete, don't do that.")
1325 } 1425 }
1326 d.data[k.String()], _ = vals[i].Save(false) 1426 d.data[k.String()], _ = vals[i].Save(false)
1327 cb(k, nil) 1427 cb(k, nil)
1328 } 1428 }
1329 return nil 1429 return nil
1330 } 1430 }
1331 1431
1332 func TestSchemaChange(t *testing.T) { 1432 func TestSchemaChange(t *testing.T) {
1333 t.Parallel() 1433 t.Parallel()
(...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after
1814 if err != nil { 1914 if err != nil {
1815 panic(fmt.Errorf("failed to find absolute path f or `%s`", sameLevelDir)) 1915 panic(fmt.Errorf("failed to find absolute path f or `%s`", sameLevelDir))
1816 } 1916 }
1817 1917
1818 ids, err := FindAndParseIndexYAML(abs) 1918 ids, err := FindAndParseIndexYAML(abs)
1819 So(err, ShouldBeNil) 1919 So(err, ShouldBeNil)
1820 So(ids[1].Kind, ShouldEqual, "Test Foo") 1920 So(ids[1].Kind, ShouldEqual, "Test Foo")
1821 }) 1921 })
1822 }) 1922 })
1823 } 1923 }
OLDNEW
« no previous file with comments | « service/datastore/datastore.go ('k') | service/datastore/finalized_query.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698