concurrent-ruby 0.6.0.pre.2 → 0.6.0

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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -8
  3. data/lib/concurrent.rb +2 -0
  4. data/lib/concurrent/actor/actor.rb +3 -3
  5. data/lib/concurrent/actor/postable.rb +1 -1
  6. data/lib/concurrent/actors.rb +0 -3
  7. data/lib/concurrent/actress.rb +75 -0
  8. data/lib/concurrent/actress/ad_hoc.rb +14 -0
  9. data/lib/concurrent/actress/context.rb +96 -0
  10. data/lib/concurrent/actress/core.rb +204 -0
  11. data/lib/concurrent/actress/core_delegations.rb +37 -0
  12. data/lib/concurrent/actress/doc.md +53 -0
  13. data/lib/concurrent/actress/envelope.rb +25 -0
  14. data/lib/concurrent/actress/errors.rb +14 -0
  15. data/lib/concurrent/actress/reference.rb +64 -0
  16. data/lib/concurrent/actress/type_check.rb +48 -0
  17. data/lib/concurrent/agent.rb +20 -11
  18. data/lib/concurrent/async.rb +54 -25
  19. data/lib/concurrent/atomic/atomic.rb +48 -0
  20. data/lib/concurrent/atomic/atomic_boolean.rb +13 -13
  21. data/lib/concurrent/atomic/atomic_fixnum.rb +9 -17
  22. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +7 -4
  23. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +16 -14
  24. data/lib/concurrent/atomic/event.rb +11 -16
  25. data/lib/concurrent/atomics.rb +1 -0
  26. data/lib/concurrent/channel/channel.rb +4 -2
  27. data/lib/concurrent/collection/blocking_ring_buffer.rb +1 -1
  28. data/lib/concurrent/configuration.rb +59 -47
  29. data/lib/concurrent/delay.rb +28 -12
  30. data/lib/concurrent/dereferenceable.rb +6 -6
  31. data/lib/concurrent/errors.rb +30 -0
  32. data/lib/concurrent/executor/executor.rb +11 -4
  33. data/lib/concurrent/executor/immediate_executor.rb +1 -0
  34. data/lib/concurrent/executor/java_thread_pool_executor.rb +4 -0
  35. data/lib/concurrent/executor/one_by_one.rb +24 -12
  36. data/lib/concurrent/executor/per_thread_executor.rb +1 -0
  37. data/lib/concurrent/executor/ruby_single_thread_executor.rb +2 -1
  38. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +7 -2
  39. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +3 -0
  40. data/lib/concurrent/executor/timer_set.rb +1 -1
  41. data/lib/concurrent/future.rb +0 -2
  42. data/lib/concurrent/ivar.rb +31 -6
  43. data/lib/concurrent/logging.rb +17 -0
  44. data/lib/concurrent/mvar.rb +45 -0
  45. data/lib/concurrent/obligation.rb +61 -20
  46. data/lib/concurrent/observable.rb +7 -0
  47. data/lib/concurrent/promise.rb +1 -0
  48. data/lib/concurrent/runnable.rb +2 -2
  49. data/lib/concurrent/supervisor.rb +1 -2
  50. data/lib/concurrent/timer_task.rb +17 -13
  51. data/lib/concurrent/tvar.rb +113 -73
  52. data/lib/concurrent/utility/processor_count.rb +141 -116
  53. data/lib/concurrent/utility/timeout.rb +4 -5
  54. data/lib/concurrent/version.rb +1 -1
  55. data/spec/concurrent/actor/postable_shared.rb +1 -1
  56. data/spec/concurrent/actress_spec.rb +191 -0
  57. data/spec/concurrent/async_spec.rb +35 -3
  58. data/spec/concurrent/atomic/atomic_boolean_spec.rb +1 -1
  59. data/spec/concurrent/atomic/atomic_fixnum_spec.rb +1 -1
  60. data/spec/concurrent/atomic/atomic_spec.rb +133 -0
  61. data/spec/concurrent/atomic/count_down_latch_spec.rb +1 -1
  62. data/spec/concurrent/collection/priority_queue_spec.rb +1 -1
  63. data/spec/concurrent/configuration_spec.rb +5 -2
  64. data/spec/concurrent/delay_spec.rb +14 -0
  65. data/spec/concurrent/exchanger_spec.rb +4 -9
  66. data/spec/concurrent/executor/java_cached_thread_pool_spec.rb +1 -1
  67. data/spec/concurrent/executor/java_fixed_thread_pool_spec.rb +1 -1
  68. data/spec/concurrent/executor/java_single_thread_executor_spec.rb +1 -1
  69. data/spec/concurrent/executor/java_thread_pool_executor_spec.rb +1 -1
  70. data/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb +4 -4
  71. data/spec/concurrent/ivar_spec.rb +2 -2
  72. data/spec/concurrent/obligation_spec.rb +113 -24
  73. data/spec/concurrent/observable_shared.rb +4 -0
  74. data/spec/concurrent/observable_spec.rb +8 -3
  75. data/spec/concurrent/runnable_spec.rb +2 -2
  76. data/spec/concurrent/scheduled_task_spec.rb +1 -0
  77. data/spec/concurrent/supervisor_spec.rb +26 -11
  78. data/spec/concurrent/timer_task_spec.rb +36 -35
  79. data/spec/concurrent/tvar_spec.rb +1 -1
  80. data/spec/concurrent/utility/timer_spec.rb +8 -8
  81. data/spec/spec_helper.rb +8 -18
  82. data/spec/support/example_group_extensions.rb +48 -0
  83. metadata +23 -16
  84. data/lib/concurrent/actor/actor_context.rb +0 -77
  85. data/lib/concurrent/actor/actor_ref.rb +0 -67
  86. data/lib/concurrent/actor/simple_actor_ref.rb +0 -94
  87. data/lib/concurrent_ruby_ext.bundle +0 -0
  88. data/spec/concurrent/actor/actor_context_spec.rb +0 -29
  89. data/spec/concurrent/actor/actor_ref_shared.rb +0 -263
  90. data/spec/concurrent/actor/simple_actor_ref_spec.rb +0 -135
  91. data/spec/support/functions.rb +0 -25
@@ -10,6 +10,9 @@ module Concurrent
10
10
  Class.new do
11
11
  include Concurrent::Async
12
12
  attr_accessor :accessor
13
+ def initialize
14
+ init_mutex
15
+ end
13
16
  def echo(msg)
14
17
  msg
15
18
  end
@@ -103,7 +106,7 @@ module Concurrent
103
106
  context 'executor' do
104
107
 
105
108
  it 'returns the default executor when #executor= has never been called' do
106
- Concurrent.configuration.should_receive(:global_task_pool).
109
+ Concurrent.configuration.should_receive(:global_operation_pool).
107
110
  and_return(ImmediateExecutor.new)
108
111
  subject = async_class.new
109
112
  subject.async.echo(:foo)
@@ -117,10 +120,10 @@ module Concurrent
117
120
  subject.async.echo(:foo)
118
121
  end
119
122
 
120
- it 'raises an exception if #executor= is called multiple times' do
123
+ it 'raises an exception if #executor= is called after initialization complete' do
121
124
  executor = ImmediateExecutor.new
122
125
  subject = async_class.new
123
- subject.executor = executor
126
+ subject.async.echo(:foo)
124
127
  expect {
125
128
  subject.executor = executor
126
129
  }.to raise_error(ArgumentError)
@@ -303,6 +306,7 @@ module Concurrent
303
306
  object = Class.new {
304
307
  include Concurrent::Async
305
308
  attr_reader :bucket
309
+ def initialize() init_mutex; end
306
310
  def gather(seconds, first, *rest)
307
311
  sleep(seconds)
308
312
  (@bucket ||= []).concat([first])
@@ -315,6 +319,34 @@ module Concurrent
315
319
  object.await.gather(0, :c, :d)
316
320
  object.bucket.should eq [:a, :b, :c, :d]
317
321
  end
322
+
323
+ context 'raises an InitializationError' do
324
+
325
+ let(:async_class) do
326
+ Class.new do
327
+ include Concurrent::Async
328
+ def echo(msg) msg; end
329
+ end
330
+ end
331
+
332
+ it 'when #async is called before #init_mutex' do
333
+ expect {
334
+ async_class.new.async.echo(:foo)
335
+ }.to raise_error(Concurrent::InitializationError)
336
+ end
337
+
338
+ it 'when #await is called before #init_mutex' do
339
+ expect {
340
+ async_class.new.async.echo(:foo)
341
+ }.to raise_error(Concurrent::InitializationError)
342
+ end
343
+
344
+ it 'when #executor= is called before #init_mutex' do
345
+ expect {
346
+ async_class.new.executor = Concurrent::ImmediateExecutor.new
347
+ }.to raise_error(Concurrent::InitializationError)
348
+ end
349
+ end
318
350
  end
319
351
  end
320
352
  end
@@ -151,7 +151,7 @@ module Concurrent
151
151
  end
152
152
  end
153
153
 
154
- if jruby?
154
+ if TestHelpers.jruby?
155
155
 
156
156
  describe JavaAtomicBoolean do
157
157
  it_should_behave_like :atomic_boolean
@@ -165,7 +165,7 @@ module Concurrent
165
165
  end
166
166
  end
167
167
 
168
- if jruby?
168
+ if TestHelpers.jruby?
169
169
 
170
170
  describe JavaAtomicFixnum do
171
171
  it_should_behave_like :atomic_fixnum
@@ -0,0 +1,133 @@
1
+ require 'spec_helper'
2
+
3
+ share_examples_for :atomic do
4
+
5
+ context 'construction' do
6
+
7
+ it 'sets the initial value' do
8
+ described_class.new(:foo).value.should eq :foo
9
+ end
10
+
11
+ it 'defaults the initial value to nil' do
12
+ described_class.new.value.should eq nil
13
+ end
14
+ end
15
+
16
+ context '#value' do
17
+
18
+ it 'returns the current value' do
19
+ counter = described_class.new(:foo)
20
+ counter.value.should eq :foo
21
+ end
22
+ end
23
+
24
+ context '#value=' do
25
+
26
+ it 'sets the #value to the given object' do
27
+ atomic = described_class.new(:foo)
28
+ atomic.value = :bar
29
+ atomic.value.should eq :bar
30
+ end
31
+
32
+ it 'returns the new value' do
33
+ atomic = described_class.new(:foo)
34
+ (atomic.value = :bar).should eq :bar
35
+ end
36
+ end
37
+
38
+ context '#modify' do
39
+
40
+ it 'yields the current value' do
41
+ atomic = described_class.new(:foo)
42
+ current = []
43
+ atomic.modify { |value| current << value }
44
+ current.should eq [:foo]
45
+ end
46
+
47
+ it 'stores the value returned from the yield' do
48
+ atomic = described_class.new(:foo)
49
+ atomic.modify { |value| :bar }
50
+ atomic.value.should eq :bar
51
+ end
52
+
53
+ it 'returns the new value' do
54
+ atomic = described_class.new(:foo)
55
+ atomic.modify{ |value| :bar }.should eq :bar
56
+ end
57
+ end
58
+
59
+ context '#compare_and_set' do
60
+
61
+ it 'returns false if the value is not found' do
62
+ described_class.new(:foo).compare_and_set(:bar, :foo).should eq false
63
+ end
64
+
65
+ it 'returns true if the value is found' do
66
+ described_class.new(:foo).compare_and_set(:foo, :bar).should eq true
67
+ end
68
+
69
+ it 'sets if the value is found' do
70
+ f = described_class.new(:foo)
71
+ f.compare_and_set(:foo, :bar)
72
+ f.value.should eq :bar
73
+ end
74
+
75
+ it 'does not set if the value is not found' do
76
+ f = described_class.new(:foo)
77
+ f.compare_and_set(:bar, :baz)
78
+ f.value.should eq :foo
79
+ end
80
+ end
81
+ end
82
+
83
+ module Concurrent
84
+
85
+ describe MutexAtomic do
86
+
87
+ it_should_behave_like :atomic
88
+
89
+ specify 'construction is synchronized' do
90
+ mutex = double('mutex')
91
+ Mutex.should_receive(:new).once.with(no_args).and_return(mutex)
92
+ described_class.new
93
+ end
94
+
95
+ specify 'value is synchronized' do
96
+ mutex = double('mutex')
97
+ Mutex.stub(:new).with(no_args).and_return(mutex)
98
+ mutex.should_receive(:lock)
99
+ mutex.should_receive(:unlock)
100
+ described_class.new.value
101
+ end
102
+
103
+ specify 'value= is synchronized' do
104
+ mutex = double('mutex')
105
+ Mutex.stub(:new).with(no_args).and_return(mutex)
106
+ mutex.should_receive(:lock)
107
+ mutex.should_receive(:unlock)
108
+ described_class.new.value = 10
109
+ end
110
+
111
+ specify 'modify is synchronized' do
112
+ mutex = double('mutex')
113
+ Mutex.stub(:new).with(no_args).and_return(mutex)
114
+ mutex.should_receive(:lock)
115
+ mutex.should_receive(:unlock)
116
+ described_class.new(:foo).modify { |value| value }
117
+ end
118
+
119
+ specify 'compare_and_set is synchronized' do
120
+ mutex = double('mutex')
121
+ Mutex.stub(:new).with(no_args).and_return(mutex)
122
+ mutex.should_receive(:lock)
123
+ mutex.should_receive(:unlock)
124
+ described_class.new(14).compare_and_set(14, 2)
125
+ end
126
+ end
127
+
128
+ describe Atomic do
129
+ it 'inherits from MutexAtomic' do
130
+ Atomic.ancestors.should include(MutexAtomic)
131
+ end
132
+ end
133
+ end
@@ -129,7 +129,7 @@ module Concurrent
129
129
  end
130
130
  end
131
131
 
132
- if jruby?
132
+ if TestHelpers.jruby?
133
133
 
134
134
  describe JavaCountDownLatch do
135
135
 
@@ -295,7 +295,7 @@ module Concurrent
295
295
  it_should_behave_like :priority_queue
296
296
  end
297
297
 
298
- if jruby?
298
+ if TestHelpers.jruby?
299
299
 
300
300
  describe JavaPriorityQueue do
301
301
 
@@ -3,6 +3,7 @@ require 'spec_helper'
3
3
  module Concurrent
4
4
 
5
5
  describe Configuration do
6
+ with_full_reset
6
7
 
7
8
  it 'creates a global timer pool' do
8
9
  Concurrent.configuration.global_timer_set.should_not be_nil
@@ -24,11 +25,12 @@ module Concurrent
24
25
  Concurrent.configuration.global_task_pool.should eq executor
25
26
  end
26
27
 
27
- specify 'writer raises an exception if called twice' do
28
+ specify 'writer raises an exception if called after initialization' do
28
29
  executor = ImmediateExecutor.new
29
30
  Concurrent.configure do |config|
30
31
  config.global_task_pool = executor
31
32
  end
33
+ Concurrent.configuration.global_task_pool
32
34
  expect {
33
35
  Concurrent.configure do |config|
34
36
  config.global_task_pool = executor
@@ -52,11 +54,12 @@ module Concurrent
52
54
  Concurrent.configuration.global_operation_pool.should eq executor
53
55
  end
54
56
 
55
- specify 'writer raises an exception if called twice' do
57
+ specify 'writer raises an exception if called after initialization' do
56
58
  executor = ImmediateExecutor.new
57
59
  Concurrent.configure do |config|
58
60
  config.global_operation_pool = executor
59
61
  end
62
+ Concurrent.configuration.global_operation_pool
60
63
  expect {
61
64
  Concurrent.configure do |config|
62
65
  config.global_operation_pool = executor
@@ -53,6 +53,20 @@ module Concurrent
53
53
  end
54
54
  end
55
55
 
56
+
57
+ context '#reconfigure' do
58
+ it 'returns value of block used in reconfiguration' do
59
+ Delay.new { nil }.tap { |d| d.reconfigure { true } }.value.should be_true
60
+ end
61
+
62
+ it 'returns false when process completed?' do
63
+ d = Delay.new { 1 }
64
+ d.reconfigure { 2 }.should be_true
65
+ d.value.should be 2
66
+ d.reconfigure { 3 }.should be_false
67
+ end
68
+ end
69
+
56
70
  context '#value' do
57
71
 
58
72
  let(:task){ proc{ nil } }
@@ -50,20 +50,15 @@ module Concurrent
50
50
  context 'with timeout' do
51
51
  it 'should block until timeout' do
52
52
 
53
- latch = Concurrent::CountDownLatch.new(1)
54
53
  value = 0
55
54
  start = Time.now.to_f
56
55
 
57
- t = Thread.new do
58
- value = exchanger.exchange(2, 0.2)
59
- latch.count_down
56
+ future = Concurrent::Future.execute do
57
+ exchanger.exchange(2, 0.2)
60
58
  end
61
-
62
- latch.wait(1)
63
-
59
+
60
+ future.value.should be_nil
64
61
  (Time.now.to_f - start).should >= 0.2
65
- t.status.should be_false
66
- value.should be_nil
67
62
  end
68
63
  end
69
64
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- if jruby?
3
+ if Concurrent::TestHelpers.jruby?
4
4
 
5
5
  require_relative 'cached_thread_pool_shared'
6
6
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- if jruby?
3
+ if Concurrent::TestHelpers.jruby?
4
4
 
5
5
  require_relative 'fixed_thread_pool_shared'
6
6
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- if jruby?
3
+ if Concurrent::TestHelpers.jruby?
4
4
 
5
5
  require_relative 'thread_pool_shared'
6
6
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- if jruby?
3
+ if Concurrent::TestHelpers.jruby?
4
4
 
5
5
  require_relative 'thread_pool_executor_shared'
6
6
 
@@ -119,20 +119,20 @@ module Concurrent
119
119
 
120
120
  specify 'a #post task is never executed when the queue is at capacity' do
121
121
  executed = Concurrent::AtomicFixnum.new(0)
122
- 100.times do
122
+ 1000.times do
123
123
  subject.post{ executed.increment }
124
124
  end
125
125
  sleep(0.1)
126
- executed.value.should < 100
126
+ executed.value.should < 1000
127
127
  end
128
128
 
129
129
  specify 'a #<< task is never executed when the queue is at capacity' do
130
130
  executed = Concurrent::AtomicFixnum.new(0)
131
- 100.times do
131
+ 1000.times do
132
132
  subject << proc { executed.increment }
133
133
  end
134
134
  sleep(0.1)
135
- executed.value.should < 100
135
+ executed.value.should < 1000
136
136
  end
137
137
  end
138
138
 
@@ -108,7 +108,7 @@ module Concurrent
108
108
  it 'raises an exception if set more than once' do
109
109
  i = IVar.new
110
110
  i.set(14)
111
- expect {i.set(2)}.to raise_error(MultipleAssignmentError)
111
+ expect {i.set(2)}.to raise_error(Concurrent::MultipleAssignmentError)
112
112
  i.value.should eq 14
113
113
  end
114
114
 
@@ -135,7 +135,7 @@ module Concurrent
135
135
  it 'raises an exception if set more than once' do
136
136
  i = IVar.new
137
137
  i.fail
138
- expect {i.fail}.to raise_error(MultipleAssignmentError)
138
+ expect {i.fail}.to raise_error(Concurrent::MultipleAssignmentError)
139
139
  i.value.should be_nil
140
140
  end
141
141
 
@@ -30,24 +30,28 @@ module Concurrent
30
30
  obligation.should be_incomplete
31
31
  end
32
32
 
33
- describe '#value' do
33
+ methods = [:value, :value!, :no_error!]
34
+ methods.each do |method|
35
+ describe "##{method}" do
34
36
 
35
- it 'should return immediately if timeout is zero' do
36
- obligation.value(0).should be_nil
37
- end
37
+ it 'should return immediately if timeout is zero' do
38
+ obligation.send(method, 0).should(method == :no_error! ? eq(obligation) : be_nil)
39
+ end
38
40
 
39
- it 'should block on the event if timeout is not set' do
40
- obligation.stub(:event).and_return(event)
41
- event.should_receive(:wait).with(nil)
41
+ it 'should block on the event if timeout is not set' do
42
+ obligation.stub(:event).and_return(event)
43
+ event.should_receive(:wait).with(nil)
42
44
 
43
- obligation.value
44
- end
45
+ obligation.send method
46
+ end
47
+
48
+ it 'should block on the event if timeout is not zero' do
49
+ obligation.stub(:event).and_return(event)
50
+ event.should_receive(:wait).with(5)
45
51
 
46
- it 'should block on the event if timeout is not zero' do
47
- obligation.stub(:event).and_return(event)
48
- event.should_receive(:wait).with(5)
52
+ obligation.send(method, 5)
53
+ end
49
54
 
50
- obligation.value(5)
51
55
  end
52
56
  end
53
57
  end
@@ -98,6 +102,45 @@ module Concurrent
98
102
 
99
103
  end
100
104
 
105
+ describe '#value!' do
106
+
107
+ it 'should return immediately if timeout is zero' do
108
+ obligation.value!(0).should eq 42
109
+ end
110
+
111
+ it 'should return immediately if timeout is not set' do
112
+ event.should_not_receive(:wait)
113
+
114
+ obligation.value!.should eq 42
115
+ end
116
+
117
+ it 'should return immediately if timeout is not zero' do
118
+ event.should_not_receive(:wait)
119
+
120
+ obligation.value!(5).should eq 42
121
+ end
122
+
123
+ end
124
+
125
+ describe '#no_error!' do
126
+
127
+ it 'should return immediately if timeout is zero' do
128
+ obligation.no_error!(0).should eq obligation
129
+ end
130
+
131
+ it 'should return immediately if timeout is not set' do
132
+ event.should_not_receive(:wait)
133
+
134
+ obligation.no_error!.should eq obligation
135
+ end
136
+
137
+ it 'should return immediately if timeout is not zero' do
138
+ event.should_not_receive(:wait)
139
+
140
+ obligation.no_error!(5).should eq obligation
141
+ end
142
+
143
+ end
101
144
 
102
145
  end
103
146
 
@@ -115,26 +158,72 @@ module Concurrent
115
158
  it 'should be not incomplete' do
116
159
  obligation.should_not be_incomplete
117
160
  end
118
- end
119
161
 
120
- describe '#value' do
121
162
 
122
- it 'should return immediately if timeout is zero' do
123
- event.should_not_receive(:wait)
163
+ describe '#value' do
164
+
165
+ it 'should return immediately if timeout is zero' do
166
+ event.should_not_receive(:wait)
167
+
168
+ obligation.value(0).should be_nil
169
+ end
170
+
171
+ it 'should return immediately if timeout is not set' do
172
+ event.should_not_receive(:wait)
173
+
174
+ obligation.value.should be_nil
175
+ end
176
+
177
+ it 'should return immediately if timeout is not zero' do
178
+ event.should_not_receive(:wait)
179
+
180
+ obligation.value(5).should be_nil
181
+ end
124
182
 
125
- obligation.value(0).should be_nil
126
183
  end
127
184
 
128
- it 'should return immediately if timeout is not set' do
129
- event.should_not_receive(:wait)
185
+ describe '#value!' do
186
+
187
+ it 'should return immediately if timeout is zero' do
188
+ event.should_not_receive(:wait)
189
+
190
+ -> { obligation.value!(0) }.should raise_error
191
+ end
192
+
193
+ it 'should return immediately if timeout is not set' do
194
+ event.should_not_receive(:wait)
195
+
196
+ -> { obligation.value! }.should raise_error
197
+ end
198
+
199
+ it 'should return immediately if timeout is not zero' do
200
+ event.should_not_receive(:wait)
201
+
202
+ -> { obligation.value!(5) }.should raise_error
203
+ end
130
204
 
131
- obligation.value.should be_nil
132
205
  end
133
206
 
134
- it 'should return immediately if timeout is not zero' do
135
- event.should_not_receive(:wait)
207
+ describe '#no_error!' do
208
+
209
+ it 'should return immediately if timeout is zero' do
210
+ event.should_not_receive(:wait)
211
+
212
+ -> { obligation.no_error!(0) }.should raise_error
213
+ end
214
+
215
+ it 'should return immediately if timeout is not set' do
216
+ event.should_not_receive(:wait)
217
+
218
+ -> { obligation.no_error! }.should raise_error
219
+ end
220
+
221
+ it 'should return immediately if timeout is not zero' do
222
+ event.should_not_receive(:wait)
223
+
224
+ -> { obligation.no_error!(5) }.should raise_error
225
+ end
136
226
 
137
- obligation.value(5).should be_nil
138
227
  end
139
228
 
140
229
  end