polyphony 0.24 → 0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|