concurrent-ruby 0.6.1 → 0.7.0.rc0

Sign up to get free protection for your applications and to get access to all the features.
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