OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |