concurrent-ruby 0.2.0 → 0.2.1

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.
Files changed (57) hide show
  1. data/LICENSE +21 -21
  2. data/README.md +275 -275
  3. data/lib/concurrent.rb +28 -28
  4. data/lib/concurrent/agent.rb +114 -114
  5. data/lib/concurrent/cached_thread_pool.rb +131 -129
  6. data/lib/concurrent/defer.rb +65 -65
  7. data/lib/concurrent/event.rb +60 -60
  8. data/lib/concurrent/event_machine_defer_proxy.rb +23 -23
  9. data/lib/concurrent/executor.rb +96 -95
  10. data/lib/concurrent/fixed_thread_pool.rb +99 -95
  11. data/lib/concurrent/functions.rb +120 -120
  12. data/lib/concurrent/future.rb +42 -42
  13. data/lib/concurrent/global_thread_pool.rb +16 -16
  14. data/lib/concurrent/goroutine.rb +29 -29
  15. data/lib/concurrent/null_thread_pool.rb +22 -22
  16. data/lib/concurrent/obligation.rb +67 -67
  17. data/lib/concurrent/promise.rb +174 -174
  18. data/lib/concurrent/reactor.rb +166 -166
  19. data/lib/concurrent/reactor/drb_async_demux.rb +83 -83
  20. data/lib/concurrent/reactor/tcp_sync_demux.rb +131 -131
  21. data/lib/concurrent/supervisor.rb +105 -100
  22. data/lib/concurrent/thread_pool.rb +76 -76
  23. data/lib/concurrent/utilities.rb +32 -32
  24. data/lib/concurrent/version.rb +3 -3
  25. data/lib/concurrent_ruby.rb +1 -1
  26. data/md/agent.md +123 -123
  27. data/md/defer.md +174 -174
  28. data/md/event.md +32 -32
  29. data/md/executor.md +187 -187
  30. data/md/future.md +83 -83
  31. data/md/goroutine.md +52 -52
  32. data/md/obligation.md +32 -32
  33. data/md/promise.md +227 -227
  34. data/md/thread_pool.md +224 -224
  35. data/spec/concurrent/agent_spec.rb +386 -386
  36. data/spec/concurrent/cached_thread_pool_spec.rb +125 -125
  37. data/spec/concurrent/defer_spec.rb +195 -195
  38. data/spec/concurrent/event_machine_defer_proxy_spec.rb +256 -256
  39. data/spec/concurrent/event_spec.rb +134 -134
  40. data/spec/concurrent/executor_spec.rb +200 -200
  41. data/spec/concurrent/fixed_thread_pool_spec.rb +83 -83
  42. data/spec/concurrent/functions_spec.rb +217 -217
  43. data/spec/concurrent/future_spec.rb +108 -108
  44. data/spec/concurrent/global_thread_pool_spec.rb +38 -38
  45. data/spec/concurrent/goroutine_spec.rb +67 -67
  46. data/spec/concurrent/null_thread_pool_spec.rb +57 -54
  47. data/spec/concurrent/obligation_shared.rb +132 -132
  48. data/spec/concurrent/promise_spec.rb +312 -312
  49. data/spec/concurrent/reactor/drb_async_demux_spec.rb +196 -196
  50. data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +410 -410
  51. data/spec/concurrent/reactor_spec.rb +364 -364
  52. data/spec/concurrent/supervisor_spec.rb +269 -258
  53. data/spec/concurrent/thread_pool_shared.rb +204 -204
  54. data/spec/concurrent/utilities_spec.rb +74 -74
  55. data/spec/spec_helper.rb +32 -32
  56. metadata +20 -16
  57. checksums.yaml +0 -7
@@ -1,364 +1,364 @@
1
- require 'spec_helper'
2
-
3
- module Concurrent
4
-
5
- describe Reactor do
6
-
7
- let(:sync_demux) do
8
- Class.new {
9
- def initialize
10
- @running = false
11
- @queue = Queue.new
12
- end
13
- def run() @running = true; end
14
- def stop
15
- @queue.push(:stop)
16
- @running = false
17
- end
18
- def running?() return @running == true; end
19
- def accept()
20
- event = @queue.pop
21
- if event == :stop
22
- return nil
23
- else
24
- return Reactor::EventContext.new(event)
25
- end
26
- end
27
- def respond(result, message) return [result, message]; end
28
- def send(event) @queue.push(event) end
29
- }.new
30
- end
31
-
32
- let(:async_demux) do
33
- Class.new {
34
- def initialize() @running = false; end
35
- def run() @running = true; end
36
- def stop() @running = false; end
37
- def running?() return @running == true; end
38
- def set_reactor(reactor) @reactor = reactor; end
39
- def send(event) @reactor.handle(event); end
40
- }.new
41
- end
42
-
43
- after(:each) do
44
- Thread.kill(@thread) unless @thread.nil?
45
- end
46
-
47
- context '#initialize' do
48
-
49
- it 'raises an exception when the demux is not valid' do
50
- lambda {
51
- Reactor.new('bogus demux')
52
- }.should raise_error(ArgumentError)
53
- end
54
-
55
- it 'sets the initial state to not running' do
56
- Reactor.new.should_not be_running
57
- end
58
- end
59
-
60
- context '#running?' do
61
-
62
- it 'returns true when the reactor is running' do
63
- reactor = Reactor.new
64
- @thread = Thread.new{ reactor.run }
65
- sleep(0.1)
66
- reactor.should be_running
67
- reactor.stop
68
- end
69
-
70
- it 'returns false when the reactor is stopped' do
71
- reactor = Reactor.new
72
- @thread = Thread.new{ reactor.run }
73
- sleep(0.1)
74
- reactor.stop
75
- sleep(0.1)
76
- reactor.should_not be_running
77
- end
78
- end
79
-
80
- context '#add_handler' do
81
-
82
- it 'raises an exception is the event name is reserved' do
83
- reactor = Reactor.new
84
- lambda {
85
- reactor.add_handler(Reactor::RESERVED_EVENTS.first){ nil }
86
- }.should raise_error(ArgumentError)
87
- end
88
-
89
- it 'raises an exception if no block is given' do
90
- reactor = Reactor.new
91
- lambda {
92
- reactor.add_handler('no block given')
93
- }.should raise_error(ArgumentError)
94
- end
95
-
96
- it 'returns true if the handler is added' do
97
- reactor = Reactor.new
98
- reactor.add_handler('good'){ nil }.should be_true
99
- end
100
- end
101
-
102
- context '#remove_handler' do
103
-
104
- it 'returns true if the handler is found and removed' do
105
- reactor = Reactor.new
106
- reactor.add_handler('good'){ nil }
107
- reactor.remove_handler('good').should be_true
108
- end
109
-
110
- it 'returns false if the handler is not found' do
111
- reactor = Reactor.new
112
- reactor.remove_handler('not found').should be_false
113
- end
114
- end
115
-
116
- context '#stop_on_signal' do
117
-
118
- if Functional::PLATFORM.mri? && ! Functional::PLATFORM.windows?
119
-
120
- it 'traps each valid signal' do
121
- Signal.should_receive(:trap).with('USR1')
122
- Signal.should_receive(:trap).with('USR2')
123
- reactor = Reactor.new
124
- reactor.stop_on_signal('USR1', 'USR2')
125
- end
126
-
127
- it 'raises an exception if given an invalid signal' do
128
- if Functional::PLATFORM.mri?
129
- reactor = Reactor.new
130
- lambda {
131
- reactor.stop_on_signal('BOGUS')
132
- }.should raise_error(ArgumentError)
133
- end
134
- end
135
-
136
- it 'stops the reactor when it receives a trapped signal' do
137
- reactor = Reactor.new
138
- reactor.stop_on_signal('USR1')
139
- reactor.should_receive(:stop).with(no_args())
140
- Process.kill('USR1', Process.pid)
141
- sleep(0.1)
142
- end
143
- end
144
- end
145
-
146
- context '#handle' do
147
-
148
- it 'raises an exception if the demux is synchronous' do
149
- reactor = Reactor.new(sync_demux)
150
- lambda {
151
- reactor.handle('event')
152
- }.should raise_error(NotImplementedError)
153
- end
154
-
155
- it 'returns :stopped if the reactor is not running' do
156
- reactor = Reactor.new
157
- reactor.handle('event').first.should eq :stopped
158
- end
159
-
160
- it 'returns :ok and the block result on success' do
161
- reactor = Reactor.new
162
- reactor.add_handler(:event){ 10 }
163
- @thread = Thread.new{ reactor.run }
164
- sleep(0.1)
165
- result = reactor.handle(:event)
166
- result.first.should eq :ok
167
- result.last.should eq 10
168
- reactor.stop
169
- end
170
-
171
- it 'returns :ex and the exception on failure' do
172
- reactor = Reactor.new
173
- reactor.add_handler(:event){ raise StandardError }
174
- @thread = Thread.new{ reactor.run }
175
- sleep(0.1)
176
- result = reactor.handle(:event)
177
- result.first.should eq :ex
178
- result.last.should be_a(StandardError)
179
- reactor.stop
180
- end
181
-
182
- it 'returns :noop when there is no handler' do
183
- reactor = Reactor.new
184
- @thread = Thread.new{ reactor.run }
185
- sleep(0.1)
186
- result = reactor.handle(:event)
187
- sleep(0.1)
188
- result.first.should eq :noop
189
- reactor.stop
190
- end
191
-
192
- it 'triggers handlers added after the reactor is runed' do
193
- @expected = false
194
- reactor = Reactor.new
195
- @thread = Thread.new{ reactor.run }
196
- sleep(0.1)
197
- reactor.add_handler(:event){ @expected = true }
198
- reactor.handle(:event)
199
- @expected.should be_true
200
- reactor.stop
201
- end
202
-
203
- it 'does not trigger an event that was removed' do
204
- @expected = false
205
- reactor = Reactor.new
206
- reactor.add_handler(:event){ @expected = true }
207
- reactor.remove_handler(:event)
208
- @thread = Thread.new{ reactor.run }
209
- sleep(0.1)
210
- reactor.handle(:event)
211
- @expected.should be_false
212
- reactor.stop
213
- end
214
- end
215
-
216
- context '#run' do
217
-
218
- it 'raises an exception if the reactor is already running' do
219
- reactor = Reactor.new
220
- @thread = Thread.new{ reactor.run }
221
- sleep(0.1)
222
- lambda {
223
- reactor.run
224
- }.should raise_error(StandardError)
225
- reactor.stop
226
- end
227
-
228
- it 'runs the reactor if it is not running' do
229
- reactor = Reactor.new(async_demux)
230
- reactor.should_receive(:run_async).with(no_args())
231
- @thread = Thread.new{ reactor.run }
232
- sleep(0.1)
233
- reactor.should be_running
234
- reactor.stop
235
-
236
- reactor = Reactor.new(sync_demux)
237
- reactor.should_receive(:run_sync).with(no_args())
238
- @thread = Thread.new{ reactor.run }
239
- sleep(0.1)
240
- reactor.should be_running
241
- reactor.stop
242
- end
243
- end
244
-
245
- context '#stop' do
246
-
247
- it 'returns if the reactor is not running' do
248
- reactor = Reactor.new
249
- reactor.stop.should be_true
250
- end
251
-
252
- it 'stops the reactor when running and synchronous' do
253
- reactor = Reactor.new(sync_demux)
254
- @thread = Thread.new{ sleep(0.1); reactor.stop }
255
- Thread.pass
256
- reactor.run
257
- end
258
-
259
- it 'stops the reactor when running and asynchronous' do
260
- reactor = Reactor.new(async_demux)
261
- @thread = Thread.new{ sleep(0.1); reactor.stop }
262
- Thread.pass
263
- reactor.run
264
- end
265
-
266
- it 'stops the reactor when running without a demux' do
267
- reactor = Reactor.new
268
- @thread = Thread.new{ sleep(0.1); reactor.stop }
269
- Thread.pass
270
- reactor.run
271
- end
272
- end
273
-
274
- specify 'synchronous demultiplexing' do
275
-
276
- if Functional::PLATFORM.mri? && ! Functional::PLATFORM.windows?
277
-
278
- demux = sync_demux
279
- reactor = Concurrent::Reactor.new(demux)
280
-
281
- reactor.should_not be_running
282
-
283
- reactor.add_handler(:foo){ 'Foo' }
284
- reactor.add_handler(:bar){ 'Bar' }
285
- reactor.add_handler(:baz){ 'Baz' }
286
- reactor.add_handler(:fubar){ raise StandardError.new('Boom!') }
287
-
288
- reactor.stop_on_signal('USR1')
289
-
290
- demux.should_receive(:respond).with(:ok, 'Foo')
291
- demux.send(:foo)
292
-
293
- @thread = Thread.new do
294
- reactor.run
295
- end
296
- @thread.abort_on_exception = true
297
- sleep(0.1)
298
-
299
- reactor.should be_running
300
-
301
- demux.should_receive(:respond).with(:ok, 'Bar')
302
- demux.should_receive(:respond).with(:ok, 'Baz')
303
- demux.should_receive(:respond).with(:noop, anything())
304
- demux.should_receive(:respond).with(:ex, anything())
305
-
306
- demux.send(:bar)
307
- demux.send(:baz)
308
- demux.send(:bogus)
309
- demux.send(:fubar)
310
-
311
- reactor.should be_running
312
-
313
- Process.kill('USR1', Process.pid)
314
- sleep(0.1)
315
-
316
- demux.should_not_receive(:respond).with(:foo, anything())
317
- demux.send(:foo)
318
- reactor.should_not be_running
319
- end
320
- end
321
-
322
- specify 'asynchronous demultiplexing' do
323
-
324
- if Functional::PLATFORM.mri? && ! Functional::PLATFORM.windows?
325
-
326
- demux = async_demux
327
- reactor = Concurrent::Reactor.new(demux)
328
-
329
- reactor.should_not be_running
330
-
331
- reactor.add_handler(:foo){ 'Foo' }
332
- reactor.add_handler(:bar){ 'Bar' }
333
- reactor.add_handler(:baz){ 'Baz' }
334
- reactor.add_handler(:fubar){ raise StandardError.new('Boom!') }
335
-
336
- reactor.stop_on_signal('USR2')
337
-
338
- demux.send(:foo).first.should eq :stopped
339
-
340
- @thread = Thread.new do
341
- reactor.run
342
- end
343
- @thread.abort_on_exception = true
344
- sleep(0.1)
345
-
346
- reactor.should be_running
347
-
348
- demux.send(:foo).should eq [:ok, 'Foo']
349
- demux.send(:bar).should eq [:ok, 'Bar']
350
- demux.send(:baz).should eq [:ok, 'Baz']
351
- demux.send(:bogus).first.should eq :noop
352
- demux.send(:fubar).first.should eq :ex
353
-
354
- reactor.should be_running
355
-
356
- Process.kill('USR2', Process.pid)
357
- sleep(0.1)
358
-
359
- demux.send(:foo).first.should eq :stopped
360
- reactor.should_not be_running
361
- end
362
- end
363
- end
364
- end
1
+ require 'spec_helper'
2
+
3
+ module Concurrent
4
+
5
+ describe Reactor do
6
+
7
+ let(:sync_demux) do
8
+ Class.new {
9
+ def initialize
10
+ @running = false
11
+ @queue = Queue.new
12
+ end
13
+ def run() @running = true; end
14
+ def stop
15
+ @queue.push(:stop)
16
+ @running = false
17
+ end
18
+ def running?() return @running == true; end
19
+ def accept()
20
+ event = @queue.pop
21
+ if event == :stop
22
+ return nil
23
+ else
24
+ return Reactor::EventContext.new(event)
25
+ end
26
+ end
27
+ def respond(result, message) return [result, message]; end
28
+ def send(event) @queue.push(event) end
29
+ }.new
30
+ end
31
+
32
+ let(:async_demux) do
33
+ Class.new {
34
+ def initialize() @running = false; end
35
+ def run() @running = true; end
36
+ def stop() @running = false; end
37
+ def running?() return @running == true; end
38
+ def set_reactor(reactor) @reactor = reactor; end
39
+ def send(event) @reactor.handle(event); end
40
+ }.new
41
+ end
42
+
43
+ after(:each) do
44
+ Thread.kill(@thread) unless @thread.nil?
45
+ end
46
+
47
+ context '#initialize' do
48
+
49
+ it 'raises an exception when the demux is not valid' do
50
+ lambda {
51
+ Reactor.new('bogus demux')
52
+ }.should raise_error(ArgumentError)
53
+ end
54
+
55
+ it 'sets the initial state to not running' do
56
+ Reactor.new.should_not be_running
57
+ end
58
+ end
59
+
60
+ context '#running?' do
61
+
62
+ it 'returns true when the reactor is running' do
63
+ reactor = Reactor.new
64
+ @thread = Thread.new{ reactor.run }
65
+ sleep(0.1)
66
+ reactor.should be_running
67
+ reactor.stop
68
+ end
69
+
70
+ it 'returns false when the reactor is stopped' do
71
+ reactor = Reactor.new
72
+ @thread = Thread.new{ reactor.run }
73
+ sleep(0.1)
74
+ reactor.stop
75
+ sleep(0.1)
76
+ reactor.should_not be_running
77
+ end
78
+ end
79
+
80
+ context '#add_handler' do
81
+
82
+ it 'raises an exception is the event name is reserved' do
83
+ reactor = Reactor.new
84
+ lambda {
85
+ reactor.add_handler(Reactor::RESERVED_EVENTS.first){ nil }
86
+ }.should raise_error(ArgumentError)
87
+ end
88
+
89
+ it 'raises an exception if no block is given' do
90
+ reactor = Reactor.new
91
+ lambda {
92
+ reactor.add_handler('no block given')
93
+ }.should raise_error(ArgumentError)
94
+ end
95
+
96
+ it 'returns true if the handler is added' do
97
+ reactor = Reactor.new
98
+ reactor.add_handler('good'){ nil }.should be_true
99
+ end
100
+ end
101
+
102
+ context '#remove_handler' do
103
+
104
+ it 'returns true if the handler is found and removed' do
105
+ reactor = Reactor.new
106
+ reactor.add_handler('good'){ nil }
107
+ reactor.remove_handler('good').should be_true
108
+ end
109
+
110
+ it 'returns false if the handler is not found' do
111
+ reactor = Reactor.new
112
+ reactor.remove_handler('not found').should be_false
113
+ end
114
+ end
115
+
116
+ context '#stop_on_signal' do
117
+
118
+ if Functional::PLATFORM.mri? && ! Functional::PLATFORM.windows?
119
+
120
+ it 'traps each valid signal' do
121
+ Signal.should_receive(:trap).with('USR1')
122
+ Signal.should_receive(:trap).with('USR2')
123
+ reactor = Reactor.new
124
+ reactor.stop_on_signal('USR1', 'USR2')
125
+ end
126
+
127
+ it 'raises an exception if given an invalid signal' do
128
+ if Functional::PLATFORM.mri?
129
+ reactor = Reactor.new
130
+ lambda {
131
+ reactor.stop_on_signal('BOGUS')
132
+ }.should raise_error(ArgumentError)
133
+ end
134
+ end
135
+
136
+ it 'stops the reactor when it receives a trapped signal' do
137
+ reactor = Reactor.new
138
+ reactor.stop_on_signal('USR1')
139
+ reactor.should_receive(:stop).with(no_args())
140
+ Process.kill('USR1', Process.pid)
141
+ sleep(0.1)
142
+ end
143
+ end
144
+ end
145
+
146
+ context '#handle' do
147
+
148
+ it 'raises an exception if the demux is synchronous' do
149
+ reactor = Reactor.new(sync_demux)
150
+ lambda {
151
+ reactor.handle('event')
152
+ }.should raise_error(NotImplementedError)
153
+ end
154
+
155
+ it 'returns :stopped if the reactor is not running' do
156
+ reactor = Reactor.new
157
+ reactor.handle('event').first.should eq :stopped
158
+ end
159
+
160
+ it 'returns :ok and the block result on success' do
161
+ reactor = Reactor.new
162
+ reactor.add_handler(:event){ 10 }
163
+ @thread = Thread.new{ reactor.run }
164
+ sleep(0.1)
165
+ result = reactor.handle(:event)
166
+ result.first.should eq :ok
167
+ result.last.should eq 10
168
+ reactor.stop
169
+ end
170
+
171
+ it 'returns :ex and the exception on failure' do
172
+ reactor = Reactor.new
173
+ reactor.add_handler(:event){ raise StandardError }
174
+ @thread = Thread.new{ reactor.run }
175
+ sleep(0.1)
176
+ result = reactor.handle(:event)
177
+ result.first.should eq :ex
178
+ result.last.should be_a(StandardError)
179
+ reactor.stop
180
+ end
181
+
182
+ it 'returns :noop when there is no handler' do
183
+ reactor = Reactor.new
184
+ @thread = Thread.new{ reactor.run }
185
+ sleep(0.1)
186
+ result = reactor.handle(:event)
187
+ sleep(0.1)
188
+ result.first.should eq :noop
189
+ reactor.stop
190
+ end
191
+
192
+ it 'triggers handlers added after the reactor is runed' do
193
+ @expected = false
194
+ reactor = Reactor.new
195
+ @thread = Thread.new{ reactor.run }
196
+ sleep(0.1)
197
+ reactor.add_handler(:event){ @expected = true }
198
+ reactor.handle(:event)
199
+ @expected.should be_true
200
+ reactor.stop
201
+ end
202
+
203
+ it 'does not trigger an event that was removed' do
204
+ @expected = false
205
+ reactor = Reactor.new
206
+ reactor.add_handler(:event){ @expected = true }
207
+ reactor.remove_handler(:event)
208
+ @thread = Thread.new{ reactor.run }
209
+ sleep(0.1)
210
+ reactor.handle(:event)
211
+ @expected.should be_false
212
+ reactor.stop
213
+ end
214
+ end
215
+
216
+ context '#run' do
217
+
218
+ it 'raises an exception if the reactor is already running' do
219
+ reactor = Reactor.new
220
+ @thread = Thread.new{ reactor.run }
221
+ sleep(0.1)
222
+ lambda {
223
+ reactor.run
224
+ }.should raise_error(StandardError)
225
+ reactor.stop
226
+ end
227
+
228
+ it 'runs the reactor if it is not running' do
229
+ reactor = Reactor.new(async_demux)
230
+ reactor.should_receive(:run_async).with(no_args())
231
+ @thread = Thread.new{ reactor.run }
232
+ sleep(0.1)
233
+ reactor.should be_running
234
+ reactor.stop
235
+
236
+ reactor = Reactor.new(sync_demux)
237
+ reactor.should_receive(:run_sync).with(no_args())
238
+ @thread = Thread.new{ reactor.run }
239
+ sleep(0.1)
240
+ reactor.should be_running
241
+ reactor.stop
242
+ end
243
+ end
244
+
245
+ context '#stop' do
246
+
247
+ it 'returns if the reactor is not running' do
248
+ reactor = Reactor.new
249
+ reactor.stop.should be_true
250
+ end
251
+
252
+ it 'stops the reactor when running and synchronous' do
253
+ reactor = Reactor.new(sync_demux)
254
+ @thread = Thread.new{ sleep(0.1); reactor.stop }
255
+ Thread.pass
256
+ reactor.run
257
+ end
258
+
259
+ it 'stops the reactor when running and asynchronous' do
260
+ reactor = Reactor.new(async_demux)
261
+ @thread = Thread.new{ sleep(0.1); reactor.stop }
262
+ Thread.pass
263
+ reactor.run
264
+ end
265
+
266
+ it 'stops the reactor when running without a demux' do
267
+ reactor = Reactor.new
268
+ @thread = Thread.new{ sleep(0.1); reactor.stop }
269
+ Thread.pass
270
+ reactor.run
271
+ end
272
+ end
273
+
274
+ specify 'synchronous demultiplexing' do
275
+
276
+ if Functional::PLATFORM.mri? && ! Functional::PLATFORM.windows?
277
+
278
+ demux = sync_demux
279
+ reactor = Concurrent::Reactor.new(demux)
280
+
281
+ reactor.should_not be_running
282
+
283
+ reactor.add_handler(:foo){ 'Foo' }
284
+ reactor.add_handler(:bar){ 'Bar' }
285
+ reactor.add_handler(:baz){ 'Baz' }
286
+ reactor.add_handler(:fubar){ raise StandardError.new('Boom!') }
287
+
288
+ reactor.stop_on_signal('USR1')
289
+
290
+ demux.should_receive(:respond).with(:ok, 'Foo')
291
+ demux.send(:foo)
292
+
293
+ @thread = Thread.new do
294
+ reactor.run
295
+ end
296
+ @thread.abort_on_exception = true
297
+ sleep(0.1)
298
+
299
+ reactor.should be_running
300
+
301
+ demux.should_receive(:respond).with(:ok, 'Bar')
302
+ demux.should_receive(:respond).with(:ok, 'Baz')
303
+ demux.should_receive(:respond).with(:noop, anything())
304
+ demux.should_receive(:respond).with(:ex, anything())
305
+
306
+ demux.send(:bar)
307
+ demux.send(:baz)
308
+ demux.send(:bogus)
309
+ demux.send(:fubar)
310
+
311
+ reactor.should be_running
312
+
313
+ Process.kill('USR1', Process.pid)
314
+ sleep(0.1)
315
+
316
+ demux.should_not_receive(:respond).with(:foo, anything())
317
+ demux.send(:foo)
318
+ reactor.should_not be_running
319
+ end
320
+ end
321
+
322
+ specify 'asynchronous demultiplexing' do
323
+
324
+ if Functional::PLATFORM.mri? && ! Functional::PLATFORM.windows?
325
+
326
+ demux = async_demux
327
+ reactor = Concurrent::Reactor.new(demux)
328
+
329
+ reactor.should_not be_running
330
+
331
+ reactor.add_handler(:foo){ 'Foo' }
332
+ reactor.add_handler(:bar){ 'Bar' }
333
+ reactor.add_handler(:baz){ 'Baz' }
334
+ reactor.add_handler(:fubar){ raise StandardError.new('Boom!') }
335
+
336
+ reactor.stop_on_signal('USR2')
337
+
338
+ demux.send(:foo).first.should eq :stopped
339
+
340
+ @thread = Thread.new do
341
+ reactor.run
342
+ end
343
+ @thread.abort_on_exception = true
344
+ sleep(0.1)
345
+
346
+ reactor.should be_running
347
+
348
+ demux.send(:foo).should eq [:ok, 'Foo']
349
+ demux.send(:bar).should eq [:ok, 'Bar']
350
+ demux.send(:baz).should eq [:ok, 'Baz']
351
+ demux.send(:bogus).first.should eq :noop
352
+ demux.send(:fubar).first.should eq :ex
353
+
354
+ reactor.should be_running
355
+
356
+ Process.kill('USR2', Process.pid)
357
+ sleep(0.1)
358
+
359
+ demux.send(:foo).first.should eq :stopped
360
+ reactor.should_not be_running
361
+ end
362
+ end
363
+ end
364
+ end