-
Notifications
You must be signed in to change notification settings - Fork 10
/
Race_test.go
74 lines (63 loc) · 2.01 KB
/
Race_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//go:build !race
// +build !race
package testcase_test
// The build tag "race" is defined when building with the -race flag.
import (
"fmt"
"sync/atomic"
"testing"
"time"
"go.llib.dev/testcase/sandbox"
"go.llib.dev/testcase"
"go.llib.dev/testcase/assert"
"go.llib.dev/testcase/internal/doubles"
)
func TestRace(t *testing.T) {
eventually := assert.Retry{Strategy: assert.Waiter{Timeout: time.Second}}
t.Run(`functions run in race against each other`, func(t *testing.T) {
eventually.Assert(t, func(it assert.It) {
var counter, total int32
blk := func() {
atomic.AddInt32(&total, 1)
c := counter
time.Sleep(time.Millisecond)
counter = c + 1 // counter++ would not work
}
testcase.Race(blk, blk, blk, blk)
it.Must.Equal(int32(4), total)
it.Log(`counter:`, counter, `total:`, total)
it.Must.True(counter < total,
assert.Message(fmt.Sprintf(`counter was expected to be less that the total block run during race`)))
})
})
t.Run(`each block runs once`, func(t *testing.T) {
var sum int32
testcase.Race(func() {
atomic.AddInt32(&sum, 1)
}, func() {
atomic.AddInt32(&sum, 10)
}, func() {
atomic.AddInt32(&sum, 100)
}, func() {
atomic.AddInt32(&sum, 1000)
})
assert.Must(t).Equal(int32(1111), sum)
})
t.Run(`goexit propagated back from the lambdas after each lambda finished`, func(t *testing.T) {
var fn1Finished, fn2Finished, afterRaceFinished bool
sandbox.Run(func() {
testcase.Race(func() {
fn1Finished = true
}, func() {
fakeTB := &doubles.TB{}
// this only meant to represent why goroutine exit needs to be propagated.
fakeTB.FailNow()
fn2Finished = true
})
afterRaceFinished = true
})
assert.Must(t).True(fn1Finished, `first race block was expected to finish regardless the second's FailNow call`)
assert.Must(t).True(!fn2Finished, `second race block exited with FailNow, it shouldn't finished`)
assert.Must(t).True(!afterRaceFinished, `after the second block exited, the exit should have propagated to the top one`)
})
}