pipeline 0.0.8 → 0.0.9

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.
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), '..', 'spec_helper')
1
+ require 'spec/spec_helper'
2
2
 
3
3
  module Pipeline
4
4
  describe ApiMethods do
@@ -48,6 +48,7 @@ module Pipeline
48
48
  describe "#resume" do
49
49
  before(:each) do
50
50
  @pipeline = Pipeline::Base.new
51
+ @pipeline.stub!(:resume)
51
52
  Pipeline::Base.stub!(:find).with('1').and_return(@pipeline)
52
53
  Delayed::Job.stub!(:enqueue)
53
54
  end
@@ -72,10 +73,10 @@ module Pipeline
72
73
  Pipeline.resume('1')
73
74
  end
74
75
 
75
- it "should raise error is trying to resume in invalid state" do
76
- @pipeline.send(:_setup)
76
+ it "should resume pipeline instance" do
77
+ @pipeline.should_receive(:resume)
77
78
 
78
- lambda {Pipeline.resume('1')}.should raise_error(InvalidStatusError, "Status is already in progress")
79
+ Pipeline.resume('1')
79
80
  end
80
81
 
81
82
  end
@@ -1,53 +1,9 @@
1
- require File.join(File.dirname(__FILE__), '..', 'spec_helper')
2
-
3
- class FirstStage < Pipeline::Stage::Base
4
- def run
5
- @executed = true
6
- end
7
-
8
- def executed?
9
- !!@executed
10
- end
11
- end
12
-
13
- class SecondStage < FirstStage; end # Ugly.. just so I don't have to write stub again
14
-
15
- class IrrecoverableStage < FirstStage
16
- def run
17
- super
18
- raise Pipeline::IrrecoverableError.new
19
- end
20
- end
21
-
22
- class RecoverableInputRequiredStage < FirstStage
23
- def run
24
- super
25
- raise Pipeline::RecoverableError.new("message", true)
26
- end
27
- end
28
-
29
- class RecoverableStage < FirstStage
30
- def run
31
- super
32
- raise Pipeline::RecoverableError.new("message")
33
- end
34
- end
35
-
36
- class GenericErrorStage < FirstStage
37
- def run
38
- super
39
- raise Exception.new
40
- end
41
- end
42
-
43
- class SamplePipeline < Pipeline::Base
44
- define_stages FirstStage >> SecondStage
45
- end
1
+ require 'spec/spec_helper'
46
2
 
47
3
  module Pipeline
48
4
  describe Base do
49
5
 
50
- describe "- configuring" do
6
+ context "- configuring" do
51
7
  before(:each) do
52
8
  class ::SamplePipeline
53
9
  define_stages FirstStage >> SecondStage
@@ -70,7 +26,7 @@ module Pipeline
70
26
  end
71
27
  end
72
28
 
73
- describe "- setup" do
29
+ context "- setup" do
74
30
  before(:each) do
75
31
  @pipeline = SamplePipeline.new
76
32
  end
@@ -88,15 +44,15 @@ module Pipeline
88
44
  end
89
45
  end
90
46
 
91
- describe "- persistence" do
47
+ context "- persistence" do
92
48
  before(:each) do
93
49
  @pipeline = Base.new
94
50
  end
95
51
 
96
52
  it "should persist pipeline instance" do
97
- @pipeline.id.should be_nil
53
+ @pipeline.should be_new_record
98
54
  lambda {@pipeline.save!}.should_not raise_error
99
- @pipeline.id.should_not be_nil
55
+ @pipeline.should_not be_new_record
100
56
  end
101
57
 
102
58
  it "should allow retrieval by id" do
@@ -149,20 +105,15 @@ module Pipeline
149
105
  end
150
106
  end
151
107
 
152
- describe "- execution (success)" do
108
+ context "- execution (success)" do
153
109
  before(:each) do
154
- class ::SamplePipeline
155
- define_stages FirstStage >> SecondStage
156
- end
157
- @pipeline = ::SamplePipeline.new
110
+ @pipeline = SamplePipeline.new
158
111
  end
159
112
 
160
113
  it "should increment attempts" do
161
- pipeline = SamplePipeline.new
162
-
163
- pipeline.attempts.should == 0
164
- pipeline.perform
165
- pipeline.attempts.should == 1
114
+ @pipeline.attempts.should == 0
115
+ @pipeline.perform
116
+ @pipeline.attempts.should == 1
166
117
  end
167
118
 
168
119
  it "should perform each stage" do
@@ -183,7 +134,7 @@ module Pipeline
183
134
  end
184
135
  end
185
136
 
186
- describe "- execution (in progress)" do
137
+ context "- execution (in progress)" do
187
138
  it "should set status to in_progress" do
188
139
  pipeline = SamplePipeline.new
189
140
  pipeline.send(:_setup)
@@ -193,7 +144,7 @@ module Pipeline
193
144
  end
194
145
  end
195
146
 
196
- describe "- execution (irrecoverable error)" do
147
+ context "- execution (irrecoverable error)" do
197
148
  before(:each) do
198
149
  class ::SamplePipeline
199
150
  define_stages FirstStage >> IrrecoverableStage
@@ -217,7 +168,7 @@ module Pipeline
217
168
  end
218
169
  end
219
170
 
220
- describe "- execution (recoverable error that doesn't require user input)" do
171
+ context "- execution (recoverable error that doesn't require user input)" do
221
172
  before(:each) do
222
173
  class ::SamplePipeline
223
174
  define_stages FirstStage >> RecoverableStage
@@ -241,7 +192,7 @@ module Pipeline
241
192
  end
242
193
  end
243
194
 
244
- describe "- execution (recoverable error that requires user input)" do
195
+ context "- execution (recoverable error that requires user input)" do
245
196
  before(:each) do
246
197
  class ::SamplePipeline
247
198
  define_stages FirstStage >> RecoverableInputRequiredStage
@@ -265,7 +216,7 @@ module Pipeline
265
216
  end
266
217
  end
267
218
 
268
- describe "- execution (other errors will use failure mode to pause/cancel pipeline)" do
219
+ context "- execution (other errors will use failure mode to pause/cancel pipeline)" do
269
220
  before(:each) do
270
221
  class ::SamplePipeline
271
222
  define_stages FirstStage >> GenericErrorStage
@@ -304,7 +255,7 @@ module Pipeline
304
255
  end
305
256
  end
306
257
 
307
- describe "- execution (retrying)" do
258
+ context "- execution (retrying)" do
308
259
  before(:each) do
309
260
  class ::SamplePipeline
310
261
  define_stages FirstStage >> RecoverableInputRequiredStage
@@ -344,15 +295,14 @@ module Pipeline
344
295
 
345
296
  # Status gets updated to failed on the database (not on the current instance)
346
297
  same_pipeline = SamplePipeline.find(@pipeline.id)
347
- same_pipeline.send(:status=, :failed)
348
- same_pipeline.save!
298
+ same_pipeline.update_attribute(:status, :failed)
349
299
 
350
300
  # Retrying should fail because pipeline is now failed
351
301
  lambda {@pipeline.perform}.should raise_error(InvalidStatusError, "Status is already failed")
352
302
  end
353
303
  end
354
304
 
355
- describe "- execution (state transitions)" do
305
+ context "- execution (state transitions)" do
356
306
  before(:each) do
357
307
  @pipeline = Base.new
358
308
  end
@@ -363,42 +313,42 @@ module Pipeline
363
313
  end
364
314
 
365
315
  it "should execute if status is :paused (for retrying)" do
366
- @pipeline.send(:status=, :paused)
316
+ @pipeline.update_attribute(:status, :paused)
367
317
 
368
318
  @pipeline.should be_ok_to_resume
369
319
  lambda {@pipeline.perform}.should_not raise_error(InvalidStatusError)
370
320
  end
371
321
 
372
322
  it "should execute if status is :retry" do
373
- @pipeline.send(:status=, :retry)
323
+ @pipeline.update_attribute(:status, :retry)
374
324
 
375
325
  @pipeline.should be_ok_to_resume
376
326
  lambda {@pipeline.perform}.should_not raise_error(InvalidStatusError)
377
327
  end
378
328
 
379
329
  it "should not execute if status is :in_progress" do
380
- @pipeline.send(:status=, :in_progress)
330
+ @pipeline.update_attribute(:status, :in_progress)
381
331
 
382
332
  @pipeline.should_not be_ok_to_resume
383
333
  lambda {@pipeline.perform}.should raise_error(InvalidStatusError, "Status is already in progress")
384
334
  end
385
335
 
386
336
  it "should not execute if status is :completed" do
387
- @pipeline.send(:status=, :completed)
337
+ @pipeline.update_attribute(:status, :completed)
388
338
 
389
339
  @pipeline.should_not be_ok_to_resume
390
340
  lambda {@pipeline.perform}.should raise_error(InvalidStatusError, "Status is already completed")
391
341
  end
392
342
 
393
343
  it "should not execute if status is :failed" do
394
- @pipeline.send(:status=, :failed)
344
+ @pipeline.update_attribute(:status, :failed)
395
345
 
396
346
  @pipeline.should_not be_ok_to_resume
397
347
  lambda {@pipeline.perform}.should raise_error(InvalidStatusError, "Status is already failed")
398
348
  end
399
349
  end
400
350
 
401
- describe "- cancelling" do
351
+ context "- cancelling" do
402
352
  before(:each) do
403
353
  class ::SamplePipeline
404
354
  define_stages FirstStage >> RecoverableInputRequiredStage
@@ -417,9 +367,22 @@ module Pipeline
417
367
  @pipeline.cancel
418
368
  @pipeline.reload.status.should == :failed
419
369
  end
370
+
371
+ it "should refresh object (in case it was updated after job was scheduled)" do
372
+ # Gets paused on the first time
373
+ @pipeline.save!
374
+
375
+ # Status gets updated to failed on the database (not on the current instance)
376
+ same_pipeline = SamplePipeline.find(@pipeline.id)
377
+ same_pipeline.update_attribute(:status, :failed)
378
+
379
+ # Retrying should fail because pipeline is now failed
380
+ lambda {@pipeline.cancel}.should raise_error(InvalidStatusError, "Status is already failed")
381
+ end
382
+
420
383
  end
421
384
 
422
- describe "- cancelling (state transitions)" do
385
+ context "- cancelling (state transitions)" do
423
386
  before(:each) do
424
387
  @pipeline = Base.new
425
388
  end
@@ -429,29 +392,105 @@ module Pipeline
429
392
  end
430
393
 
431
394
  it "should cancel if status is :paused (for retrying)" do
432
- @pipeline.send(:status=, :paused)
395
+ @pipeline.update_attribute(:status, :paused)
433
396
 
434
397
  lambda {@pipeline.cancel}.should_not raise_error(InvalidStatusError)
435
398
  end
436
399
 
437
400
  it "should not cancel if status is :in_progress" do
438
- @pipeline.send(:status=, :in_progress)
401
+ @pipeline.update_attribute(:status, :in_progress)
439
402
 
440
403
  lambda {@pipeline.cancel}.should raise_error(InvalidStatusError, "Status is already in progress")
441
404
  end
442
405
 
443
406
  it "should not cancel if status is :completed" do
444
- @pipeline.send(:status=, :completed)
407
+ @pipeline.update_attribute(:status, :completed)
445
408
 
446
409
  lambda {@pipeline.cancel}.should raise_error(InvalidStatusError, "Status is already completed")
447
410
  end
448
411
 
449
412
  it "should not cancel if status is :failed" do
450
- @pipeline.send(:status=, :failed)
413
+ @pipeline.update_attribute(:status, :failed)
451
414
 
452
415
  lambda {@pipeline.cancel}.should raise_error(InvalidStatusError, "Status is already failed")
453
416
  end
454
417
  end
418
+
419
+ context "- resuming" do
420
+ before(:each) do
421
+ class ::SamplePipeline
422
+ define_stages FirstStage >> RecoverableInputRequiredStage
423
+ end
424
+ @pipeline = SamplePipeline.new
425
+ @pipeline.perform
426
+ end
427
+
428
+ it "should refresh object (in case it was updated after job was scheduled)" do
429
+ # Gets paused on the first time
430
+ @pipeline.save!
431
+
432
+ # Status gets updated to failed on the database (not on the current instance)
433
+ same_pipeline = SamplePipeline.find(@pipeline.id)
434
+ same_pipeline.update_attribute(:status, :failed)
435
+
436
+ # Retrying should fail because pipeline is now failed
437
+ lambda {@pipeline.resume}.should raise_error(InvalidStatusError, "Status is already failed")
438
+ end
439
+ end
455
440
 
441
+ context "- resuming (state transitions)" do
442
+ before(:each) do
443
+ @pipeline = Base.new
444
+ end
445
+
446
+ it "should resume if status is :not_started" do
447
+ lambda {@pipeline.resume}.should_not raise_error(InvalidStatusError)
448
+ end
449
+
450
+ it "should resume if status is :paused (for retrying)" do
451
+ @pipeline.update_attribute(:status, :paused)
452
+
453
+ lambda {@pipeline.resume}.should_not raise_error(InvalidStatusError)
454
+ end
455
+
456
+ it "should not resume if status is :in_progress" do
457
+ @pipeline.update_attribute(:status, :in_progress)
458
+
459
+ lambda {@pipeline.resume}.should raise_error(InvalidStatusError, "Status is already in progress")
460
+ end
461
+
462
+ it "should not resume if status is :completed" do
463
+ @pipeline.update_attribute(:status, :completed)
464
+
465
+ lambda {@pipeline.resume}.should raise_error(InvalidStatusError, "Status is already completed")
466
+ end
467
+
468
+ it "should not resume if status is :failed" do
469
+ @pipeline.update_attribute(:status, :failed)
470
+
471
+ lambda {@pipeline.resume}.should raise_error(InvalidStatusError, "Status is already failed")
472
+ end
473
+ end
474
+
475
+ context "- callbacks" do
476
+ before(:each) do
477
+ @pipeline = ::SamplePipeline.new
478
+ end
479
+
480
+ it "should allow callback before running the pipeline" do
481
+ @pipeline.should_receive(:before_pipeline_callback).once
482
+ @pipeline.perform
483
+ end
484
+
485
+ it "should allow callback after running the pipeline" do
486
+ @pipeline.should_receive(:after_pipeline_callback).once
487
+ @pipeline.perform
488
+ end
489
+
490
+ it "should run callback after cancelling a pipeline" do
491
+ @pipeline.should_receive(:after_pipeline_callback).once
492
+ @pipeline.cancel
493
+ end
494
+ end
456
495
  end
457
496
  end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec/spec_helper'
2
2
 
3
3
  # Reusing stage table to simplify database integration tests
4
4
  class FakeForSymbolAttribute < ActiveRecord::Base
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec/spec_helper'
2
2
 
3
3
  # Reusing stage table to simplify database integration tests
4
4
  class FakeForTransactionalAttribute < ActiveRecord::Base
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
1
+ require 'spec/spec_helper'
2
2
 
3
3
  module Pipeline
4
4
  describe InvalidPipelineError do
@@ -1,20 +1,10 @@
1
- require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
2
-
3
- class SampleStage < Pipeline::Stage::Base
4
- def run
5
- @executed = true
6
- end
7
-
8
- def executed?
9
- !!@executed
10
- end
11
- end
1
+ require 'spec/spec_helper'
12
2
 
13
3
  module Pipeline
14
4
  module Stage
15
5
  describe Base do
16
6
 
17
- describe "- chaining" do
7
+ context "- chaining" do
18
8
  class Step1 < Base; end
19
9
  class Step2 < Base; end
20
10
  class Step3 < Base; end
@@ -32,23 +22,23 @@ module Pipeline
32
22
  end
33
23
  end
34
24
 
35
- describe "- setup" do
25
+ context "- setup" do
36
26
  it "should set default name" do
37
27
  Base.new.name.should == "Pipeline::Stage::Base"
38
- SampleStage.new.name.should == "SampleStage"
28
+ ::SampleStage.new.name.should == "SampleStage"
39
29
  end
40
30
 
41
31
  it "should allow overriding name at class level" do
42
- SampleStage.default_name = "My custom stage name"
43
- SampleStage.new.name.should == "My custom stage name"
32
+ StubStage.default_name = "My custom stage name"
33
+ StubStage.new.name.should == "My custom stage name"
44
34
 
45
- SampleStage.default_name = :some_symbol
46
- SampleStage.new.name.should == "some_symbol"
35
+ StubStage.default_name = :some_symbol
36
+ StubStage.new.name.should == "some_symbol"
47
37
  end
48
38
 
49
39
  it "should allow specifying a name on creation" do
50
40
  Base.new(:name => "My Name").name.should == "My Name"
51
- SampleStage.new(:name => "Customized Name").name.should == "Customized Name"
41
+ StubStage.new(:name => "Customized Name").name.should == "Customized Name"
52
42
  end
53
43
 
54
44
  it "should start with status not_started" do
@@ -57,24 +47,28 @@ module Pipeline
57
47
 
58
48
  it "should validate status" do
59
49
  lambda {Base.new(:status => :something_else)}.should raise_error
50
+ end
51
+
52
+ it "should raise error if subclass doesn't implement #run" do
53
+ lambda {Base.new.run}.should raise_error("This method must be implemented by any subclass of Pipeline::Stage::Base")
60
54
  end
61
55
  end
62
56
 
63
- describe "- persistence" do
57
+ context "- persistence" do
64
58
  before(:each) do
65
- @stage = SampleStage.new
59
+ @stage = StubStage.new
66
60
  end
67
61
 
68
62
  it "should persist stage" do
69
- @stage.id.should be_nil
63
+ @stage.should be_new_record
70
64
  lambda {@stage.save!}.should_not raise_error
71
- @stage.id.should_not be_nil
65
+ @stage.should_not be_new_record
72
66
  end
73
67
 
74
68
  it "should allow retrieval by id" do
75
69
  @stage.save!
76
70
 
77
- s = SampleStage.find(@stage.id)
71
+ s = StubStage.find(@stage.id)
78
72
  s.should === @stage
79
73
 
80
74
  lambda {Base.find('invalid_id')}.should raise_error(ActiveRecord::RecordNotFound)
@@ -83,7 +77,7 @@ module Pipeline
83
77
  it "should persist type as single table inheritance" do
84
78
  @stage.save!
85
79
  stage = Base.find(@stage.id)
86
- stage.should be_an_instance_of(SampleStage)
80
+ stage.should be_an_instance_of(StubStage)
87
81
  end
88
82
 
89
83
  it "should belong to pipeline instance" do
@@ -96,9 +90,9 @@ module Pipeline
96
90
 
97
91
  end
98
92
 
99
- describe "- execution (success)" do
93
+ context "- execution (success)" do
100
94
  before(:each) do
101
- @stage = SampleStage.new
95
+ @stage = StubStage.new
102
96
  end
103
97
 
104
98
  it "should update status after finished" do
@@ -128,89 +122,90 @@ module Pipeline
128
122
 
129
123
  end
130
124
 
131
- describe "- execution (failure)" do
132
- before(:each) do
133
- @stage = SampleStage.new
134
- @stage.stub!(:run).and_raise(StandardError.new)
135
- end
136
-
125
+ context "- execution (failure)" do
137
126
  it "should re-raise error" do
138
- lambda {@stage.perform}.should raise_error
127
+ stage = FailedStage.new
128
+ lambda {stage.perform}.should raise_error
139
129
  end
140
130
 
141
131
  it "should update status on irrecoverable error" do
142
- @stage.should_receive(:run).and_raise(IrrecoverableError.new)
143
- lambda {@stage.perform}.should raise_error(IrrecoverableError)
144
- @stage.status.should == :failed
145
- @stage.reload.status.should == :failed
132
+ stage = IrrecoverableStage.new
133
+ lambda {stage.perform}.should raise_error(IrrecoverableError)
134
+ stage.status.should == :failed
135
+ stage.reload.status.should == :failed
146
136
  end
147
137
 
148
138
  it "should update message on irrecoverable error" do
149
- @stage.should_receive(:run).and_raise(IrrecoverableError.new("message"))
150
- lambda {@stage.perform}.should raise_error(IrrecoverableError)
151
- @stage.message.should == "message"
152
- @stage.reload.message.should == "message"
139
+ stage = IrrecoverableStage.new
140
+ lambda {stage.perform}.should raise_error(IrrecoverableError)
141
+ stage.message.should == "message"
142
+ stage.reload.message.should == "message"
153
143
  end
154
144
 
155
145
  it "should update status on recoverable error (not requiring input)" do
156
- @stage.should_receive(:run).and_raise(RecoverableError.new)
157
- lambda {@stage.perform}.should raise_error(RecoverableError)
158
- @stage.status.should == :failed
159
- @stage.reload.status.should == :failed
146
+ stage = RecoverableStage.new
147
+ lambda {stage.perform}.should raise_error(RecoverableError)
148
+ stage.status.should == :failed
149
+ stage.reload.status.should == :failed
160
150
  end
161
151
 
162
152
  it "should update status on recoverable error (requiring input)" do
163
- @stage.should_receive(:run).and_raise(RecoverableError.new("message", true))
164
- lambda {@stage.perform}.should raise_error(RecoverableError)
165
- @stage.status.should == :failed
166
- @stage.reload.status.should == :failed
153
+ stage = RecoverableInputRequiredStage.new
154
+ lambda {stage.perform}.should raise_error(RecoverableError)
155
+ stage.status.should == :failed
156
+ stage.reload.status.should == :failed
167
157
  end
168
158
 
169
159
  it "should update message on recoverable error" do
170
- @stage.should_receive(:run).and_raise(RecoverableError.new("message"))
171
- lambda {@stage.perform}.should raise_error(RecoverableError)
172
- @stage.message.should == "message"
173
- @stage.reload.message.should == "message"
160
+ stage = RecoverableStage.new
161
+ lambda {stage.perform}.should raise_error(RecoverableError)
162
+ stage.message.should == "message"
163
+ stage.reload.message.should == "message"
174
164
  end
175
165
 
176
166
  it "should capture generic Exception" do
177
- @stage.should_receive(:run).and_raise(Exception.new)
178
- lambda {@stage.perform}.should raise_error(Exception)
179
- @stage.status.should == :failed
180
- @stage.reload.status.should == :failed
167
+ stage = GenericErrorStage.new
168
+ lambda {stage.perform}.should raise_error(Exception)
169
+ stage.status.should == :failed
170
+ stage.reload.status.should == :failed
181
171
  end
182
172
 
183
173
  it "should log exception message and backtrace" do
184
- SampleStage.default_name = "SampleStage"
185
- error = StandardError.new("error message")
186
- error.set_backtrace(['a', 'b', 'c'])
187
- @stage.should_receive(:run).and_raise(error)
174
+ class StageFailWithDetails < StubStage
175
+ self.default_name = "Fail With Details"
176
+
177
+ def run
178
+ super
179
+ error = StandardError.new("error message")
180
+ error.set_backtrace(['a', 'b', 'c'])
181
+ raise error
182
+ end
183
+ end
184
+ stage = StageFailWithDetails.new
188
185
 
189
- @stage.logger.should_receive(:info).with("Error on stage SampleStage: error message")
190
- @stage.logger.should_receive(:info).with("a\nb\nc")
191
- lambda {@stage.perform}.should raise_error
186
+ stage.logger.should_receive(:info).with("Error on stage Fail With Details: error message")
187
+ stage.logger.should_receive(:info).with("a\nb\nc")
188
+ lambda {stage.perform}.should raise_error
192
189
  end
193
190
 
194
191
  it "should refresh object (in case it was cancelled after job was scheduled)" do
195
192
  # Gets failed on the first time
196
- @stage.save!
197
- @stage.should_receive(:run).and_raise(RecoverableError.new("message"))
198
- lambda {@stage.perform}.should raise_error(RecoverableError)
193
+ stage = RecoverableStage.create!
194
+ lambda {stage.perform}.should raise_error(RecoverableError)
199
195
 
200
196
  # Status gets updated to completed on the database (not on the current instance)
201
- same_stage = SampleStage.find(@stage.id)
202
- same_stage.send(:status=, :completed)
203
- same_stage.save!
197
+ same_stage = StubStage.find(stage.id)
198
+ same_stage.update_attribute(:status, :completed)
204
199
 
205
200
  # Retrying should fail because stage is now completed
206
- lambda {@stage.perform}.should raise_error(InvalidStatusError, "Status is already completed")
201
+ lambda {stage.perform}.should raise_error(InvalidStatusError, "Status is already completed")
207
202
  end
208
203
 
209
204
  end
210
205
 
211
- describe "- execution (in progress)" do
206
+ context "- execution (in progress)" do
212
207
  it "should set status to in_progress" do
213
- stage = SampleStage.new
208
+ stage = StubStage.new
214
209
  stage.send(:_setup)
215
210
 
216
211
  stage.status.should == :in_progress
@@ -218,7 +213,7 @@ module Pipeline
218
213
  end
219
214
 
220
215
  it "should clear message when restarting" do
221
- stage = SampleStage.new(:message => 'some message')
216
+ stage = StubStage.new(:message => 'some message')
222
217
  stage.send(:_setup)
223
218
 
224
219
  stage.message.should be_nil
@@ -226,35 +221,55 @@ module Pipeline
226
221
  end
227
222
  end
228
223
 
229
- describe "- execution (state transitions)" do
224
+ context "- execution (state transitions)" do
225
+ before(:each) do
226
+ @stage = StubStage.new
227
+ end
228
+
230
229
  it "should execute if status is :not_started" do
231
- stage = SampleStage.new
232
-
233
- lambda {stage.perform}.should_not raise_error(InvalidStatusError)
230
+ lambda {@stage.perform}.should_not raise_error(InvalidStatusError)
234
231
  end
235
232
 
236
233
  it "should execute if status is :failed (for retrying)" do
237
- stage = SampleStage.new
238
- stage.send(:status=, :failed)
234
+ @stage.update_attribute(:status, :failed)
239
235
 
240
- lambda {stage.perform}.should_not raise_error(InvalidStatusError)
236
+ lambda {@stage.perform}.should_not raise_error(InvalidStatusError)
241
237
  end
242
238
 
243
239
  it "should not execute if status is :in_progress" do
244
- stage = SampleStage.new
245
- stage.send(:status=, :in_progress)
240
+ @stage.update_attribute(:status, :in_progress)
246
241
 
247
- lambda {stage.perform}.should raise_error(InvalidStatusError, "Status is already in progress")
242
+ lambda {@stage.perform}.should raise_error(InvalidStatusError, "Status is already in progress")
248
243
  end
249
244
 
250
245
  it "should not execute if status is :completed" do
251
- stage = SampleStage.new
252
- stage.send(:status=, :completed)
246
+ @stage.update_attribute(:status, :completed)
253
247
 
254
- lambda {stage.perform}.should raise_error(InvalidStatusError, "Status is already completed")
248
+ lambda {@stage.perform}.should raise_error(InvalidStatusError, "Status is already completed")
255
249
  end
256
250
  end
257
251
 
252
+ context "- callbacks" do
253
+ before(:each) do
254
+ @stage = ::SampleStage.new
255
+ end
256
+
257
+ it "should allow callback before running the stage" do
258
+ @stage.should_receive(:before_stage_callback).once
259
+ @stage.perform
260
+ end
261
+
262
+ it "should allow callback after running the stage on success" do
263
+ @stage.should_receive(:after_stage_callback).once
264
+ @stage.perform
265
+ end
266
+
267
+ it "should allow callback after running the stage on failure" do
268
+ @stage.stub!(:run).and_raise("error")
269
+ @stage.should_receive(:after_stage_callback).once
270
+ lambda {@stage.perform}.should raise_error
271
+ end
272
+ end
258
273
  end
259
274
  end
260
275
  end