rutema 2.0.1 → 2.0.2

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,10 +1,9 @@
1
1
  # Copyright (c) 2007-2021 Vassilis Rizopoulos. All rights reserved.
2
2
 
3
- require 'thread'
4
- require_relative 'parser'
5
- require_relative 'reporter'
6
- require_relative 'runner'
7
- require_relative '../version'
3
+ require_relative "parser"
4
+ require_relative "reporter"
5
+ require_relative "runner"
6
+ require_relative "../version"
8
7
 
9
8
  module Rutema
10
9
  ##
@@ -29,21 +28,21 @@ module Rutema
29
28
  #
30
29
  # * +configuration+ - a Configuration instance according to which Engine,
31
30
  # its components and the test run shall be set up
32
- def initialize configuration
33
- @queue=Queue.new
34
- @parser=instantiate_class(configuration.parser,configuration) if configuration.parser
31
+ def initialize(configuration)
32
+ @queue = Queue.new
33
+ @parser = instantiate_class(configuration.parser, configuration) if configuration.parser
35
34
  if configuration.runner
36
- if configuration.runner[:class]
37
- @runner=configuration.runner[:class].new(configuration.context,@queue)
38
- else
39
- raise RutemaError,"Runner settting overriden, but missing :class"
40
- end
35
+ raise RutemaError, "Runner settting overriden, but missing :class" unless configuration.runner[:class]
36
+
37
+ @runner = configuration.runner[:class].new(configuration.context, @queue)
38
+
41
39
  else
42
- @runner=Rutema::Runners::Default.new(configuration.context,@queue)
40
+ @runner = Rutema::Runners::Default.new(configuration.context, @queue)
43
41
  end
44
- raise RutemaError,"Could not instantiate parser" unless @parser
45
- @dispatcher=Dispatcher.new(@queue,configuration)
46
- @configuration=configuration
42
+ raise RutemaError, "Could not instantiate parser" unless @parser
43
+
44
+ @dispatcher = Dispatcher.new(@queue, configuration)
45
+ @configuration = configuration
47
46
  end
48
47
 
49
48
  ##
@@ -52,18 +51,18 @@ module Rutema
52
51
  # * +test_identifier+ - an optional identifier of a single test case to be
53
52
  # executed, this cannot be an arbitrary one but must still be contained
54
53
  # in the configured test specification identifiers
55
- def run test_identifier=nil
54
+ def run(test_identifier = nil)
56
55
  @dispatcher.run!
57
56
  # start
58
57
  message("start")
59
- suite_setup,suite_teardown,setup,teardown,tests=*parse(test_identifier)
60
- if tests.empty?
58
+ suite_setup, suite_teardown, setup, teardown, tests = *parse(test_identifier)
59
+ if tests.empty?
61
60
  @dispatcher.exit
62
- raise RutemaError,"No tests to run!"
61
+ raise RutemaError, "No tests to run!"
63
62
  else
64
63
  # running - at this point all checks are done and the tests are active
65
64
  message("running")
66
- run_scenarios(tests,suite_setup,suite_teardown,setup,teardown)
65
+ run_scenarios(tests, suite_setup, suite_teardown, setup, teardown)
67
66
  end
68
67
  message("end")
69
68
  @dispatcher.exit
@@ -77,23 +76,23 @@ module Rutema
77
76
  # * +test_identifier+ - an optional identifier of a single test case to be
78
77
  # executed, this cannot be an arbitrary one but must still be contained
79
78
  # in the configured test specification identifiers
80
- def parse test_identifier=nil
81
- specs=[]
82
- #so, while we are parsing, we have a list of tests
83
- #we're either parsing all of the tests, or just one
84
- #make sure the one test is on the list
79
+ def parse(test_identifier = nil)
80
+ specs = []
81
+ # so, while we are parsing, we have a list of tests
82
+ # we're either parsing all of the tests, or just one
83
+ # make sure the one test is on the list
85
84
  if test_identifier
86
85
  if is_spec_included?(test_identifier)
87
- specs<<parse_specification(File.expand_path(test_identifier))
86
+ specs << parse_specification(File.expand_path(test_identifier))
88
87
  else
89
- error(File.expand_path(test_identifier),"does not exist in the configuration")
88
+ error(File.expand_path(test_identifier), "does not exist in the configuration")
90
89
  end
91
90
  else
92
- specs=parse_specifications(@configuration.tests)
91
+ specs = parse_specifications(@configuration.tests)
93
92
  end
94
93
  specs.compact!
95
- suite_setup,suite_teardown,setup,teardown=parse_specials(@configuration)
96
- return [suite_setup,suite_teardown,setup,teardown,specs]
94
+ suite_setup, suite_teardown, setup, teardown = parse_specials(@configuration)
95
+ return [suite_setup, suite_teardown, setup, teardown, specs]
97
96
  end
98
97
 
99
98
  private
@@ -103,8 +102,8 @@ module Rutema
103
102
  #
104
103
  # * +tests+ - an array containing paths to test specification files or the
105
104
  # test specifications' texts themselves
106
- def parse_specifications tests
107
- tests.map do |t|
105
+ def parse_specifications(tests)
106
+ tests.map do |t|
108
107
  parse_specification(t)
109
108
  end.compact
110
109
  end
@@ -116,13 +115,11 @@ module Rutema
116
115
  # actual test specification text itself
117
116
  #
118
117
  # A ParserError is raised upon failure.
119
- def parse_specification spec_identifier
120
- begin
121
- @parser.parse_specification(spec_identifier)
122
- rescue Rutema::ParserError
123
- error(spec_identifier,$!.message)
124
- raise Rutema::ParserError, "In #{spec_identifier}: #{$!.message}"
125
- end
118
+ def parse_specification(spec_identifier)
119
+ @parser.parse_specification(spec_identifier)
120
+ rescue Rutema::ParserError
121
+ error(spec_identifier, $!.message)
122
+ raise Rutema::ParserError, "In #{spec_identifier}: #{$!.message}"
126
123
  end
127
124
 
128
125
  ##
@@ -133,24 +130,16 @@ module Rutema
133
130
  # * test suite teardown
134
131
  # * test setup
135
132
  # * test teardown
136
- def parse_specials configuration
137
- suite_setup=nil
138
- suite_teardown=nil
139
- setup=nil
140
- teardown=nil
141
- if configuration.suite_setup
142
- suite_setup=parse_specification(configuration.suite_setup)
143
- end
144
- if configuration.suite_teardown
145
- suite_teardown=parse_specification(configuration.suite_teardown)
146
- end
147
- if configuration.setup
148
- setup=parse_specification(configuration.setup)
149
- end
150
- if configuration.teardown
151
- teardown=parse_specification(configuration.teardown)
152
- end
153
- return suite_setup,suite_teardown,setup,teardown
133
+ def parse_specials(configuration)
134
+ suite_setup = nil
135
+ suite_teardown = nil
136
+ setup = nil
137
+ teardown = nil
138
+ suite_setup = parse_specification(configuration.suite_setup) if configuration.suite_setup
139
+ suite_teardown = parse_specification(configuration.suite_teardown) if configuration.suite_teardown
140
+ setup = parse_specification(configuration.setup) if configuration.setup
141
+ teardown = parse_specification(configuration.teardown) if configuration.teardown
142
+ return suite_setup, suite_teardown, setup, teardown
154
143
  end
155
144
 
156
145
  ##
@@ -162,7 +151,7 @@ module Rutema
162
151
  # * +suite_teardown+ - a test suite teardown Specification instance
163
152
  def run_scenarios(specs, suite_setup, suite_teardown, setup, teardown)
164
153
  if specs.empty?
165
- error(nil,"No tests to run")
154
+ error(nil, "No tests to run")
166
155
  else
167
156
  @runner.setup = nil
168
157
  @runner.teardown = nil
@@ -170,7 +159,7 @@ module Rutema
170
159
  if !suite_setup || (run_test(suite_setup, true) == :success)
171
160
  @runner.setup = setup
172
161
  @runner.teardown = teardown
173
- specs.each{|spec| run_test(spec)}
162
+ specs.each { |spec| run_test(spec) }
174
163
  else
175
164
  error(nil, "Suite setup test failed")
176
165
  end
@@ -182,41 +171,39 @@ module Rutema
182
171
  end
183
172
  end
184
173
 
185
- ##
186
- #
187
174
  def run_test(specification, is_special = false)
188
175
  if specification.scenario
189
176
  status = @runner.run(specification, is_special)["status"]
190
177
  else
191
- status=:not_executed
192
- message(:test=>specification.name,:text=>"No scenario", :status=>status)
178
+ status = :not_executed
179
+ message(:test => specification.name, :text => "No scenario", :status => status)
193
180
  end
194
181
  return status
195
182
  end
196
183
 
197
- ##
198
184
  # Instantiate a new class of a given type passing it a given configuration
199
185
  # upon construction
200
186
  #
201
187
  # * +definition+ - class of which a new instance shall be instantiated
202
188
  # * +configuration+ - Configuration instance which shall be passed to the
203
189
  # initializer of the to be created instance
204
- def instantiate_class definition,configuration
190
+ def instantiate_class(definition, configuration)
205
191
  if definition[:class]
206
- klass=definition[:class]
192
+ klass = definition[:class]
207
193
  return klass.new(configuration)
208
194
  end
209
195
  return nil
210
196
  end
211
197
 
198
+ # rubocop:disable Naming/PredicatePrefix
212
199
  ##
213
200
  # Check if the given test identifier belongs to the normal test cases or to
214
201
  # one of the special ones (the test (suite) setups and teardowns)
215
202
  #
216
203
  # * +test_identifier+ - the test identifier to check against membership in
217
204
  # the normal or special test case identifier sets
218
- def is_spec_included? test_identifier
219
- full_path=File.expand_path(test_identifier)
205
+ def is_spec_included?(test_identifier)
206
+ full_path = File.expand_path(test_identifier)
220
207
  return @configuration.tests.include?(full_path) || is_special?(test_identifier)
221
208
  end
222
209
 
@@ -228,23 +215,24 @@ module Rutema
228
215
  #
229
216
  # * +test_identifier+ - the test identifier which shall be checked for being
230
217
  # a special one
231
- def is_special? test_identifier
232
- full_path=File.expand_path(test_identifier)
233
- return full_path==@configuration.suite_setup ||
234
- full_path==@configuration.suite_teardown ||
235
- full_path==@configuration.setup ||
236
- full_path==@configuration.teardown
218
+ def is_special?(test_identifier)
219
+ full_path = File.expand_path(test_identifier)
220
+ return full_path == @configuration.suite_setup ||
221
+ full_path == @configuration.suite_teardown ||
222
+ full_path == @configuration.setup ||
223
+ full_path == @configuration.teardown
237
224
  end
238
225
  end
239
226
 
227
+ # rubocop:enable Naming/PredicatePrefix
240
228
  ##
241
- # Class functioning as a demultiplexer between the Engine and the various
229
+ # Class functioning as a de-multiplexer between the Engine and the various
242
230
  # Reporters instances
243
231
  #
244
232
  # In stream mode the incoming queue is popped periodically and the messages
245
233
  # are distributed to the queues of any subscribed event reporters. By default
246
234
  # this includes Reporters::Collector which is then used at the end of a run to
247
- # provide the collected data to all registered block mode reporters
235
+ # provide the collected data to all registered block mode reporters
248
236
  class Dispatcher
249
237
  ##
250
238
  # The interval between queue operations
@@ -257,19 +245,19 @@ module Rutema
257
245
  # * +queue+ - the queue which will be shared between the Engine instance and
258
246
  # the Reporter instances
259
247
  # * +configuration+ - the Configuration instance of the rutema run
260
- def initialize queue,configuration
248
+ def initialize(queue, configuration)
261
249
  @queue = queue
262
250
  @queues = {}
263
- @streaming_reporters=[]
264
- @block_reporters=[]
265
- @collector=Rutema::Reporters::Collector.new(nil,self)
251
+ @streaming_reporters = []
252
+ @block_reporters = []
253
+ @collector = Rutema::Reporters::Collector.new(nil, self)
266
254
  if configuration.reporters
267
- instances=configuration.reporters.values.map{|v| instantiate_reporter(v,configuration) if v[:class] != Reporters::Summary}.compact
268
- @streaming_reporters,_=instances.partition{|rep| rep.respond_to?(:update)}
269
- @block_reporters,_=instances.partition{|rep| rep.respond_to?(:report)}
255
+ instances = configuration.reporters.values.map { |v| instantiate_reporter(v, configuration) if v[:class] != Reporters::Summary }.compact
256
+ @streaming_reporters, = instances.partition { |rep| rep.respond_to?(:update) }
257
+ @block_reporters, = instances.partition { |rep| rep.respond_to?(:report) }
270
258
  end
271
- @streaming_reporters<<@collector
272
- @configuration=configuration
259
+ @streaming_reporters << @collector
260
+ @configuration = configuration
273
261
  end
274
262
 
275
263
  ##
@@ -281,8 +269,8 @@ module Rutema
281
269
  #
282
270
  # * +identifier+ - a unique identifier for the queue. If two identifiers
283
271
  # collide the new subscriber will replace the earlier one
284
- def subscribe identifier
285
- @queues[identifier]=Queue.new
272
+ def subscribe(identifier)
273
+ @queues[identifier] = Queue.new
286
274
  return @queues[identifier]
287
275
  end
288
276
 
@@ -292,10 +280,10 @@ module Rutema
292
280
  # incoming queue
293
281
  def run!
294
282
  puts "Running #{@streaming_reporters.size} streaming reporters" if $DEBUG
295
- @streaming_reporters.each {|r| r.run!}
296
- @thread=Thread.new do
297
- while true do
298
- dispatch()
283
+ @streaming_reporters.each(&:run!)
284
+ @thread = Thread.new do
285
+ loop do
286
+ dispatch
299
287
  sleep INTERVAL
300
288
  end
301
289
  end
@@ -303,11 +291,11 @@ module Rutema
303
291
 
304
292
  ##
305
293
  # Call all block reporters' BlockReporter#report method
306
- def report specs
294
+ def report(specs)
307
295
  @block_reporters.each do |r|
308
- r.report(specs,@collector.states,@collector.errors)
296
+ r.report(specs, @collector.states, @collector.errors)
309
297
  end
310
- Reporters::Summary.new(@configuration,self).report(specs,@collector.states,@collector.errors)
298
+ Reporters::Summary.new(@configuration, self).report(specs, @collector.states, @collector.errors)
311
299
  end
312
300
 
313
301
  ##
@@ -316,11 +304,11 @@ module Rutema
316
304
  # dispatch thread
317
305
  def exit
318
306
  puts "Exiting main dispatcher" if $DEBUG
319
- if @thread
320
- flush
321
- @streaming_reporters.each {|r| r.exit}
322
- Thread.kill(@thread)
323
- end
307
+ return unless @thread
308
+
309
+ flush
310
+ @streaming_reporters.each(&:exit)
311
+ Thread.kill(@thread)
324
312
  end
325
313
 
326
314
  private
@@ -330,11 +318,11 @@ module Rutema
330
318
  # incoming queue is empty
331
319
  def flush
332
320
  puts "Flushing queues" if $DEBUG
333
- if @thread
334
- while @queue.size>0 do
335
- dispatch()
336
- sleep INTERVAL
337
- end
321
+ return unless @thread
322
+
323
+ until @queue.empty?
324
+ dispatch
325
+ sleep INTERVAL
338
326
  end
339
327
  end
340
328
 
@@ -349,10 +337,10 @@ module Rutema
349
337
  #
350
338
  # This either returns the new class instance or _nil_ if the passed hash
351
339
  # did not contain a key +:class+
352
- def instantiate_reporter definition,configuration
340
+ def instantiate_reporter(definition, configuration)
353
341
  if definition[:class]
354
- klass=definition[:class]
355
- return klass.new(configuration,self)
342
+ klass = definition[:class]
343
+ return klass.new(configuration, self)
356
344
  end
357
345
  return nil
358
346
  end
@@ -362,10 +350,10 @@ module Rutema
362
350
  # empty) and distribute it to all subscribed Reporters::EventReporter
363
351
  # instances
364
352
  def dispatch
365
- if @queue.size>0
366
- data=@queue.pop
367
- @queues.each{ |i,q| q.push(data) } if data
368
- end
353
+ return if @queue.empty?
354
+
355
+ data = @queue.pop
356
+ @queues.each_value { |q| q.push(data) } if data
369
357
  end
370
358
  end
371
359
  end
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) 2021 Vassilis Rizopoulos. All rights reserved.
2
2
 
3
3
  module Rutema
4
- STATUS_CODES=[:started,:skipped,:success,:warning,:error]
4
+ STATUS_CODES = [:not_executed, :started, :skipped, :success, :warning, :error].freeze
5
5
 
6
6
  ##
7
7
  # Simple base for classes concerned with message passing to report test
@@ -32,19 +32,19 @@ module Rutema
32
32
  # * +:text+ - the text of the message
33
33
  # * +:timestamp+ - most often the timestamp of the creation of the message,
34
34
  # defaults to +Time.now+
35
- def initialize params
36
- @test=params.fetch(:test,"")
37
- @test||=""
38
- @text=params.fetch(:text,"")
39
- @timestamp=params.fetch(:timestamp,Time.now)
35
+ def initialize(params)
36
+ @test = params.fetch(:test, "")
37
+ @test ||= ""
38
+ @text = params.fetch(:text, "")
39
+ @timestamp = params.fetch(:timestamp, Time.now)
40
40
  end
41
41
 
42
42
  ##
43
43
  # Convert the instance to a convenient textual representation
44
44
  def to_s
45
- msg=""
46
- msg<<"#{@test} " unless @test.empty?
47
- msg<<@text
45
+ msg = ""
46
+ msg << "#{@test} " unless @test.empty?
47
+ msg << @text
48
48
  return msg
49
49
  end
50
50
  end
@@ -55,13 +55,13 @@ module Rutema
55
55
  # The reported on errors may concern the test specifications, parser errors or
56
56
  # errors which occurred during test execution. Logic errors of rutema itself
57
57
  # are not reported by means of this class.
58
- class ErrorMessage<Message
58
+ class ErrorMessage < Message
59
59
  ##
60
60
  # Convert the instance to a convenient textual representation
61
61
  def to_s
62
- msg="ERROR - "
63
- msg<<"#{@test} " unless @test.empty?
64
- msg<<@text
62
+ msg = "ERROR - "
63
+ msg << "#{@test} " unless @test.empty?
64
+ msg << @text
65
65
  return msg
66
66
  end
67
67
  end
@@ -73,7 +73,7 @@ module Rutema
73
73
  # These messages inform about the progress of test execution. Test errors are
74
74
  # propagated through instances of this class as well. If it's an engine error
75
75
  # (e.g. during parsing), then an ErrorMessage will be used in that case.
76
- class RunnerMessage<Message
76
+ class RunnerMessage < Message
77
77
  attr_accessor :duration, :status, :number, :out, :err, :is_special
78
78
 
79
79
  ##
@@ -85,58 +85,58 @@ module Rutema
85
85
  # * "status" - the status of the respective step
86
86
  # * +:timestamp+ - most often the timestamp of the creation of the message,
87
87
  # defaults to +Time.now+
88
- def initialize params
89
- super(params)
90
- @duration=params.fetch("duration",0)
91
- @status=params.fetch("status",:none)
92
- @number=params.fetch("number",1)
93
- @out=params.fetch("out","")
94
- @err=params.fetch("err","")
95
- @backtrace=params.fetch("backtrace","")
96
- @is_special=params.fetch("is_special","")
88
+ def initialize(params)
89
+ super
90
+ @duration = params.fetch("duration", 0)
91
+ @status = params.fetch("status", :none)
92
+ @number = params.fetch("number", 1)
93
+ @out = params.fetch("out", "")
94
+ @err = params.fetch("err", "")
95
+ @backtrace = params.fetch("backtrace", [])
96
+ @is_special = params.fetch("is_special", "")
97
97
  end
98
98
 
99
99
  ##
100
100
  # Convert the instance to a convenient textual representation
101
101
  def to_s
102
- msg="#{@test}:"
103
- msg<<" #{@timestamp.strftime("%H:%M:%S")} :"
104
- msg<<"#{@text}." unless @text.empty?
105
- outpt=output()
106
- msg<<" Output" + (outpt.empty? ? "." : ":\n#{outpt}") # unless outpt.empty? || @status!=:error
102
+ msg = "#{@test}:"
103
+ msg << " #{@timestamp.strftime("%H:%M:%S")} :"
104
+ msg << "#{@text}." unless @text.empty?
105
+ outpt = output
106
+ msg << " Output:\n#{outpt}" unless outpt.empty? || @status != :error
107
107
  return msg
108
108
  end
109
109
 
110
110
  def output
111
- msg=""
112
- msg<<"#{@out}\n" unless @out.empty?
113
- msg<<@err unless @err.empty?
114
- msg<<"\n" + (@backtrace.kind_of?(Array) ? @backtrace.join("\n") : @backtrace) unless @backtrace.empty?
111
+ msg = ""
112
+ msg << "#{@out}\n" unless @out.empty?
113
+ msg << @err unless @err.empty?
114
+ msg << "\n#{@backtrace.is_a?(Array) ? @backtrace.join("\n") : @backtrace}" unless @backtrace.empty?
115
115
  return msg.chomp
116
116
  end
117
117
  end
118
118
 
119
- #While executing tests the state of each test is collected in an
120
- #instance of ReportState and the collection is at the end passed to the available block reporters
119
+ # While executing tests the state of each test is collected in an
120
+ # instance of ReportState and the collection is at the end passed to the available block reporters
121
121
  #
122
- #ReportState assumes the timestamp of the first message, the status of the last message
123
- #and accumulates the duration reported by all messages in it's collection.
122
+ # ReportState assumes the timestamp of the first message, the status of the last message
123
+ # and accumulates the duration reported by all messages in it's collection.
124
124
  class ReportState
125
125
  attr_accessor :steps
126
126
  attr_reader :test, :timestamp, :duration, :status, :is_special
127
-
128
- def initialize message
129
- @test=message.test
130
- @timestamp=message.timestamp
131
- @duration=message.duration
132
- @status=message.status
133
- @steps=[message]
134
- @is_special=message.is_special
127
+
128
+ def initialize(message)
129
+ @test = message.test
130
+ @timestamp = message.timestamp
131
+ @duration = message.duration
132
+ @status = message.status
133
+ @steps = [message]
134
+ @is_special = message.is_special
135
135
  end
136
136
 
137
137
  def <<(message)
138
- @steps<<message
139
- @duration+=message.duration
138
+ @steps << message
139
+ @duration += message.duration
140
140
  @status = message.status unless message.status.nil? \
141
141
  || (!@status.nil? && STATUS_CODES.find_index(message.status) < STATUS_CODES.find_index(@status))
142
142
  end
@@ -153,8 +153,8 @@ module Rutema
153
153
  # * +identifier+ - in most cases this would be the name of a test or its
154
154
  # specification file
155
155
  # * +message+ - a short descriptive message detailing the error condition
156
- def error identifier,message
157
- @queue.push(ErrorMessage.new(:test=>identifier,:text=>message,:timestamp=>Time.now))
156
+ def error(identifier, message)
157
+ @queue.push(ErrorMessage.new(:test => identifier, :text => message, :timestamp => Time.now))
158
158
  end
159
159
 
160
160
  ##
@@ -164,14 +164,14 @@ module Rutema
164
164
  # queue. If it's of type Hash it will be passed to the initializer of
165
165
  # RunnerMessage if it has both the keys :test and "status" or to the
166
166
  # initializer of Message if not so.
167
- def message message
167
+ def message(message)
168
168
  case message
169
169
  when String
170
- @queue.push(Message.new(:text=>message,:timestamp=>Time.now))
170
+ @queue.push(Message.new(:text => message, :timestamp => Time.now))
171
171
  when Hash
172
- hm=Message.new(message)
173
- hm=RunnerMessage.new(message) if message[:test] && message["status"]
174
- hm.timestamp=Time.now
172
+ hm = Message.new(message)
173
+ hm = RunnerMessage.new(message) if message[:test] && message["status"]
174
+ hm.timestamp = Time.now
175
175
  @queue.push(hm)
176
176
  end
177
177
  end
@@ -185,7 +185,7 @@ module Rutema
185
185
  # * ParserError
186
186
  # * ReportError
187
187
  # * RunnerError
188
- class RutemaError<RuntimeError
188
+ class RutemaError < RuntimeError
189
189
  end
190
190
 
191
191
  ##