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.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +55 -51
  3. data/lib/concurrent/actress/ad_hoc.rb +6 -0
  4. data/lib/concurrent/actress/context.rb +10 -8
  5. data/lib/concurrent/actress/core.rb +44 -20
  6. data/lib/concurrent/actress/core_delegations.rb +5 -0
  7. data/lib/concurrent/actress/envelope.rb +21 -5
  8. data/lib/concurrent/actress/reference.rb +5 -5
  9. data/lib/concurrent/actress.rb +152 -6
  10. data/lib/concurrent/agent.rb +9 -9
  11. data/lib/concurrent/atomic.rb +46 -0
  12. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +7 -0
  13. data/lib/concurrent/atomic_reference/delegated_update.rb +28 -0
  14. data/lib/concurrent/atomic_reference/direct_update.rb +28 -0
  15. data/lib/concurrent/atomic_reference/jruby.rb +8 -0
  16. data/lib/concurrent/atomic_reference/mutex_atomic.rb +47 -0
  17. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +24 -0
  18. data/lib/concurrent/atomic_reference/rbx.rb +16 -0
  19. data/lib/concurrent/atomic_reference/ruby.rb +16 -0
  20. data/lib/concurrent/atomics.rb +1 -1
  21. data/lib/concurrent/configuration.rb +7 -2
  22. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +0 -1
  23. data/lib/concurrent/executor/{one_by_one.rb → serialized_execution.rb} +21 -8
  24. data/lib/concurrent/executor/timer_set.rb +6 -1
  25. data/lib/concurrent/executors.rb +1 -1
  26. data/lib/concurrent/logging.rb +1 -1
  27. data/lib/concurrent/observable.rb +1 -1
  28. data/lib/concurrent/supervisor.rb +1 -1
  29. data/lib/concurrent/timer_task.rb +0 -36
  30. data/lib/concurrent/version.rb +1 -1
  31. data/lib/concurrent.rb +3 -4
  32. data/lib/concurrent_ruby_ext.so +0 -0
  33. data/lib/extension_helper.rb +9 -0
  34. metadata +19 -152
  35. data/lib/concurrent/actor/actor.rb +0 -270
  36. data/lib/concurrent/actor/postable.rb +0 -102
  37. data/lib/concurrent/actors.rb +0 -2
  38. data/lib/concurrent/actress/doc.md +0 -53
  39. data/lib/concurrent/atomic/atomic.rb +0 -48
  40. data/lib/concurrent/runnable.rb +0 -90
  41. data/lib/concurrent/stoppable.rb +0 -20
  42. data/spec/concurrent/actor/actor_spec.rb +0 -376
  43. data/spec/concurrent/actor/postable_shared.rb +0 -218
  44. data/spec/concurrent/actress_spec.rb +0 -191
  45. data/spec/concurrent/agent_spec.rb +0 -500
  46. data/spec/concurrent/async_spec.rb +0 -352
  47. data/spec/concurrent/atomic/atomic_boolean_spec.rb +0 -172
  48. data/spec/concurrent/atomic/atomic_fixnum_spec.rb +0 -186
  49. data/spec/concurrent/atomic/atomic_spec.rb +0 -133
  50. data/spec/concurrent/atomic/condition_spec.rb +0 -171
  51. data/spec/concurrent/atomic/copy_on_notify_observer_set_spec.rb +0 -10
  52. data/spec/concurrent/atomic/copy_on_write_observer_set_spec.rb +0 -10
  53. data/spec/concurrent/atomic/count_down_latch_spec.rb +0 -151
  54. data/spec/concurrent/atomic/cyclic_barrier_spec.rb +0 -248
  55. data/spec/concurrent/atomic/event_spec.rb +0 -200
  56. data/spec/concurrent/atomic/observer_set_shared.rb +0 -242
  57. data/spec/concurrent/atomic/thread_local_var_spec.rb +0 -113
  58. data/spec/concurrent/channel/buffered_channel_spec.rb +0 -151
  59. data/spec/concurrent/channel/channel_spec.rb +0 -39
  60. data/spec/concurrent/channel/probe_spec.rb +0 -77
  61. data/spec/concurrent/channel/unbuffered_channel_spec.rb +0 -132
  62. data/spec/concurrent/collection/blocking_ring_buffer_spec.rb +0 -149
  63. data/spec/concurrent/collection/priority_queue_spec.rb +0 -317
  64. data/spec/concurrent/collection/ring_buffer_spec.rb +0 -126
  65. data/spec/concurrent/configuration_spec.rb +0 -71
  66. data/spec/concurrent/dataflow_spec.rb +0 -242
  67. data/spec/concurrent/delay_spec.rb +0 -91
  68. data/spec/concurrent/dereferenceable_shared.rb +0 -146
  69. data/spec/concurrent/exchanger_spec.rb +0 -66
  70. data/spec/concurrent/executor/cached_thread_pool_shared.rb +0 -115
  71. data/spec/concurrent/executor/fixed_thread_pool_shared.rb +0 -136
  72. data/spec/concurrent/executor/global_thread_pool_shared.rb +0 -35
  73. data/spec/concurrent/executor/immediate_executor_spec.rb +0 -12
  74. data/spec/concurrent/executor/java_cached_thread_pool_spec.rb +0 -44
  75. data/spec/concurrent/executor/java_fixed_thread_pool_spec.rb +0 -64
  76. data/spec/concurrent/executor/java_single_thread_executor_spec.rb +0 -21
  77. data/spec/concurrent/executor/java_thread_pool_executor_spec.rb +0 -71
  78. data/spec/concurrent/executor/per_thread_executor_spec.rb +0 -57
  79. data/spec/concurrent/executor/ruby_cached_thread_pool_spec.rb +0 -69
  80. data/spec/concurrent/executor/ruby_fixed_thread_pool_spec.rb +0 -39
  81. data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +0 -18
  82. data/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb +0 -171
  83. data/spec/concurrent/executor/safe_task_executor_spec.rb +0 -103
  84. data/spec/concurrent/executor/thread_pool_class_cast_spec.rb +0 -52
  85. data/spec/concurrent/executor/thread_pool_executor_shared.rb +0 -155
  86. data/spec/concurrent/executor/thread_pool_shared.rb +0 -239
  87. data/spec/concurrent/executor/timer_set_spec.rb +0 -183
  88. data/spec/concurrent/future_spec.rb +0 -329
  89. data/spec/concurrent/ivar_spec.rb +0 -215
  90. data/spec/concurrent/mvar_spec.rb +0 -380
  91. data/spec/concurrent/obligation_shared.rb +0 -102
  92. data/spec/concurrent/obligation_spec.rb +0 -282
  93. data/spec/concurrent/observable_shared.rb +0 -177
  94. data/spec/concurrent/observable_spec.rb +0 -56
  95. data/spec/concurrent/options_parser_spec.rb +0 -71
  96. data/spec/concurrent/promise_spec.rb +0 -367
  97. data/spec/concurrent/runnable_shared.rb +0 -68
  98. data/spec/concurrent/runnable_spec.rb +0 -235
  99. data/spec/concurrent/scheduled_task_spec.rb +0 -342
  100. data/spec/concurrent/stoppable_shared.rb +0 -37
  101. data/spec/concurrent/supervisor_spec.rb +0 -1148
  102. data/spec/concurrent/timer_task_spec.rb +0 -258
  103. data/spec/concurrent/tvar_spec.rb +0 -137
  104. data/spec/concurrent/utility/processor_count_spec.rb +0 -20
  105. data/spec/concurrent/utility/timeout_spec.rb +0 -50
  106. data/spec/concurrent/utility/timer_spec.rb +0 -52
  107. data/spec/spec_helper.rb +0 -31
  108. data/spec/support/example_group_extensions.rb +0 -48
  109. data/spec/support/less_than_or_equal_to_matcher.rb +0 -5
  110. /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