diff options
author | Matt Joiner <anacrolix@gmail.com> | 2019-11-06 16:14:47 +1100 |
---|---|---|
committer | Matt Joiner <anacrolix@gmail.com> | 2019-11-06 16:14:47 +1100 |
commit | e749ba3531cf430b66e1d3f310f53ea2972e3aa3 (patch) | |
tree | 328dbb9b2078908a8967483a0829ac4acb54cc9a /stm_test.go | |
parent | Add WouldBlock (diff) | |
download | stm-e749ba3531cf430b66e1d3f310f53ea2972e3aa3.tar.gz stm-e749ba3531cf430b66e1d3f310f53ea2972e3aa3.tar.xz |
Make returns explicit
Diffstat (limited to 'stm_test.go')
-rw-r--r-- | stm_test.go | 92 |
1 files changed, 43 insertions, 49 deletions
diff --git a/stm_test.go b/stm_test.go index aeb0907..ffb4011 100644 --- a/stm_test.go +++ b/stm_test.go @@ -6,21 +6,22 @@ import ( "time" _ "github.com/anacrolix/envpprof" + "github.com/stretchr/testify/assert" ) func TestDecrement(t *testing.T) { x := NewVar(1000) for i := 0; i < 500; i++ { - go Atomically(func(tx *Tx) { + go Atomically(VoidOperation(func(tx *Tx) { cur := tx.Get(x).(int) tx.Set(x, cur-1) - }) + })) } done := make(chan struct{}) go func() { - Atomically(func(tx *Tx) { + Atomically(VoidOperation(func(tx *Tx) { tx.Assert(tx.Get(x) == 500) - }) + })) close(done) }() select { @@ -47,12 +48,12 @@ func TestReadVerify(t *testing.T) { // spawn a transaction that reads x, then y. The other tx will modify x in // between the reads, causing this tx to retry. var x2, y2 int - Atomically(func(tx *Tx) { + Atomically(VoidOperation(func(tx *Tx) { x2 = tx.Get(x).(int) read <- struct{}{} <-read // wait for other tx to complete y2 = tx.Get(y).(int) - }) + })) if x2 == 1 && y2 == 2 { t.Fatal("read was not verified") } @@ -65,22 +66,22 @@ func TestRetry(t *testing.T) { go func() { for i := 0; i < 10; i++ { time.Sleep(10 * time.Millisecond) - Atomically(func(tx *Tx) { + Atomically(VoidOperation(func(tx *Tx) { cur := tx.Get(x).(int) tx.Set(x, cur-1) - }) + })) } }() // Each time we read x before the above loop has finished, we need to // retry. This should result in no more than 1 retry per transaction. retry := 0 - Atomically(func(tx *Tx) { + Atomically(VoidOperation(func(tx *Tx) { cur := tx.Get(x).(int) if cur != 0 { retry++ tx.Retry() } - }) + })) if retry > 10 { t.Fatal("should have retried at most 10 times, got", retry) } @@ -96,12 +97,12 @@ func TestVerify(t *testing.T) { // spawn a transaction that modifies x go func() { - Atomically(func(tx *Tx) { + Atomically(VoidOperation(func(tx *Tx) { <-read rx := tx.Get(x).(*foo) rx.i = 7 tx.Set(x, rx) - }) + })) read <- struct{}{} // other tx should retry, so we need to read/send again read <- <-read @@ -110,12 +111,12 @@ func TestVerify(t *testing.T) { // spawn a transaction that reads x, then y. The other tx will modify x in // between the reads, causing this tx to retry. var i int - Atomically(func(tx *Tx) { + Atomically(VoidOperation(func(tx *Tx) { f := tx.Get(x).(*foo) i = f.i read <- struct{}{} <-read // wait for other tx to complete - }) + })) if i == 3 { t.Fatal("verify did not retry despite modified Var", i) } @@ -136,37 +137,33 @@ func TestSelect(t *testing.T) { // with one arg, Select adds no effect x := NewVar(2) - Atomically(Select(func(tx *Tx) { + Atomically(Select(VoidOperation(func(tx *Tx) { tx.Assert(tx.Get(x).(int) == 2) - })) + }))) - var picked int - Atomically(Select( + picked := Atomically(Select( // always blocks; should never be selected - func(tx *Tx) { + VoidOperation(func(tx *Tx) { tx.Retry() - picked = 1 - }, + }), // always succeeds; should always be selected - func(tx *Tx) { - picked = 2 + func(tx *Tx) interface{} { + return 2 }, // always succeeds; should never be selected - func(tx *Tx) { - picked = 3 + func(tx *Tx) interface{} { + return 3 }, - )) - if picked != 2 { - t.Fatal("Select selected wrong transaction:", picked) - } + )).(int) + assert.EqualValues(t, 2, picked) } func TestCompose(t *testing.T) { nums := make([]int, 100) - fns := make([]func(*Tx), 100) + fns := make([]Operation, 100) for i := range fns { - fns[i] = func(x int) func(*Tx) { - return func(*Tx) { nums[x] = x } + fns[i] = func(x int) Operation { + return VoidOperation(func(*Tx) { nums[x] = x }) }(i) // capture loop var } Atomically(Compose(fns...)) @@ -178,14 +175,11 @@ func TestCompose(t *testing.T) { } func TestPanic(t *testing.T) { - defer func() { - if recover() == nil { - t.Fatal("expected panic, got nil") - } - }() // normal panics should escape Atomically - Atomically(func(*Tx) { - panic("foo") + assert.PanicsWithValue(t, "foo", func() { + Atomically(func(*Tx) interface{} { + panic("foo") + }) }) } @@ -193,10 +187,10 @@ func TestReadWritten(t *testing.T) { // reading a variable written in the same transaction should return the // previously written value x := NewVar(3) - Atomically(func(tx *Tx) { + Atomically(VoidOperation(func(tx *Tx) { tx.Set(x, 5) tx.Assert(tx.Get(x).(int) == 5) - }) + })) } func TestAtomicSetRetry(t *testing.T) { @@ -204,9 +198,9 @@ func TestAtomicSetRetry(t *testing.T) { x := NewVar(3) done := make(chan struct{}) go func() { - Atomically(func(tx *Tx) { + Atomically(VoidOperation(func(tx *Tx) { tx.Assert(tx.Get(x).(int) == 5) - }) + })) done <- struct{}{} }() time.Sleep(10 * time.Millisecond) @@ -226,18 +220,18 @@ func testPingPong(t testing.TB, n int, afterHit func(string)) { var wg sync.WaitGroup bat := func(from, to interface{}, noise string) { defer wg.Done() - for !Atomically(func(tx *Tx) { + for !Atomically(func(tx *Tx) interface{} { if tx.Get(doneVar).(bool) { - tx.Return(true) + return true } tx.Assert(tx.Get(ready).(bool)) if tx.Get(ball) == from { tx.Set(ball, to) tx.Set(hits, tx.Get(hits).(int)+1) tx.Set(ready, false) - tx.Return(false) + return false } - tx.Retry() + panic(Retry) }).(bool) { afterHit(noise) AtomicSet(ready, true) @@ -246,10 +240,10 @@ func testPingPong(t testing.TB, n int, afterHit func(string)) { wg.Add(2) go bat(false, true, "ping!") go bat(true, false, "pong!") - Atomically(func(tx *Tx) { + Atomically(VoidOperation(func(tx *Tx) { tx.Assert(tx.Get(hits).(int) >= n) tx.Set(doneVar, true) - }) + })) wg.Wait() } |