rung 0.0.1.pre.alpha → 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +72 -0
  3. data/.config/cucumber.yml +1 -0
  4. data/.gitignore +3 -0
  5. data/.rspec +0 -1
  6. data/.rubocop.yml +22 -0
  7. data/Gemfile +6 -2
  8. data/Gemfile.lock +23 -1
  9. data/README.adoc +111 -0
  10. data/Rakefile +19 -4
  11. data/features/{steps_definition.feature → 010_operation.feature} +29 -6
  12. data/features/{state.feature → 020_state.feature} +17 -4
  13. data/features/{failure.feature → 030_failure.feature} +29 -6
  14. data/features/040_failure_step.feature +118 -0
  15. data/features/050_other_steps.feature +135 -0
  16. data/features/051_fail_fast.feature +66 -0
  17. data/features/060_step_wrappers.feature +170 -0
  18. data/features/070_operation_wrappers.feature +41 -0
  19. data/features/080_exceptions_handling.feature +57 -0
  20. data/features/090_around_step_wrapper.feature +130 -0
  21. data/features/200_misc.feature +18 -0
  22. data/features/step_definitions/output.rb +8 -3
  23. data/features/step_definitions/temporary_code_scope.rb +8 -7
  24. data/lib/rung.rb +7 -6
  25. data/lib/rung/definition/callback.rb +14 -0
  26. data/lib/rung/definition/nested_step.rb +16 -0
  27. data/lib/rung/definition/operation_dsl.rb +31 -0
  28. data/lib/rung/definition/step.rb +43 -0
  29. data/lib/rung/definition/steps_dsl.rb +33 -18
  30. data/lib/rung/{base.rb → operation.rb} +3 -2
  31. data/lib/rung/runner/call_helper.rb +30 -12
  32. data/lib/rung/runner/run_context.rb +23 -6
  33. data/lib/rung/runner/runner.rb +34 -14
  34. data/lib/rung/state.rb +35 -0
  35. data/lib/rung/value_object.rb +12 -0
  36. data/lib/rung/version.rb +1 -1
  37. data/rung.gemspec +15 -16
  38. data/target/cukedoctor-intro.adoc +1 -0
  39. data/target/cukedoctor.css +3 -0
  40. metadata +39 -23
  41. data/README.md +0 -79
  42. data/lib/rung/definition/steps/nested_step.rb +0 -20
  43. data/lib/rung/definition/steps/step.rb +0 -30
  44. data/lib/rung/definition/steps_definition.rb +0 -13
  45. data/lib/rung/runner/result.rb +0 -24
  46. data/lib/rung/runner/run_state.rb +0 -12
@@ -0,0 +1,118 @@
1
+ # order: 40
2
+ Feature: Failure Step
3
+ :!hardbreaks:
4
+ When operations fails next normal steps are no ignored and not executed.
5
+
6
+ There's a way to react to a failure with special failure steps.
7
+
8
+ Failure steps can be defined similarly to normal steps (as a block, method, or a callable object).
9
+ They are *only* executed when operation has failed.
10
+
11
+ Scenario: Failure step is executed when operation fails
12
+ Given definition
13
+ """ruby
14
+ class Operation < Rung::Operation
15
+ step do
16
+ print_to_output "Working..."
17
+ # something went wrong...
18
+ false
19
+ end
20
+
21
+ failure do
22
+ print_to_output " Oops!"
23
+ end
24
+
25
+ step do
26
+ print_to_output "This won't be executed"
27
+ end
28
+ end
29
+ """
30
+ When I run
31
+ """
32
+ Operation.new.call
33
+ """
34
+ Then I see output
35
+ """
36
+ Working... Oops!
37
+ """
38
+
39
+ Scenario: Failure step is not executed when operation doesn't fail
40
+ Given definition
41
+ """ruby
42
+ class Operation < Rung::Operation
43
+ step do
44
+ print_to_output "Working..."
45
+ # everything's fine
46
+ true
47
+ end
48
+
49
+ failure do
50
+ print_to_output " Oops!"
51
+ end
52
+ end
53
+ """
54
+ When I run
55
+ """
56
+ Operation.new.call
57
+ """
58
+ Then I see output
59
+ """
60
+ Working...
61
+ """
62
+
63
+ Scenario: It's possible to define multiple failure steps
64
+ Given definition
65
+ """ruby
66
+ class Operation < Rung::Operation
67
+ step do |state|
68
+ print_to_output "Working..."
69
+ # something went wrong...
70
+ state[:error] = "404"
71
+ false
72
+ end
73
+
74
+ failure do
75
+ print_to_output " Error: "
76
+ end
77
+
78
+ failure do |state|
79
+ print_to_output state[:error]
80
+ end
81
+ end
82
+ """
83
+ When I run
84
+ """
85
+ Operation.new.call
86
+ """
87
+ Then I see output
88
+ """
89
+ Working... Error: 404
90
+ """
91
+
92
+ Scenario: Failure step is executed only when it's defined after failed step
93
+ Given definition
94
+ """ruby
95
+ class Operation < Rung::Operation
96
+ failure do
97
+ print_to_output "Something's wrong"
98
+ end
99
+
100
+ step do
101
+ print_to_output "Working..."
102
+ # something went wrong...
103
+ false
104
+ end
105
+
106
+ failure do
107
+ print_to_output " Oops!"
108
+ end
109
+ end
110
+ """
111
+ When I run
112
+ """
113
+ Operation.new.call
114
+ """
115
+ Then I see output
116
+ """
117
+ Working... Oops!
118
+ """
@@ -0,0 +1,135 @@
1
+ # order: 50
2
+ Feature: Other steps
3
+ :!hardbreaks:
4
+
5
+ `step` and `failure` are the basic step types.
6
+ For the convenience there are also two additional step
7
+ types defined:
8
+
9
+ * `tee` - works the same way as `step` but ignores the return value
10
+ * `always` - executes on both success and failure. Return value is not checked
11
+
12
+ .Table Step behaviours
13
+ |===
14
+ |Step name|Execute on success|Execute on failure|Ignore return value
15
+
16
+ |step|✓|✗|✗
17
+ |failure|✗|✓|✓
18
+ |tee|✓|✗|✓
19
+ |always|✓|✓|✓
20
+
21
+ Scenario: `tee` step result is not checked
22
+ Given definition
23
+ """ruby
24
+ class Operation < Rung::Operation
25
+ tee do
26
+ print_to_output "Hello "
27
+ false
28
+ end
29
+
30
+ step do
31
+ print_to_output "World!"
32
+ end
33
+ end
34
+ """
35
+ When I run
36
+ """
37
+ Operation.new.call
38
+ """
39
+ Then I see output
40
+ """
41
+ Hello World!
42
+ """
43
+
44
+ Scenario: `tee` is not executed when operation is failed
45
+ Given definition
46
+ """ruby
47
+ class Operation < Rung::Operation
48
+ step do
49
+ print_to_output "Hello"
50
+ false # fail
51
+ end
52
+
53
+ tee do
54
+ print_to_output "World!"
55
+ end
56
+ end
57
+ """
58
+ When I run
59
+ """
60
+ Operation.new.call
61
+ """
62
+ Then I see output
63
+ """
64
+ Hello
65
+ """
66
+
67
+
68
+ Scenario: `always` is called when operation is successful
69
+ Given definition
70
+ """ruby
71
+ class Operation < Rung::Operation
72
+ step do
73
+ print_to_output "Hello "
74
+ end
75
+
76
+ always do
77
+ print_to_output "World!"
78
+ end
79
+ end
80
+ """
81
+ When I run
82
+ """
83
+ Operation.new.call
84
+ """
85
+ Then I see output
86
+ """
87
+ Hello World!
88
+ """
89
+
90
+ Scenario: `always` is called when operation is failed
91
+ Given definition
92
+ """ruby
93
+ class Operation < Rung::Operation
94
+ step do
95
+ print_to_output "Hello "
96
+ false # fail
97
+ end
98
+
99
+ always do
100
+ print_to_output "World!"
101
+ end
102
+ end
103
+ """
104
+ When I run
105
+ """
106
+ Operation.new.call
107
+ """
108
+ Then I see output
109
+ """
110
+ Hello World!
111
+ """
112
+
113
+ Scenario: state object provides information about operation success with `success?` and `fail?`
114
+ Given definition
115
+ """ruby
116
+ class Operation < Rung::Operation
117
+ step do
118
+ print_to_output "Hello"
119
+ false # fail
120
+ end
121
+
122
+ always do |state|
123
+ print_to_output " World!" if state.success?
124
+ print_to_output " There!" if state.fail?
125
+ end
126
+ end
127
+ """
128
+ When I run
129
+ """
130
+ Operation.new.call
131
+ """
132
+ Then I see output
133
+ """
134
+ Hello There!
135
+ """
@@ -0,0 +1,66 @@
1
+ # order: 51
2
+ Feature: Fail fast
3
+ :!hardbreaks:
4
+ When a fail-fast step is executed and the operation is a failure then
5
+ no next step is executed, including `always` and `failure` steps.
6
+
7
+ It doesn't matter if a failure is caused by the fail-fast step itself or if it
8
+ was caused by any previous step, it behaves the same way.
9
+
10
+ Scenario: When step with `fail_fast` fails the execution is immediately stopped
11
+ Given definition
12
+ """ruby
13
+ class Operation < Rung::Operation
14
+ step(fail_fast: true) do
15
+ print_to_output "Hello"
16
+ false
17
+ end
18
+
19
+ step do
20
+ print_to_output " World!"
21
+ end
22
+ end
23
+ """
24
+ When I run
25
+ """
26
+ @result = Operation.new.call
27
+ """
28
+ Then I see output
29
+ """
30
+ Hello
31
+ """
32
+ And I can assure that
33
+ """
34
+ @result.failure?
35
+ """
36
+
37
+ Scenario: Any kind of step can use `fail_fast`
38
+ Given definition
39
+ """ruby
40
+ class Operation < Rung::Operation
41
+ step do
42
+ print_to_output "Hello"
43
+ false
44
+ end
45
+
46
+ failure fail_fast: true do
47
+ print_to_output "...Goodbye!"
48
+ end
49
+
50
+ step do
51
+ print_to_output " World!"
52
+ end
53
+ end
54
+ """
55
+ When I run
56
+ """
57
+ @result = Operation.new.call
58
+ """
59
+ Then I see output
60
+ """
61
+ Hello...Goodbye!
62
+ """
63
+ And I can assure that
64
+ """
65
+ @result.failure?
66
+ """
@@ -0,0 +1,170 @@
1
+ # order: 60
2
+ Feature: Step wrappers
3
+ :!hardbreaks:
4
+ It's possible to step around a group of successive steps.
5
+ This is a common use case for surrounding multiple steps in
6
+ a database transaction and rolling back when steps inside fail.
7
+
8
+ Steps wrapper is defined as a step (of any type, e.g. `step` or `tee`)
9
+ with callable wrapper-action and additional
10
+ block defining nested steps.
11
+
12
+ Wrapper-action is a Callable or method name.
13
+
14
+ Yielding the block calls inner steps. Yield returns `false` if
15
+ any of the inner steps failed or `true` otherwise.
16
+
17
+ Example usage:
18
+ ```ruby
19
+ class Operation < Rung::Operation
20
+ class TransactionWrapper
21
+ def self.call(state)
22
+ return if state.fail?
23
+ ActiveRecord::Base.transaction do
24
+ success = yield
25
+ raise ActiveRecord::Rollback unless success
26
+ true
27
+ end
28
+ end
29
+ end
30
+
31
+ step TransactionWrapper do
32
+ step :create_new_entity
33
+ step :update_counter
34
+ end
35
+ end
36
+ ```
37
+
38
+ Scenario: Wrapper can yield to execute inner steps
39
+ Given definition
40
+ """ruby
41
+ class Operation < Rung::Operation
42
+ class Wrapper
43
+ def self.call
44
+ print_to_output "Starting\n"
45
+ success = yield
46
+ if success
47
+ print_to_output "\nSuccess!"
48
+ else
49
+ print_to_output "\nFailure!"
50
+ end
51
+ end
52
+ end
53
+
54
+ step Wrapper do
55
+ step { print_to_output "Hello " }
56
+ step do |state|
57
+ print_to_output "World!"
58
+ state[:variable] # return variable passed by the user
59
+ end
60
+ end
61
+ end
62
+ """
63
+ When I run
64
+ """
65
+ Operation.new.call(variable: true)
66
+ """
67
+ Then I see output
68
+ """
69
+ Starting
70
+ Hello World!
71
+ Success!
72
+ """
73
+ Then I clear output
74
+ When I run
75
+ """
76
+ Operation.new.call(variable: false)
77
+ """
78
+ Then I see output
79
+ """
80
+ Starting
81
+ Hello World!
82
+ Failure!
83
+ """
84
+
85
+ Scenario: Wrappers can be nested
86
+ Given definition
87
+ """ruby
88
+ class Operation < Rung::Operation
89
+ class Wrapper
90
+ def initialize(name)
91
+ @name = name
92
+ end
93
+
94
+ def call
95
+ print_to_output "Starting #{@name}\n"
96
+ yield
97
+ print_to_output "Finishing #{@name}\n"
98
+ end
99
+ end
100
+
101
+ step Wrapper.new("first") do
102
+ step { print_to_output "Hello\n" }
103
+ step Wrapper.new("second") do
104
+ step { print_to_output "Hi\n" }
105
+ end
106
+ end
107
+ end
108
+ """
109
+ When I run
110
+ """
111
+ Operation.new.call
112
+ """
113
+ Then I see output
114
+ """
115
+ Starting first
116
+ Hello
117
+ Starting second
118
+ Hi
119
+ Finishing second
120
+ Finishing first
121
+
122
+ """
123
+
124
+ Scenario: step type is important when calling a wrapper
125
+ Given definition
126
+ """ruby
127
+ class Operation < Rung::Operation
128
+ class Wrapper
129
+ def initialize(name)
130
+ @name = name
131
+ end
132
+
133
+ def call
134
+ print_to_output "from: #{@name}\n"
135
+ yield
136
+ end
137
+ end
138
+
139
+ step do
140
+ print_to_output "RED ALERT\n"
141
+ false
142
+ end
143
+
144
+ step Wrapper.new("OK") do
145
+ step { print_to_output "Hurray!\n" }
146
+ end
147
+
148
+ failure Wrapper.new("FAIL") do
149
+ failure { print_to_output "Oops!\n" }
150
+ end
151
+
152
+ always Wrapper.new("ALWAYS") do
153
+ step { print_to_output "We're done!\n" }
154
+ failure { print_to_output "We're done, but something went wrong!\n" }
155
+ end
156
+ end
157
+ """
158
+ When I run
159
+ """
160
+ Operation.new.call(variable: true)
161
+ """
162
+ Then I see output
163
+ """
164
+ RED ALERT
165
+ from: FAIL
166
+ Oops!
167
+ from: ALWAYS
168
+ We're done, but something went wrong!
169
+
170
+ """