-
Notifications
You must be signed in to change notification settings - Fork 55
/
testsemaphore.nim
207 lines (156 loc) · 4.59 KB
/
testsemaphore.nim
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
{.used.}
# Nim-Libp2p
# Copyright (c) 2023 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
# at your option.
# This file may not be copied, modified, or distributed except according to
# those terms.
import random
import chronos
import ../libp2p/utils/semaphore
import ./helpers
randomize()
suite "AsyncSemaphore":
asyncTest "should acquire":
let sema = newAsyncSemaphore(3)
await sema.acquire()
await sema.acquire()
await sema.acquire()
check sema.count == 0
asyncTest "should release":
let sema = newAsyncSemaphore(3)
await sema.acquire()
await sema.acquire()
await sema.acquire()
check sema.count == 0
sema.release()
sema.release()
sema.release()
check sema.count == 3
asyncTest "should queue acquire":
let sema = newAsyncSemaphore(1)
await sema.acquire()
let fut = sema.acquire()
check sema.count == 0
sema.release()
sema.release()
check sema.count == 1
await sleepAsync(10.millis)
check fut.finished()
asyncTest "should keep count == size":
let sema = newAsyncSemaphore(1)
sema.release()
sema.release()
sema.release()
check sema.count == 1
asyncTest "should tryAcquire":
let sema = newAsyncSemaphore(1)
await sema.acquire()
check sema.tryAcquire() == false
asyncTest "should tryAcquire and acquire":
let sema = newAsyncSemaphore(4)
check sema.tryAcquire() == true
check sema.tryAcquire() == true
check sema.tryAcquire() == true
check sema.tryAcquire() == true
check sema.count == 0
let fut = sema.acquire()
check fut.finished == false
check sema.count == 0
sema.release()
sema.release()
sema.release()
sema.release()
sema.release()
check fut.finished == true
check sema.count == 4
asyncTest "should restrict resource access":
let sema = newAsyncSemaphore(3)
var resource = 0
proc task() {.async.} =
try:
await sema.acquire()
resource.inc()
check resource > 0 and resource <= 3
let sleep = rand(0 .. 10).millis
# echo sleep
await sleepAsync(sleep)
finally:
resource.dec()
sema.release()
var tasks: seq[Future[void]]
for i in 0 ..< 10:
tasks.add(task())
await allFutures(tasks)
asyncTest "should cancel sequential semaphore slot":
let sema = newAsyncSemaphore(1)
await sema.acquire()
let
tmp = sema.acquire()
tmp2 = sema.acquire()
check:
not tmp.finished()
not tmp2.finished()
tmp.cancel()
sema.release()
check tmp2.finished()
sema.release()
check await sema.acquire().withTimeout(10.millis)
asyncTest "should handle out of order cancellations":
let sema = newAsyncSemaphore(1)
await sema.acquire() # 1st acquire
let tmp1 = sema.acquire() # 2nd acquire
check not tmp1.finished()
let tmp2 = sema.acquire() # 3rd acquire
check not tmp2.finished()
let tmp3 = sema.acquire() # 4th acquire
check not tmp3.finished()
# up to this point, we've called acquire 4 times
tmp1.cancel() # 1st release (implicit)
tmp2.cancel() # 2nd release (implicit)
check not tmp3.finished() # check that we didn't release the wrong slot
sema.release() # 3rd release (explicit)
check tmp3.finished()
sema.release() # 4th release
check await sema.acquire().withTimeout(10.millis)
asyncTest "should properly handle timeouts and cancellations":
let sema = newAsyncSemaphore(1)
await sema.acquire()
check not (await sema.acquire().withTimeout(1.millis))
# should not acquire but cancel
sema.release()
check await sema.acquire().withTimeout(10.millis)
asyncTest "should handle forceAcquire properly":
let sema = newAsyncSemaphore(1)
await sema.acquire()
check not (await sema.acquire().withTimeout(1.millis))
# should not acquire but cancel
let
fut1 = sema.acquire()
fut2 = sema.acquire()
sema.forceAcquire()
sema.release()
await fut1 or fut2 or sleepAsync(1.millis)
check:
fut1.finished()
not fut2.finished()
sema.release()
await fut1 or fut2 or sleepAsync(1.millis)
check:
fut1.finished()
fut2.finished()
sema.forceAcquire()
sema.forceAcquire()
let
fut3 = sema.acquire()
fut4 = sema.acquire()
fut5 = sema.acquire()
sema.release()
sema.release()
await sleepAsync(1.millis)
check:
fut3.finished()
fut4.finished()
not fut5.finished()