step_machine 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,80 @@
1
+ module StepMachine
2
+
3
+ class Step
4
+
5
+ attr_accessor :name, :block, :next_step, :group, :exception
6
+ attr_reader :result, :validation, :condition_block
7
+
8
+ def initialize(name)
9
+ self.name = name
10
+ end
11
+
12
+ def validate(value = nil, &block)
13
+ @validation = block || value
14
+ self
15
+ end
16
+
17
+ def errors(init_error = nil)
18
+ @errors = init_error if (!init_error.nil? and init_error.class != @errors.class)
19
+ @errors = [] if (init_error.nil? && @errors.nil?)
20
+ @errors
21
+ end
22
+
23
+ def success(&block)
24
+ @success = block
25
+ self
26
+ end
27
+
28
+ def next_step(&block)
29
+ @next_step = block if block
30
+ @next_step
31
+ end
32
+
33
+ def condition(&block)
34
+ @condition_block = block if block
35
+ self
36
+ end
37
+
38
+ def next
39
+ return next_step.call(self) if next_step.is_a?(Proc)
40
+ next_step
41
+ end
42
+
43
+ def perform
44
+ return true unless condition_satisfied
45
+ @performed = true
46
+ @result = block.call(self)
47
+ valid = valid?
48
+ @success.call(self) if @success && valid
49
+ valid
50
+ rescue => e
51
+ @exception = e
52
+ false
53
+ end
54
+
55
+ def performed?
56
+ !!@performed
57
+ end
58
+
59
+ private
60
+
61
+ def valid?
62
+ if validation
63
+ return (!(validation.call(self) === false) && errors.empty?) if validation.is_a?(Proc)
64
+ return false unless errors.empty?
65
+ return result.match(validation) if validation.is_a?(Regexp)
66
+ return validation == result
67
+ end
68
+ true
69
+ end
70
+
71
+ def condition_satisfied
72
+ return false if (group && group.condition_block && !group.condition_block.call)
73
+ return false if (condition_block && !condition_block.call)
74
+ true
75
+ end
76
+
77
+
78
+ end
79
+
80
+ end
@@ -0,0 +1,3 @@
1
+ module StepMachine
2
+ VERSION = "0.0.3"
3
+ end
@@ -0,0 +1,585 @@
1
+ require "spec_helper"
2
+
3
+ describe StepMachine::Runner do
4
+
5
+ before :each do
6
+ @runner = StepMachine::Runner.new
7
+ end
8
+
9
+ describe 'on group' do
10
+
11
+ it "should create and return the group" do
12
+ group = @runner.group(:group)
13
+
14
+ group.should be_a(StepMachine::Group)
15
+ group.name.should == :group
16
+ end
17
+
18
+ it "should return an existing group" do
19
+ group = @runner.group(:group)
20
+
21
+ expect(@runner.group(:group)).to eql(group)
22
+ end
23
+
24
+ it "should assign the first step defined as first step of group" do
25
+ @runner.group(:group_1) do
26
+ @runner.step(:step_1) {}
27
+ @runner.step(:step_2) {}
28
+ end
29
+
30
+ @runner.group(:group_1).first_step.should == @runner.step(:step_1)
31
+ end
32
+
33
+ it "should create an step with the surrounding group" do
34
+ @runner.group(:group_1) do
35
+ @runner.step(:step_1) {}
36
+ end
37
+
38
+ @runner.group(:group_2) do
39
+ @runner.step(:step_2) {}
40
+ end
41
+
42
+ @runner.step(:step_3) {}
43
+
44
+ @runner.step(:step_1).group.name.should == :group_1
45
+ @runner.step(:step_2).group.name.should == :group_2
46
+ @runner.step(:step_3).group.should be_nil
47
+ end
48
+
49
+ it "should assign a condition with group" do
50
+ block = proc {x + 1}
51
+ @runner.group(:group_1) do
52
+ @runner.step(:step_2) {}
53
+ end.condition &block
54
+ expect(@runner.group(:group_1).condition_block).to eql(block)
55
+ end
56
+
57
+ end
58
+
59
+ describe "on step" do
60
+
61
+ it "should create an step with the given name and block" do
62
+
63
+ block = proc { x + 1 }
64
+ step = @runner.step(:name, &block)
65
+
66
+ step.name.should == :name
67
+ step.block.should == block
68
+ end
69
+
70
+ it "should return the required step" do
71
+ step_1 = @runner.step(:step_1) {}
72
+ step_2 = @runner.step(:step_2) {}
73
+
74
+ @runner.step(:step_1).should == step_1
75
+ end
76
+
77
+ it "should update the step with the last given block" do
78
+ block = proc { x + 1 }
79
+
80
+ @runner.step(:step_1) {}
81
+ @runner.step(:step_1, &block)
82
+
83
+ @runner.step(:step_1).block.should == block
84
+ end
85
+
86
+ it "should assign the next step automatically" do
87
+ step_1 = @runner.step(:step_1) {}
88
+ step_2 = @runner.step(:step_2) {}
89
+
90
+ step_1.next_step.should == step_2
91
+ end
92
+
93
+ it "should assign the first step automatically" do
94
+ step_1 = @runner.step(:step_1) {}
95
+ @runner.first_step.should == step_1
96
+
97
+ step_2 = @runner.step(:step_2) {}
98
+ @runner.first_step.should == step_1
99
+ end
100
+ end
101
+
102
+ describe "on run" do
103
+ it "should run the given step" do
104
+ @runner.step(:step) { 1 + 1}
105
+
106
+ @runner.run
107
+
108
+ @runner.step(:step).result.should == 2
109
+ end
110
+
111
+ it "should run the steps based in the steps order" do
112
+ x = 0
113
+
114
+ @runner.step(:step_1) { x += 1 }
115
+ @runner.step(:step_2) { x += 1 }
116
+
117
+ @runner.run
118
+
119
+ x.should == 2
120
+ end
121
+
122
+ it "should run the steps correctly wne the order is changed" do
123
+ order = []
124
+
125
+ block = proc { |s| order << s.name }
126
+
127
+ @runner.step(:step_1, &block)
128
+ @runner.step(:step_2, &block)
129
+ @runner.step(:step_3, &block)
130
+
131
+ @runner.step(:step_1).next_step = @runner.step(:step_3)
132
+ @runner.step(:step_3).next_step = @runner.step(:step_2)
133
+ @runner.step(:step_2).next_step = nil
134
+
135
+ @runner.run
136
+
137
+ order.should == [:step_1, :step_3, :step_2]
138
+ end
139
+
140
+ it "should run the steps correctly wne the order is changed" do
141
+ order = []
142
+
143
+ block = proc { |s| order << s.name }
144
+
145
+ @runner.step(:step_1, &block)
146
+ @runner.step(:step_2, &block)
147
+ @runner.step(:step_3, &block)
148
+
149
+ @runner.step(:step_1).next_step = @runner.step(:step_3)
150
+ @runner.step(:step_3).next_step { @runner.step(:step_2) }
151
+ @runner.step(:step_2).next_step = nil
152
+
153
+ @runner.run
154
+
155
+ order.should == [:step_1, :step_3, :step_2]
156
+ end
157
+
158
+ it "should start on the given first step" do
159
+ order = []
160
+
161
+ block = proc { |s| order << s.name }
162
+
163
+ @runner.step(:step_1, &block)
164
+ @runner.step(:step_2, &block)
165
+ @runner.step(:step_3, &block)
166
+
167
+ @runner.step(:step_1).next_step = @runner.step(:step_3)
168
+ @runner.step(:step_3).next_step { @runner.step(:step_2) }
169
+ @runner.step(:step_2).next_step = nil
170
+
171
+ @runner.first_step = @runner.step(:step_2)
172
+
173
+ @runner.run
174
+
175
+ order.should == [:step_2]
176
+ end
177
+
178
+ it "should stop execution if a step fail" do
179
+ order = []
180
+
181
+ block = proc { |s| order << s.name }
182
+
183
+ @runner.step(:step_1, &block)
184
+ @runner.step(:step_2, &block)
185
+ @runner.step(:step_3, &block).validate { false }
186
+
187
+ @runner.step(:step_1).next_step = @runner.step(:step_3)
188
+ @runner.step(:step_3).next_step { @runner.step(:step_2) }
189
+ @runner.step(:step_2).next_step = nil
190
+
191
+ @runner.run
192
+
193
+ order.should == [:step_1, :step_3]
194
+ end
195
+
196
+
197
+ it "should store the failed step" do
198
+ @runner.step(:step_1) {}
199
+ @runner.step(:step_2) {}
200
+ @runner.step(:step_3) {}.validate { false }
201
+
202
+ @runner.step(:step_1).next_step = @runner.step(:step_3)
203
+ @runner.step(:step_3).next_step { @runner.step(:step_2) }
204
+ @runner.step(:step_2).next_step = nil
205
+
206
+ @runner.run
207
+
208
+ @runner.failed_step.should == @runner.step(:step_3)
209
+ end
210
+
211
+ it "should run only the steps of the given group" do
212
+ order = []
213
+
214
+ block = proc { |s| order << s.name }
215
+
216
+ @runner.group :group do
217
+ @runner.step(:step_1, &block)
218
+ @runner.step(:step_2, &block)
219
+ end
220
+ @runner.step(:step_3, &block)
221
+
222
+ @runner.run( :group => :group )
223
+
224
+ order.should == [:step_1, :step_2]
225
+ end
226
+
227
+ it "should run the steps up to given step" do
228
+ order = []
229
+ block = proc { |s| order << s.name }
230
+ @runner.step(:step_1, &block)
231
+ @runner.step(:step_2, &block)
232
+ @runner.step(:step_3, &block)
233
+ @runner.run( :upto => :step_2 )
234
+ order.should == [:step_1, :step_2]
235
+ end
236
+
237
+ it "should run the steps from given step" do
238
+ order = []
239
+ block = proc { |s| order << s.name }
240
+ @runner.step(:step_1, &block)
241
+ @runner.step(:step_2, &block)
242
+ @runner.step(:step_3, &block)
243
+ @runner.run( :from => :step_2 )
244
+ order.should == [:step_2, :step_3]
245
+ end
246
+
247
+ it "should run the steps from step_2 upto step_3" do
248
+ order = []
249
+ block = proc { |s| order << s.name }
250
+ @runner.step(:step_1, &block)
251
+ @runner.step(:step_2, &block)
252
+ @runner.step(:step_3, &block)
253
+ @runner.step(:step_4, &block)
254
+ @runner.run( :from => :step_2, :upto => :step_3 )
255
+ order.should == [:step_2, :step_3]
256
+ end
257
+
258
+ it "should evaluate the group condition" do
259
+ order = []
260
+ block = proc { |s| order << s.name }
261
+
262
+ @runner.step(:step_1, &block)
263
+
264
+ @runner.group :group do
265
+ @runner.step(:step_2, &block)
266
+ @runner.step(:step_3, &block)
267
+ end.condition { false }
268
+
269
+ @runner.step(:step_4, &block)
270
+
271
+ @runner.run
272
+
273
+ expect(order).to eql([:step_1, :step_4])
274
+ end
275
+
276
+ end
277
+
278
+ describe "on_step_failure" do
279
+
280
+ it "it should execute the given block if the step fails" do
281
+ @runner.step(:step_1){ }.validate{false}
282
+
283
+ x = 0
284
+ @runner.on_step_failure{x += 1}
285
+
286
+ @runner.run
287
+
288
+ x.should == 1
289
+ end
290
+
291
+ it "it should execute more than one blocks if the step fails" do
292
+ @runner.step(:step_1){ }.validate{false}
293
+
294
+ x = 0
295
+ @runner.on_step_failure{x += 1}
296
+ @runner.on_step_failure{x += 2}
297
+
298
+ @runner.run
299
+
300
+ x.should == 3
301
+ end
302
+
303
+ it "should pass the failed step to the block" do
304
+ step_1 = @runner.step(:step_1){ }.validate{false}
305
+
306
+ x = 0
307
+ @runner.on_step_failure do |f|
308
+ f.step.should == step_1
309
+ end
310
+
311
+ @runner.run
312
+ end
313
+
314
+ it "should execute the on step failure block only on the given steps" do
315
+ @runner.step(:step_1) {}.validate {false}
316
+ @runner.step(:step_2) {}.validate {false}
317
+
318
+ step_failed = nil
319
+ @runner.on_step_failure :only => [:step_1] {|f| step_failed = f.step.name}
320
+ @runner.run
321
+ step_failed.should == :step_1
322
+
323
+ @runner.first_step = step(:step_2)
324
+ step_failed = nil
325
+ @runner.run
326
+ step_failed.should == nil
327
+ end
328
+
329
+ it "should execute the on step failure block excluding on the given steps" do
330
+ @runner.step(:step_1) {}.validate {false}
331
+ @runner.step(:step_2) {}.validate {false}
332
+
333
+ step_failed = nil
334
+ @runner.on_step_failure :except => [:step_2] {|f| step_failed = f.step.name}
335
+ @runner.run
336
+ step_failed.should == :step_1
337
+
338
+ @runner.first_step = step(:step_2)
339
+ step_failed = nil
340
+ @runner.run
341
+ step_failed.should == nil
342
+ end
343
+
344
+ it "should go to the specified step" do
345
+ order = []
346
+
347
+ block = proc {|s| order << s.name}
348
+
349
+ @runner.step(:step_1, &block).validate {false}
350
+ @runner.step(:step_2, &block)
351
+
352
+ @runner.on_step_failure do |treatment|
353
+ treatment.go_to :step_2
354
+ end
355
+
356
+ @runner.run
357
+
358
+ order.should == [:step_1, :step_2]
359
+ @runner.status.should == :success
360
+ end
361
+
362
+ it "should repeat the failed step" do
363
+ order = []
364
+ count = 0
365
+
366
+ block = proc {|s| order << s.name}
367
+
368
+ @runner.step(:step_1, &block).validate {false}
369
+ @runner.step(:step_2, &block)
370
+
371
+ @runner.on_step_failure do |f|
372
+ f.repeat if count == 0
373
+ count += 1
374
+ end
375
+
376
+ @runner.run
377
+
378
+ order.should == [:step_1, :step_1]
379
+ @runner.status.should == :failure
380
+ end
381
+
382
+ it "should ignore the failure and continue" do
383
+ order = []
384
+
385
+ block = proc {|s| order << s.name}
386
+
387
+ @runner.step(:step_1, &block).validate {false}
388
+ @runner.step(:step_2, &block)
389
+
390
+ @runner.on_step_failure do |f|
391
+ f.continue
392
+ end
393
+
394
+ @runner.run
395
+
396
+ order.should == [:step_1, :step_2]
397
+ @runner.status.should == :success
398
+ end
399
+
400
+
401
+ it "should restart the process" do
402
+ order = []
403
+ count = 0
404
+
405
+ block = proc {|s| order << s.name}
406
+
407
+ @runner.step(:step_1, &block)
408
+ @runner.step(:step_2, &block).validate do |s|
409
+ count += 1
410
+ count > 1
411
+ end
412
+ @runner.step(:step_3, &block)
413
+
414
+ @runner.on_step_failure do |f|
415
+ f.restart
416
+ end
417
+
418
+ @runner.run
419
+
420
+ order.should == [:step_1, :step_2, :step_1, :step_2, :step_3]
421
+ @runner.status.should == :success
422
+ end
423
+
424
+ it "should restart the process 2 times" do
425
+ order = []
426
+
427
+ block = proc {|s| order << s.name}
428
+
429
+ @runner.step(:step_1, &block)
430
+ @runner.step(:step_2, &block).validate { false }
431
+ @runner.step(:step_3, &block)
432
+
433
+ @runner.on_step_failure do |f|
434
+ f.restart.times(2)
435
+ end
436
+
437
+ @runner.run
438
+
439
+ order.should == [:step_1, :step_2, :step_1, :step_2, :step_1, :step_2]
440
+ @runner.times_to_repeat.should == -1
441
+ @runner.status.should == :failure
442
+ end
443
+
444
+ it "should repeat step 2 times" do
445
+ order = []
446
+
447
+ block = proc {|s| order << s.name}
448
+
449
+ @runner.step(:step_1, &block)
450
+ @runner.step(:step_2, &block).validate { false }
451
+ @runner.step(:step_3, &block)
452
+
453
+ @runner.on_step_failure do |f|
454
+ f.repeat.times(2)
455
+ end
456
+
457
+ @runner.run
458
+
459
+ order.should == [:step_1, :step_2, :step_2, :step_2]
460
+ @runner.times_to_repeat.should == -1
461
+ @runner.status.should == :failure
462
+ end
463
+
464
+ it "it should execute failure when has errors message on step" do
465
+ @runner.step(:step_1_errors){x=1}.validate {|step| step.errors << 'errors' }
466
+ x = 0
467
+ @runner.on_step_failure{x += 1}
468
+ @runner.on_step_failure{x += 2}
469
+
470
+ @runner.run
471
+
472
+ x.should == 3
473
+ end
474
+
475
+ it "it should execute success when hasn't errors message on step" do
476
+ @runner.step(:step_1_not_failed){x=1}.validate {}
477
+ x = 0
478
+ @runner.on_step_failure{x += 1}
479
+ @runner.on_step_failure{x += 2}
480
+
481
+ @runner.run
482
+
483
+ x.should == 0
484
+ end
485
+
486
+ end
487
+
488
+ describe "before each step" do
489
+ it "should execute the block given" do
490
+ executed = []
491
+
492
+ @runner.step(:step_1) {}
493
+ @runner.step(:step_2) {}
494
+
495
+ @runner.before_each_step {|s| executed << s.name}
496
+ @runner.run
497
+
498
+ executed.should == [:step_1, :step_2]
499
+ end
500
+
501
+ it "should execute the block given only in the given steps" do
502
+ executed = []
503
+
504
+ @runner.step(:step_1) {}
505
+ @runner.step(:step_2) {}
506
+
507
+ @runner.before_each_step :only => [:step_2] {|s| executed << s.name}
508
+ @runner.run
509
+
510
+ executed.should == [:step_2]
511
+ end
512
+
513
+ it "should execute the block given except in the given steps" do
514
+ executed = []
515
+
516
+ @runner.step(:step_1) {}
517
+ @runner.step(:step_2) {}
518
+
519
+ @runner.before_each_step :except => [:step_2] {|s| executed << s.name}
520
+ @runner.run
521
+
522
+ executed.should == [:step_1]
523
+ end
524
+ end
525
+
526
+ describe "after each step" do
527
+ it "should execute the block given" do
528
+ executed = []
529
+
530
+ @runner.step(:step_1) {}
531
+ @runner.step(:step_2) {}
532
+
533
+ @runner.after_each_step {|s| executed << s.name}
534
+ @runner.run
535
+
536
+ executed.should == [:step_1, :step_2]
537
+ end
538
+
539
+ it "should execute the block given only in the given steps" do
540
+ executed = []
541
+
542
+ @runner.step(:step_1) {}
543
+ @runner.step(:step_2) {}
544
+
545
+ @runner.after_each_step :only => [:step_2] {|s| executed << s.name}
546
+ @runner.run
547
+
548
+ executed.should == [:step_2]
549
+ end
550
+
551
+ it "should execute the block given except in the given steps" do
552
+ executed = []
553
+
554
+ @runner.step(:step_1) {}
555
+ @runner.step(:step_2) {}
556
+
557
+ @runner.after_each_step :except => [:step_2] {|s| executed << s.name}
558
+ @runner.run
559
+
560
+ executed.should == [:step_1]
561
+ end
562
+ end
563
+
564
+ describe "result status" do
565
+
566
+ it "should be success if all steps were performed" do
567
+ @runner.step(:step_1) {}
568
+ @runner.step(:step_2) {}
569
+
570
+ @runner.run
571
+
572
+ @runner.status.should == :success
573
+ end
574
+
575
+ it "should be failure if all steps were performed" do
576
+ @runner.step(:step_1) {}
577
+ @runner.step(:step_2) {}.validate {false}
578
+
579
+ @runner.run
580
+
581
+ @runner.status.should == :failure
582
+ end
583
+
584
+ end
585
+ end