concurrent-ruby 0.3.0.pre.1 → 0.3.0.pre.2

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -33
  3. data/lib/concurrent.rb +5 -11
  4. data/lib/concurrent/{channel.rb → actor.rb} +14 -18
  5. data/lib/concurrent/agent.rb +5 -4
  6. data/lib/concurrent/cached_thread_pool.rb +116 -25
  7. data/lib/concurrent/cached_thread_pool/worker.rb +91 -0
  8. data/lib/concurrent/event.rb +13 -14
  9. data/lib/concurrent/event_machine_defer_proxy.rb +0 -1
  10. data/lib/concurrent/executor.rb +0 -1
  11. data/lib/concurrent/fixed_thread_pool.rb +111 -14
  12. data/lib/concurrent/fixed_thread_pool/worker.rb +54 -0
  13. data/lib/concurrent/future.rb +0 -2
  14. data/lib/concurrent/global_thread_pool.rb +21 -3
  15. data/lib/concurrent/goroutine.rb +1 -5
  16. data/lib/concurrent/obligation.rb +0 -19
  17. data/lib/concurrent/promise.rb +2 -5
  18. data/lib/concurrent/runnable.rb +2 -8
  19. data/lib/concurrent/supervisor.rb +9 -4
  20. data/lib/concurrent/utilities.rb +24 -0
  21. data/lib/concurrent/version.rb +1 -1
  22. data/md/agent.md +3 -3
  23. data/md/future.md +4 -4
  24. data/md/promise.md +15 -25
  25. data/md/thread_pool.md +9 -8
  26. data/spec/concurrent/actor_spec.rb +377 -0
  27. data/spec/concurrent/agent_spec.rb +2 -1
  28. data/spec/concurrent/cached_thread_pool_spec.rb +19 -29
  29. data/spec/concurrent/event_machine_defer_proxy_spec.rb +1 -1
  30. data/spec/concurrent/event_spec.rb +1 -1
  31. data/spec/concurrent/executor_spec.rb +0 -8
  32. data/spec/concurrent/fixed_thread_pool_spec.rb +27 -16
  33. data/spec/concurrent/future_spec.rb +0 -13
  34. data/spec/concurrent/global_thread_pool_spec.rb +73 -0
  35. data/spec/concurrent/goroutine_spec.rb +0 -15
  36. data/spec/concurrent/obligation_shared.rb +1 -38
  37. data/spec/concurrent/promise_spec.rb +28 -47
  38. data/spec/concurrent/supervisor_spec.rb +1 -2
  39. data/spec/concurrent/thread_pool_shared.rb +28 -7
  40. data/spec/concurrent/utilities_spec.rb +50 -0
  41. data/spec/spec_helper.rb +0 -1
  42. data/spec/support/functions.rb +17 -0
  43. metadata +12 -27
  44. data/lib/concurrent/functions.rb +0 -105
  45. data/lib/concurrent/null_thread_pool.rb +0 -25
  46. data/lib/concurrent/thread_pool.rb +0 -149
  47. data/md/reactor.md +0 -32
  48. data/spec/concurrent/channel_spec.rb +0 -446
  49. data/spec/concurrent/functions_spec.rb +0 -197
  50. data/spec/concurrent/null_thread_pool_spec.rb +0 -78
@@ -240,9 +240,10 @@ module Concurrent
240
240
 
241
241
  it 'ignores rescuers without a block' do
242
242
  @expected = nil
243
- Promise.new{ raise StandardError }.
243
+ subject.
244
244
  rescue(StandardError).
245
245
  rescue(StandardError){|ex| @expected = ex }
246
+ subject.post{ raise StandardError }
246
247
  sleep(0.1)
247
248
  @expected.should be_a(StandardError)
248
249
  end
@@ -29,39 +29,39 @@ module Concurrent
29
29
  end
30
30
  end
31
31
 
32
- context '#size' do
32
+ context '#length' do
33
33
 
34
34
  it 'returns zero for a new thread pool' do
35
- subject.size.should eq 0
35
+ subject.length.should eq 0
36
36
  end
37
37
 
38
- it 'returns the size of the subject when running' do
38
+ it 'returns the length of the subject when running' do
39
39
  5.times{ sleep(0.1); subject << proc{ sleep(1) } }
40
- subject.size.should eq 5
40
+ subject.length.should eq 5
41
41
  end
42
42
 
43
43
  it 'returns zero once shut down' do
44
44
  subject.shutdown
45
- subject.size.should eq 0
45
+ subject.length.should eq 0
46
46
  end
47
47
  end
48
48
 
49
49
  context 'worker creation and caching' do
50
50
 
51
51
  it 'creates new workers when there are none available' do
52
- subject.size.should eq 0
52
+ subject.length.should eq 0
53
53
  5.times{ sleep(0.1); subject << proc{ sleep } }
54
54
  sleep(1)
55
- subject.size.should eq 5
55
+ subject.length.should eq 5
56
56
  end
57
57
 
58
58
  it 'uses existing idle threads' do
59
59
  5.times{ subject << proc{ sleep(0.1) } }
60
60
  sleep(1)
61
- subject.size.should eq 5
61
+ subject.length.should >= 5
62
62
  3.times{ subject << proc{ sleep } }
63
63
  sleep(0.1)
64
- subject.size.should eq 5
64
+ subject.length.should >= 5
65
65
  end
66
66
 
67
67
  it 'never creates more than :max_threads threads' do
@@ -79,32 +79,22 @@ module Concurrent
79
79
 
80
80
  context 'garbage collection' do
81
81
 
82
- subject{ CachedThreadPool.new(gc_interval: 1, idletime: 0.1) }
82
+ subject{ CachedThreadPool.new(gc_interval: 1, idletime: 1) }
83
83
 
84
84
  it 'removes from pool any thread that has been idle too long' do
85
+ 3.times { subject << proc{ sleep(0.1) } }
86
+ subject.length.should eq 3
87
+ sleep(2)
85
88
  subject << proc{ nil }
86
- subject.size.should eq 1
87
- sleep(1.5)
88
- subject.size.should eq 0
89
+ subject.length.should < 3
89
90
  end
90
91
 
91
92
  it 'removed from pool any dead thread' do
92
- subject << proc{ raise StandardError }
93
- subject.size.should eq 1
94
- sleep(1.5)
95
- subject.size.should eq 0
96
- end
97
- end
98
-
99
- context '#status' do
100
-
101
- it 'returns an empty collection when the pool is empty' do
102
- subject.status.should be_empty
103
- end
104
-
105
- it 'returns one status object for each thread in the pool' do
106
- 3.times{ sleep(0.1); subject << proc{ sleep(0.5) } }
107
- subject.status.length.should eq 3
93
+ 3.times { subject << proc{ sleep(0.1); raise Exception } }
94
+ subject.length.should == 3
95
+ sleep(2)
96
+ subject << proc{ nil }
97
+ subject.length.should < 3
108
98
  end
109
99
  end
110
100
  end
@@ -5,7 +5,7 @@ require 'concurrent/future'
5
5
  require 'concurrent/goroutine'
6
6
  require 'concurrent/promise'
7
7
 
8
- if Functional::PLATFORM.mri?
8
+ if mri?
9
9
 
10
10
  module Concurrent
11
11
 
@@ -83,7 +83,7 @@ module Concurrent
83
83
  subject.reset
84
84
  @expected = false
85
85
  Thread.new{ subject.wait(0.5); @expected = true}
86
- sleep(1)
86
+ sleep(2)
87
87
  @expected.should be_true
88
88
  end
89
89
 
@@ -171,14 +171,6 @@ module Concurrent
171
171
  @expected.should eq args
172
172
  end
173
173
 
174
- it 'supresses exceptions thrown by the execution block' do
175
- lambda {
176
- @subject = Executor.new('Foo', execution_interval: 0.5) { raise StandardError }
177
- @thread = Thread.new { @subject.run }
178
- sleep(1)
179
- }.should_not raise_error
180
- end
181
-
182
174
  it 'kills the worker thread if the timeout is reached' do
183
175
  # the after(:each) block will trigger this expectation
184
176
  Thread.should_receive(:kill).at_least(1).with(any_args())
@@ -16,46 +16,46 @@ module Concurrent
16
16
 
17
17
  context '#initialize' do
18
18
 
19
- it 'raises an exception when the pool size is less than one' do
19
+ it 'raises an exception when the pool length is less than one' do
20
20
  lambda {
21
21
  FixedThreadPool.new(0)
22
22
  }.should raise_error(ArgumentError)
23
23
  end
24
24
 
25
- it 'raises an exception when the pool size is greater than MAX_POOL_SIZE' do
25
+ it 'raises an exception when the pool length is greater than MAX_POOL_SIZE' do
26
26
  lambda {
27
27
  FixedThreadPool.new(FixedThreadPool::MAX_POOL_SIZE + 1)
28
28
  }.should raise_error(ArgumentError)
29
29
  end
30
30
  end
31
31
 
32
- context '#size' do
32
+ context '#length' do
33
33
 
34
- let(:pool_size) { 3 }
35
- subject { FixedThreadPool.new(pool_size) }
34
+ let(:pool_length) { 3 }
35
+ subject { FixedThreadPool.new(pool_length) }
36
36
 
37
37
  it 'returns zero on start' do
38
38
  subject.shutdown
39
- subject.size.should eq 0
39
+ subject.length.should eq 0
40
40
  end
41
41
 
42
- it 'returns the size of the pool when running' do
43
- pool_size.times do |i|
42
+ it 'returns the length of the pool when running' do
43
+ pool_length.times do |i|
44
44
  subject.post{ sleep }
45
45
  sleep(0.1)
46
- subject.size.should eq i+1
46
+ subject.length.should eq pool_length
47
47
  end
48
48
  end
49
49
 
50
50
  it 'returns zero while shutting down' do
51
51
  subject.post{ sleep(1) }
52
52
  subject.shutdown
53
- subject.size.should eq 0
53
+ subject.length.should eq 0
54
54
  end
55
55
 
56
56
  it 'returns zero once shut down' do
57
57
  subject.shutdown
58
- subject.size.should eq 0
58
+ subject.length.should eq 0
59
59
  end
60
60
  end
61
61
 
@@ -63,10 +63,10 @@ module Concurrent
63
63
 
64
64
  it 'creates new workers when there are none available' do
65
65
  pool = FixedThreadPool.new(5)
66
- pool.size.should eq 0
66
+ pool.length.should eq 0
67
67
  5.times{ sleep(0.1); pool << proc{ sleep } }
68
68
  sleep(0.1)
69
- pool.size.should eq 5
69
+ pool.length.should eq 5
70
70
  pool.kill
71
71
  end
72
72
 
@@ -77,16 +77,27 @@ module Concurrent
77
77
  pool.length.should eq 5
78
78
  pool.kill
79
79
  end
80
+
81
+ it 'creates new threads when garbage collecting' do
82
+ pool = FixedThreadPool.new(5)
83
+ pool.length.should == 0
84
+ pool << proc { sleep }
85
+ sleep(0.1)
86
+ pool.length.should == 5
87
+ pool.instance_variable_set(:@max_threads, 25)
88
+ pool << proc { sleep }
89
+ pool.length.should == 25
90
+ end
80
91
  end
81
92
 
82
93
  context 'exception handling' do
83
94
 
84
95
  it 'restarts threads that experience exception' do
96
+ pending
85
97
  pool = FixedThreadPool.new(5)
86
98
  5.times{ pool << proc{ raise StandardError } }
87
- sleep(5)
88
- pool.size.should eq 5
89
- pool.status.should_not include(nil)
99
+ sleep(1)
100
+ pool.length.should eq 5
90
101
  end
91
102
  end
92
103
  end
@@ -30,17 +30,6 @@ module Concurrent
30
30
 
31
31
  it_should_behave_like Concurrent::Obligation
32
32
 
33
- context 'behavior' do
34
-
35
- it 'implements :future behavior' do
36
- lambda {
37
- Future.new{ nil }
38
- }.should_not raise_error
39
-
40
- Future.new{ nil }.behaves_as?(:future).should be_true
41
- end
42
- end
43
-
44
33
  context '#initialize' do
45
34
 
46
35
  it 'spawns a new thread when a block is given' do
@@ -151,7 +140,6 @@ module Concurrent
151
140
  sleep(0.1)
152
141
  future.value.should == 42
153
142
  future.add_observer(observer)
154
- observer.value.should be_nil
155
143
  sleep(0.1)
156
144
  observer.value.should == 42
157
145
  end
@@ -161,7 +149,6 @@ module Concurrent
161
149
  sleep(0.1)
162
150
  future.reason.should be_a(StandardError)
163
151
  future.add_observer(observer)
164
- observer.value.should be_nil
165
152
  sleep(0.1)
166
153
  observer.reason.should be_a(StandardError)
167
154
  end
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'concurrent/goroutine'
2
3
  require_relative 'uses_global_thread_pool_shared'
3
4
 
4
5
  module Concurrent
@@ -8,4 +9,76 @@ module Concurrent
8
9
  let!(:thread_pool_user){ Class.new{ include UsesGlobalThreadPool } }
9
10
  it_should_behave_like Concurrent::UsesGlobalThreadPool
10
11
  end
12
+
13
+ describe NullThreadPool do
14
+
15
+ subject { NullThreadPool.new }
16
+
17
+ after(:all) do
18
+ $GLOBAL_THREAD_POOL = FixedThreadPool.new(1)
19
+ end
20
+
21
+ context '#post' do
22
+
23
+ it 'creates a new thread for a call without arguments' do
24
+ thread = Thread.new{ nil }
25
+ Thread.should_receive(:new).with(no_args()).and_return(thread)
26
+ $GLOBAL_THREAD_POOL.should_not_receive(:post).with(any_args())
27
+ subject.post{ nil }
28
+ end
29
+
30
+ it 'executes a call without arguments' do
31
+ @expected = false
32
+ subject.post{ @expected = true }
33
+ sleep(0.1)
34
+ @expected.should be_true
35
+ end
36
+
37
+ it 'creates a new thread for a call with arguments' do
38
+ thread = Thread.new{ nil }
39
+ Thread.should_receive(:new).with(1,2,3).and_return(thread)
40
+ $GLOBAL_THREAD_POOL.should_not_receive(:post).with(any_args())
41
+ subject.post(1,2,3){ nil }
42
+ end
43
+
44
+ it 'executes a call with one argument' do
45
+ @expected = 0
46
+ subject.post(1){|one| @expected = one }
47
+ sleep(0.1)
48
+ @expected.should == 1
49
+ end
50
+
51
+ it 'executes a call with multiple arguments' do
52
+ @expected = nil
53
+ subject.post(1,2,3,4,5){|*args| @expected = args }
54
+ sleep(0.1)
55
+ @expected.should eq [1,2,3,4,5]
56
+ end
57
+
58
+ it 'aliases #<<' do
59
+ thread = Thread.new{ nil }
60
+ Thread.should_receive(:new).with(no_args()).and_return(thread)
61
+ $GLOBAL_THREAD_POOL.should_not_receive(:post).with(any_args())
62
+ subject << proc{ nil }
63
+ end
64
+ end
65
+
66
+ context 'operation' do
67
+
68
+ context 'goroutine' do
69
+
70
+ it 'gets a new thread' do
71
+ $GLOBAL_THREAD_POOL = subject
72
+
73
+ t = Thread.new{ nil }
74
+
75
+ Thread.should_receive(:new).with(no_args()).and_return(t)
76
+ go{ nil }
77
+
78
+ Thread.should_receive(:new).with(1,2,3).and_return(t)
79
+ go(1,2,3){ nil }
80
+ end
81
+ end
82
+ end
83
+ end
11
84
  end
@@ -48,20 +48,5 @@ module Concurrent
48
48
  sleep(0.1)
49
49
  @expected.should eq [1,2,3]
50
50
  end
51
-
52
- it 'accepts an alternate thread pool as the first argument' do
53
- pool = Concurrent::FixedThreadPool.new(2)
54
- pool.should_receive(:post).with(no_args())
55
- go(pool){ sleep(0.1) }
56
- sleep(0.2)
57
- end
58
-
59
- it 'passes all other arguments to the block when a thread pool is given' do
60
- @expected = nil
61
- pool = Concurrent::FixedThreadPool.new(2)
62
- go(pool, 1, 2, 3){|a, b, c| @expected = [c, b, a] }
63
- sleep(0.1)
64
- @expected.should eq [3, 2, 1]
65
- end
66
51
  end
67
52
  end
@@ -38,7 +38,7 @@ share_examples_for Concurrent::Obligation do
38
38
  end
39
39
 
40
40
  it 'returns immediately when timeout is zero' do
41
- Timeout.should_not_receive(:timeout).with(any_args())
41
+ Concurrent.should_not_receive(:timeout).with(any_args())
42
42
  f = pending_subject
43
43
  f.value(0).should be_nil
44
44
  f.should be_pending
@@ -87,41 +87,4 @@ share_examples_for Concurrent::Obligation do
87
87
  rejected_subject.reason.to_s.should =~ /#{rejected_reason}/
88
88
  end
89
89
  end
90
-
91
- context 'Kernel aliases' do
92
-
93
- it 'aliases Kernel#deref for #deref' do
94
- deref(fulfilled_subject).should eq fulfilled_value
95
- deref(fulfilled_subject, 0).should eq fulfilled_value
96
- end
97
-
98
- it 'aliases Kernel#pending? for #pending?' do
99
- #NOTE: was structured like others but was incorrectly failing
100
- # on fulfilled_subject
101
- fulfilled_subject.should_receive(:pending?).once
102
- pending?(fulfilled_subject)
103
- pending_subject.should_receive(:pending?).once
104
- pending?(pending_subject)
105
- rejected_subject.should_receive(:pending?).once
106
- pending?(rejected_subject)
107
- end
108
-
109
- it 'aliases Kernel#fulfilled? for #fulfilled?' do
110
- fulfilled?(fulfilled_subject).should be_true
111
- fulfilled?(pending_subject).should be_false
112
- fulfilled?(rejected_subject).should be_false
113
- end
114
-
115
- it 'aliases Kernel#realized? for #realized?' do
116
- realized?(fulfilled_subject).should be_true
117
- realized?(pending_subject).should be_false
118
- realized?(rejected_subject).should be_false
119
- end
120
-
121
- it 'aliases Kernel#rejected? for #rejected?' do
122
- rejected?(rejected_subject).should be_true
123
- rejected?(fulfilled_subject).should be_false
124
- rejected?(pending_subject).should be_false
125
- end
126
- end
127
90
  end
@@ -31,25 +31,6 @@ module Concurrent
31
31
 
32
32
  it_should_behave_like Concurrent::Obligation
33
33
 
34
- context 'behavior' do
35
-
36
- it 'implements :promise behavior' do
37
- lambda {
38
- Promise.new{ nil }
39
- }.should_not raise_error
40
-
41
- Promise.new{ nil }.behaves_as?(:promise).should be_true
42
- end
43
-
44
- it 'implements :future behavior' do
45
- lambda {
46
- Promise.new{ nil }
47
- }.should_not raise_error
48
-
49
- Promise.new{ nil }.behaves_as?(:future).should be_true
50
- end
51
- end
52
-
53
34
  context '#then' do
54
35
 
55
36
  it 'returns a new Promise when :pending' do
@@ -154,8 +135,8 @@ module Concurrent
154
135
  context 'rejection' do
155
136
 
156
137
  it 'sets the promise reason the error object on exception' do
157
- p = Promise.new{ raise StandardError.new('Boom!') }
158
- sleep(0.1)
138
+ p = Promise.new{ sleep(0.1); raise StandardError.new('Boom!') }
139
+ sleep(0.2)
159
140
  p.reason.should be_a(StandardError)
160
141
  p.reason.should.to_s =~ /Boom!/
161
142
  end
@@ -167,36 +148,36 @@ module Concurrent
167
148
  end
168
149
 
169
150
  it 'recursively rejects all children' do
170
- p = Promise.new{ raise StandardError.new('Boom!') }
151
+ p = Promise.new{ sleep(0.1); raise StandardError.new('Boom!') }
171
152
  promises = 10.times.collect{ p.then{ true } }
172
- sleep(0.1)
153
+ sleep(0.5)
173
154
  10.times.each{|i| promises[i].should be_rejected }
174
155
  end
175
156
 
176
157
  it 'skips processing rejected promises' do
177
- p = Promise.new{ raise StandardError.new('Boom!') }
158
+ p = Promise.new{ sleep(0.1); raise StandardError.new('Boom!') }
178
159
  promises = 3.times.collect{ p.then{ true } }
179
- sleep(0.1)
160
+ sleep(0.5)
180
161
  promises.each{|p| p.value.should_not be_true }
181
162
  end
182
163
 
183
164
  it 'calls the first exception block with a matching class' do
184
165
  @expected = nil
185
- Promise.new{ raise StandardError }.
166
+ Promise.new{ sleep(0.1); raise StandardError }.
186
167
  rescue(StandardError){|ex| @expected = 1 }.
187
168
  rescue(StandardError){|ex| @expected = 2 }.
188
169
  rescue(StandardError){|ex| @expected = 3 }
189
- sleep(0.1)
170
+ sleep(0.2)
190
171
  @expected.should eq 1
191
172
  end
192
173
 
193
174
  it 'matches all with a rescue with no class given' do
194
175
  @expected = nil
195
- Promise.new{ raise NoMethodError }.
176
+ Promise.new{ sleep(0.1); raise NoMethodError }.
196
177
  rescue(LoadError){|ex| @expected = 1 }.
197
178
  rescue{|ex| @expected = 2 }.
198
179
  rescue(StandardError){|ex| @expected = 3 }
199
- sleep(0.1)
180
+ sleep(0.2)
200
181
  @expected.should eq 2
201
182
  end
202
183
 
@@ -204,84 +185,84 @@ module Concurrent
204
185
  Promise.thread_pool = CachedThreadPool.new
205
186
 
206
187
  @expected = nil
207
- Promise.new{ raise ArgumentError }.
188
+ Promise.new{ sleep(0.1); raise ArgumentError }.
208
189
  rescue(ArgumentError){|ex| @expected = 1 }.
209
190
  rescue(LoadError){|ex| @expected = 2 }.
210
191
  rescue(StandardError){|ex| @expected = 3 }
211
- sleep(0.1)
192
+ sleep(0.2)
212
193
  @expected.should eq 1
213
194
 
214
195
  @expected = nil
215
- Promise.new{ raise LoadError }.
196
+ Promise.new{ sleep(0.1); raise LoadError }.
216
197
  rescue(ArgumentError){|ex| @expected = 1 }.
217
198
  rescue(LoadError){|ex| @expected = 2 }.
218
199
  rescue(StandardError){|ex| @expected = 3 }
219
- sleep(0.1)
200
+ sleep(0.2)
220
201
  @expected.should eq 2
221
202
 
222
203
  @expected = nil
223
- Promise.new{ raise StandardError }.
204
+ Promise.new{ sleep(0.1); raise StandardError }.
224
205
  rescue(ArgumentError){|ex| @expected = 1 }.
225
206
  rescue(LoadError){|ex| @expected = 2 }.
226
207
  rescue(StandardError){|ex| @expected = 3 }
227
- sleep(0.1)
208
+ sleep(0.2)
228
209
  @expected.should eq 3
229
210
  end
230
211
 
231
212
  it 'passes the exception object to the matched block' do
232
213
  @expected = nil
233
- Promise.new{ raise StandardError }.
214
+ Promise.new{ sleep(0.1); raise StandardError }.
234
215
  rescue(ArgumentError){|ex| @expected = ex }.
235
216
  rescue(LoadError){|ex| @expected = ex }.
236
217
  rescue(StandardError){|ex| @expected = ex }
237
- sleep(0.1)
218
+ sleep(0.2)
238
219
  @expected.should be_a(StandardError)
239
220
  end
240
221
 
241
222
  it 'ignores rescuers without a block' do
242
223
  @expected = nil
243
- Promise.new{ raise StandardError }.
224
+ Promise.new{ sleep(0.1); raise StandardError }.
244
225
  rescue(StandardError).
245
226
  rescue(StandardError){|ex| @expected = ex }
246
- sleep(0.1)
227
+ sleep(0.2)
247
228
  @expected.should be_a(StandardError)
248
229
  end
249
230
 
250
231
  it 'supresses the exception if no rescue matches' do
251
232
  lambda {
252
- Promise.new{ raise StandardError }.
233
+ Promise.new{ sleep(0.1); raise StandardError }.
253
234
  rescue(ArgumentError){|ex| @expected = ex }.
254
235
  rescue(NotImplementedError){|ex| @expected = ex }.
255
236
  rescue(NoMethodError){|ex| @expected = ex }
256
- sleep(0.1)
237
+ sleep(0.2)
257
238
  }.should_not raise_error
258
239
  end
259
240
 
260
241
  it 'supresses exceptions thrown from rescue handlers' do
261
242
  lambda {
262
- Promise.new{ raise ArgumentError }.
243
+ Promise.new{ sleep(0.1); raise ArgumentError }.
263
244
  rescue(StandardError){ raise StandardError }
264
- sleep(0.1)
245
+ sleep(0.2)
265
246
  }.should_not raise_error
266
247
  end
267
248
 
268
249
  it 'calls matching rescue handlers on all children' do
269
250
  @expected = []
270
- Promise.new{ raise StandardError }.
251
+ Promise.new{ sleep(0.1); raise StandardError }.
271
252
  then{ sleep(0.1) }.rescue{ @expected << 'Boom!' }.
272
253
  then{ sleep(0.1) }.rescue{ @expected << 'Boom!' }.
273
254
  then{ sleep(0.1) }.rescue{ @expected << 'Boom!' }.
274
255
  then{ sleep(0.1) }.rescue{ @expected << 'Boom!' }.
275
256
  then{ sleep(0.1) }.rescue{ @expected << 'Boom!' }
276
- sleep(0.1)
257
+ sleep(1)
277
258
 
278
259
  @expected.length.should eq 5
279
260
  end
280
261
 
281
262
  it 'matches a rescue handler added after rejection' do
282
263
  @expected = false
283
- p = Promise.new{ raise StandardError }
284
- sleep(0.1)
264
+ p = Promise.new{ sleep(0.1); raise StandardError }
265
+ sleep(0.2)
285
266
  p.rescue(StandardError){ @expected = true }
286
267
  @expected.should be_true
287
268
  end