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

Side by Side Diff: impl/memory/datastore_test.go

Issue 1335083002: Add emulation of transaction retries to memory impl of RunInTransaction. (Closed) Base URL: https://github.com/luci/gae.git@master
Patch Set: add Testable() to non-Raw interfaces Created 5 years, 3 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 | « impl/memory/datastore_query_execution_test.go ('k') | impl/memory/taskqueue_test.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 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
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
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
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 }
OLDNEW
« no previous file with comments | « impl/memory/datastore_query_execution_test.go ('k') | impl/memory/taskqueue_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698