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.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/concurrent.rb +3 -4
  4. data/lib/concurrent/atomic.rb +46 -0
  5. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +7 -0
  6. data/lib/concurrent/atomic_reference/delegated_update.rb +28 -0
  7. data/lib/concurrent/atomic_reference/direct_update.rb +28 -0
  8. data/lib/concurrent/atomic_reference/jruby.rb +8 -0
  9. data/lib/concurrent/atomic_reference/mutex_atomic.rb +47 -0
  10. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +24 -0
  11. data/lib/concurrent/atomic_reference/rbx.rb +16 -0
  12. data/lib/concurrent/atomic_reference/ruby.rb +16 -0
  13. data/lib/concurrent/atomics.rb +1 -1
  14. data/lib/concurrent/configuration.rb +1 -1
  15. data/lib/concurrent/supervisor.rb +1 -1
  16. data/lib/concurrent/timer_task.rb +0 -36
  17. data/lib/concurrent/version.rb +1 -1
  18. data/lib/concurrent_ruby_ext.so +0 -0
  19. data/lib/extension_helper.rb +9 -0
  20. metadata +16 -148
  21. data/lib/concurrent/actor/actor.rb +0 -270
  22. data/lib/concurrent/actor/postable.rb +0 -102
  23. data/lib/concurrent/actors.rb +0 -2
  24. data/lib/concurrent/atomic/atomic.rb +0 -48
  25. data/lib/concurrent/runnable.rb +0 -90
  26. data/lib/concurrent/stoppable.rb +0 -20
  27. data/spec/concurrent/actor/actor_spec.rb +0 -376
  28. data/spec/concurrent/actor/postable_shared.rb +0 -218
  29. data/spec/concurrent/actress_spec.rb +0 -211
  30. data/spec/concurrent/agent_spec.rb +0 -500
  31. data/spec/concurrent/async_spec.rb +0 -352
  32. data/spec/concurrent/atomic/atomic_boolean_spec.rb +0 -172
  33. data/spec/concurrent/atomic/atomic_fixnum_spec.rb +0 -186
  34. data/spec/concurrent/atomic/atomic_spec.rb +0 -133
  35. data/spec/concurrent/atomic/condition_spec.rb +0 -171
  36. data/spec/concurrent/atomic/copy_on_notify_observer_set_spec.rb +0 -10
  37. data/spec/concurrent/atomic/copy_on_write_observer_set_spec.rb +0 -10
  38. data/spec/concurrent/atomic/count_down_latch_spec.rb +0 -151
  39. data/spec/concurrent/atomic/cyclic_barrier_spec.rb +0 -248
  40. data/spec/concurrent/atomic/event_spec.rb +0 -200
  41. data/spec/concurrent/atomic/observer_set_shared.rb +0 -242
  42. data/spec/concurrent/atomic/thread_local_var_spec.rb +0 -113
  43. data/spec/concurrent/channel/buffered_channel_spec.rb +0 -151
  44. data/spec/concurrent/channel/channel_spec.rb +0 -39
  45. data/spec/concurrent/channel/probe_spec.rb +0 -77
  46. data/spec/concurrent/channel/unbuffered_channel_spec.rb +0 -132
  47. data/spec/concurrent/collection/blocking_ring_buffer_spec.rb +0 -149
  48. data/spec/concurrent/collection/priority_queue_spec.rb +0 -317
  49. data/spec/concurrent/collection/ring_buffer_spec.rb +0 -126
  50. data/spec/concurrent/configuration_spec.rb +0 -69
  51. data/spec/concurrent/dataflow_spec.rb +0 -242
  52. data/spec/concurrent/delay_spec.rb +0 -91
  53. data/spec/concurrent/dereferenceable_shared.rb +0 -146
  54. data/spec/concurrent/exchanger_spec.rb +0 -66
  55. data/spec/concurrent/executor/cached_thread_pool_shared.rb +0 -115
  56. data/spec/concurrent/executor/fixed_thread_pool_shared.rb +0 -136
  57. data/spec/concurrent/executor/global_thread_pool_shared.rb +0 -35
  58. data/spec/concurrent/executor/immediate_executor_spec.rb +0 -12
  59. data/spec/concurrent/executor/java_cached_thread_pool_spec.rb +0 -44
  60. data/spec/concurrent/executor/java_fixed_thread_pool_spec.rb +0 -64
  61. data/spec/concurrent/executor/java_single_thread_executor_spec.rb +0 -21
  62. data/spec/concurrent/executor/java_thread_pool_executor_spec.rb +0 -71
  63. data/spec/concurrent/executor/per_thread_executor_spec.rb +0 -57
  64. data/spec/concurrent/executor/ruby_cached_thread_pool_spec.rb +0 -69
  65. data/spec/concurrent/executor/ruby_fixed_thread_pool_spec.rb +0 -39
  66. data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +0 -18
  67. data/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb +0 -171
  68. data/spec/concurrent/executor/safe_task_executor_spec.rb +0 -103
  69. data/spec/concurrent/executor/thread_pool_class_cast_spec.rb +0 -52
  70. data/spec/concurrent/executor/thread_pool_executor_shared.rb +0 -155
  71. data/spec/concurrent/executor/thread_pool_shared.rb +0 -269
  72. data/spec/concurrent/executor/timer_set_spec.rb +0 -183
  73. data/spec/concurrent/future_spec.rb +0 -329
  74. data/spec/concurrent/ivar_spec.rb +0 -215
  75. data/spec/concurrent/mvar_spec.rb +0 -380
  76. data/spec/concurrent/obligation_shared.rb +0 -102
  77. data/spec/concurrent/obligation_spec.rb +0 -282
  78. data/spec/concurrent/observable_shared.rb +0 -177
  79. data/spec/concurrent/observable_spec.rb +0 -56
  80. data/spec/concurrent/options_parser_spec.rb +0 -71
  81. data/spec/concurrent/promise_spec.rb +0 -367
  82. data/spec/concurrent/runnable_shared.rb +0 -68
  83. data/spec/concurrent/runnable_spec.rb +0 -235
  84. data/spec/concurrent/scheduled_task_spec.rb +0 -340
  85. data/spec/concurrent/stoppable_shared.rb +0 -37
  86. data/spec/concurrent/supervisor_spec.rb +0 -1149
  87. data/spec/concurrent/timer_task_spec.rb +0 -256
  88. data/spec/concurrent/tvar_spec.rb +0 -137
  89. data/spec/concurrent/utility/processor_count_spec.rb +0 -20
  90. data/spec/concurrent/utility/timeout_spec.rb +0 -50
  91. data/spec/concurrent/utility/timer_spec.rb +0 -52
  92. data/spec/spec_helper.rb +0 -41
  93. data/spec/support/example_group_extensions.rb +0 -52
  94. data/spec/support/less_than_or_equal_to_matcher.rb +0 -5
@@ -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
@@ -1,340 +0,0 @@
1
- require 'spec_helper'
2
- require 'timecop'
3
- require_relative 'dereferenceable_shared'
4
- require_relative 'obligation_shared'
5
- require_relative 'observable_shared'
6
-
7
- module Concurrent
8
-
9
- describe ScheduledTask do
10
- context 'behavior' do
11
-
12
- # obligation
13
-
14
- let!(:fulfilled_value) { 10 }
15
- let!(:rejected_reason) { StandardError.new('mojo jojo') }
16
-
17
- let(:pending_subject) do
18
- ScheduledTask.new(1){ fulfilled_value }.execute
19
- end
20
-
21
- let(:fulfilled_subject) do
22
- latch = Concurrent::CountDownLatch.new(1)
23
- task = ScheduledTask.new(0.1){ latch.count_down; fulfilled_value }.execute
24
- latch.wait(1)
25
- sleep(0.1)
26
- task
27
- end
28
-
29
- let(:rejected_subject) do
30
- latch = Concurrent::CountDownLatch.new(1)
31
- task = ScheduledTask.new(0.1){ latch.count_down; raise rejected_reason }.execute
32
- latch.wait(1)
33
- sleep(0.1)
34
- task
35
- end
36
-
37
- it_should_behave_like :obligation
38
-
39
- # dereferenceable
40
-
41
- def dereferenceable_subject(value, opts = {})
42
- ScheduledTask.execute(0.1, opts){ value }.tap{ sleep(0.2) }
43
- end
44
-
45
- def dereferenceable_observable(opts = {})
46
- ScheduledTask.new(0.1, opts){ 'value' }
47
- end
48
-
49
- def execute_dereferenceable(subject)
50
- subject.execute
51
- sleep(0.2)
52
- end
53
-
54
- it_should_behave_like :dereferenceable
55
-
56
- # observable
57
-
58
- subject{ ScheduledTask.new(0.1){ nil } }
59
-
60
- def trigger_observable(observable)
61
- observable.execute
62
- sleep(0.2)
63
- end
64
-
65
- it_should_behave_like :observable
66
- end
67
-
68
- context '#initialize' do
69
-
70
- it 'accepts a number of seconds (from now) as the schedule time' do
71
- Timecop.freeze do
72
- now = Time.now
73
- task = ScheduledTask.new(60){ nil }.execute
74
- task.schedule_time.to_i.should eq now.to_i + 60
75
- end
76
- end
77
-
78
- it 'accepts a time object as the schedule time' do
79
- schedule = Time.now + (60*10)
80
- task = ScheduledTask.new(schedule){ nil }.execute
81
- task.schedule_time.should eq schedule
82
- end
83
-
84
- it 'raises an exception when seconds is less than zero' do
85
- expect {
86
- ScheduledTask.new(-1){ nil }
87
- }.to raise_error(ArgumentError)
88
- end
89
-
90
- it 'raises an exception when schedule time is in the past' do
91
- expect {
92
- ScheduledTask.new(Time.now - 60){ nil }
93
- }.to raise_error(ArgumentError)
94
- end
95
-
96
- it 'raises an exception when no block given' do
97
- expect {
98
- ScheduledTask.new(1)
99
- }.to raise_error(ArgumentError)
100
- end
101
-
102
- it 'sets the initial state to :unscheduled' do
103
- task = ScheduledTask.new(1){ nil }
104
- task.should be_unscheduled
105
- end
106
-
107
- it 'sets the #schedule_time to nil prior to execution' do
108
- task = ScheduledTask.new(1){ nil }
109
- task.schedule_time.should be_nil
110
- end
111
- end
112
-
113
- context 'instance #execute' do
114
-
115
- it 'does nothing unless the state is :unscheduled' do
116
- Thread.should_not_receive(:new).with(any_args)
117
- task = ScheduledTask.new(1){ nil }
118
- task.instance_variable_set(:@state, :pending)
119
- task.execute
120
- task.instance_variable_set(:@state, :rejected)
121
- task.execute
122
- task.instance_variable_set(:@state, :fulfilled)
123
- task.execute
124
- end
125
-
126
- it 'calculates the #schedule_time on execution' do
127
- Timecop.freeze do
128
- now = Time.now
129
- task = ScheduledTask.new(5){ nil }
130
- Timecop.travel(10)
131
- task.execute
132
- task.schedule_time.to_i.should eq now.to_i + 15
133
- end
134
- end
135
-
136
- it 'raises an exception if expected schedule time is in the past' do
137
- Timecop.freeze do
138
- schedule = Time.now + (10)
139
- task = ScheduledTask.new(schedule){ nil }
140
- Timecop.travel(60)
141
- expect {
142
- task.execute
143
- }.to raise_error(ArgumentError)
144
- end
145
- end
146
-
147
- it 'sets the sate to :pending' do
148
- task = ScheduledTask.new(1){ nil }
149
- task.execute
150
- task.should be_pending
151
- end
152
-
153
- it 'returns self' do
154
- task = ScheduledTask.new(1){ nil }
155
- task.execute.should eq task
156
- end
157
- end
158
-
159
- context 'class #execute' do
160
-
161
- it 'creates a new ScheduledTask' do
162
- task = ScheduledTask.execute(1){ nil }
163
- task.should be_a(ScheduledTask)
164
- end
165
-
166
- it 'passes the block to the new ScheduledTask' do
167
- @expected = false
168
- task = ScheduledTask.execute(0.1){ @expected = true }
169
- task.value(1)
170
- @expected.should be_true
171
- end
172
-
173
- it 'calls #execute on the new ScheduledTask' do
174
- task = ScheduledTask.new(0.1){ nil }
175
- ScheduledTask.stub(:new).with(any_args).and_return(task)
176
- task.should_receive(:execute).with(no_args)
177
- ScheduledTask.execute(0.1){ nil }
178
- end
179
- end
180
-
181
- context '#cancel' do
182
-
183
- it 'returns false if the task has already been performed' do
184
- task = ScheduledTask.new(0.1){ 42 }.execute
185
- task.value(1)
186
- task.cancel.should be_false
187
- end
188
-
189
- it 'returns false if the task is already in progress' do
190
- latch = Concurrent::CountDownLatch.new(1)
191
- task = ScheduledTask.new(0.1) {
192
- latch.count_down
193
- sleep(1)
194
- }.execute
195
- latch.wait(1)
196
- task.cancel.should be_false
197
- end
198
-
199
- it 'cancels the task if it has not yet scheduled' do
200
- latch = Concurrent::CountDownLatch.new(1)
201
- task = ScheduledTask.new(0.1){ latch.count_down }
202
- task.cancel
203
- task.execute
204
- latch.wait(0.3).should be_false
205
- end
206
-
207
-
208
- it 'cancels the task if it has not yet started' do
209
- latch = Concurrent::CountDownLatch.new(1)
210
- task = ScheduledTask.new(0.3){ latch.count_down }.execute
211
- sleep(0.1)
212
- task.cancel
213
- latch.wait(0.5).should be_false
214
- end
215
-
216
- it 'returns true on success' do
217
- task = ScheduledTask.new(10){ nil }.execute
218
- sleep(0.1)
219
- task.cancel.should be_true
220
- end
221
-
222
- it 'sets the state to :cancelled when cancelled' do
223
- task = ScheduledTask.new(10){ 42 }.execute
224
- sleep(0.1)
225
- task.cancel
226
- task.should be_cancelled
227
- end
228
- end
229
-
230
- context 'execution' do
231
-
232
- it 'sets the state to :in_progress when the task is running' do
233
- latch = Concurrent::CountDownLatch.new(1)
234
- task = ScheduledTask.new(0.1) {
235
- latch.count_down
236
- sleep(1)
237
- }.execute
238
- latch.wait(1)
239
- task.should be_in_progress
240
- end
241
- end
242
-
243
- context 'observation' do
244
-
245
- let(:clazz) do
246
- Class.new do
247
- attr_reader :value
248
- attr_reader :reason
249
- attr_reader :count
250
- attr_reader :latch
251
- def initialize
252
- @latch = Concurrent::CountDownLatch.new(1)
253
- end
254
- def update(time, value, reason)
255
- @count = @count.to_i + 1
256
- @value = value
257
- @reason = reason
258
- @latch.count_down
259
- end
260
- end
261
- end
262
-
263
- let(:observer) { clazz.new }
264
-
265
- it 'returns true for an observer added while :unscheduled' do
266
- task = ScheduledTask.new(0.1){ 42 }
267
- task.add_observer(observer).should be_true
268
- end
269
-
270
- it 'returns true for an observer added while :pending' do
271
- task = ScheduledTask.new(0.1){ 42 }.execute
272
- task.add_observer(observer).should be_true
273
- end
274
-
275
- it 'returns true for an observer added while :in_progress' do
276
- task = ScheduledTask.new(0.1){ sleep(1); 42 }.execute
277
- sleep(0.2)
278
- task.add_observer(observer).should be_true
279
- end
280
-
281
- it 'returns false for an observer added once :cancelled' do
282
- task = ScheduledTask.new(1){ 42 }
283
- task.cancel
284
- task.add_observer(observer).should be_false
285
- end
286
-
287
- it 'returns false for an observer added once :fulfilled' do
288
- task = ScheduledTask.new(0.1){ 42 }.execute
289
- task.value(1)
290
- task.add_observer(observer).should be_false
291
- end
292
-
293
- it 'returns false for an observer added once :rejected' do
294
- task = ScheduledTask.new(0.1){ raise StandardError }.execute
295
- task.value(0.2)
296
- task.add_observer(observer).should be_false
297
- end
298
-
299
- it 'notifies all observers on fulfillment' do
300
- task = ScheduledTask.new(0.1){ 42 }.execute
301
- task.add_observer(observer)
302
- observer.latch.wait(1)
303
- observer.value.should == 42
304
- observer.reason.should be_nil
305
- end
306
-
307
- it 'notifies all observers on rejection' do
308
- task = ScheduledTask.new(0.1){ raise StandardError }.execute
309
- task.add_observer(observer)
310
- observer.latch.wait(1)
311
- observer.value.should be_nil
312
- observer.reason.should be_a(StandardError)
313
- end
314
-
315
- it 'does not notify an observer added after fulfillment' do
316
- observer.should_not_receive(:update).with(any_args)
317
- task = ScheduledTask.new(0.1){ 42 }.execute
318
- task.value(1)
319
- task.add_observer(observer)
320
- sleep(0.1)
321
- end
322
-
323
- it 'does not notify an observer added after rejection' do
324
- observer.should_not_receive(:update).with(any_args)
325
- task = ScheduledTask.new(0.1){ raise StandardError }.execute
326
- task.value(1)
327
- task.add_observer(observer)
328
- sleep(0.1)
329
- end
330
-
331
- it 'does not notify an observer added after cancellation' do
332
- observer.should_not_receive(:update).with(any_args)
333
- task = ScheduledTask.new(0.1){ 42 }.execute
334
- task.cancel
335
- task.add_observer(observer)
336
- task.value(1)
337
- end
338
- end
339
- end
340
- end