OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package memory | 5 package memory |
6 | 6 |
7 import ( | 7 import ( |
8 "fmt" | 8 "fmt" |
9 "testing" | 9 "testing" |
10 | 10 |
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 So(txnDS.Get(f), ShouldBeNil) | 294 So(txnDS.Get(f), ShouldBeNil) |
295 So(f.Val, ShouldEqual, 10) | 295 So(f.Val, ShouldEqual, 10) |
296 | 296 |
297 f.Val = 20 | 297 f.Val = 20 |
298 So(txnDS.Put(f), ShouldBeNil) | 298 So(txnDS.Put(f), ShouldBeNil) |
299 | 299 |
300 So(txnDS.Get(f), ShouldBeNil) | 300 So(txnDS.Get(f), ShouldBeNil) |
301 So(f.Val, ShouldEqual, 10) // st
ill gets 10 | 301 So(f.Val, ShouldEqual, 10) // st
ill gets 10 |
302 | 302 |
303 return nil | 303 return nil |
304 » » » » » }, nil) | 304 » » » » » }, &dsS.TransactionOptions{Attempts: 1}) |
305 So(err.Error(), ShouldContainSubstring,
"concurrent") | 305 So(err.Error(), ShouldContainSubstring,
"concurrent") |
306 | 306 |
307 f := &Foo{Id: 1} | 307 f := &Foo{Id: 1} |
308 So(ds.Get(f), ShouldBeNil) | 308 So(ds.Get(f), ShouldBeNil) |
309 So(f.Val, ShouldEqual, 11) | 309 So(f.Val, ShouldEqual, 11) |
310 }) | 310 }) |
311 | 311 |
312 Convey("Reusing a transaction context is bad new
s", func() { | 312 Convey("Reusing a transaction context is bad new
s", func() { |
313 txnDS := dsS.Interface(nil) | 313 txnDS := dsS.Interface(nil) |
314 err := ds.RunInTransaction(func(c contex
t.Context) error { | 314 err := ds.RunInTransaction(func(c contex
t.Context) error { |
(...skipping 11 matching lines...) Expand all Loading... |
326 panic("noooo") | 326 panic("noooo") |
327 }, nil) | 327 }, nil) |
328 So(err.Error(), ShouldContainSub
string, "nested transactions") | 328 So(err.Error(), ShouldContainSub
string, "nested transactions") |
329 return nil | 329 return nil |
330 }, nil) | 330 }, nil) |
331 So(err, ShouldBeNil) | 331 So(err, ShouldBeNil) |
332 }) | 332 }) |
333 | 333 |
334 Convey("Concurrent transactions only accept one
set of changes", func() { | 334 Convey("Concurrent transactions only accept one
set of changes", func() { |
335 // Note: I think this implementation is
actually /slightly/ wrong. | 335 // Note: I think this implementation is
actually /slightly/ wrong. |
336 » » » » » // Accorting to my read of the docs for
appengine, when you open a | 336 » » » » » // According to my read of the docs for
appengine, when you open a |
337 // transaction it actually (essentially)
holds a reference to the | 337 // transaction it actually (essentially)
holds a reference to the |
338 // entire datastore. Our implementation
takes a snapshot of the | 338 // entire datastore. Our implementation
takes a snapshot of the |
339 // entity group as soon as something obs
erves/affects it. | 339 // entity group as soon as something obs
erves/affects it. |
340 // | 340 // |
341 // That said... I'm not sure if there's
really a semantic difference. | 341 // That said... I'm not sure if there's
really a semantic difference. |
342 err := ds.RunInTransaction(func(c contex
t.Context) error { | 342 err := ds.RunInTransaction(func(c contex
t.Context) error { |
343 So(dsS.Get(c).Put(&Foo{Id: 1, Va
l: 21}), ShouldBeNil) | 343 So(dsS.Get(c).Put(&Foo{Id: 1, Va
l: 21}), ShouldBeNil) |
344 | 344 |
345 err := ds.RunInTransaction(func(
c context.Context) error { | 345 err := ds.RunInTransaction(func(
c context.Context) error { |
346 So(dsS.Get(c).Put(&Foo{I
d: 1, Val: 27}), ShouldBeNil) | 346 So(dsS.Get(c).Put(&Foo{I
d: 1, Val: 27}), ShouldBeNil) |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
410 So(ds.Put(&Foo{V
al: 200}), ShouldBeNil) | 410 So(ds.Put(&Foo{V
al: 200}), ShouldBeNil) |
411 panic("wheeeeee"
) | 411 panic("wheeeeee"
) |
412 }, nil) | 412 }, nil) |
413 }, ShouldPanic) | 413 }, ShouldPanic) |
414 | 414 |
415 f := &Foo{Id: 1} | 415 f := &Foo{Id: 1} |
416 So(ds.Get(f), ShouldBeNil) | 416 So(ds.Get(f), ShouldBeNil) |
417 So(f.Val, ShouldEqual, 10) | 417 So(f.Val, ShouldEqual, 10) |
418 }) | 418 }) |
419 }) | 419 }) |
| 420 |
| 421 Convey("Transaction retries", func() { |
| 422 tst := ds.Testable() |
| 423 Reset(func() { tst.SetTransactionRetryCo
unt(0) }) |
| 424 |
| 425 Convey("SetTransactionRetryCount set to
zere", func() { |
| 426 tst.SetTransactionRetryCount(0) |
| 427 calls := 0 |
| 428 So(ds.RunInTransaction(func(c co
ntext.Context) error { |
| 429 calls++ |
| 430 return nil |
| 431 }, nil), ShouldBeNil) |
| 432 So(calls, ShouldEqual, 1) |
| 433 }) |
| 434 |
| 435 Convey("default TransactionOptions is 3
attempts", func() { |
| 436 tst.SetTransactionRetryCount(100
) // more than 3 |
| 437 calls := 0 |
| 438 So(ds.RunInTransaction(func(c co
ntext.Context) error { |
| 439 calls++ |
| 440 return nil |
| 441 }, nil), ShouldEqual, dsS.ErrCon
currentTransaction) |
| 442 So(calls, ShouldEqual, 3) |
| 443 }) |
| 444 |
| 445 Convey("non-default TransactionOptions "
, func() { |
| 446 tst.SetTransactionRetryCount(100
) // more than 20 |
| 447 calls := 0 |
| 448 So(ds.RunInTransaction(func(c co
ntext.Context) error { |
| 449 calls++ |
| 450 return nil |
| 451 }, &dsS.TransactionOptions{Attem
pts: 20}), ShouldEqual, dsS.ErrConcurrentTransaction) |
| 452 So(calls, ShouldEqual, 20) |
| 453 }) |
| 454 |
| 455 Convey("SetTransactionRetryCount is resp
ected", func() { |
| 456 tst.SetTransactionRetryCount(1)
// less than 3 |
| 457 calls := 0 |
| 458 So(ds.RunInTransaction(func(c co
ntext.Context) error { |
| 459 calls++ |
| 460 return nil |
| 461 }, nil), ShouldBeNil) |
| 462 So(calls, ShouldEqual, 2) |
| 463 }) |
| 464 |
| 465 Convey("fatal errors are not retried", f
unc() { |
| 466 tst.SetTransactionRetryCount(1) |
| 467 calls := 0 |
| 468 So(ds.RunInTransaction(func(c co
ntext.Context) error { |
| 469 calls++ |
| 470 return fmt.Errorf("omg") |
| 471 }, nil).Error(), ShouldEqual, "o
mg") |
| 472 So(calls, ShouldEqual, 1) |
| 473 }) |
| 474 }) |
420 }) | 475 }) |
421 }) | 476 }) |
422 | |
423 }) | 477 }) |
424 } | 478 } |
425 | 479 |
426 func TestCompoundIndexes(t *testing.T) { | 480 func TestCompoundIndexes(t *testing.T) { |
427 t.Parallel() | 481 t.Parallel() |
428 | 482 |
429 idxKey := func(def dsS.IndexDefinition) string { | 483 idxKey := func(def dsS.IndexDefinition) string { |
430 So(def, ShouldNotBeNil) | 484 So(def, ShouldNotBeNil) |
431 return "idx::" + string(serialize.ToBytes(*def.PrepForIdxTable()
)) | 485 return "idx::" + string(serialize.ToBytes(*def.PrepForIdxTable()
)) |
432 } | 486 } |
433 | 487 |
434 numItms := func(c *memCollection) uint64 { | 488 numItms := func(c *memCollection) uint64 { |
435 ret, _ := c.GetTotals() | 489 ret, _ := c.GetTotals() |
436 return ret | 490 return ret |
437 } | 491 } |
438 | 492 |
439 Convey("Test Compound indexes", t, func() { | 493 Convey("Test Compound indexes", t, func() { |
440 type Model struct { | 494 type Model struct { |
441 ID int64 `gae:"$id"` | 495 ID int64 `gae:"$id"` |
442 | 496 |
443 Field1 []string | 497 Field1 []string |
444 Field2 []int64 | 498 Field2 []int64 |
445 } | 499 } |
446 | 500 |
447 c := Use(context.Background()) | 501 c := Use(context.Background()) |
448 ds := dsS.Get(c) | 502 ds := dsS.Get(c) |
449 » » t := ds.Raw().Testable().(*dsImpl) | 503 » » t := ds.Testable().(*dsImpl) |
450 head := t.data.head | 504 head := t.data.head |
451 | 505 |
452 So(ds.Put(&Model{1, []string{"hello", "world"}, []int64{10, 11}}
), ShouldBeNil) | 506 So(ds.Put(&Model{1, []string{"hello", "world"}, []int64{10, 11}}
), ShouldBeNil) |
453 | 507 |
454 idx := dsS.IndexDefinition{ | 508 idx := dsS.IndexDefinition{ |
455 Kind: "Model", | 509 Kind: "Model", |
456 SortBy: []dsS.IndexColumn{ | 510 SortBy: []dsS.IndexColumn{ |
457 {Property: "Field2"}, | 511 {Property: "Field2"}, |
458 }, | 512 }, |
459 } | 513 } |
460 | 514 |
461 coll := head.GetCollection(idxKey(idx)) | 515 coll := head.GetCollection(idxKey(idx)) |
462 So(coll, ShouldNotBeNil) | 516 So(coll, ShouldNotBeNil) |
463 So(numItms(coll), ShouldEqual, 2) | 517 So(numItms(coll), ShouldEqual, 2) |
464 | 518 |
465 idx.SortBy[0].Property = "Field1" | 519 idx.SortBy[0].Property = "Field1" |
466 coll = head.GetCollection(idxKey(idx)) | 520 coll = head.GetCollection(idxKey(idx)) |
467 So(coll, ShouldNotBeNil) | 521 So(coll, ShouldNotBeNil) |
468 So(numItms(coll), ShouldEqual, 2) | 522 So(numItms(coll), ShouldEqual, 2) |
469 | 523 |
470 idx.SortBy = append(idx.SortBy, dsS.IndexColumn{Property: "Field
1"}) | 524 idx.SortBy = append(idx.SortBy, dsS.IndexColumn{Property: "Field
1"}) |
471 So(head.GetCollection(idxKey(idx)), ShouldBeNil) | 525 So(head.GetCollection(idxKey(idx)), ShouldBeNil) |
472 | 526 |
473 t.AddIndexes(&idx) | 527 t.AddIndexes(&idx) |
474 coll = head.GetCollection(idxKey(idx)) | 528 coll = head.GetCollection(idxKey(idx)) |
475 So(coll, ShouldNotBeNil) | 529 So(coll, ShouldNotBeNil) |
476 So(numItms(coll), ShouldEqual, 4) | 530 So(numItms(coll), ShouldEqual, 4) |
477 }) | 531 }) |
478 } | 532 } |
OLD | NEW |