forked from NebulousLabs/Sia
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtrymutex_test.go
176 lines (155 loc) · 3.83 KB
/
trymutex_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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package sync
import (
"sync"
"testing"
"time"
)
// TestTryMutexBasicMutex verifies that Lock and Unlock work the same as a
// normal mutex would.
func TestTryMutexBasicMutex(t *testing.T) {
// Check that two calls to lock will execute in the correct order.
var tm TryMutex
var data int
tm.Lock()
go func() {
data = 15
tm.Unlock()
}()
tm.Lock()
if data != 15 {
t.Error("Locking did not safely protect the data")
}
tm.Unlock()
}
// TestTryMutexConcurrentLocking checks that doing lots of concurrent locks is
// handled as expected.
func TestTryMutexConcurrentLocking(t *testing.T) {
if testing.Short() {
t.SkipNow()
}
// Try executing multiple additions concurrently.
var tm TryMutex
var data int
var wg sync.WaitGroup
for i := 0; i < 250; i++ {
wg.Add(1)
go func() {
tm.Lock()
data++
tm.Unlock()
wg.Done()
}()
}
wg.Wait()
if data != 250 {
t.Error("Locking did not safely protect the data")
}
}
// TestTryMutexBasicTryLock checks that a TryLock will succeed if nobody is
// holding a lock, and will fail if the lock is being held.
func TestTryMutexBasicTryLock(t *testing.T) {
// Lock and then TryLock.
var tm TryMutex
tm.Lock()
if tm.TryLock() {
t.Error("TryLock should have failed")
}
tm.Unlock()
tm.Lock()
tm.Unlock()
// TryLock and then TryLock.
if !tm.TryLock() {
t.Error("Could not get a blank lock")
}
if tm.TryLock() {
t.Error("should not have been able to get the lock")
}
tm.Unlock()
}
// TestTryMutexConcurrentTries attempts to grab locks from many threads, giving
// the race detector a chance to detect any issues.
func TestTryMutexConncurrentTries(t *testing.T) {
if testing.Short() {
t.SkipNow()
}
// Try executing multiple additions concurrently.
var tm TryMutex
var data int
var wg sync.WaitGroup
for i := 0; i < 250; i++ {
wg.Add(1)
go func() {
for !tm.TryLock() {
}
data++
tm.Unlock()
wg.Done()
}()
}
wg.Wait()
if data != 250 {
t.Error("Locking did not safely protect the data")
}
}
// TestTryMutexTimed checks that a timed lock will correctly time out if it
// cannot grab a lock.
func TestTryMutexTimed(t *testing.T) {
if testing.Short() {
t.SkipNow()
}
var tm TryMutex
tm.Lock()
startTime := time.Now()
if tm.TryLockTimed(time.Millisecond * 500) {
t.Error("was able to grab a locked lock")
}
wait := time.Now().Sub(startTime)
if wait < time.Millisecond*450 {
t.Error("lock did not wait the correct amount of time before timing out", wait)
}
if wait > time.Millisecond*900 {
t.Error("lock waited too long before timing out", wait)
}
tm.Unlock()
if !tm.TryLockTimed(time.Millisecond * 1) {
t.Error("Unable to get an unlocked lock")
}
tm.Unlock()
}
// TestTryMutexTimedConcurrent checks that a timed lock will correctly time out
// if it cannot grab a lock.
func TestTryMutexTimedConcurrent(t *testing.T) {
if testing.Short() {
t.SkipNow()
}
var tm TryMutex
// Engage a lock and launch a gothread to wait for a lock, fail, and then
// call unlock.
tm.Lock()
go func() {
startTime := time.Now()
if tm.TryLockTimed(time.Millisecond * 500) {
t.Error("was able to grab a locked lock")
}
wait := time.Now().Sub(startTime)
if wait < time.Millisecond*450 {
t.Error("lock did not wait the correct amount of time before timing out:", wait)
}
if wait > time.Millisecond*900 {
t.Error("lock waited too long before timing out", wait)
}
tm.Unlock()
}()
// Try to get a lock, but don't wait long enough.
if tm.TryLockTimed(time.Millisecond * 250) {
// Lock shoud time out because the gothread responsible for releasing
// the lock will be idle for 500 milliseconds.
t.Error("Lock should have timed out")
}
if !tm.TryLockTimed(time.Millisecond * 950) {
// Lock should be successful - the above thread should finish in under
// 950 milliseconds.
t.Error("Lock should have been successful")
}
tm.Unlock()
}