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

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