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