concurrent-ruby 0.6.0 → 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 +55 -51
- data/lib/concurrent/actress/ad_hoc.rb +6 -0
- data/lib/concurrent/actress/context.rb +10 -8
- data/lib/concurrent/actress/core.rb +44 -20
- data/lib/concurrent/actress/core_delegations.rb +5 -0
- data/lib/concurrent/actress/envelope.rb +21 -5
- data/lib/concurrent/actress/reference.rb +5 -5
- data/lib/concurrent/actress.rb +152 -6
- data/lib/concurrent/agent.rb +9 -9
- 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 +7 -2
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +0 -1
- data/lib/concurrent/executor/{one_by_one.rb → serialized_execution.rb} +21 -8
- data/lib/concurrent/executor/timer_set.rb +6 -1
- data/lib/concurrent/executors.rb +1 -1
- data/lib/concurrent/logging.rb +1 -1
- data/lib/concurrent/observable.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.rb +3 -4
- data/lib/concurrent_ruby_ext.so +0 -0
- data/lib/extension_helper.rb +9 -0
- metadata +19 -152
- 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/actress/doc.md +0 -53
- 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 -191
- 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 -71
- 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 -239
- 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 -342
- data/spec/concurrent/stoppable_shared.rb +0 -37
- data/spec/concurrent/supervisor_spec.rb +0 -1148
- data/spec/concurrent/timer_task_spec.rb +0 -258
- 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 -31
- data/spec/support/example_group_extensions.rb +0 -48
- data/spec/support/less_than_or_equal_to_matcher.rb +0 -5
- /data/{LICENSE → LICENSE.txt} +0 -0
|
@@ -1,367 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require_relative 'obligation_shared'
|
|
3
|
-
|
|
4
|
-
module Concurrent
|
|
5
|
-
|
|
6
|
-
describe Promise do
|
|
7
|
-
|
|
8
|
-
let(:executor) { PerThreadExecutor.new }
|
|
9
|
-
|
|
10
|
-
let(:empty_root) { Promise.new(executor: executor){ nil } }
|
|
11
|
-
let!(:fulfilled_value) { 10 }
|
|
12
|
-
let!(:rejected_reason) { StandardError.new('mojo jojo') }
|
|
13
|
-
|
|
14
|
-
let(:pending_subject) do
|
|
15
|
-
Promise.new(executor: executor){ sleep(0.3); fulfilled_value }.execute
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
let(:fulfilled_subject) do
|
|
19
|
-
Promise.fulfill(fulfilled_value, executor: executor)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
let(:rejected_subject) do
|
|
23
|
-
Promise.reject(rejected_reason, executor: executor)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
it_should_behave_like :obligation
|
|
27
|
-
|
|
28
|
-
it 'includes Dereferenceable' do
|
|
29
|
-
promise = Promise.new{ nil }
|
|
30
|
-
promise.should be_a(Dereferenceable)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
context 'initializers' do
|
|
34
|
-
describe '.fulfill' do
|
|
35
|
-
|
|
36
|
-
subject { Promise.fulfill(10) }
|
|
37
|
-
|
|
38
|
-
it 'should return a Promise' do
|
|
39
|
-
subject.should be_a Promise
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
it 'should return a fulfilled Promise' do
|
|
43
|
-
subject.should be_fulfilled
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
it 'should return a Promise with set value' do
|
|
47
|
-
subject.value.should eq 10
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
describe '.reject' do
|
|
52
|
-
|
|
53
|
-
let(:reason) { ArgumentError.new }
|
|
54
|
-
subject { Promise.reject(reason) }
|
|
55
|
-
|
|
56
|
-
it 'should return a Promise' do
|
|
57
|
-
subject.should be_a Promise
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
it 'should return a rejected Promise' do
|
|
61
|
-
subject.should be_rejected
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
it 'should return a Promise with set reason' do
|
|
65
|
-
subject.reason.should be reason
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
describe '.new' do
|
|
70
|
-
it 'should return an unscheduled Promise' do
|
|
71
|
-
p = Promise.new(executor: executor){ nil }
|
|
72
|
-
p.should be_unscheduled
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
describe '.execute' do
|
|
77
|
-
it 'creates a new Promise' do
|
|
78
|
-
p = Promise.execute(executor: executor){ nil }
|
|
79
|
-
p.should be_a(Promise)
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
it 'passes the block to the new Promise' do
|
|
83
|
-
p = Promise.execute(executor: executor){ 20 }
|
|
84
|
-
sleep(0.1)
|
|
85
|
-
p.value.should eq 20
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
it 'calls #execute on the new Promise' do
|
|
89
|
-
p = double('promise')
|
|
90
|
-
Promise.stub(:new).with({executor: executor}).and_return(p)
|
|
91
|
-
p.should_receive(:execute).with(no_args)
|
|
92
|
-
Promise.execute(executor: executor){ nil }
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
context '#execute' do
|
|
98
|
-
|
|
99
|
-
context 'unscheduled' do
|
|
100
|
-
|
|
101
|
-
it 'sets the promise to :pending' do
|
|
102
|
-
p = Promise.new(executor: executor){ sleep(0.1) }.execute
|
|
103
|
-
p.should be_pending
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
it 'posts the block given in construction' do
|
|
107
|
-
executor.should_receive(:post).with(any_args)
|
|
108
|
-
Promise.new(executor: executor){ nil }.execute
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
context 'pending' do
|
|
113
|
-
|
|
114
|
-
it 'sets the promise to :pending' do
|
|
115
|
-
p = pending_subject.execute
|
|
116
|
-
p.should be_pending
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
it 'does not posts again' do
|
|
120
|
-
executor.should_receive(:post).with(any_args).once
|
|
121
|
-
pending_subject.execute
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
describe 'with children' do
|
|
126
|
-
|
|
127
|
-
let(:root) { Promise.new(executor: executor){ sleep(0.1); nil } }
|
|
128
|
-
let(:c1) { root.then { sleep(0.1); nil } }
|
|
129
|
-
let(:c2) { root.then { sleep(0.1); nil } }
|
|
130
|
-
let(:c2_1) { c2.then { sleep(0.1); nil } }
|
|
131
|
-
|
|
132
|
-
context 'when called on the root' do
|
|
133
|
-
it 'should set all promises to :pending' do
|
|
134
|
-
root.execute
|
|
135
|
-
|
|
136
|
-
c1.should be_pending
|
|
137
|
-
c2.should be_pending
|
|
138
|
-
c2_1.should be_pending
|
|
139
|
-
[root, c1, c2, c2_1].each { |p| p.should be_pending }
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
context 'when called on a child' do
|
|
144
|
-
it 'should set all promises to :pending' do
|
|
145
|
-
c2_1.execute
|
|
146
|
-
|
|
147
|
-
[root, c1, c2, c2_1].each { |p| p.should be_pending }
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
describe '#then' do
|
|
154
|
-
|
|
155
|
-
it 'returns a new promise when a block is passed' do
|
|
156
|
-
child = empty_root.then { nil }
|
|
157
|
-
child.should be_a Promise
|
|
158
|
-
child.should_not be empty_root
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
it 'returns a new promise when a rescuer is passed' do
|
|
162
|
-
child = empty_root.then(Proc.new{})
|
|
163
|
-
child.should be_a Promise
|
|
164
|
-
child.should_not be empty_root
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
it 'returns a new promise when a block and rescuer are passed' do
|
|
168
|
-
child = empty_root.then(Proc.new{}) { nil }
|
|
169
|
-
child.should be_a Promise
|
|
170
|
-
child.should_not be empty_root
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
it 'should have block or rescuers' do
|
|
174
|
-
expect { empty_root.then }.to raise_error(ArgumentError)
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
context 'unscheduled' do
|
|
178
|
-
|
|
179
|
-
let(:p1) { Promise.new(executor: executor){nil} }
|
|
180
|
-
let(:child) { p1.then{} }
|
|
181
|
-
|
|
182
|
-
it 'returns a new promise' do
|
|
183
|
-
child.should be_a Promise
|
|
184
|
-
p1.should_not be child
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
it 'returns an unscheduled promise' do
|
|
188
|
-
child.should be_unscheduled
|
|
189
|
-
end
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
context 'pending' do
|
|
193
|
-
|
|
194
|
-
let(:child) { pending_subject.then{} }
|
|
195
|
-
|
|
196
|
-
it 'returns a new promise' do
|
|
197
|
-
child.should be_a Promise
|
|
198
|
-
pending_subject.should_not be child
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
it 'returns a pending promise' do
|
|
202
|
-
child.should be_pending
|
|
203
|
-
end
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
context 'fulfilled' do
|
|
207
|
-
it 'returns a new Promise' do
|
|
208
|
-
p1 = fulfilled_subject
|
|
209
|
-
p2 = p1.then{}
|
|
210
|
-
p2.should be_a(Promise)
|
|
211
|
-
p1.should_not eq p2
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
it 'notifies fulfillment to new child' do
|
|
215
|
-
child = fulfilled_subject.then(Proc.new{ 7 }) { |v| v + 5 }
|
|
216
|
-
child.value.should eq fulfilled_value + 5
|
|
217
|
-
end
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
context 'rejected' do
|
|
221
|
-
it 'returns a new Promise when :rejected' do
|
|
222
|
-
p1 = rejected_subject
|
|
223
|
-
p2 = p1.then{}
|
|
224
|
-
p2.should be_a(Promise)
|
|
225
|
-
p1.should_not eq p2
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
it 'notifies rejection to new child' do
|
|
229
|
-
child = rejected_subject.then(Proc.new{ 7 }) { |v| v + 5 }
|
|
230
|
-
child.value.should eq 7
|
|
231
|
-
end
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
it 'can be called more than once' do
|
|
235
|
-
p = pending_subject
|
|
236
|
-
p1 = p.then{}
|
|
237
|
-
p2 = p.then{}
|
|
238
|
-
p1.should_not be p2
|
|
239
|
-
end
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
describe 'on_success' do
|
|
243
|
-
it 'should have a block' do
|
|
244
|
-
expect { empty_root.on_success }.to raise_error(ArgumentError)
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
it 'returns a new promise' do
|
|
248
|
-
child = empty_root.on_success { nil }
|
|
249
|
-
child.should be_a Promise
|
|
250
|
-
child.should_not be empty_root
|
|
251
|
-
end
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
context '#rescue' do
|
|
255
|
-
|
|
256
|
-
it 'returns a new promise' do
|
|
257
|
-
child = empty_root.rescue { nil }
|
|
258
|
-
child.should be_a Promise
|
|
259
|
-
child.should_not be empty_root
|
|
260
|
-
end
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
context 'fulfillment' do
|
|
264
|
-
|
|
265
|
-
it 'passes the result of each block to all its children' do
|
|
266
|
-
expected = nil
|
|
267
|
-
Promise.new(executor: executor){ 20 }.then{ |result| expected = result }.execute
|
|
268
|
-
sleep(0.1)
|
|
269
|
-
expected.should eq 20
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
it 'sets the promise value to the result if its block' do
|
|
273
|
-
root = Promise.new(executor: executor){ 20 }
|
|
274
|
-
p = root.then{ |result| result * 2}.execute
|
|
275
|
-
sleep(0.1)
|
|
276
|
-
root.value.should eq 20
|
|
277
|
-
p.value.should eq 40
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
it 'sets the promise state to :fulfilled if the block completes' do
|
|
281
|
-
p = Promise.new(executor: executor){ 10 * 2 }.then{|result| result * 2}.execute
|
|
282
|
-
sleep(0.1)
|
|
283
|
-
p.should be_fulfilled
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
it 'passes the last result through when a promise has no block' do
|
|
287
|
-
expected = nil
|
|
288
|
-
Promise.new(executor: executor){ 20 }.then(Proc.new{}).then{|result| expected = result}.execute
|
|
289
|
-
sleep(0.1)
|
|
290
|
-
expected.should eq 20
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
it 'uses result as fulfillment value when a promise has no block' do
|
|
294
|
-
p = Promise.new(executor: executor){ 20 }.then(Proc.new{}).execute
|
|
295
|
-
sleep(0.1)
|
|
296
|
-
p.value.should eq 20
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
it 'can manage long chain' do
|
|
300
|
-
root = Promise.new(executor: executor){ 20 }
|
|
301
|
-
p1 = root.then { |b| b * 3 }
|
|
302
|
-
p2 = root.then { |c| c + 2 }
|
|
303
|
-
p3 = p1.then { |d| d + 7 }
|
|
304
|
-
|
|
305
|
-
root.execute
|
|
306
|
-
sleep(0.1)
|
|
307
|
-
|
|
308
|
-
root.value.should eq 20
|
|
309
|
-
p1.value.should eq 60
|
|
310
|
-
p2.value.should eq 22
|
|
311
|
-
p3.value.should eq 67
|
|
312
|
-
end
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
context 'rejection' do
|
|
316
|
-
|
|
317
|
-
it 'passes the reason to all its children' do
|
|
318
|
-
expected = nil
|
|
319
|
-
Promise.new(executor: executor){ raise ArgumentError }.then(Proc.new{ |reason| expected = reason }).execute
|
|
320
|
-
sleep(0.1)
|
|
321
|
-
expected.should be_a ArgumentError
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
it 'sets the promise value to the result if its block' do
|
|
325
|
-
root = Promise.new(executor: executor){ raise ArgumentError }
|
|
326
|
-
p = root.then(Proc.new{ |reason| 42 }).execute
|
|
327
|
-
sleep(0.1)
|
|
328
|
-
p.value.should eq 42
|
|
329
|
-
end
|
|
330
|
-
|
|
331
|
-
it 'sets the promise state to :rejected if the block completes' do
|
|
332
|
-
p = Promise.new(executor: executor){ raise ArgumentError }.execute
|
|
333
|
-
sleep(0.1)
|
|
334
|
-
p.should be_rejected
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
it 'uses reason as rejection reason when a promise has no rescue callable' do
|
|
338
|
-
p = Promise.new(executor: ImmediateExecutor.new){ raise ArgumentError }.then{ |val| val }.execute
|
|
339
|
-
sleep(0.1)
|
|
340
|
-
p.should be_rejected
|
|
341
|
-
p.reason.should be_a ArgumentError
|
|
342
|
-
end
|
|
343
|
-
|
|
344
|
-
end
|
|
345
|
-
|
|
346
|
-
context 'aliases' do
|
|
347
|
-
|
|
348
|
-
it 'aliases #realized? for #fulfilled?' do
|
|
349
|
-
fulfilled_subject.should be_realized
|
|
350
|
-
end
|
|
351
|
-
|
|
352
|
-
it 'aliases #deref for #value' do
|
|
353
|
-
fulfilled_subject.deref.should eq fulfilled_value
|
|
354
|
-
end
|
|
355
|
-
|
|
356
|
-
it 'aliases #catch for #rescue' do
|
|
357
|
-
child = rejected_subject.catch { 7 }
|
|
358
|
-
child.value.should eq 7
|
|
359
|
-
end
|
|
360
|
-
|
|
361
|
-
it 'aliases #on_error for #rescue' do
|
|
362
|
-
child = rejected_subject.on_error { 7 }
|
|
363
|
-
child.value.should eq 7
|
|
364
|
-
end
|
|
365
|
-
end
|
|
366
|
-
end
|
|
367
|
-
end
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
share_examples_for :runnable do
|
|
4
|
-
|
|
5
|
-
after(:each) do
|
|
6
|
-
subject.stop
|
|
7
|
-
@thread.kill unless @thread.nil?
|
|
8
|
-
sleep(0.1)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
context '#run' do
|
|
12
|
-
|
|
13
|
-
it 'starts the (blocking) runner on the current thread when stopped' do
|
|
14
|
-
@thread = Thread.new { subject.run }
|
|
15
|
-
@thread.join(0.1).should be_nil
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
it 'raises an exception when already running' do
|
|
19
|
-
@thread = Thread.new { subject.run }
|
|
20
|
-
@thread.join(0.1)
|
|
21
|
-
expect {
|
|
22
|
-
subject.run
|
|
23
|
-
}.to raise_error
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
it 'returns true when stopped normally' do
|
|
27
|
-
@expected = false
|
|
28
|
-
@thread = Thread.new { @expected = subject.run }
|
|
29
|
-
@thread.join(0.1)
|
|
30
|
-
subject.stop
|
|
31
|
-
@thread.join(1)
|
|
32
|
-
@expected.should be_true
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
context '#stop' do
|
|
37
|
-
|
|
38
|
-
it 'returns true when not running' do
|
|
39
|
-
subject.stop.should be_true
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
it 'returns true when successfully stopped' do
|
|
43
|
-
@thread = Thread.new { subject.run }
|
|
44
|
-
@thread.join(0.1)
|
|
45
|
-
subject.stop.should be_true
|
|
46
|
-
subject.should_not be_running
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
context '#running?' do
|
|
51
|
-
|
|
52
|
-
it 'returns true when running' do
|
|
53
|
-
@thread = Thread.new { subject.run }
|
|
54
|
-
@thread.join(0.1)
|
|
55
|
-
subject.should be_running
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
it 'returns false when first created' do
|
|
59
|
-
subject.should_not be_running
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
it 'returns false when not running' do
|
|
63
|
-
subject.stop
|
|
64
|
-
sleep(0.1)
|
|
65
|
-
subject.should_not be_running
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require_relative 'runnable_shared'
|
|
3
|
-
|
|
4
|
-
module Concurrent
|
|
5
|
-
|
|
6
|
-
describe Runnable do
|
|
7
|
-
|
|
8
|
-
let(:runnable) do
|
|
9
|
-
Class.new {
|
|
10
|
-
include Runnable
|
|
11
|
-
attr_reader :thread
|
|
12
|
-
def initialize(*args, &block)
|
|
13
|
-
yield if block_given?
|
|
14
|
-
end
|
|
15
|
-
def on_task
|
|
16
|
-
@thread = Thread.current
|
|
17
|
-
sleep(0.1)
|
|
18
|
-
end
|
|
19
|
-
def on_run() return true; end
|
|
20
|
-
def after_run() return true; end
|
|
21
|
-
def on_stop() return true; end
|
|
22
|
-
}
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
subject { runnable.new }
|
|
26
|
-
|
|
27
|
-
it_should_behave_like :runnable
|
|
28
|
-
|
|
29
|
-
after(:each) do
|
|
30
|
-
subject.stop
|
|
31
|
-
@thread.kill unless @thread.nil?
|
|
32
|
-
sleep(0.1)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
context '#run' do
|
|
36
|
-
|
|
37
|
-
it 'calls #on_run when implemented' do
|
|
38
|
-
subject.should_receive(:on_run).with(no_args())
|
|
39
|
-
@thread = Thread.new { subject.run }
|
|
40
|
-
sleep(0.1)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
it 'does not attempt to call #on_run when not implemented' do
|
|
44
|
-
subject.class.send(:remove_method, :on_run)
|
|
45
|
-
@thread = Thread.new do
|
|
46
|
-
expect {
|
|
47
|
-
subject.run
|
|
48
|
-
}.not_to raise_error
|
|
49
|
-
end
|
|
50
|
-
sleep(0.1)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
it 'return false when #on_run raises an exception' do
|
|
54
|
-
@expected = true
|
|
55
|
-
subject.stub(:on_run).and_raise(StandardError)
|
|
56
|
-
@thread = Thread.new do
|
|
57
|
-
@expected = subject.run
|
|
58
|
-
end
|
|
59
|
-
sleep(0.1)
|
|
60
|
-
@expected.should be_false
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
it 'calls #on_task in an infinite loop' do
|
|
64
|
-
subject.should_receive(:on_task).with(no_args()).at_least(1)
|
|
65
|
-
@thread = Thread.new { subject.run }
|
|
66
|
-
@thread.join(1)
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
it 'raises an exception if the #on_task callback is not implemented' do
|
|
70
|
-
runner = Class.new { include Runnable }.new
|
|
71
|
-
expect {
|
|
72
|
-
runner.run
|
|
73
|
-
}.to raise_error(Concurrent::LifecycleError)
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
it 'returns false when the task loop raises an exception' do
|
|
77
|
-
@expected = false
|
|
78
|
-
subject.stub(:on_task).and_raise(StandardError)
|
|
79
|
-
@thread = Thread.new { @expected = subject.run }
|
|
80
|
-
@thread.join(0.1)
|
|
81
|
-
@expected.should be_false
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
context '#stop' do
|
|
86
|
-
|
|
87
|
-
it 'calls #on_stop when implemented' do
|
|
88
|
-
subject.should_receive(:on_stop).with(no_args())
|
|
89
|
-
@thread = Thread.new { subject.run }
|
|
90
|
-
sleep(0.1)
|
|
91
|
-
subject.stop
|
|
92
|
-
sleep(0.1)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
it 'does not attempt to call #on_stop when not implemented' do
|
|
96
|
-
subject.class.send(:remove_method, :on_stop)
|
|
97
|
-
@thread = Thread.new { subject.run }
|
|
98
|
-
sleep(0.1)
|
|
99
|
-
expect {
|
|
100
|
-
subject.stop
|
|
101
|
-
sleep(0.1)
|
|
102
|
-
}.not_to raise_error
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
it 'return false when #on_stop raises an exception' do
|
|
106
|
-
subject.stub(:on_stop).and_raise(StandardError)
|
|
107
|
-
@thread = Thread.new { subject.run }
|
|
108
|
-
sleep(0.1)
|
|
109
|
-
subject.stop.should be_false
|
|
110
|
-
subject.should_not be_running
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
it 'calls #after_run when implemented' do
|
|
114
|
-
subject.should_receive(:after_run).with(no_args())
|
|
115
|
-
@thread = Thread.new { subject.run }
|
|
116
|
-
sleep(0.1)
|
|
117
|
-
subject.stop
|
|
118
|
-
sleep(0.2)
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
it 'does not attempt to call #after_run when not implemented' do
|
|
122
|
-
subject.class.send(:remove_method, :after_run)
|
|
123
|
-
@thread = Thread.new { subject.run }
|
|
124
|
-
sleep(0.1)
|
|
125
|
-
expect {
|
|
126
|
-
subject.stop
|
|
127
|
-
sleep(0.2)
|
|
128
|
-
}.not_to raise_error
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
context '#running?' do
|
|
133
|
-
|
|
134
|
-
it 'returns false if runner abends' do
|
|
135
|
-
subject.stub(:on_task).and_raise(StandardError)
|
|
136
|
-
@thread = Thread.new { subject.run }
|
|
137
|
-
@thread.join(0.1)
|
|
138
|
-
subject.should_not be_running
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
context 'instance #run!' do
|
|
143
|
-
|
|
144
|
-
after(:each) do
|
|
145
|
-
@thread.kill if @thread
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
it 'raises an exception when already running' do
|
|
149
|
-
@thread = Thread.new{ subject.run }
|
|
150
|
-
@thread.join(0.1)
|
|
151
|
-
expect {
|
|
152
|
-
@thread = subject.run!
|
|
153
|
-
}.to raise_exception(Concurrent::LifecycleError)
|
|
154
|
-
sleep(0.1)
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
it 'creates a new thread' do
|
|
158
|
-
t = Thread.new{ nil }
|
|
159
|
-
Thread.should_receive(:new).with(no_args()).and_return(t)
|
|
160
|
-
@thread = subject.run!
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
it 'calls the #run method on the new thread' do
|
|
164
|
-
subject.should_receive(:run)
|
|
165
|
-
@thread = subject.run!
|
|
166
|
-
sleep(0.1)
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
it 'returns the new thread' do
|
|
170
|
-
@thread = subject.run!
|
|
171
|
-
sleep(0.1)
|
|
172
|
-
@thread.should be_a(Thread)
|
|
173
|
-
end
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
context 'module #run!' do
|
|
177
|
-
|
|
178
|
-
let(:clazz) do
|
|
179
|
-
Class.new { include Runnable }
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
after(:each) do
|
|
183
|
-
@context.runner.stop if @context && @context.runner
|
|
184
|
-
@context.thread.kill if @context && @context.thread
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
it 'creates a new runner' do
|
|
188
|
-
clazz.should_receive(:new).once.with(no_args())
|
|
189
|
-
@context = clazz.run!
|
|
190
|
-
sleep(0.1)
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
it 'passes all args to the runner constructor' do
|
|
194
|
-
args = [1, 2, :three, :four]
|
|
195
|
-
clazz.should_receive(:new).once.with(*args)
|
|
196
|
-
@context = clazz.run!(*args)
|
|
197
|
-
sleep(0.1)
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
it 'passes a block argument to the runner constructor' do
|
|
201
|
-
@expected = false
|
|
202
|
-
@context = runnable.run!{ @expected = true }
|
|
203
|
-
sleep(0.1)
|
|
204
|
-
@expected.should be_true
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
it 'creates a new thread' do
|
|
208
|
-
Thread.should_receive(:new).with(any_args()).and_return(nil)
|
|
209
|
-
@context = runnable.run!
|
|
210
|
-
sleep(0.1)
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
it 'runs the runner on the new thread' do
|
|
214
|
-
@context = runnable.run!
|
|
215
|
-
sleep(0.1)
|
|
216
|
-
@context.runner.thread.should_not eq Thread.current
|
|
217
|
-
@context.runner.thread.should eq @context.thread
|
|
218
|
-
@context.thread.should_not eq Thread.current
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
it 'returns a context object on success' do
|
|
222
|
-
@context = runnable.run!
|
|
223
|
-
sleep(0.1)
|
|
224
|
-
@context.should be_a(Runnable::Context)
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
it 'returns nil on failure' do
|
|
228
|
-
Thread.stub(:new).with(any_args()).and_raise(StandardError)
|
|
229
|
-
@context = runnable.run!
|
|
230
|
-
sleep(0.1)
|
|
231
|
-
@context.should be_nil
|
|
232
|
-
end
|
|
233
|
-
end
|
|
234
|
-
end
|
|
235
|
-
end
|