vxx2 / vlib / x / executor / lifecycle_test.v
259 lines · 224 sloc · 5.49 KB · e80386b6af8a071a2e13fd654ebcdb2105fb9202
Raw
1module executor
2
3import time
4
5fn test_run_drains_accepted_jobs_then_wait_returns() {
6 mut ex := new(queue_size: 4)!
7 ran := chan int{cap: 3}
8 result := chan string{cap: 1}
9
10 for i in 0 .. 3 {
11 ex.try_post(fn [ran, i] () ! {
12 ran <- i
13 })!
14 }
15
16 runner := spawn fn [mut ex, result] () {
17 ex.run() or {
18 result <- err.msg()
19 return
20 }
21 result <- 'ok'
22 }()
23
24 assert wait_for_int(ran, 'first run job missing') == 0
25 assert wait_for_int(ran, 'second run job missing') == 1
26 assert wait_for_int(ran, 'third run job missing') == 2
27 ex.stop()
28 assert wait_for_string(result, 'run did not return after stop') == 'ok'
29 ex.wait()!
30 runner.wait()
31}
32
33fn test_stop_from_owner_callback_does_not_deadlock() {
34 mut ex := new(queue_size: 2)!
35 ran := chan bool{cap: 1}
36 result := chan string{cap: 1}
37
38 ex.try_post(fn [mut ex, ran] () ! {
39 ex.stop()
40 ran <- true
41 })!
42
43 runner := spawn fn [mut ex, result] () {
44 ex.run() or {
45 result <- err.msg()
46 return
47 }
48 result <- 'ok'
49 }()
50
51 assert wait_for_bool(ran, 'owner callback did not run')
52 assert wait_for_string(result, 'run did not return after owner stop') == 'ok'
53 ex.wait()!
54 runner.wait()
55}
56
57fn test_wait_from_owner_callback_after_stop_returns_error_without_consuming_wait() {
58 mut ex := new(queue_size: 2)!
59 wait_result := chan string{cap: 1}
60 run_result := chan string{cap: 1}
61
62 ex.try_post(fn [mut ex, wait_result] () ! {
63 ex.stop()
64 ex.wait() or {
65 wait_result <- err.msg()
66 return
67 }
68 wait_result <- 'ok'
69 })!
70
71 runner := spawn fn [mut ex, run_result] () {
72 ex.run() or {
73 run_result <- err.msg()
74 return
75 }
76 run_result <- 'ok'
77 }()
78
79 assert wait_for_string(wait_result, 'owner wait did not return') == 'executor: wait cannot be called from executor owner thread'
80 assert wait_for_string(run_result, 'run did not return after owner stop') == 'ok'
81 ex.wait()!
82 runner.wait()
83}
84
85fn test_wait_before_terminal_pump_returns_error() {
86 mut ex := new(queue_size: 1)!
87 ex.wait() or {
88 assert err.msg() == 'executor: wait requires a running pump or stopped executor'
89 ex.stop()
90 return
91 }
92 assert false, 'wait returned successfully before a terminal owner pump'
93}
94
95fn test_wait_before_runner_run_does_not_consume_wait() {
96 mut ex := new(queue_size: 2)!
97 start_run := chan bool{cap: 1}
98 started := chan bool{cap: 1}
99 result := chan string{cap: 1}
100
101 ex.try_post(fn [started] () ! {
102 started <- true
103 })!
104
105 runner := spawn fn [mut ex, start_run, result] () {
106 _ := <-start_run
107 ex.run() or {
108 result <- err.msg()
109 return
110 }
111 result <- 'ok'
112 }()
113
114 mut saw_precondition := false
115 ex.wait() or {
116 assert err.msg() == 'executor: wait requires a running pump or stopped executor'
117 saw_precondition = true
118 }
119 assert saw_precondition
120
121 start_run <- true
122 assert wait_for_bool(started, 'runner did not start owner pump')
123 ex.stop()
124 assert wait_for_string(result, 'run did not return after stop') == 'ok'
125 ex.wait()!
126 mut saw_second_wait := false
127 ex.wait() or {
128 assert err.msg() == 'executor: wait was already called'
129 saw_second_wait = true
130 }
131 assert saw_second_wait
132 runner.wait()
133}
134
135fn test_run_after_stop_closes_admission_and_second_run_is_stopped() {
136 mut ex := new(queue_size: 1)!
137 ex.stop()
138
139 mut rejected_after_stop := false
140 ex.try_post(fn () ! {}) or {
141 assert err.msg() == 'executor: executor is closed'
142 rejected_after_stop = true
143 }
144 assert rejected_after_stop
145
146 ex.run() or {
147 assert err.msg() == 'executor: executor is stopped'
148 return
149 }
150 assert false, 'run after stop returned successfully'
151}
152
153fn test_second_wait_returns_error() {
154 mut ex := new(queue_size: 1)!
155 started := chan bool{cap: 1}
156 release := chan bool{cap: 1}
157 result := chan string{cap: 1}
158
159 ex.try_post(fn [started, release] () ! {
160 started <- true
161 _ := <-release
162 })!
163
164 runner := spawn fn [mut ex, result] () {
165 ex.run() or {
166 result <- err.msg()
167 return
168 }
169 result <- 'ok'
170 }()
171
172 assert wait_for_bool(started, 'run did not start before wait test')
173 release <- true
174 ex.stop()
175 assert wait_for_string(result, 'run did not stop') == 'ok'
176 ex.wait()!
177 ex.wait() or {
178 assert err.msg() == 'executor: wait was already called'
179 runner.wait()
180 return
181 }
182 assert false, 'second wait returned successfully'
183}
184
185fn test_second_concurrent_run_returns_error() {
186 mut ex := new(queue_size: 2)!
187 started := chan bool{cap: 1}
188 release := chan bool{cap: 1}
189 first_result := chan string{cap: 1}
190 second_result := chan string{cap: 1}
191
192 ex.try_post(fn [started, release] () ! {
193 started <- true
194 _ := <-release
195 })!
196
197 first := spawn fn [mut ex, first_result] () {
198 ex.run() or {
199 first_result <- err.msg()
200 return
201 }
202 first_result <- 'ok'
203 }()
204 assert wait_for_bool(started, 'first run did not start owner job')
205
206 second := spawn fn [mut ex, second_result] () {
207 ex.run() or {
208 second_result <- err.msg()
209 return
210 }
211 second_result <- 'ok'
212 }()
213
214 msg := wait_for_string(second_result, 'second run did not return')
215 assert msg == 'executor: owner pump is already running'
216
217 release <- true
218 ex.stop()
219 assert wait_for_string(first_result, 'first run did not stop') == 'ok'
220 ex.wait()!
221 first.wait()
222 second.wait()
223}
224
225fn wait_for_bool(signal chan bool, message string) bool {
226 select {
227 value := <-signal {
228 return value
229 }
230 1 * time.second {
231 assert false, message
232 }
233 }
234 return false
235}
236
237fn wait_for_int(signal chan int, message string) int {
238 select {
239 value := <-signal {
240 return value
241 }
242 1 * time.second {
243 assert false, message
244 }
245 }
246 return 0
247}
248
249fn wait_for_string(signal chan string, message string) string {
250 select {
251 value := <-signal {
252 return value
253 }
254 1 * time.second {
255 assert false, message
256 }
257 }
258 return ''
259}
260