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,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