concurrent-ruby 0.6.1 → 0.7.0.rc0
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/README.md +1 -1
- data/lib/concurrent.rb +3 -4
- data/lib/concurrent/atomic.rb +46 -0
- data/lib/concurrent/atomic_reference/concurrent_update_error.rb +7 -0
- data/lib/concurrent/atomic_reference/delegated_update.rb +28 -0
- data/lib/concurrent/atomic_reference/direct_update.rb +28 -0
- data/lib/concurrent/atomic_reference/jruby.rb +8 -0
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +47 -0
- data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +24 -0
- data/lib/concurrent/atomic_reference/rbx.rb +16 -0
- data/lib/concurrent/atomic_reference/ruby.rb +16 -0
- data/lib/concurrent/atomics.rb +1 -1
- data/lib/concurrent/configuration.rb +1 -1
- data/lib/concurrent/supervisor.rb +1 -1
- data/lib/concurrent/timer_task.rb +0 -36
- data/lib/concurrent/version.rb +1 -1
- data/lib/concurrent_ruby_ext.so +0 -0
- data/lib/extension_helper.rb +9 -0
- metadata +16 -148
- data/lib/concurrent/actor/actor.rb +0 -270
- data/lib/concurrent/actor/postable.rb +0 -102
- data/lib/concurrent/actors.rb +0 -2
- data/lib/concurrent/atomic/atomic.rb +0 -48
- data/lib/concurrent/runnable.rb +0 -90
- data/lib/concurrent/stoppable.rb +0 -20
- data/spec/concurrent/actor/actor_spec.rb +0 -376
- data/spec/concurrent/actor/postable_shared.rb +0 -218
- data/spec/concurrent/actress_spec.rb +0 -211
- data/spec/concurrent/agent_spec.rb +0 -500
- data/spec/concurrent/async_spec.rb +0 -352
- data/spec/concurrent/atomic/atomic_boolean_spec.rb +0 -172
- data/spec/concurrent/atomic/atomic_fixnum_spec.rb +0 -186
- data/spec/concurrent/atomic/atomic_spec.rb +0 -133
- data/spec/concurrent/atomic/condition_spec.rb +0 -171
- data/spec/concurrent/atomic/copy_on_notify_observer_set_spec.rb +0 -10
- data/spec/concurrent/atomic/copy_on_write_observer_set_spec.rb +0 -10
- data/spec/concurrent/atomic/count_down_latch_spec.rb +0 -151
- data/spec/concurrent/atomic/cyclic_barrier_spec.rb +0 -248
- data/spec/concurrent/atomic/event_spec.rb +0 -200
- data/spec/concurrent/atomic/observer_set_shared.rb +0 -242
- data/spec/concurrent/atomic/thread_local_var_spec.rb +0 -113
- data/spec/concurrent/channel/buffered_channel_spec.rb +0 -151
- data/spec/concurrent/channel/channel_spec.rb +0 -39
- data/spec/concurrent/channel/probe_spec.rb +0 -77
- data/spec/concurrent/channel/unbuffered_channel_spec.rb +0 -132
- data/spec/concurrent/collection/blocking_ring_buffer_spec.rb +0 -149
- data/spec/concurrent/collection/priority_queue_spec.rb +0 -317
- data/spec/concurrent/collection/ring_buffer_spec.rb +0 -126
- data/spec/concurrent/configuration_spec.rb +0 -69
- data/spec/concurrent/dataflow_spec.rb +0 -242
- data/spec/concurrent/delay_spec.rb +0 -91
- data/spec/concurrent/dereferenceable_shared.rb +0 -146
- data/spec/concurrent/exchanger_spec.rb +0 -66
- data/spec/concurrent/executor/cached_thread_pool_shared.rb +0 -115
- data/spec/concurrent/executor/fixed_thread_pool_shared.rb +0 -136
- data/spec/concurrent/executor/global_thread_pool_shared.rb +0 -35
- data/spec/concurrent/executor/immediate_executor_spec.rb +0 -12
- data/spec/concurrent/executor/java_cached_thread_pool_spec.rb +0 -44
- data/spec/concurrent/executor/java_fixed_thread_pool_spec.rb +0 -64
- data/spec/concurrent/executor/java_single_thread_executor_spec.rb +0 -21
- data/spec/concurrent/executor/java_thread_pool_executor_spec.rb +0 -71
- data/spec/concurrent/executor/per_thread_executor_spec.rb +0 -57
- data/spec/concurrent/executor/ruby_cached_thread_pool_spec.rb +0 -69
- data/spec/concurrent/executor/ruby_fixed_thread_pool_spec.rb +0 -39
- data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +0 -18
- data/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb +0 -171
- data/spec/concurrent/executor/safe_task_executor_spec.rb +0 -103
- data/spec/concurrent/executor/thread_pool_class_cast_spec.rb +0 -52
- data/spec/concurrent/executor/thread_pool_executor_shared.rb +0 -155
- data/spec/concurrent/executor/thread_pool_shared.rb +0 -269
- data/spec/concurrent/executor/timer_set_spec.rb +0 -183
- data/spec/concurrent/future_spec.rb +0 -329
- data/spec/concurrent/ivar_spec.rb +0 -215
- data/spec/concurrent/mvar_spec.rb +0 -380
- data/spec/concurrent/obligation_shared.rb +0 -102
- data/spec/concurrent/obligation_spec.rb +0 -282
- data/spec/concurrent/observable_shared.rb +0 -177
- data/spec/concurrent/observable_spec.rb +0 -56
- data/spec/concurrent/options_parser_spec.rb +0 -71
- data/spec/concurrent/promise_spec.rb +0 -367
- data/spec/concurrent/runnable_shared.rb +0 -68
- data/spec/concurrent/runnable_spec.rb +0 -235
- data/spec/concurrent/scheduled_task_spec.rb +0 -340
- data/spec/concurrent/stoppable_shared.rb +0 -37
- data/spec/concurrent/supervisor_spec.rb +0 -1149
- data/spec/concurrent/timer_task_spec.rb +0 -256
- data/spec/concurrent/tvar_spec.rb +0 -137
- data/spec/concurrent/utility/processor_count_spec.rb +0 -20
- data/spec/concurrent/utility/timeout_spec.rb +0 -50
- data/spec/concurrent/utility/timer_spec.rb +0 -52
- data/spec/spec_helper.rb +0 -41
- data/spec/support/example_group_extensions.rb +0 -52
- data/spec/support/less_than_or_equal_to_matcher.rb +0 -5
data/lib/concurrent/stoppable.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'concurrent/runnable'
|
2
|
-
|
3
|
-
module Concurrent
|
4
|
-
|
5
|
-
module Stoppable
|
6
|
-
|
7
|
-
def before_stop(&block)
|
8
|
-
raise ArgumentError.new('no block given') unless block_given?
|
9
|
-
raise Runnable::LifecycleError.new('#before_stop already set') if @before_stop_proc
|
10
|
-
@before_stop_proc = block
|
11
|
-
self
|
12
|
-
end
|
13
|
-
|
14
|
-
protected
|
15
|
-
|
16
|
-
def before_stop_proc
|
17
|
-
@before_stop_proc
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,376 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require_relative 'postable_shared'
|
3
|
-
require_relative '../runnable_shared'
|
4
|
-
|
5
|
-
module Concurrent
|
6
|
-
|
7
|
-
describe Actor do
|
8
|
-
|
9
|
-
before do
|
10
|
-
# suppress deprecation warnings.
|
11
|
-
Concurrent::Actor.any_instance.stub(:warn)
|
12
|
-
Concurrent::Actor.stub(:warn)
|
13
|
-
end
|
14
|
-
|
15
|
-
let(:actor_class) do
|
16
|
-
Class.new(Actor) do
|
17
|
-
attr_reader :last_message
|
18
|
-
def initialize(&block)
|
19
|
-
@task = block
|
20
|
-
super()
|
21
|
-
end
|
22
|
-
def act(*message)
|
23
|
-
@last_message = message
|
24
|
-
@task.call(*message) unless @task.nil?
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
## :runnable
|
30
|
-
subject { Class.new(actor_class).new }
|
31
|
-
it_should_behave_like :runnable
|
32
|
-
|
33
|
-
## :postable
|
34
|
-
|
35
|
-
let!(:postable_class){ actor_class }
|
36
|
-
|
37
|
-
let(:sender_class) do
|
38
|
-
Class.new(Actor) do
|
39
|
-
def act(*message)
|
40
|
-
if message.first.is_a?(Exception)
|
41
|
-
raise message.first
|
42
|
-
else
|
43
|
-
return message.first
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
let(:sender) { sender_class.new }
|
50
|
-
let(:receiver) { postable_class.new }
|
51
|
-
|
52
|
-
it_should_behave_like :postable
|
53
|
-
|
54
|
-
context '#run' do
|
55
|
-
|
56
|
-
it 'empties the queue' do
|
57
|
-
@thread = Thread.new{ subject.run }
|
58
|
-
@thread.join(0.1)
|
59
|
-
q = subject.instance_variable_get(:@queue)
|
60
|
-
q.size.should == 0
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
context '#stop' do
|
65
|
-
|
66
|
-
it 'empties the queue' do
|
67
|
-
actor = actor_class.new{|msg| sleep }
|
68
|
-
@thread = Thread.new{ actor.run }
|
69
|
-
10.times { actor.post(true) }
|
70
|
-
@thread.join(0.1)
|
71
|
-
actor.stop
|
72
|
-
@thread.join(0.1)
|
73
|
-
q = actor.instance_variable_get(:@queue)
|
74
|
-
if q.size >= 1
|
75
|
-
q.pop.should == :stop
|
76
|
-
else
|
77
|
-
q.size.should == 0
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
it 'pushes a :stop message onto the queue' do
|
82
|
-
@thread = Thread.new{ subject.run }
|
83
|
-
@thread.join(0.1)
|
84
|
-
q = subject.instance_variable_get(:@queue)
|
85
|
-
q.should_receive(:push).once.with(:stop)
|
86
|
-
subject.stop
|
87
|
-
@thread.join(0.1)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
context 'exception handling' do
|
92
|
-
|
93
|
-
#it 'supresses exceptions thrown when handling messages' do
|
94
|
-
#pending('intermittently failing; deprecated')
|
95
|
-
#actor = actor_class.new{|msg| raise StandardError }
|
96
|
-
#@thread = Thread.new{ actor.run }
|
97
|
-
#expect {
|
98
|
-
#@thread.join(0.1)
|
99
|
-
#10.times { actor.post(true) }
|
100
|
-
#}.not_to raise_error
|
101
|
-
#actor.stop
|
102
|
-
#end
|
103
|
-
end
|
104
|
-
|
105
|
-
context 'observation' do
|
106
|
-
|
107
|
-
let(:actor_class) do
|
108
|
-
Class.new(Actor) do
|
109
|
-
def act(*message)
|
110
|
-
if message.first.is_a?(Exception)
|
111
|
-
raise message.first
|
112
|
-
else
|
113
|
-
return message.first
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
subject { Class.new(actor_class).new }
|
120
|
-
|
121
|
-
let(:observer) do
|
122
|
-
Class.new {
|
123
|
-
attr_reader :time
|
124
|
-
attr_reader :message
|
125
|
-
attr_reader :value
|
126
|
-
attr_reader :reason
|
127
|
-
def update(time, message, value, reason)
|
128
|
-
@time = time
|
129
|
-
@message = message
|
130
|
-
@value = value
|
131
|
-
@reason = reason
|
132
|
-
end
|
133
|
-
}.new
|
134
|
-
end
|
135
|
-
|
136
|
-
#it 'notifies observers when a message is successfully handled' do
|
137
|
-
#pending('intermittently failing; deprecated')
|
138
|
-
#observer.should_receive(:update).exactly(10).times.with(any_args())
|
139
|
-
#subject.add_observer(observer)
|
140
|
-
#@thread = Thread.new{ subject.run }
|
141
|
-
#@thread.join(0.1)
|
142
|
-
#10.times { subject.post(42) }
|
143
|
-
#@thread.join(0.1)
|
144
|
-
#end
|
145
|
-
|
146
|
-
#it 'notifies observers when a message raises an exception' do
|
147
|
-
#pending('intermittently failing; deprecated')
|
148
|
-
#error = StandardError.new
|
149
|
-
#observer.should_receive(:update).exactly(10).times.with(any_args())
|
150
|
-
#subject.add_observer(observer)
|
151
|
-
#@thread = Thread.new{ subject.run }
|
152
|
-
#@thread.join(0.1)
|
153
|
-
#10.times { subject.post(error) }
|
154
|
-
#@thread.join(0.1)
|
155
|
-
#end
|
156
|
-
|
157
|
-
it 'passes the time, message, value, and reason to the observer on success' do
|
158
|
-
subject.add_observer(observer)
|
159
|
-
@thread = Thread.new{ subject.run }
|
160
|
-
@thread.join(0.1)
|
161
|
-
subject.post(42)
|
162
|
-
@thread.join(0.1)
|
163
|
-
|
164
|
-
observer.time.should be_a(Time)
|
165
|
-
observer.message.should eq [42]
|
166
|
-
observer.value.should eq 42
|
167
|
-
observer.reason.should be_nil
|
168
|
-
end
|
169
|
-
|
170
|
-
it 'passes the time, message, value, and reason to the observer on exception' do
|
171
|
-
error = StandardError.new
|
172
|
-
subject.add_observer(observer)
|
173
|
-
@thread = Thread.new{ subject.run }
|
174
|
-
@thread.join(0.1)
|
175
|
-
subject.post(error)
|
176
|
-
@thread.join(0.1)
|
177
|
-
|
178
|
-
observer.time.should be_a(Time)
|
179
|
-
observer.message.should eq [error]
|
180
|
-
observer.value.should be_nil
|
181
|
-
observer.reason.should be_a(Exception)
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
context '#pool' do
|
186
|
-
|
187
|
-
let(:clazz){ Class.new(actor_class) }
|
188
|
-
|
189
|
-
it 'raises an exception if the count is zero or less' do
|
190
|
-
expect {
|
191
|
-
clazz.pool(0)
|
192
|
-
}.to raise_error(ArgumentError)
|
193
|
-
end
|
194
|
-
|
195
|
-
it 'creates the requested number of pool' do
|
196
|
-
mailbox, pool = clazz.pool(5)
|
197
|
-
pool.size.should == 5
|
198
|
-
end
|
199
|
-
|
200
|
-
it 'passes all optional arguments to the individual constructors' do
|
201
|
-
clazz.should_receive(:new).with(1, 2, 3).exactly(5).times
|
202
|
-
clazz.pool(5, 1, 2, 3)
|
203
|
-
end
|
204
|
-
|
205
|
-
it 'passes a duplicate of the given block to each actor in the pool' do
|
206
|
-
block = proc{ nil }
|
207
|
-
block.should_receive(:dup).exactly(5).times.and_return(proc{ nil })
|
208
|
-
mailbox, pool = clazz.pool(5, &block)
|
209
|
-
end
|
210
|
-
|
211
|
-
it 'gives all pool the same mailbox' do
|
212
|
-
mailbox, pool = clazz.pool(2)
|
213
|
-
mbox1 = pool.first.instance_variable_get(:@queue)
|
214
|
-
mbox2 = pool.last.instance_variable_get(:@queue)
|
215
|
-
mbox1.should eq mbox2
|
216
|
-
end
|
217
|
-
|
218
|
-
it 'returns a Poolbox as the first retval' do
|
219
|
-
mailbox, pool = clazz.pool(2)
|
220
|
-
mailbox.should be_a(Actor::Poolbox)
|
221
|
-
end
|
222
|
-
|
223
|
-
it 'gives the Poolbox the same mailbox as the pool' do
|
224
|
-
mailbox, pool = clazz.pool(1)
|
225
|
-
mbox1 = mailbox.instance_variable_get(:@queue)
|
226
|
-
mbox2 = pool.first.instance_variable_get(:@queue)
|
227
|
-
mbox1.should eq mbox2
|
228
|
-
end
|
229
|
-
|
230
|
-
it 'returns an array of pool as the second retval' do
|
231
|
-
mailbox, pool = clazz.pool(2)
|
232
|
-
pool.each do |actor|
|
233
|
-
actor.should be_a(clazz)
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
it 'posts to the mailbox with Poolbox#post' do
|
238
|
-
mailbox, pool = clazz.pool(1)
|
239
|
-
@thread = Thread.new{ pool.first.run }
|
240
|
-
sleep(0.1)
|
241
|
-
mailbox.post(42)
|
242
|
-
sleep(0.1)
|
243
|
-
pool.first.last_message.should eq [42]
|
244
|
-
pool.first.stop
|
245
|
-
@thread.kill
|
246
|
-
end
|
247
|
-
|
248
|
-
#it 'posts to the mailbox with Poolbox#<<' do
|
249
|
-
#pending('intermittently failing; deprecated')
|
250
|
-
#@expected = false
|
251
|
-
#mailbox, pool = clazz.pool(1)
|
252
|
-
#@thread = Thread.new{ pool.first.run }
|
253
|
-
#sleep(0.1)
|
254
|
-
#mailbox << 42
|
255
|
-
#sleep(0.1)
|
256
|
-
#pool.first.last_message.should eq [42]
|
257
|
-
#pool.first.stop
|
258
|
-
#@thread.kill
|
259
|
-
#end
|
260
|
-
end
|
261
|
-
|
262
|
-
context 'subclassing' do
|
263
|
-
|
264
|
-
after(:each) do
|
265
|
-
@thread.kill unless @thread.nil?
|
266
|
-
end
|
267
|
-
|
268
|
-
context '#pool' do
|
269
|
-
|
270
|
-
it 'creates pool of the appropriate subclass' do
|
271
|
-
actor = Class.new(actor_class)
|
272
|
-
mailbox, pool = actor.pool(1)
|
273
|
-
pool.first.should be_a(actor)
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
|
-
context '#act overloading' do
|
278
|
-
|
279
|
-
it 'raises an exception if #act is not implemented in the subclass' do
|
280
|
-
actor = Class.new(Actor).new
|
281
|
-
@thread = Thread.new{ actor.run }
|
282
|
-
@thread.join(0.1)
|
283
|
-
expect {
|
284
|
-
actor.post(:foo)
|
285
|
-
@thread.join(0.1)
|
286
|
-
}.to raise_error(NotImplementedError)
|
287
|
-
actor.stop
|
288
|
-
end
|
289
|
-
|
290
|
-
it 'uses the subclass #act implementation' do
|
291
|
-
actor = actor_class.new{|*args| @expected = true }
|
292
|
-
@thread = Thread.new{ actor.run }
|
293
|
-
@thread.join(0.1)
|
294
|
-
actor.post(:foo)
|
295
|
-
@thread.join(0.1)
|
296
|
-
actor.last_message.should eq [:foo]
|
297
|
-
actor.stop
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
context '#on_error overloading' do
|
302
|
-
|
303
|
-
let(:bad_actor) do
|
304
|
-
Class.new(actor_class) {
|
305
|
-
attr_reader :last_error
|
306
|
-
def act(*message)
|
307
|
-
raise StandardError
|
308
|
-
end
|
309
|
-
def on_error(*args)
|
310
|
-
@last_error = args
|
311
|
-
end
|
312
|
-
}
|
313
|
-
end
|
314
|
-
|
315
|
-
it 'uses the subclass #on_error implementation' do
|
316
|
-
actor = bad_actor.new
|
317
|
-
@thread = Thread.new{ actor.run }
|
318
|
-
@thread.join(0.1)
|
319
|
-
actor.post(42)
|
320
|
-
@thread.join(0.1)
|
321
|
-
actor.last_error[0].should be_a(Time)
|
322
|
-
actor.last_error[1].should eq [42]
|
323
|
-
actor.last_error[2].should be_a(StandardError)
|
324
|
-
actor.stop
|
325
|
-
end
|
326
|
-
end
|
327
|
-
end
|
328
|
-
|
329
|
-
context 'supervision' do
|
330
|
-
|
331
|
-
it 'can be started by a Supervisor' do
|
332
|
-
actor = actor_class.new
|
333
|
-
supervisor = Supervisor.new
|
334
|
-
supervisor.add_worker(actor)
|
335
|
-
|
336
|
-
actor.should_receive(:run).with(no_args())
|
337
|
-
supervisor.run!
|
338
|
-
sleep(0.1)
|
339
|
-
|
340
|
-
supervisor.stop
|
341
|
-
sleep(0.1)
|
342
|
-
actor.stop
|
343
|
-
end
|
344
|
-
|
345
|
-
it 'can receive messages while under supervision' do
|
346
|
-
@expected = false
|
347
|
-
actor = actor_class.new{|*args| @expected = true}
|
348
|
-
supervisor = Supervisor.new
|
349
|
-
supervisor.add_worker(actor)
|
350
|
-
supervisor.run!
|
351
|
-
sleep(0.1)
|
352
|
-
|
353
|
-
actor.post(42)
|
354
|
-
sleep(0.1)
|
355
|
-
@expected.should be_true
|
356
|
-
|
357
|
-
supervisor.stop
|
358
|
-
sleep(0.1)
|
359
|
-
actor.stop
|
360
|
-
end
|
361
|
-
|
362
|
-
it 'can be stopped by a supervisor' do
|
363
|
-
actor = actor_class.new
|
364
|
-
supervisor = Supervisor.new
|
365
|
-
supervisor.add_worker(actor)
|
366
|
-
|
367
|
-
supervisor.run!
|
368
|
-
sleep(0.1)
|
369
|
-
|
370
|
-
actor.should_receive(:stop).with(no_args())
|
371
|
-
supervisor.stop
|
372
|
-
sleep(0.1)
|
373
|
-
end
|
374
|
-
end
|
375
|
-
end
|
376
|
-
end
|
@@ -1,218 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
share_examples_for :postable do
|
4
|
-
|
5
|
-
after(:each) do
|
6
|
-
subject.stop
|
7
|
-
@thread.kill unless @thread.nil?
|
8
|
-
sleep(0.1)
|
9
|
-
end
|
10
|
-
|
11
|
-
context '#post' do
|
12
|
-
|
13
|
-
it 'raises an exception when the message is empty' do
|
14
|
-
expect {
|
15
|
-
subject.post
|
16
|
-
}.to raise_error(ArgumentError)
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'returns false when not running' do
|
20
|
-
subject.post(42).should be_false
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'pushes a message onto the queue' do
|
24
|
-
@expected = false
|
25
|
-
postable = postable_class.new{|msg| @expected = msg }
|
26
|
-
@thread = Thread.new{ postable.run }
|
27
|
-
@thread.join(0.1)
|
28
|
-
postable.post(true)
|
29
|
-
@thread.join(0.1)
|
30
|
-
@expected.should be_true
|
31
|
-
postable.stop
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'returns true on success' do
|
35
|
-
postable = postable_class.new{|msg| sleep }
|
36
|
-
@thread = Thread.new{ postable.run }
|
37
|
-
5.times{ @thread.join(0.1); break if postable.running? }
|
38
|
-
postable.post(true).should be_true
|
39
|
-
postable.stop
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'is aliased a <<' do
|
43
|
-
@expected = false
|
44
|
-
postable = postable_class.new{|msg| @expected = msg }
|
45
|
-
@thread = Thread.new{ postable.run }
|
46
|
-
@thread.join(0.1)
|
47
|
-
postable << true
|
48
|
-
@thread.join(0.1)
|
49
|
-
@expected.should be_true
|
50
|
-
postable.stop
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
context '#post?' do
|
55
|
-
|
56
|
-
it 'returns nil when not running' do
|
57
|
-
subject.post?(42).should be_false
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'returns an Obligation' do
|
61
|
-
postable = postable_class.new{ nil }
|
62
|
-
@thread = Thread.new{ postable.run }
|
63
|
-
@thread.join(0.1)
|
64
|
-
obligation = postable.post?(nil)
|
65
|
-
obligation.should be_a(Concurrent::Obligation)
|
66
|
-
postable.stop
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'fulfills the obligation on success' do
|
70
|
-
postable = postable_class.new{|msg| @expected = msg }
|
71
|
-
@thread = Thread.new{ postable.run }
|
72
|
-
@thread.join(0.1)
|
73
|
-
obligation = postable.post?(42)
|
74
|
-
@thread.join(0.1)
|
75
|
-
obligation.should be_fulfilled
|
76
|
-
obligation.value.should == 42
|
77
|
-
postable.stop
|
78
|
-
end
|
79
|
-
|
80
|
-
it 'rejects the obligation on failure' do
|
81
|
-
postable = postable_class.new{|msg| raise StandardError.new('Boom!') }
|
82
|
-
@thread = Thread.new{ postable.run }
|
83
|
-
@thread.join(0.1)
|
84
|
-
obligation = postable.post?(42)
|
85
|
-
@thread.join(0.1)
|
86
|
-
obligation.should be_rejected
|
87
|
-
obligation.reason.should be_a(StandardError)
|
88
|
-
postable.stop
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
context '#post!' do
|
93
|
-
|
94
|
-
it 'raises Concurrent::Runnable::LifecycleError when not running' do
|
95
|
-
expect {
|
96
|
-
subject.post!(1, 'Hello World!')
|
97
|
-
}.to raise_error(Concurrent::LifecycleError)
|
98
|
-
end
|
99
|
-
|
100
|
-
it 'blocks for up to the given number of seconds' do
|
101
|
-
postable = postable_class.new{|msg| sleep }
|
102
|
-
@thread = Thread.new{ postable.run }
|
103
|
-
@thread.join(0.1)
|
104
|
-
start = Time.now.to_i
|
105
|
-
expect {
|
106
|
-
postable.post!(2, nil)
|
107
|
-
}.to raise_error
|
108
|
-
elapsed = Time.now.to_i - start
|
109
|
-
elapsed.should >= 2
|
110
|
-
postable.stop
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'raises Concurrent::TimeoutError when seconds is zero' do
|
114
|
-
postable = postable_class.new{|msg| 42 }
|
115
|
-
@thread = Thread.new{ postable.run }
|
116
|
-
@thread.join(0.1)
|
117
|
-
expect {
|
118
|
-
postable.post!(0, nil)
|
119
|
-
}.to raise_error(Concurrent::TimeoutError)
|
120
|
-
postable.stop
|
121
|
-
end
|
122
|
-
|
123
|
-
it 'raises Concurrent::TimeoutError on timeout' do
|
124
|
-
postable = postable_class.new{|msg| sleep }
|
125
|
-
@thread = Thread.new{ postable.run }
|
126
|
-
@thread.join(0.1)
|
127
|
-
expect {
|
128
|
-
postable.post!(1, nil)
|
129
|
-
}.to raise_error(Concurrent::TimeoutError)
|
130
|
-
postable.stop
|
131
|
-
end
|
132
|
-
|
133
|
-
it 'bubbles the exception on error' do
|
134
|
-
postable = postable_class.new{|msg| raise StandardError.new('Boom!') }
|
135
|
-
@thread = Thread.new{ postable.run }
|
136
|
-
@thread.join(0.1)
|
137
|
-
expect {
|
138
|
-
postable.post!(1, nil)
|
139
|
-
}.to raise_error(StandardError)
|
140
|
-
postable.stop
|
141
|
-
end
|
142
|
-
|
143
|
-
it 'returns the result on success' do
|
144
|
-
postable = postable_class.new{|msg| 42 }
|
145
|
-
@thread = Thread.new{ postable.run }
|
146
|
-
@thread.join(0.1)
|
147
|
-
expected = postable.post!(1, nil)
|
148
|
-
expected.should == 42
|
149
|
-
postable.stop
|
150
|
-
end
|
151
|
-
|
152
|
-
it 'attempts to cancel the operation on timeout' do
|
153
|
-
@expected = 0
|
154
|
-
postable = postable_class.new{|msg| sleep(0.5); @expected += 1 }
|
155
|
-
@thread = Thread.new{ postable.run }
|
156
|
-
@thread.join(0.1)
|
157
|
-
postable.post(nil) # block the postable
|
158
|
-
expect {
|
159
|
-
postable.post!(0.1, nil)
|
160
|
-
}.to raise_error(Concurrent::TimeoutError)
|
161
|
-
sleep(1.5)
|
162
|
-
@expected.should == 1
|
163
|
-
postable.stop
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
context '#forward' do
|
168
|
-
|
169
|
-
let(:observer) { double('observer') }
|
170
|
-
|
171
|
-
before(:each) do
|
172
|
-
@sender = Thread.new{ sender.run }
|
173
|
-
@receiver = Thread.new{ receiver.run }
|
174
|
-
@sender.join(0.1)
|
175
|
-
@receiver.join(0.1)
|
176
|
-
end
|
177
|
-
|
178
|
-
after(:each) do
|
179
|
-
sender.stop
|
180
|
-
receiver.stop
|
181
|
-
sleep(0.1)
|
182
|
-
@sender.kill unless @sender.nil?
|
183
|
-
@receiver.kill unless @receiver.nil?
|
184
|
-
end
|
185
|
-
|
186
|
-
it 'returns false when sender not running' do
|
187
|
-
sender.stop
|
188
|
-
sleep(0.1)
|
189
|
-
sender.forward(receiver, 'Hello World!').should be_false
|
190
|
-
end
|
191
|
-
|
192
|
-
it 'forwards the result to the receiver on success' do
|
193
|
-
receiver.should_receive(:post).with(42)
|
194
|
-
sender.forward(receiver, 42)
|
195
|
-
sleep(0.1)
|
196
|
-
end
|
197
|
-
|
198
|
-
it 'does not forward on exception' do
|
199
|
-
receiver.should_not_receive(:post).with(42)
|
200
|
-
sender.forward(receiver, StandardError.new)
|
201
|
-
sleep(0.1)
|
202
|
-
end
|
203
|
-
|
204
|
-
it 'notifies observers on success' do
|
205
|
-
observer.should_receive(:update).with(any_args())
|
206
|
-
sender.add_observer(observer)
|
207
|
-
sender.forward(receiver, 42)
|
208
|
-
sleep(0.1)
|
209
|
-
end
|
210
|
-
|
211
|
-
it 'notifies observers on exception' do
|
212
|
-
observer.should_not_receive(:update).with(any_args())
|
213
|
-
sender.add_observer(observer)
|
214
|
-
sender.forward(receiver, StandardError.new)
|
215
|
-
sleep(0.1)
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|