deferred 0.5.3
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.
- data/.gitignore +5 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/MIT_LICENSE +19 -0
- data/README.markdown +215 -0
- data/Rakefile +1 -0
- data/deferred.gemspec +23 -0
- data/examples/threadpool_job_subtask.rb +203 -0
- data/lib/deferred.rb +32 -0
- data/lib/deferred/accessors.rb +170 -0
- data/lib/deferred/default.rb +36 -0
- data/lib/deferred/extensions.rb +22 -0
- data/lib/deferred/instance_methods.rb +82 -0
- data/lib/deferred/threadpool_job.rb +63 -0
- data/lib/deferred/version.rb +3 -0
- data/spec/deferred/accessors_spec.rb +95 -0
- data/spec/deferred/instance_methods_spec.rb +297 -0
- data/spec/deferred/threadpool_job_spec.rb +172 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/support/accessorized.rb +8 -0
- data/spec/support/bollocks_error.rb +2 -0
- data/spec/support/deferred_state_xtn.rb +22 -0
- metadata +166 -0
@@ -0,0 +1,297 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Deferred::InstanceMethods' do
|
4
|
+
# test Deferred::Default, as it mixes this in
|
5
|
+
|
6
|
+
before do
|
7
|
+
@dd = Deferred::Default.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it %[should set a callback and return self] do
|
11
|
+
cb_called = nil
|
12
|
+
|
13
|
+
rval = @dd.callback { cb_called = true }
|
14
|
+
rval.should == @dd
|
15
|
+
|
16
|
+
@dd.succeed
|
17
|
+
cb_called.should be_true
|
18
|
+
end
|
19
|
+
|
20
|
+
it %[should set an errback and return self] do
|
21
|
+
eb_called = nil
|
22
|
+
|
23
|
+
rval = @dd.errback { eb_called = true }
|
24
|
+
rval.should == @dd
|
25
|
+
|
26
|
+
@dd.fail
|
27
|
+
eb_called.should be_true
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'ensure_that' do
|
31
|
+
before do
|
32
|
+
@block_called = false
|
33
|
+
@rval = @dd.ensure_that { @block_called = true }
|
34
|
+
end
|
35
|
+
|
36
|
+
it %[should return self] do
|
37
|
+
@rval.should == @dd
|
38
|
+
end
|
39
|
+
|
40
|
+
it %[should set a callback] do
|
41
|
+
@dd.succeed
|
42
|
+
@block_called.should be_true
|
43
|
+
end
|
44
|
+
|
45
|
+
it %[should set an errback] do
|
46
|
+
@dd.fail
|
47
|
+
@block_called.should be_true
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe 'errback_on_exception' do
|
52
|
+
it %[should fire the errback with the exception instance as an argument] do
|
53
|
+
@dd.errback do |exc|
|
54
|
+
exc.should be_instance_of(RuntimeError)
|
55
|
+
end
|
56
|
+
|
57
|
+
@dd.errback_on_exception do
|
58
|
+
raise "Oh noes!"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it %[should do the right thing when errback is a proc] do
|
63
|
+
eb = proc do |exc|
|
64
|
+
exc.should be_instance_of(RuntimeError)
|
65
|
+
end
|
66
|
+
|
67
|
+
@dd.errback(&eb)
|
68
|
+
|
69
|
+
@dd.errback_on_exception do
|
70
|
+
raise "Oh noes!"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it %[should do the right thing when errback is a lambda] do
|
75
|
+
eb = lambda do |exc|
|
76
|
+
exc.should be_instance_of(RuntimeError)
|
77
|
+
end
|
78
|
+
|
79
|
+
@dd.errback(&eb)
|
80
|
+
|
81
|
+
@dd.errback_on_exception do
|
82
|
+
raise "Oh noes!"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'timeout' do
|
88
|
+
include EventedSpec::SpecHelper
|
89
|
+
default_timeout 1.0
|
90
|
+
|
91
|
+
class TestTimeoutError < StandardError; end
|
92
|
+
class OtherTestTimeoutError < StandardError; end
|
93
|
+
|
94
|
+
it %[should fire the errback with no arguments if an exception_klass is not given] do
|
95
|
+
@dd.errback do |*a|
|
96
|
+
a.should be_empty
|
97
|
+
done
|
98
|
+
end
|
99
|
+
|
100
|
+
em do
|
101
|
+
@dd.timeout(0.01)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it %[should fire the errback with an instance of the given klass if given] do
|
106
|
+
@dd.errback do |*a|
|
107
|
+
a.length.should == 1
|
108
|
+
exc = a.first
|
109
|
+
exc.should be_kind_of(TestTimeoutError)
|
110
|
+
exc.backtrace.should_not be_nil
|
111
|
+
|
112
|
+
done
|
113
|
+
end
|
114
|
+
|
115
|
+
em do
|
116
|
+
@dd.timeout(0.01, TestTimeoutError)
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
# make sure this is compatible with the rest of EM::Deferrable
|
122
|
+
it %[should not fire the timeout if cancel_timeout is called] do
|
123
|
+
@dd.errback { raise "This should not have been called" }
|
124
|
+
@dd.callback { done }
|
125
|
+
|
126
|
+
em do
|
127
|
+
@dd.timeout(0.3) # set the timeout
|
128
|
+
|
129
|
+
delayed(0.1) { @dd.cancel_timeout }
|
130
|
+
delayed(0.4) { @dd.succeed }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
it %[should reset the timeout if timeout is called a second time] do
|
135
|
+
@dd.errback do |e|
|
136
|
+
e.should be_kind_of(OtherTestTimeoutError)
|
137
|
+
done
|
138
|
+
end
|
139
|
+
|
140
|
+
em do
|
141
|
+
@dd.timeout(0.2, TestTimeoutError) # set the first timeout
|
142
|
+
|
143
|
+
# cancel the first timeout before it can fire, raise a different error
|
144
|
+
delayed(0.1) { @dd.timeout(0, OtherTestTimeoutError) }
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end # describe timeout
|
148
|
+
|
149
|
+
describe 'chain_to' do
|
150
|
+
before do
|
151
|
+
@one = Deferred::Default.new
|
152
|
+
@two = Deferred::Default.new
|
153
|
+
end
|
154
|
+
|
155
|
+
it %[should call the second's callbacks with the results of the first] do
|
156
|
+
@two.chain_to(@one)
|
157
|
+
|
158
|
+
callback_called = nil
|
159
|
+
|
160
|
+
@two.callback do |*args|
|
161
|
+
args.should_not be_empty
|
162
|
+
args.first.should == 'boogers'
|
163
|
+
callback_called = true
|
164
|
+
end
|
165
|
+
|
166
|
+
@one.succeed('boogers')
|
167
|
+
callback_called.should be_true
|
168
|
+
end
|
169
|
+
|
170
|
+
it %[should call the second's errbacks with the fail of the first] do
|
171
|
+
@two.chain_to(@one)
|
172
|
+
|
173
|
+
errback_called = nil
|
174
|
+
|
175
|
+
@two.errback do |*args|
|
176
|
+
args.should_not be_empty
|
177
|
+
args.first.should == 'boogers'
|
178
|
+
errback_called = true
|
179
|
+
end
|
180
|
+
|
181
|
+
@one.fail('boogers')
|
182
|
+
errback_called.should be_true
|
183
|
+
end
|
184
|
+
|
185
|
+
it %[should return self] do
|
186
|
+
@two.chain_to(@one).should == @two
|
187
|
+
end
|
188
|
+
|
189
|
+
it %[should not add the errback if :ignore_errors is true] do
|
190
|
+
@two.chain_to(@one, :ignore_errors => true)
|
191
|
+
|
192
|
+
one_errback_called = two_errback_called = false
|
193
|
+
|
194
|
+
@two.callback do |*a|
|
195
|
+
callback_called = true
|
196
|
+
end
|
197
|
+
|
198
|
+
@two.errback do |*args|
|
199
|
+
args.should_not be_empty
|
200
|
+
args.first.should == 'boogers'
|
201
|
+
two_errback_called = true
|
202
|
+
end
|
203
|
+
|
204
|
+
@one.errback do |*a|
|
205
|
+
one_errback_called = true
|
206
|
+
end
|
207
|
+
|
208
|
+
@one.fail('boogers')
|
209
|
+
one_errback_called.should be_true
|
210
|
+
two_errback_called.should be_false
|
211
|
+
end
|
212
|
+
|
213
|
+
it %[should add the errback if :only_errors is true] do
|
214
|
+
@two.chain_to(@one, :only_errors => true)
|
215
|
+
|
216
|
+
one_errback_called = two_errback_called = false
|
217
|
+
|
218
|
+
@one.errback do |*a|
|
219
|
+
one_errback_called = true
|
220
|
+
end
|
221
|
+
|
222
|
+
@two.errback do |*args|
|
223
|
+
args.should_not be_empty
|
224
|
+
args.first.should == 'boogers'
|
225
|
+
two_errback_called = true
|
226
|
+
end
|
227
|
+
|
228
|
+
@one.fail('boogers')
|
229
|
+
|
230
|
+
one_errback_called.should be_true
|
231
|
+
two_errback_called.should be_true
|
232
|
+
end
|
233
|
+
|
234
|
+
it %[should not add the callback if :only_errors is true] do
|
235
|
+
@two.chain_to(@one, :only_errors => true)
|
236
|
+
|
237
|
+
one_errback_called = two_errback_called =
|
238
|
+
one_callback_called = two_callback_called = false
|
239
|
+
|
240
|
+
@one.errback { |*| one_errback_called = true }
|
241
|
+
@one.callback { |*| one_callback_called = true }
|
242
|
+
@two.errback { |*| two_errback_called = true }
|
243
|
+
@two.callback { |*| two_callback_called = true }
|
244
|
+
|
245
|
+
@one.succeed('boogers')
|
246
|
+
|
247
|
+
one_callback_called.should be_true
|
248
|
+
two_callback_called.should be_false
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
describe 'chain_err' do
|
253
|
+
before do
|
254
|
+
@one = Deferred::Default.new
|
255
|
+
@two = Deferred::Default.new
|
256
|
+
end
|
257
|
+
|
258
|
+
it %[should chain the errbacks] do
|
259
|
+
@two.chain_to(@one, :only_errors => true)
|
260
|
+
|
261
|
+
one_errback_called = two_errback_called = false
|
262
|
+
|
263
|
+
@one.errback do |*a|
|
264
|
+
one_errback_called = true
|
265
|
+
end
|
266
|
+
|
267
|
+
@two.errback do |*args|
|
268
|
+
args.should_not be_empty
|
269
|
+
args.first.should == 'boogers'
|
270
|
+
two_errback_called = true
|
271
|
+
end
|
272
|
+
|
273
|
+
@one.fail('boogers')
|
274
|
+
|
275
|
+
one_errback_called.should be_true
|
276
|
+
two_errback_called.should be_true
|
277
|
+
end
|
278
|
+
|
279
|
+
it %[should not add the callback if :only_errors is true] do
|
280
|
+
@two.chain_to(@one, :only_errors => true)
|
281
|
+
|
282
|
+
one_errback_called = two_errback_called =
|
283
|
+
one_callback_called = two_callback_called = false
|
284
|
+
|
285
|
+
@one.errback { |*| one_errback_called = true }
|
286
|
+
@one.callback { |*| one_callback_called = true }
|
287
|
+
@two.errback { |*| two_errback_called = true }
|
288
|
+
@two.callback { |*| two_callback_called = true }
|
289
|
+
|
290
|
+
@one.succeed('boogers')
|
291
|
+
|
292
|
+
one_callback_called.should be_true
|
293
|
+
two_callback_called.should be_false
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Deferred::ThreadpoolJob do
|
4
|
+
|
5
|
+
describe 'defer!' do
|
6
|
+
include EventedSpec::SpecHelper
|
7
|
+
default_timeout 3.0
|
8
|
+
|
9
|
+
it %[should barf with an OnRunBlockNotRegisteredError if on_run was not called] do
|
10
|
+
tpj = Deferred::DefaultThreadpoolJob.new
|
11
|
+
lambda { tpj.defer! }.should raise_error(Deferred::OnRunBlockNotRegisteredError)
|
12
|
+
end
|
13
|
+
|
14
|
+
it %[should use a block passed to new as the on_run_block] do
|
15
|
+
orb = lambda { $stderr.puts "hooray!" }
|
16
|
+
tpj = Deferred::DefaultThreadpoolJob.new(&orb)
|
17
|
+
|
18
|
+
tpj.on_run_block.should == orb
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'success' do
|
22
|
+
before do
|
23
|
+
@rval = %w[foo bar]
|
24
|
+
@tpj = Deferred::DefaultThreadpoolJob.new { @rval }
|
25
|
+
end
|
26
|
+
|
27
|
+
it %[should call the callback if the block succeeds] do
|
28
|
+
cb_called = false
|
29
|
+
|
30
|
+
@tpj.callback do |result|
|
31
|
+
cb_called = true
|
32
|
+
result.should == @rval
|
33
|
+
done
|
34
|
+
end
|
35
|
+
|
36
|
+
em do
|
37
|
+
@tpj.defer!
|
38
|
+
end
|
39
|
+
|
40
|
+
cb_called.should be_true
|
41
|
+
end
|
42
|
+
|
43
|
+
it %[should fire the before_run callbacks before deferring the job] do
|
44
|
+
cb_ary = []
|
45
|
+
|
46
|
+
@tpj.before_run do
|
47
|
+
cb_ary << :before_run
|
48
|
+
end
|
49
|
+
|
50
|
+
@tpj.callback do |*a|
|
51
|
+
cb_ary << :after_run
|
52
|
+
end
|
53
|
+
|
54
|
+
@tpj.ensure_that do
|
55
|
+
cb_ary.should == [:before_run, :after_run]
|
56
|
+
done
|
57
|
+
end
|
58
|
+
|
59
|
+
em do
|
60
|
+
@tpj.defer!
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'failure' do
|
66
|
+
before do
|
67
|
+
@tpj = Deferred::DefaultThreadpoolJob.new { raise BollocksError }
|
68
|
+
end
|
69
|
+
|
70
|
+
it %[should fire the errbacks in the chain] do
|
71
|
+
@tpj.errback do |exc|
|
72
|
+
exc.should be_instance_of(BollocksError)
|
73
|
+
done
|
74
|
+
end
|
75
|
+
|
76
|
+
em do
|
77
|
+
@tpj.defer!
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end # describe 'failure'
|
81
|
+
|
82
|
+
describe 'on_run returns a ThreadpoolJob' do
|
83
|
+
describe 'success' do
|
84
|
+
before do
|
85
|
+
@rval = %w[one two]
|
86
|
+
@sub_job = Deferred::DefaultThreadpoolJob.new { @rval }
|
87
|
+
@first_job = Deferred::DefaultThreadpoolJob.new { @sub_job }
|
88
|
+
end
|
89
|
+
|
90
|
+
it %[should return the sub_job rval to the callback] do
|
91
|
+
@first_job.callback do |result|
|
92
|
+
result.should == @rval
|
93
|
+
done
|
94
|
+
end
|
95
|
+
|
96
|
+
em { @first_job.defer! }
|
97
|
+
end # it
|
98
|
+
end # describe 'success'
|
99
|
+
|
100
|
+
describe 'failure' do
|
101
|
+
before do
|
102
|
+
@rval = %w[one two]
|
103
|
+
@sub_job = Deferred::DefaultThreadpoolJob.new { raise BollocksError }
|
104
|
+
@first_job = Deferred::DefaultThreadpoolJob.new { @sub_job }
|
105
|
+
end
|
106
|
+
|
107
|
+
it %[should fire the errback on the first_job] do
|
108
|
+
@first_job.errback do |exc|
|
109
|
+
exc.should be_instance_of(BollocksError)
|
110
|
+
done
|
111
|
+
end
|
112
|
+
|
113
|
+
em { @first_job.defer! }
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe 'before_run' do
|
118
|
+
|
119
|
+
it %[should call the before_run callbacks in the reactor thread] do
|
120
|
+
rval = "hooray"
|
121
|
+
|
122
|
+
sub_job = Deferred::DefaultThreadpoolJob.new { rval }
|
123
|
+
|
124
|
+
sub_job.before_run { EM.reactor_thread?.should be_true }
|
125
|
+
sub_job.callback { |*| done }
|
126
|
+
|
127
|
+
first_job = Deferred::DefaultThreadpoolJob.new { sub_job }
|
128
|
+
|
129
|
+
em { first_job.defer! }
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end # describe returns a ThreadpoolJob
|
133
|
+
|
134
|
+
describe 'on_run returns a Deferred' do
|
135
|
+
before do
|
136
|
+
@rval = %w[one two]
|
137
|
+
@deferred = Deferred::Default.new
|
138
|
+
@sub_job = Deferred::DefaultThreadpoolJob.new { @deferred }
|
139
|
+
@first_job = Deferred::DefaultThreadpoolJob.new { @sub_job }
|
140
|
+
end
|
141
|
+
|
142
|
+
it %[should chain the deferred's callback] do
|
143
|
+
EM.next_tick do
|
144
|
+
@deferred.succeed(*@rval)
|
145
|
+
end
|
146
|
+
|
147
|
+
@first_job.callback do |*a|
|
148
|
+
a.should == @rval
|
149
|
+
done
|
150
|
+
end
|
151
|
+
|
152
|
+
em { @first_job.defer! }
|
153
|
+
end
|
154
|
+
|
155
|
+
it %[should chain the deferred's errback] do
|
156
|
+
exc = BollocksError.new
|
157
|
+
|
158
|
+
@first_job.errback do |e|
|
159
|
+
e.should == exc
|
160
|
+
done
|
161
|
+
end
|
162
|
+
|
163
|
+
EM.next_tick do
|
164
|
+
@deferred.fail(exc)
|
165
|
+
end
|
166
|
+
|
167
|
+
em { @first_job.defer! }
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end # describe 'defer!'
|
171
|
+
end
|
172
|
+
|