polyphony 0.24 → 0.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +1 -1
- data/TODO.md +12 -8
- data/docs/README.md +2 -2
- data/docs/summary.md +3 -3
- data/docs/technical-overview/concurrency.md +4 -6
- data/docs/technical-overview/design-principles.md +8 -8
- data/docs/technical-overview/exception-handling.md +1 -1
- data/examples/core/{01-spinning-up-coprocesses.rb → 01-spinning-up-fibers.rb} +1 -1
- data/examples/core/{02-awaiting-coprocesses.rb → 02-awaiting-fibers.rb} +3 -3
- data/examples/core/xx-erlang-style-genserver.rb +10 -10
- data/examples/core/xx-extended_fibers.rb +150 -0
- data/examples/core/xx-sleeping.rb +9 -0
- data/examples/core/xx-supervisors.rb +1 -1
- data/examples/interfaces/pg_pool.rb +3 -3
- data/examples/performance/mem-usage.rb +19 -4
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -5
- data/ext/gyro/gyro.c +9 -15
- data/lib/polyphony/core/cancel_scope.rb +0 -2
- data/lib/polyphony/core/exceptions.rb +2 -2
- data/lib/polyphony/core/global_api.rb +7 -8
- data/lib/polyphony/core/supervisor.rb +25 -31
- data/lib/polyphony/extensions/core.rb +4 -78
- data/lib/polyphony/extensions/fiber.rb +166 -0
- data/lib/polyphony/extensions/io.rb +2 -1
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +6 -8
- data/test/test_async.rb +2 -2
- data/test/test_cancel_scope.rb +6 -6
- data/test/test_fiber.rb +382 -0
- data/test/test_global_api.rb +49 -50
- data/test/test_gyro.rb +1 -1
- data/test/test_io.rb +30 -29
- data/test/test_kernel.rb +2 -2
- data/test/test_signal.rb +1 -1
- data/test/test_supervisor.rb +27 -27
- data/test/test_timer.rb +2 -2
- metadata +7 -7
- data/examples/core/04-no-auto-run.rb +0 -16
- data/lib/polyphony/core/coprocess.rb +0 -168
- data/test/test_coprocess.rb +0 -440
data/test/test_fiber.rb
ADDED
@@ -0,0 +1,382 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
|
5
|
+
class FiberTest < MiniTest::Test
|
6
|
+
def test_that_new_spun_fiber_starts_in_suspended_state
|
7
|
+
result = nil
|
8
|
+
f = Fiber.spin { result = 42 }
|
9
|
+
assert_nil result
|
10
|
+
f.await
|
11
|
+
assert_equal 42, result
|
12
|
+
ensure
|
13
|
+
f&.stop
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_that_await_blocks_until_fiber_is_done
|
17
|
+
result = nil
|
18
|
+
f = Fiber.spin do
|
19
|
+
snooze
|
20
|
+
result = 42
|
21
|
+
end
|
22
|
+
f.await
|
23
|
+
assert_equal 42, result
|
24
|
+
ensure
|
25
|
+
f&.stop
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_that_await_returns_the_fibers_return_value
|
29
|
+
f = Fiber.spin { %i[foo bar] }
|
30
|
+
assert_equal %i[foo bar], f.await
|
31
|
+
ensure
|
32
|
+
f&.stop
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_that_await_raises_error_raised_by_fiber
|
36
|
+
result = nil
|
37
|
+
f = Fiber.spin { raise 'foo' }
|
38
|
+
begin
|
39
|
+
result = f.await
|
40
|
+
rescue Exception => e
|
41
|
+
result = { error: e }
|
42
|
+
end
|
43
|
+
assert_kind_of Hash, result
|
44
|
+
assert_kind_of RuntimeError, result[:error]
|
45
|
+
ensure
|
46
|
+
f&.stop
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_that_running_fiber_can_be_cancelled
|
50
|
+
result = []
|
51
|
+
error = nil
|
52
|
+
f = Fiber.spin do
|
53
|
+
result << 1
|
54
|
+
2.times { snooze }
|
55
|
+
result << 2
|
56
|
+
end
|
57
|
+
defer { f.cancel! }
|
58
|
+
assert_equal 0, result.size
|
59
|
+
begin
|
60
|
+
f.await
|
61
|
+
rescue Polyphony::Cancel => e
|
62
|
+
error = e
|
63
|
+
end
|
64
|
+
assert_equal 1, result.size
|
65
|
+
assert_equal 1, result[0]
|
66
|
+
assert_kind_of Polyphony::Cancel, error
|
67
|
+
ensure
|
68
|
+
f&.stop
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_that_running_fiber_can_be_interrupted
|
72
|
+
# that is, stopped without exception
|
73
|
+
result = []
|
74
|
+
f = Fiber.spin do
|
75
|
+
result << 1
|
76
|
+
2.times { snooze }
|
77
|
+
result << 2
|
78
|
+
3
|
79
|
+
end
|
80
|
+
defer { f.stop(42) }
|
81
|
+
|
82
|
+
await_result = f.await
|
83
|
+
assert_equal 1, result.size
|
84
|
+
assert_equal 42, await_result
|
85
|
+
ensure
|
86
|
+
f&.stop
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_that_fiber_can_be_awaited
|
90
|
+
result = nil
|
91
|
+
f2 = nil
|
92
|
+
f1 = spin do
|
93
|
+
f2 = Fiber.spin do
|
94
|
+
snooze
|
95
|
+
42
|
96
|
+
end
|
97
|
+
result = f2.await
|
98
|
+
end
|
99
|
+
suspend
|
100
|
+
assert_equal 42, result
|
101
|
+
ensure
|
102
|
+
f1&.stop
|
103
|
+
f2&.stop
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_that_fiber_can_be_stopped
|
107
|
+
result = nil
|
108
|
+
f = spin do
|
109
|
+
snooze
|
110
|
+
result = 42
|
111
|
+
end
|
112
|
+
defer { f.interrupt }
|
113
|
+
suspend
|
114
|
+
assert_nil result
|
115
|
+
ensure
|
116
|
+
f&.stop
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_that_fiber_can_be_cancelled
|
120
|
+
result = nil
|
121
|
+
f = spin do
|
122
|
+
snooze
|
123
|
+
result = 42
|
124
|
+
rescue Polyphony::Cancel => e
|
125
|
+
result = e
|
126
|
+
end
|
127
|
+
defer { f.cancel! }
|
128
|
+
|
129
|
+
suspend
|
130
|
+
|
131
|
+
assert_kind_of Polyphony::Cancel, result
|
132
|
+
assert_kind_of Polyphony::Cancel, f.result
|
133
|
+
assert_equal :dead, f.state
|
134
|
+
ensure
|
135
|
+
f&.stop
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_that_inner_fiber_can_be_interrupted
|
139
|
+
result = nil
|
140
|
+
f2 = nil
|
141
|
+
f1 = spin do
|
142
|
+
f2 = spin do
|
143
|
+
snooze
|
144
|
+
result = 42
|
145
|
+
end
|
146
|
+
f2.await
|
147
|
+
result && result += 1
|
148
|
+
end
|
149
|
+
defer { f2.interrupt }
|
150
|
+
suspend
|
151
|
+
assert_nil result
|
152
|
+
assert_equal :dead, f1.state
|
153
|
+
assert_equal :dead, f2.state
|
154
|
+
ensure
|
155
|
+
f1&.stop
|
156
|
+
f2&.stop
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_state
|
160
|
+
counter = 0
|
161
|
+
f = spin do
|
162
|
+
3.times do
|
163
|
+
snooze
|
164
|
+
counter += 1
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
assert_equal :scheduled, f.state
|
169
|
+
assert_equal :running, Fiber.current.state
|
170
|
+
snooze
|
171
|
+
assert_equal :scheduled, f.state
|
172
|
+
snooze while counter < 3
|
173
|
+
assert_equal :dead, f.state
|
174
|
+
ensure
|
175
|
+
f&.stop
|
176
|
+
end
|
177
|
+
|
178
|
+
def test_fiber_exception_propagation
|
179
|
+
# error is propagated to calling fiber
|
180
|
+
raised_error = nil
|
181
|
+
spin do
|
182
|
+
spin do
|
183
|
+
raise 'foo'
|
184
|
+
end
|
185
|
+
snooze # allow nested fiber to run before finishing
|
186
|
+
end
|
187
|
+
suspend
|
188
|
+
rescue Exception => e
|
189
|
+
raised_error = e
|
190
|
+
ensure
|
191
|
+
assert raised_error
|
192
|
+
assert_equal 'foo', raised_error.message
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_that_fiber_can_be_interrupted_before_first_scheduling
|
196
|
+
buffer = []
|
197
|
+
f = spin { buffer << 1 }
|
198
|
+
f.stop
|
199
|
+
|
200
|
+
snooze
|
201
|
+
assert !f.running?
|
202
|
+
assert_equal [], buffer
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_exception_propagation_for_orphan_fiber
|
206
|
+
raised_error = nil
|
207
|
+
spin do
|
208
|
+
spin do
|
209
|
+
snooze
|
210
|
+
raise 'bar'
|
211
|
+
end
|
212
|
+
end
|
213
|
+
suspend
|
214
|
+
rescue Exception => e
|
215
|
+
raised_error = e
|
216
|
+
ensure
|
217
|
+
assert raised_error
|
218
|
+
assert_equal 'bar', raised_error.message
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_await_multiple_fibers
|
222
|
+
f1 = spin { sleep 0.01; :foo }
|
223
|
+
f2 = spin { sleep 0.01; :bar }
|
224
|
+
f3 = spin { sleep 0.01; :baz }
|
225
|
+
|
226
|
+
result = Fiber.await(f1, f2, f3)
|
227
|
+
assert_equal %i{foo bar baz}, result
|
228
|
+
end
|
229
|
+
|
230
|
+
def test_join_multiple_fibers
|
231
|
+
f1 = spin { sleep 0.01; :foo }
|
232
|
+
f2 = spin { sleep 0.01; :bar }
|
233
|
+
f3 = spin { sleep 0.01; :baz }
|
234
|
+
|
235
|
+
result = Fiber.join(f1, f2, f3)
|
236
|
+
assert_equal %i{foo bar baz}, result
|
237
|
+
end
|
238
|
+
|
239
|
+
def test_select_from_multiple_fibers
|
240
|
+
buffer = []
|
241
|
+
f1 = spin { sleep 0.01; buffer << :foo; :foo }
|
242
|
+
f2 = spin { sleep 0.02; buffer << :bar; :bar }
|
243
|
+
f3 = spin { sleep 0.03; buffer << :baz; :baz }
|
244
|
+
|
245
|
+
result, selected = Fiber.select(f1, f2, f3)
|
246
|
+
assert_equal :foo, result
|
247
|
+
assert_equal f1, selected
|
248
|
+
assert_equal [:foo], buffer
|
249
|
+
end
|
250
|
+
|
251
|
+
def test_caller
|
252
|
+
location = /^#{__FILE__}:#{__LINE__ + 1}/
|
253
|
+
f = spin do
|
254
|
+
sleep 0.01
|
255
|
+
end
|
256
|
+
snooze
|
257
|
+
|
258
|
+
caller = f.caller
|
259
|
+
assert_match location, caller[0]
|
260
|
+
end
|
261
|
+
|
262
|
+
def test_location
|
263
|
+
location = /^#{__FILE__}:#{__LINE__ + 1}/
|
264
|
+
f = spin do
|
265
|
+
sleep 0.01
|
266
|
+
end
|
267
|
+
snooze
|
268
|
+
|
269
|
+
assert f.location =~ location
|
270
|
+
end
|
271
|
+
|
272
|
+
def test_when_done
|
273
|
+
flag = nil
|
274
|
+
values = []
|
275
|
+
f = spin do
|
276
|
+
snooze until flag
|
277
|
+
end
|
278
|
+
f.when_done { values << 42 }
|
279
|
+
|
280
|
+
snooze
|
281
|
+
assert values.empty?
|
282
|
+
snooze
|
283
|
+
flag = true
|
284
|
+
assert values.empty?
|
285
|
+
assert f.alive?
|
286
|
+
|
287
|
+
snooze
|
288
|
+
assert_equal [42], values
|
289
|
+
assert !f.running?
|
290
|
+
end
|
291
|
+
|
292
|
+
def test_interrupt
|
293
|
+
f = spin do
|
294
|
+
sleep 1
|
295
|
+
:foo
|
296
|
+
end
|
297
|
+
|
298
|
+
snooze
|
299
|
+
assert f.alive?
|
300
|
+
|
301
|
+
f.interrupt :bar
|
302
|
+
assert !f.running?
|
303
|
+
|
304
|
+
assert_equal :bar, f.result
|
305
|
+
end
|
306
|
+
|
307
|
+
def test_cancel
|
308
|
+
error = nil
|
309
|
+
f = spin do
|
310
|
+
sleep 1
|
311
|
+
:foo
|
312
|
+
end
|
313
|
+
|
314
|
+
snooze
|
315
|
+
f.cancel!
|
316
|
+
rescue Polyphony::Cancel => e
|
317
|
+
# cancel error should bubble up
|
318
|
+
error = e
|
319
|
+
ensure
|
320
|
+
assert error
|
321
|
+
assert_equal :dead, f.state
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
class MailboxTest < MiniTest::Test
|
326
|
+
def test_that_fiber_can_receive_messages
|
327
|
+
msgs = []
|
328
|
+
f = spin { loop { msgs << receive } }
|
329
|
+
|
330
|
+
snooze # allow fiber to start
|
331
|
+
|
332
|
+
3.times do |i|
|
333
|
+
f << i
|
334
|
+
snooze
|
335
|
+
end
|
336
|
+
|
337
|
+
assert_equal [0, 1, 2], msgs
|
338
|
+
ensure
|
339
|
+
f&.stop
|
340
|
+
end
|
341
|
+
|
342
|
+
def test_that_multiple_messages_sent_at_once_arrive_in_order
|
343
|
+
msgs = []
|
344
|
+
f = spin { loop { msgs << receive } }
|
345
|
+
|
346
|
+
snooze # allow coproc to start
|
347
|
+
|
348
|
+
3.times { |i| f << i }
|
349
|
+
|
350
|
+
snooze
|
351
|
+
|
352
|
+
assert_equal [0, 1, 2], msgs
|
353
|
+
ensure
|
354
|
+
f&.stop
|
355
|
+
end
|
356
|
+
|
357
|
+
def test_that_sent_message_are_queued_before_calling_receive
|
358
|
+
buffer = []
|
359
|
+
receiver = spin { suspend; 3.times { buffer << receive } }
|
360
|
+
sender = spin { 3.times { |i| receiver << (i * 10) } }
|
361
|
+
|
362
|
+
sender.await
|
363
|
+
receiver.schedule
|
364
|
+
receiver.await
|
365
|
+
|
366
|
+
assert_equal [0, 10, 20], buffer
|
367
|
+
end
|
368
|
+
|
369
|
+
def test_list_and_count
|
370
|
+
assert_equal 1, Fiber.count
|
371
|
+
assert_equal [Fiber.current], Fiber.list
|
372
|
+
|
373
|
+
f = spin { sleep 1 }
|
374
|
+
snooze
|
375
|
+
assert_equal 2, Fiber.count
|
376
|
+
assert_equal f, Fiber.list.last
|
377
|
+
|
378
|
+
f.stop
|
379
|
+
snooze
|
380
|
+
assert_equal 1, Fiber.count
|
381
|
+
end
|
382
|
+
end
|
data/test/test_global_api.rb
CHANGED
@@ -3,43 +3,42 @@
|
|
3
3
|
require_relative 'helper'
|
4
4
|
|
5
5
|
class SpinTest < MiniTest::Test
|
6
|
-
def
|
6
|
+
def test_that_spin_returns_a_fiber
|
7
7
|
result = nil
|
8
|
-
|
8
|
+
fiber = spin { result = 42 }
|
9
9
|
|
10
|
-
assert_kind_of
|
11
|
-
assert_nil
|
10
|
+
assert_kind_of Fiber, fiber
|
11
|
+
assert_nil result
|
12
12
|
suspend
|
13
|
-
assert_equal
|
13
|
+
assert_equal 42, result
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
16
|
+
def test_that_spin_accepts_fiber_argument
|
17
17
|
result = nil
|
18
|
-
|
19
|
-
coprocess.run
|
18
|
+
fiber = Fiber.spin { result = 42 }
|
20
19
|
|
21
|
-
assert_nil
|
20
|
+
assert_nil result
|
22
21
|
suspend
|
23
|
-
assert_equal
|
22
|
+
assert_equal 42, result
|
24
23
|
end
|
25
24
|
|
26
|
-
def
|
27
|
-
|
25
|
+
def test_that_spined_fiber_saves_result
|
26
|
+
fiber = spin { 42 }
|
28
27
|
|
29
|
-
assert_kind_of
|
30
|
-
assert_nil
|
28
|
+
assert_kind_of Fiber, fiber
|
29
|
+
assert_nil fiber.result
|
31
30
|
suspend
|
32
|
-
assert_equal
|
31
|
+
assert_equal 42, fiber.result
|
33
32
|
end
|
34
33
|
|
35
|
-
def
|
36
|
-
|
34
|
+
def test_that_spined_fiber_can_be_interrupted
|
35
|
+
fiber = spin do
|
37
36
|
sleep(1)
|
38
37
|
42
|
39
38
|
end
|
40
|
-
defer {
|
39
|
+
defer { fiber.interrupt }
|
41
40
|
suspend
|
42
|
-
assert_nil
|
41
|
+
assert_nil fiber.result
|
43
42
|
end
|
44
43
|
end
|
45
44
|
|
@@ -51,7 +50,7 @@ class CancelScopeTest < Minitest::Test
|
|
51
50
|
end
|
52
51
|
end
|
53
52
|
|
54
|
-
def
|
53
|
+
def test_that_cancel_scope_cancels_fiber
|
55
54
|
ctx = {}
|
56
55
|
spin do
|
57
56
|
after(0.005) { ctx[:cancel_scope].cancel! }
|
@@ -60,13 +59,13 @@ class CancelScopeTest < Minitest::Test
|
|
60
59
|
ctx[:result] = e
|
61
60
|
nil
|
62
61
|
end
|
63
|
-
assert_nil
|
62
|
+
assert_nil ctx[:result]
|
64
63
|
# async operation will only begin on next iteration of event loop
|
65
|
-
assert_nil
|
64
|
+
assert_nil ctx[:cancel_scope]
|
66
65
|
|
67
66
|
Gyro.run
|
68
|
-
assert_kind_of
|
69
|
-
assert_kind_of
|
67
|
+
assert_kind_of Polyphony::CancelScope, ctx[:cancel_scope]
|
68
|
+
assert_kind_of Polyphony::Cancel, ctx[:result]
|
70
69
|
end
|
71
70
|
|
72
71
|
def test_that_cancel_scope_cancels_async_op_with_stop
|
@@ -77,8 +76,8 @@ class CancelScopeTest < Minitest::Test
|
|
77
76
|
end
|
78
77
|
|
79
78
|
Gyro.run
|
80
|
-
assert
|
81
|
-
assert_nil
|
79
|
+
assert ctx[:cancel_scope]
|
80
|
+
assert_nil ctx[:result]
|
82
81
|
end
|
83
82
|
|
84
83
|
def test_that_cancel_after_raises_cancelled_exception
|
@@ -92,7 +91,7 @@ class CancelScopeTest < Minitest::Test
|
|
92
91
|
result = :cancelled
|
93
92
|
end
|
94
93
|
suspend
|
95
|
-
assert_equal
|
94
|
+
assert_equal :cancelled, result
|
96
95
|
end
|
97
96
|
|
98
97
|
# def test_that_cancel_scopes_can_be_nested
|
@@ -108,8 +107,8 @@ class CancelScopeTest < Minitest::Test
|
|
108
107
|
# outer_result = 42
|
109
108
|
# end
|
110
109
|
# suspend
|
111
|
-
# assert_nil
|
112
|
-
# assert_equal
|
110
|
+
# assert_nil inner_result
|
111
|
+
# assert_equal 42, outer_result
|
113
112
|
|
114
113
|
# Polyphony.reset!
|
115
114
|
|
@@ -124,8 +123,8 @@ class CancelScopeTest < Minitest::Test
|
|
124
123
|
# outer_result = 42
|
125
124
|
# end
|
126
125
|
# suspend
|
127
|
-
# assert_equal
|
128
|
-
# assert_equal
|
126
|
+
# assert_equal 42, inner_result
|
127
|
+
# assert_equal 42, outer_result
|
129
128
|
# end
|
130
129
|
end
|
131
130
|
|
@@ -139,22 +138,22 @@ class SupervisorTest < MiniTest::Test
|
|
139
138
|
|
140
139
|
def parallel_sleep(ctx)
|
141
140
|
supervise do |s|
|
142
|
-
(1..3).each { |idx| s.spin
|
141
|
+
(1..3).each { |idx| s.spin(&sleep_and_set(ctx, idx)) }
|
143
142
|
end
|
144
143
|
end
|
145
144
|
|
146
|
-
def
|
145
|
+
def test_that_supervisor_waits_for_all_nested_fibers_to_complete
|
147
146
|
ctx = {}
|
148
147
|
spin do
|
149
148
|
parallel_sleep(ctx)
|
150
149
|
end
|
151
150
|
suspend
|
152
|
-
assert
|
153
|
-
assert
|
154
|
-
assert
|
151
|
+
assert ctx[1]
|
152
|
+
assert ctx[2]
|
153
|
+
assert ctx[3]
|
155
154
|
end
|
156
155
|
|
157
|
-
def
|
156
|
+
def test_that_supervisor_can_add_fibers_after_having_started
|
158
157
|
result = []
|
159
158
|
spin do
|
160
159
|
supervisor = Polyphony::Supervisor.new
|
@@ -170,7 +169,7 @@ class SupervisorTest < MiniTest::Test
|
|
170
169
|
supervisor.await
|
171
170
|
end.await
|
172
171
|
|
173
|
-
assert_equal
|
172
|
+
assert_equal [0, 1, 2], result.sort
|
174
173
|
end
|
175
174
|
end
|
176
175
|
|
@@ -193,7 +192,7 @@ class ExceptionTest < MiniTest::Test
|
|
193
192
|
frames << 3
|
194
193
|
raise e
|
195
194
|
end
|
196
|
-
|
195
|
+
5.times { |i| snooze }
|
197
196
|
rescue Exception => e
|
198
197
|
error = e
|
199
198
|
ensure
|
@@ -246,12 +245,12 @@ class MoveOnAfterTest < MiniTest::Test
|
|
246
245
|
def test_spin_loop
|
247
246
|
buffer = []
|
248
247
|
counter = 0
|
249
|
-
|
248
|
+
f = spin_loop do
|
250
249
|
buffer << (counter += 1)
|
251
250
|
snooze
|
252
251
|
end
|
253
252
|
|
254
|
-
assert_kind_of
|
253
|
+
assert_kind_of Fiber, f
|
255
254
|
assert_equal [], buffer
|
256
255
|
snooze
|
257
256
|
assert_equal [1], buffer
|
@@ -259,40 +258,40 @@ class MoveOnAfterTest < MiniTest::Test
|
|
259
258
|
assert_equal [1, 2], buffer
|
260
259
|
snooze
|
261
260
|
assert_equal [1, 2, 3], buffer
|
262
|
-
|
261
|
+
f.stop
|
263
262
|
snooze
|
264
|
-
assert !
|
263
|
+
assert !f.running?
|
265
264
|
assert_equal [1, 2, 3], buffer
|
266
265
|
end
|
267
266
|
|
268
267
|
def test_throttled_loop
|
269
268
|
buffer = []
|
270
269
|
counter = 0
|
271
|
-
|
270
|
+
f = spin do
|
272
271
|
throttled_loop(50) { buffer << (counter += 1) }
|
273
272
|
end
|
274
273
|
sleep 0.1
|
275
|
-
|
274
|
+
f.stop
|
276
275
|
assert_equal [1, 2, 3, 4, 5], buffer
|
277
276
|
end
|
278
277
|
|
279
278
|
def test_throttled_loop_with_count
|
280
279
|
buffer = []
|
281
280
|
counter = 0
|
282
|
-
|
281
|
+
f = spin do
|
283
282
|
throttled_loop(50, count: 5) { buffer << (counter += 1) }
|
284
283
|
end
|
285
|
-
|
284
|
+
f.await
|
286
285
|
assert_equal [1, 2, 3, 4, 5], buffer
|
287
286
|
end
|
288
287
|
|
289
288
|
def test_every
|
290
289
|
buffer = []
|
291
|
-
|
290
|
+
f = spin do
|
292
291
|
every(0.01) { buffer << 1 }
|
293
292
|
end
|
294
293
|
sleep 0.05
|
295
|
-
|
296
|
-
|
294
|
+
f.stop
|
295
|
+
assert (4..5).include?(buffer.size)
|
297
296
|
end
|
298
297
|
end
|