lopata 0.1.24 → 0.1.26

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54faa8989dbb2e3f1750b060fe05982116ba534a50e6be067d267d0bb7849fc9
4
- data.tar.gz: 4b49ac34fa702f1784f4e23fde2d7da205474619c7ac6190cb0ce73fab1f9520
3
+ metadata.gz: c48d8c35ec3fbda8e6e707ec75a4d48c98a7e0733a4156869e932a00cadb6a10
4
+ data.tar.gz: 70ef965bafbf052815cd06f9807f1ac209dd06668e7fe17dabee4684e7066885
5
5
  SHA512:
6
- metadata.gz: 5fb1d7e3ca67d547272e868cddbaa68e7c8ec6c2cc03c617e0e81cd3d6607fca1d914a11d0834fd0eeb259b36ccd80bc4b3e787fdb153abd94a86316f7315482
7
- data.tar.gz: 4ce12c440f2e757f94863d9769a2b2532680d50942d24979ef5b6a49fb9cbb68647f388ca3ab648767a04683cce05484421bd2d2c550e758eaf8e85c353e0433
6
+ metadata.gz: 9547b0ce6a37588e0fac9a3f0c899502e755e17caf753eac1bdcaba8dbf2119b2d5ddcda3897b8450cecc03b9796a1b2234bd3f09ebe4e442501cc7f79f62410
7
+ data.tar.gz: f1c6e073a0dce8cfdd22182214fddb5ff88acef2771df288bf8109333533506a941db6e9d3111553e7ea5dea2dba05b21d096924dc424dee6dfea1f5d7cd147d
@@ -1,5 +1,4 @@
1
1
  require_relative 'backtrace_formatter'
2
- require_relative 'group_tree'
3
2
  require 'forwardable'
4
3
 
5
4
  module Lopata
@@ -34,25 +33,27 @@ module Lopata
34
33
  statuses[scenario.status] ||= 0
35
34
  statuses[scenario.status] += 1
36
35
 
37
- if scenario.failed?
38
- GroupTree.steps_hierarhy(scenario.steps).walk_through do |step|
39
- if step.is_a?(Lopata::StepExecution)
40
- next unless step.loggable?
41
- puts colored(" #{status_marker(step.status)} #{step.title}", step.status)
42
- puts indent(4, backtrace_formatter.error_message(step.exception, include_backtrace: true)) if step.failed?
43
- else # GroupTree
44
- group = step
45
- if %i{ passed skipped }.include?(group.status)
46
- puts colored(" #{status_marker(group.status)} #{group.title}", group.status)
47
- false
48
- else
49
- true
50
- end
36
+ log_steps(scenario.steps) if scenario.failed?
37
+
38
+ flush
39
+ end
40
+
41
+ # @private
42
+ def log_steps(steps)
43
+ steps.each do |step|
44
+ next unless step.loggable?
45
+ if step.group?
46
+ status = step.status
47
+ if %i{ passed skipped ignored }.include?(status)
48
+ puts colored(" #{status_marker(step.status)} #{step.title}", status)
49
+ else
50
+ log_steps(step.steps)
51
51
  end
52
+ else
53
+ puts colored(" #{status_marker(step.status)} #{step.title}", step.status)
54
+ puts indent(4, backtrace_formatter.error_message(step.exception, include_backtrace: true)) if step.failed?
52
55
  end
53
56
  end
54
-
55
- flush
56
57
  end
57
58
 
58
59
  private
@@ -61,7 +62,7 @@ module Lopata
61
62
  case status
62
63
  when :failed then red(text)
63
64
  when :passed then green(text)
64
- when :skipped then cyan(text)
65
+ when :skipped, :ignored then cyan(text)
65
66
  when :pending then yellow(text)
66
67
  else text
67
68
  end
@@ -1,7 +1,6 @@
1
1
  require 'httparty'
2
2
  require 'json'
3
3
  require_relative 'backtrace_formatter'
4
- require_relative 'group_tree'
5
4
 
6
5
  module Lopata
7
6
  module Observers
@@ -49,24 +48,7 @@ module Lopata
49
48
 
50
49
  def add_attempt(scenario, finished)
51
50
  status = scenario.failed? ? Lopata::FAILED : Lopata::PASSED
52
- steps = []
53
- GroupTree.steps_hierarhy(scenario.steps).walk_through do |step|
54
- if step.is_a?(Lopata::StepExecution)
55
- next unless step.loggable?
56
- steps << step_hash(step)
57
- else # GroupTree
58
-
59
- group = step
60
- if %i{ passed skipped }.include?(group.status)
61
- steps << group_hash(group)
62
- false
63
- else
64
- true
65
- end
66
- end
67
- end
68
-
69
- steps = scenario.steps.select(&:loggable?).map { |s| step_hash(s) }
51
+ steps = build_hashes(scenario.steps)
70
52
  request = { status: status, steps: steps, launch: { id: @launch_id, finished: finished } }
71
53
  test = test_id(scenario)
72
54
  post("/tests/#{test}/attempts.json", body: request)
@@ -76,6 +58,23 @@ module Lopata
76
58
  puts e.backtrace
77
59
  end
78
60
 
61
+ def build_hashes(steps)
62
+ hashes = []
63
+ steps.each do |step|
64
+ next unless step.loggable?
65
+ if step.group?
66
+ if %i{ passed skipped ignored }.include?(step.status)
67
+ hashes << group_hash(step)
68
+ else
69
+ hashes += build_hashes(step.steps)
70
+ end
71
+ else
72
+ hashes << step_hash(step)
73
+ end
74
+ end
75
+ hashes
76
+ end
77
+
79
78
  def step_hash(step)
80
79
  hash = { status: step.status, title: step.title }
81
80
  if step.failed?
@@ -45,8 +45,9 @@ class Lopata::Scenario
45
45
 
46
46
  # @private
47
47
  def method_missing(method, *args, &block)
48
- if execution.let_methods.include?(method)
49
- execution.let_methods[method].call_in_scenario(self, *args)
48
+
49
+ if (let_method = execution.find_let_method(method))
50
+ let_method.call_in_scenario(self, *args)
50
51
  elsif metadata.keys.include?(method)
51
52
  metadata[method]
52
53
  else
@@ -56,21 +57,18 @@ class Lopata::Scenario
56
57
 
57
58
  # @private
58
59
  def respond_to_missing?(method, *)
59
- execution.let_methods.include?(method) or metadata.keys.include?(method) or super
60
+ execution.find_let_method(method) or metadata.keys.include?(method) or super
60
61
  end
61
62
 
62
63
  # @private
63
64
  # Scenario execution and live-cycle information
64
65
  class Execution
65
- attr_reader :scenario, :status, :steps, :title, :current_step
66
-
67
- def initialize(title, options_title, metadata = {})
68
- @title = [title, options_title].compact.reject(&:empty?).join(' ')
69
- @metadata = metadata
70
- @let_methods = {}
71
- @status = :not_runned
72
- @steps = []
66
+ attr_reader :scenario, :current_step, :top
67
+
68
+ def initialize(title, metadata = {})
73
69
  @scenario = Lopata::Scenario.new(self)
70
+ @top = Lopata::GroupExecution.new(Lopata::TopStep.new(title, metadata: metadata), nil, steps: [])
71
+ @current_step = @top
74
72
  end
75
73
 
76
74
  # Provide a human-readable representation of this class
@@ -79,32 +77,42 @@ class Lopata::Scenario
79
77
  end
80
78
  alias to_s inspect
81
79
 
80
+ def steps
81
+ top.steps
82
+ end
83
+
82
84
  def run
83
- @status = :running
84
- sort_steps
85
85
  world.notify_observers(:scenario_started, self)
86
- steps.each(&method(:run_step))
87
- @status = steps.any?(&:failed?) ? :failed : :passed
86
+ run_step(top)
88
87
  world.notify_observers(:scenario_finished, self)
89
88
  cleanup
90
89
  end
91
90
 
92
91
  def run_step(step)
93
- return if step.skipped? || step.ignored?
94
- groups = step.groups
95
- if groups.length > 0 && groups != @current_groups
96
- @current_groups = groups
97
- condition = groups.last.condition
98
- if condition&.dynamic? && !condition.match_dynamic?(scenario)
99
- step.ignored!
100
- ignore_groups(groups)
101
- return
92
+ @current_step = step
93
+ return :skipped if step.skipped?
94
+ return :ignored if step.ignored?
95
+ if step.condition&.dynamic && !step.condition.match_dynamic?(scenario)
96
+ step.ignored!
97
+ return :ignored
98
+ end
99
+ if step.group?
100
+ skip_rest = false
101
+ step.steps.each do
102
+ if _1.teardown?
103
+ run_step(_1)
104
+ elsif skip_rest
105
+ _1.skip!
106
+ else
107
+ run_step(_1)
108
+ skip_rest = true if _1.failed? && _1.skip_rest_on_failure?
109
+ end
102
110
  end
111
+ step.status!
112
+ else
113
+ step.run(scenario)
114
+ step.status
103
115
  end
104
- @current_step = step
105
- step.run(scenario)
106
- skip_rest if step.failed? && step.skip_rest_on_failure?
107
- @current_step = nil
108
116
  end
109
117
 
110
118
  def world
@@ -115,55 +123,47 @@ class Lopata::Scenario
115
123
  status == :failed
116
124
  end
117
125
 
118
- def sort_steps
119
- @steps = steps.reject(&:teardown_group?) + steps.select(&:teardown_group?)
126
+ def metadata
127
+ current_step.metadata
120
128
  end
121
129
 
122
- def skip_rest
123
- steps.select { |s| s.status == :not_runned && !s.teardown? }.each(&:skip!)
130
+ def let_methods
131
+ current_step.let_methods
124
132
  end
125
133
 
126
- def ignore_groups(groups)
127
- steps.select { _1.status == :not_runned && _1.groups.take(groups.length) == groups }.each(&:ignored!)
134
+ def find_let_method(name)
135
+ current_step.find_let_method(name)
128
136
  end
129
137
 
130
- def metadata
131
- if current_step
132
- @metadata.merge(current_step.metadata)
133
- else
134
- @metadata
135
- end
138
+ def title
139
+ top.title
136
140
  end
137
141
 
138
- def let_methods
139
- if current_step
140
- @let_methods.merge(current_step.let_methods)
141
- else
142
- @let_methods
143
- end
142
+ def status
143
+ top.status
144
144
  end
145
145
 
146
146
  def let_base
147
- if current_step && !current_step.groups.empty?
148
- current_step.groups.last.let_methods
147
+ if current_step.group?
148
+ current_step
149
149
  else
150
- @let_methods
150
+ current_step.parent
151
151
  end
152
152
  end
153
153
 
154
154
  def let(method_name, &block)
155
- let_base[method_name] = LetMethod.new(&block)
155
+ let_base.add_let_method(method_name, LetMethod.new(&block))
156
156
  end
157
157
 
158
158
  def let!(method_name, &block)
159
- let_base[method_name] = LetBangMethod.new(&block)
159
+ let_base.add_let_method(method_name, LetBangMethod.new(&block))
160
160
  end
161
161
 
162
162
  def cleanup
163
163
  @title = nil
164
- @metadata = nil
165
- @steps = nil
166
164
  @scenario = nil
165
+ @top = nil
166
+ @current_step = nil
167
167
  end
168
168
  end
169
169
 
@@ -38,16 +38,20 @@ class Lopata::ScenarioBuilder
38
38
  filters = Lopata.configuration.filters
39
39
  option_combinations.each do |option_set|
40
40
  metadata = common_metadata.merge(option_set.metadata)
41
- scenario = Lopata::Scenario::Execution.new(title, option_set.title, metadata)
42
-
41
+ scenario_title = [title, option_set.title].compact.reject(&:empty?).join(' ')
42
+ scenario = Lopata::Scenario::Execution.new(scenario_title, metadata)
43
+
43
44
  unless filters.empty?
44
45
  next unless filters.all? { |f| f[scenario] }
45
46
  end
46
47
 
48
+ exec_steps = []
47
49
  steps_with_hooks.each do |step|
48
50
  next if step.condition && !step.condition.match?(scenario)
49
- step.execution_steps(scenario).each { |s| scenario.steps << s }
51
+ step.execution_steps(scenario, parent: scenario.top).each { |s| exec_steps << s }
50
52
  end
53
+ scenario.steps.push(*exec_steps.reject(&:teardown?))
54
+ scenario.steps.push(*exec_steps.select(&:teardown?))
51
55
 
52
56
  world.scenarios << scenario
53
57
  end
data/lib/lopata/step.rb CHANGED
@@ -7,12 +7,13 @@ module Lopata
7
7
  # metadata overrien by the step.
8
8
  attr_accessor :metadata
9
9
 
10
- def initialize(method_name, *args, condition: nil, shared_step: nil, &block)
10
+ def initialize(method_name, *args, condition: nil, shared_step: nil, metadata: {}, &block)
11
11
  @method_name = method_name
12
12
  @args = args
13
13
  @block = block
14
14
  @shared_step = shared_step
15
15
  @condition = condition
16
+ @metadata = metadata
16
17
  initialized! if defined? initialized!
17
18
  end
18
19
 
@@ -22,31 +23,31 @@ module Lopata
22
23
  base_title
23
24
  end
24
25
 
25
- def execution_steps(scenario, groups: [])
26
+ def execution_steps(scenario, parent:)
26
27
  return [] if condition && !condition.match?(scenario)
27
28
  return [] unless block
28
- [StepExecution.new(self, groups, condition: condition, &block)]
29
+ [StepExecution.new(self, parent, condition: condition, &block)]
29
30
  end
30
31
  end
31
32
 
32
33
  # @private
33
34
  # Used for action, setup, teardown, verify
34
35
  class ActionStep < Step
35
- def execution_steps(scenario, groups: [])
36
+ def execution_steps(scenario, parent:)
36
37
  steps = []
37
38
  return steps if condition && !condition.match?(scenario)
38
39
  convert_args(scenario).each do |step|
39
40
  if step.is_a?(String)
40
41
  Lopata::SharedStep.find(step).steps.each do |shared_step|
41
42
  next if shared_step.condition && !shared_step.condition.match?(scenario)
42
- steps += shared_step.execution_steps(scenario, groups: groups)
43
+ steps += shared_step.execution_steps(scenario, parent: parent)
43
44
  end
44
45
  elsif step.is_a?(Proc)
45
- steps << StepExecution.new(self, groups, condition: condition, &step)
46
+ steps << StepExecution.new(self, parent, condition: condition, &step)
46
47
  end
47
48
  end
48
- steps << StepExecution.new(self, groups, condition: condition, &block) if block
49
- steps.reject { |s| !s.block }
49
+ steps << StepExecution.new(self, parent, condition: condition, &block) if block
50
+ steps
50
51
  end
51
52
 
52
53
  def separate_args(args)
@@ -74,26 +75,18 @@ module Lopata
74
75
  # Used for context
75
76
  class GroupStep < Step
76
77
 
77
- def execution_steps(scenario, groups: [])
78
+ def execution_steps(scenario, parent: nil)
78
79
  steps = []
79
80
  return steps if condition && !condition.match?(scenario)
81
+ group = GroupExecution.new(self, parent, steps: steps, condition: condition)
80
82
  @steps.each do |step|
81
- steps += step.execution_steps(scenario, groups: groups + [self])
83
+ steps += step.execution_steps(scenario, parent: group)
82
84
  end
83
- steps.reject! { |s| !s.block }
84
- steps.reject { |s| s.teardown_group?(self) } + steps.select { |s| s.teardown_group?(self) }
85
+ group.steps.push(*steps.reject(&:teardown?))
86
+ group.steps.push(*steps.select(&:teardown?))
87
+ [group]
85
88
  end
86
89
 
87
- def let_methods
88
- @let_methods ||= {}
89
- end
90
-
91
- def let_bang_methods
92
- @let_bang_methods ||= {}
93
- end
94
-
95
- private
96
-
97
90
  # Group step's block is a block in context of builder, not scenario. So hide the @block to not be used in scenario.
98
91
  def initialized!
99
92
  builder = Lopata::ScenarioBuilder.new(title)
@@ -103,70 +96,60 @@ module Lopata
103
96
  end
104
97
  end
105
98
 
106
- #@private
107
- class StepExecution
108
- attr_reader :step, :status, :exception, :block, :pending_message, :groups, :condition
99
+ # @private
100
+ class TopStep < Step
101
+ def initialize(title, metadata: {})
102
+ super(:top, title, metadata: metadata)
103
+ end
104
+ end
105
+
106
+ # @private
107
+ # Abstract execution step. Composition, may be group or step.
108
+ class BaseExecution
109
+ attr_reader :step, :status, :parent, :condition
109
110
  extend Forwardable
110
111
  def_delegators :step, :method_name
111
112
 
112
- class PendingStepFixedError < StandardError; end
113
-
114
- def initialize(step, groups, condition: nil, &block)
113
+ def initialize(step, parent, condition: nil)
115
114
  @step = step
115
+ @parent = parent
116
116
  @status = :not_runned
117
- @exception = nil
118
- @block = block
119
- @groups = groups
120
117
  @condition = condition
121
118
  end
122
119
 
123
- def title
124
- "#{group_title}#{step.title}"
120
+ def group?
121
+ false
125
122
  end
126
123
 
127
- def group_title
128
- groups.map { |g| "#{g.title}: " }.join
124
+ def top?
125
+ !parent
129
126
  end
130
127
 
131
- def run(scenario)
132
- @status = :running
133
- begin
134
- unless check_dynamic_condition?(scenario)
135
- @status = :ignored
136
- return
137
- end
138
- run_step(scenario)
139
- if pending?
140
- @status = :failed
141
- raise PendingStepFixedError, 'Expected step to fail since it is pending, but it passed.'
142
- else
143
- @status = :passed
144
- end
145
- rescue Exception => e
146
- @status = :failed unless pending?
147
- @exception = e
148
- end
128
+ def teardown?
129
+ %i{ teardown cleanup }.include?(method_name)
149
130
  end
150
131
 
151
- def run_step(scenario)
152
- return unless block
153
- scenario.instance_exec(&block)
132
+ def parents
133
+ result = []
134
+ prnt = parent
135
+ while prnt
136
+ result << prnt
137
+ prnt = prnt.parent
138
+ end
139
+ result
154
140
  end
155
141
 
156
- def check_dynamic_condition?(scenario)
157
- dynamic_conditions.each do
158
- return false unless _1.match_dynamic?(scenario)
142
+ # Step metadata is a combination of metadata given for step and all contexts (groups) the step included
143
+ def metadata
144
+ result = step.metadata || {}
145
+ if parent
146
+ result = parent.metadata.merge(result)
159
147
  end
160
- true
148
+ result
161
149
  end
162
150
 
163
- def dynamic_conditions
164
- conds = []
165
- conds << condition if condition&.dynamic?
166
- groups.each do
167
- conds << _1.condition if _1.condition&.dynamic?
168
- end
169
- conds
151
+ def find_let_method(name)
152
+ parent&.find_let_method(name)
170
153
  end
171
154
 
172
155
  def failed?
@@ -193,13 +176,12 @@ module Lopata
193
176
  @status = :skipped
194
177
  end
195
178
 
196
- def pending?
197
- status == :pending
198
- end
199
-
200
- def pending!(message = nil)
201
- @status = :pending
202
- @pending_message = message
179
+ def title
180
+ if parent && !parent.top?
181
+ "#{parent.title}: #{step.title}"
182
+ else
183
+ step.title
184
+ end
203
185
  end
204
186
 
205
187
  # Need log this step.
@@ -208,35 +190,96 @@ module Lopata
208
190
  not %i{ let let! }.include?(method_name)
209
191
  end
210
192
 
211
- def teardown?
212
- %i{ teardown cleanup }.include?(method_name)
193
+ def skip_rest_on_failure?
194
+ %i{ setup action }.include?(method_name)
213
195
  end
196
+ end
197
+
198
+ # @private
199
+ class GroupExecution < BaseExecution
200
+ attr_reader :steps
214
201
 
215
- def teardown_group?(group = nil)
216
- teardown? && self.groups.last == group
202
+ def initialize(step, parent, condition: nil, steps:)
203
+ super(step, parent, condition: condition)
204
+ @steps = steps
205
+ @let_methods = {}
217
206
  end
218
207
 
219
- def in_group?(group)
220
- groups.include?(group)
208
+ def group?
209
+ true
221
210
  end
222
211
 
223
- def skip_rest_on_failure?
224
- %i{ setup action }.include?(method_name)
212
+ def status!
213
+ # return @status if @status
214
+ statuses = steps.map(&:status!).uniq
215
+ @status =
216
+ if statuses.length == 1
217
+ statuses.first
218
+ elsif statuses.include?(:failed)
219
+ :failed
220
+ else
221
+ statuses.first || :skipped
222
+ end
223
+ @status = :passed if @status == :pending
224
+ @status
225
225
  end
226
226
 
227
- # Step metadata is a combination of metadata given for step and all contexts (groups) the step included
228
- def metadata
229
- (groups + [step]).compact.inject({}) { |merged, part| merged.merge(part.metadata) }
227
+ def find_let_method(name)
228
+ @let_methods[name] || parent&.find_let_method(name)
229
+ end
230
+
231
+ def add_let_method(name, method)
232
+ @let_methods[name] = method
233
+ end
234
+
235
+ def ignored!
236
+ @status = :ignored
237
+ steps.each(&:ignored!)
238
+ end
239
+ end
240
+
241
+ # @private
242
+ class StepExecution < BaseExecution
243
+ attr_reader :exception, :block, :pending_message
244
+
245
+ class PendingStepFixedError < StandardError; end
246
+
247
+ def initialize(step, parent, condition: nil, &block)
248
+ super(step, parent, condition: condition)
249
+ @exception = nil
250
+ @block = block
251
+ end
252
+
253
+ alias status! status
254
+
255
+ def run(scenario)
256
+ @status = :running
257
+ begin
258
+ run_step(scenario)
259
+ if pending?
260
+ @status = :failed
261
+ raise PendingStepFixedError, 'Expected step to fail since it is pending, but it passed.'
262
+ else
263
+ @status = :passed
264
+ end
265
+ rescue Exception => e
266
+ @status = :failed unless pending?
267
+ @exception = e
268
+ end
269
+ end
270
+
271
+ def run_step(scenario)
272
+ return unless block
273
+ scenario.instance_exec(&block)
230
274
  end
231
275
 
232
- # Step methods is a combination of let_methods for all contexts (group) the step included
233
- def let_methods
234
- (groups).compact.inject({}) { |merged, part| merged.merge(part.let_methods) }
276
+ def pending?
277
+ status == :pending
235
278
  end
236
279
 
237
- # Step bang methods is a combination of let_bang_methods for all contexts (group) the step included
238
- def let_bang_methods
239
- (groups).compact.inject({}) { |merged, part| merged.merge(part.let_bang_methods) }
280
+ def pending!(message = nil)
281
+ @status = :pending
282
+ @pending_message = message
240
283
  end
241
284
  end
242
285
  end
@@ -1,6 +1,6 @@
1
1
  module Lopata
2
2
  # @private
3
3
  module Version
4
- STRING = '0.1.24'
4
+ STRING = '0.1.26'
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lopata
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.24
4
+ version: 0.1.26
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexey Volochnev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-09-05 00:00:00.000000000 Z
11
+ date: 2023-09-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -107,7 +107,6 @@ files:
107
107
  - lib/lopata/observers/backtrace_formatter.rb
108
108
  - lib/lopata/observers/base_observer.rb
109
109
  - lib/lopata/observers/console_output_observer.rb
110
- - lib/lopata/observers/group_tree.rb
111
110
  - lib/lopata/observers/web_logger.rb
112
111
  - lib/lopata/role.rb
113
112
  - lib/lopata/runner.rb
@@ -139,5 +138,5 @@ requirements: []
139
138
  rubygems_version: 3.2.15
140
139
  signing_key:
141
140
  specification_version: 4
142
- summary: lopata-0.1.24
141
+ summary: lopata-0.1.26
143
142
  test_files: []
@@ -1,64 +0,0 @@
1
- module Lopata
2
- GroupTree = Struct.new(:group, :items, :title) do
3
- def status
4
- # return @status if @status
5
- statuses = items.map(&:status).uniq
6
- @status =
7
- if statuses.length == 1
8
- statuses.first
9
- elsif statuses.include?(:failed)
10
- :failed
11
- elsif
12
- statuses.first
13
- end
14
- @status
15
- end
16
-
17
- # Returns steps hierarhy: Group with nestet setps or groups
18
- def self.steps_hierarhy(steps)
19
- top = GroupTree.new(nil, [], '')
20
- hierarhy = [top]
21
- current_groups = []
22
- steps.each do |step|
23
- if step.groups == current_groups
24
- hierarhy.last.items << step
25
- else
26
- # ensure hierarhy to is in current step tree - remove from hierary all groups not in new tree.
27
- while hierarhy.last.group && !step.groups.include?(hierarhy.last.group)
28
- hierarhy.pop
29
- end
30
- if hierarhy.last.group == step.groups.last
31
- hierarhy.last.items << step
32
- else
33
- group_rest = step.groups.dup
34
- while hierarhy.last.group && group_rest.first != hierarhy.last.group
35
- group_rest.shift
36
- end
37
- group_rest.shift if group_rest.first == hierarhy.last.group
38
- group_rest.each do
39
- title = (hierarhy.map(&:group).compact + [_1]).map(&:title).join(': ')
40
- group = GroupTree.new(_1, [], title)
41
- hierarhy.last.items << group
42
- hierarhy << group
43
- end
44
- hierarhy.last.items << step
45
- end
46
- current_groups = step.groups
47
- end
48
- end
49
- return top
50
- end
51
-
52
- def walk_through(&block)
53
- items.each do |step|
54
- if step.is_a?(Lopata::StepExecution)
55
- yield step
56
- else # GroupTree
57
- group = step
58
- go_dipper = yield group
59
- group.walk_through(&block) if go_dipper
60
- end
61
- end
62
- end
63
- end
64
- end