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.
- checksums.yaml +4 -4
- data/History.txt +4 -2
- data/README.md +12 -12
- data/bin/rutema +4 -4
- data/lib/rutema/application.rb +34 -31
- data/lib/rutema/core/configuration.rb +123 -117
- data/lib/rutema/core/engine.rb +101 -113
- data/lib/rutema/core/framework.rb +54 -54
- data/lib/rutema/core/objectmodel.rb +101 -90
- data/lib/rutema/core/parser.rb +8 -8
- data/lib/rutema/core/reporter.rb +78 -68
- data/lib/rutema/core/runner.rb +116 -97
- data/lib/rutema/elements/minimal.rb +29 -25
- data/lib/rutema/parsers/xml.rb +100 -93
- data/lib/rutema/reporters/json.rb +18 -20
- data/lib/rutema/reporters/junit.rb +88 -80
- data/lib/rutema/version.rb +1 -1
- metadata +7 -7
|
@@ -1,35 +1,33 @@
|
|
|
1
1
|
# Copyright (c) 2007-2021 Vassilis Rizopoulos. All rights reserved.
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "json"
|
|
4
4
|
require_relative "../core/reporter"
|
|
5
5
|
|
|
6
6
|
module Rutema
|
|
7
7
|
module Reporters
|
|
8
|
-
#Experimental reporter used to dump the data of a run on disk
|
|
8
|
+
# Experimental reporter used to dump the data of a run on disk
|
|
9
9
|
#
|
|
10
|
-
#The following configuration keys are used by Rutema::Reporters::JSON
|
|
10
|
+
# The following configuration keys are used by Rutema::Reporters::JSON
|
|
11
11
|
#
|
|
12
12
|
# filename - the filename to use to save the YAML dump. Default is 'rutema.results.json'
|
|
13
|
-
class JSON<Rutema::Reporters::BlockReporter
|
|
14
|
-
#Default report filename
|
|
15
|
-
DEFAULT_FILENAME="rutema.results.json"
|
|
13
|
+
class JSON < Rutema::Reporters::BlockReporter
|
|
14
|
+
# Default report filename
|
|
15
|
+
DEFAULT_FILENAME = "rutema.results.json".freeze
|
|
16
16
|
|
|
17
|
-
def initialize
|
|
18
|
-
super
|
|
19
|
-
@filename=configuration.reporters.fetch(self.class,{}).fetch("filename",DEFAULT_FILENAME)
|
|
17
|
+
def initialize(configuration, dispatcher)
|
|
18
|
+
super
|
|
19
|
+
@filename = configuration.reporters.fetch(self.class, {}).fetch("filename", DEFAULT_FILENAME)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
#We get all the data from a test run in here.
|
|
23
|
-
def report
|
|
24
|
-
run_entry={}
|
|
25
|
-
run_entry["specs"]=specs.size
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
run_entry
|
|
31
|
-
|
|
32
|
-
Rutema::Utilities.write_file(@filename,::JSON.dump(run_entry))
|
|
22
|
+
# We get all the data from a test run in here.
|
|
23
|
+
def report(specs, states, errors)
|
|
24
|
+
run_entry = {}
|
|
25
|
+
run_entry["specs"] = specs.size
|
|
26
|
+
run_entry["context"] = @configuration.context if @configuration&.context
|
|
27
|
+
run_entry["errors"] = errors
|
|
28
|
+
run_entry["states"] = states
|
|
29
|
+
|
|
30
|
+
Rutema::Utilities.write_file(@filename, ::JSON.dump(run_entry))
|
|
33
31
|
end
|
|
34
32
|
end
|
|
35
33
|
end
|
|
@@ -1,121 +1,129 @@
|
|
|
1
1
|
# Copyright (c) 2015-2021 Vassilis Rizopoulos. All rights reserved.
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "rexml/document"
|
|
4
4
|
require_relative "../core/reporter"
|
|
5
5
|
|
|
6
6
|
module Rutema
|
|
7
7
|
module Reporters
|
|
8
|
-
#This reporter generates an JUnit style XML result file that can be parsed by CI plugins
|
|
8
|
+
# This reporter generates an JUnit style XML result file that can be parsed by CI plugins
|
|
9
9
|
#
|
|
10
|
-
#It has been tested with Jenkins (>1.6.20)
|
|
10
|
+
# It has been tested with Jenkins (>1.6.20)
|
|
11
11
|
#
|
|
12
|
-
#The following configuration keys are used by Rutema::Reporters::JUnit
|
|
12
|
+
# The following configuration keys are used by Rutema::Reporters::JUnit
|
|
13
13
|
#
|
|
14
14
|
# filename - the filename to use when saving the report. Default is 'rutema.results.junit.xml'
|
|
15
15
|
#
|
|
16
|
-
#Example configuration:
|
|
16
|
+
# Example configuration:
|
|
17
17
|
#
|
|
18
18
|
# require "rutema/reporters/junit"
|
|
19
19
|
# cfg.reporter={:class=>Rutema::Reporters::JUnit,"filename"=>"rutema.junit.xml"}
|
|
20
|
-
class JUnit<BlockReporter
|
|
21
|
-
DEFAULT_FILENAME="rutema.results.junit.xml"
|
|
20
|
+
class JUnit < BlockReporter
|
|
21
|
+
DEFAULT_FILENAME = "rutema.results.junit.xml".freeze
|
|
22
22
|
|
|
23
|
-
def initialize
|
|
24
|
-
super
|
|
25
|
-
@filename=configuration.reporters.fetch(self.class,{}).fetch("filename",DEFAULT_FILENAME)
|
|
23
|
+
def initialize(configuration, dispatcher)
|
|
24
|
+
super
|
|
25
|
+
@filename = configuration.reporters.fetch(self.class, {}).fetch("filename", DEFAULT_FILENAME)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
#We get all the data from a test run in here.
|
|
29
|
-
def report
|
|
30
|
-
cnt=process_data(specs,states,errors)
|
|
31
|
-
Rutema::Utilities.write_file(@filename,cnt)
|
|
28
|
+
# We get all the data from a test run in here.
|
|
29
|
+
def report(specs, states, errors)
|
|
30
|
+
cnt = process_data(specs, states, errors)
|
|
31
|
+
Rutema::Utilities.write_file(@filename, cnt)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
def process_data
|
|
35
|
-
tests=[]
|
|
36
|
-
number_of_failed=0
|
|
37
|
-
total_duration=0
|
|
38
|
-
states.each do |k,v|
|
|
39
|
-
tests<<test_case(k,v)
|
|
40
|
-
number_of_failed+=1 if v.status
|
|
41
|
-
total_duration+=v.duration.to_f
|
|
34
|
+
def process_data(specs, states, errors)
|
|
35
|
+
tests = []
|
|
36
|
+
number_of_failed = 0
|
|
37
|
+
total_duration = 0
|
|
38
|
+
states.each do |k, v|
|
|
39
|
+
tests << test_case(k, v)
|
|
40
|
+
number_of_failed += 1 if v.status != :success
|
|
41
|
+
total_duration += v.duration.to_f
|
|
42
42
|
end
|
|
43
|
-
|
|
44
|
-
#name="" package="" skipped="" tests="" time="" timestamp="">
|
|
45
|
-
attributes={"id"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return junit_content(tests,attributes,errors)
|
|
43
|
+
# <testsuite disabled="0" errors="0" failures="1" hostname="" id=""
|
|
44
|
+
# name="" package="" skipped="" tests="" time="" timestamp="">
|
|
45
|
+
attributes = { "id" => @configuration.context[:config_name],
|
|
46
|
+
"name" => @configuration.context[:config_name],
|
|
47
|
+
"errors" => errors.size,
|
|
48
|
+
"failures" => number_of_failed,
|
|
49
|
+
"tests" => specs.size,
|
|
50
|
+
"time" => total_duration,
|
|
51
|
+
"timestamp" => @configuration.context[:start_time] }
|
|
52
|
+
return junit_content(tests, attributes, errors)
|
|
54
53
|
end
|
|
55
54
|
|
|
56
55
|
private
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
element_test=REXML::Element.new("testcase")
|
|
67
|
-
element_test.add_attributes("name"=>name,"time"=>state.duration,"classname"
|
|
68
|
-
if state.status
|
|
69
|
-
failed_steps = state.steps.select {|step| !step.status.nil? && STATUS_CODES.find_index(:success) < STATUS_CODES.find_index(step.status)}
|
|
70
|
-
if
|
|
71
|
-
|
|
72
|
-
fail=REXML::Element.new("failure")
|
|
73
|
-
fail.add_attribute("message","Step: #{step.text} reported non-success status: #{step.status}.")
|
|
74
|
-
fail.add_text "Step #{step.number} failed."
|
|
75
|
-
element_test.add_element(fail)
|
|
76
|
-
out=REXML::Element.new("system-out")
|
|
77
|
-
out.add_text step.out
|
|
78
|
-
element_test.add_element(out)
|
|
79
|
-
err=REXML::Element.new("system-err")
|
|
80
|
-
err.add_text step.err
|
|
81
|
-
element_test.add_element(err)
|
|
82
|
-
end
|
|
57
|
+
# <testcase name="" time=""> => the results from executing a test method
|
|
58
|
+
# <system-out> => data written to System.out during the test run
|
|
59
|
+
# <system-err> => data written to System.err during the test run
|
|
60
|
+
# <skipped/> => test was skipped
|
|
61
|
+
# <failure> => test failed
|
|
62
|
+
# <error> => test encountered an error
|
|
63
|
+
# </testcase>
|
|
64
|
+
def test_case(name, state)
|
|
65
|
+
element_test = REXML::Element.new("testcase")
|
|
66
|
+
element_test.add_attributes("name" => name, "time" => state.duration, "classname" => @configuration.context[:config_name])
|
|
67
|
+
if state.status != :success
|
|
68
|
+
failed_steps = state.steps.select { |step| !step.status.nil? && STATUS_CODES.find_index(:success) < STATUS_CODES.find_index(step.status) }
|
|
69
|
+
if failed_steps.empty?
|
|
70
|
+
add_unmatched_failure(element_test, state)
|
|
83
71
|
else
|
|
84
|
-
|
|
85
|
-
fail.add_text "Case with #{state.steps.last.number} steps failed with no matching failed step."
|
|
86
|
-
element_test.add_element(fail)
|
|
87
|
-
out=REXML::Element.new("system-out")
|
|
88
|
-
out.add_text state.steps.last.out
|
|
89
|
-
element_test.add_element(out)
|
|
90
|
-
err=REXML::Element.new("system-err")
|
|
91
|
-
err.add_text state.steps.last.err
|
|
92
|
-
element_test.add_element(err)
|
|
72
|
+
add_failed_steps(element_test, failed_steps)
|
|
93
73
|
end
|
|
94
74
|
end
|
|
95
75
|
return element_test
|
|
96
76
|
end
|
|
97
77
|
|
|
98
|
-
def
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
78
|
+
def add_unmatched_failure(element_test, state)
|
|
79
|
+
failure_element = REXML::Element.new("failure")
|
|
80
|
+
failure_element.add_attribute("message", "Case reported non-success status: #{state.status} without a matching step state.")
|
|
81
|
+
failure_element.add_text "Case with #{state.steps.last.number} steps failed with no matching failed step."
|
|
82
|
+
element_test.add_element(failure_element)
|
|
83
|
+
out = REXML::Element.new("system-out")
|
|
84
|
+
out.add_text state.steps.last.out
|
|
85
|
+
element_test.add_element(out)
|
|
86
|
+
err = REXML::Element.new("system-err")
|
|
87
|
+
err.add_text state.steps.last.err
|
|
88
|
+
element_test.add_element(err)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def add_failed_steps(element_test, failed_steps)
|
|
92
|
+
failed_steps.each do |step|
|
|
93
|
+
failure_element = REXML::Element.new("failure")
|
|
94
|
+
failure_element.add_attribute("message", "Step: #{step.text} reported non-success status: #{step.status}.")
|
|
95
|
+
failure_element.add_text "Step #{step.number} failed."
|
|
96
|
+
element_test.add_element(failure_element)
|
|
97
|
+
out = REXML::Element.new("system-out")
|
|
98
|
+
out.add_text step.out
|
|
99
|
+
element_test.add_element(out)
|
|
100
|
+
err = REXML::Element.new("system-err")
|
|
101
|
+
err.add_text step.err
|
|
102
|
+
element_test.add_element(err)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def crash(name, message)
|
|
107
|
+
failed = REXML::Element.new("testcase")
|
|
108
|
+
failed.add_attributes("name" => name, "classname" => @configuration.context[:config_name], "time" => 0)
|
|
109
|
+
msg = REXML::Element.new("error")
|
|
110
|
+
msg.add_attribute("message", message)
|
|
103
111
|
msg.add_text message
|
|
104
112
|
failed.add_element(msg)
|
|
105
113
|
return failed
|
|
106
114
|
end
|
|
107
115
|
|
|
108
|
-
def junit_content
|
|
109
|
-
element_suite=REXML::Element.new("testsuite")
|
|
110
|
-
element_suite.add_attributes(attributes)
|
|
111
|
-
errors.each{|error| element_suite.add_element(crash(error.test,error.text))}
|
|
112
|
-
tests.each{|t| element_suite.add_element(t)}
|
|
116
|
+
def junit_content(tests, attributes, errors)
|
|
117
|
+
element_suite = REXML::Element.new("testsuite")
|
|
118
|
+
element_suite.add_attributes(attributes)
|
|
119
|
+
errors.each { |error| element_suite.add_element(crash(error.test, error.text)) }
|
|
120
|
+
tests.each { |t| element_suite.add_element(t) }
|
|
113
121
|
return document(element_suite).to_s
|
|
114
122
|
end
|
|
115
123
|
|
|
116
|
-
def document
|
|
117
|
-
xmldoc=REXML::Document.new
|
|
118
|
-
xmldoc<<REXML::XMLDecl.new
|
|
124
|
+
def document(suite)
|
|
125
|
+
xmldoc = REXML::Document.new
|
|
126
|
+
xmldoc << REXML::XMLDecl.new
|
|
119
127
|
xmldoc.add_element(suite)
|
|
120
128
|
return xmldoc
|
|
121
129
|
end
|
data/lib/rutema/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rutema
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0.
|
|
4
|
+
version: 2.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vassilis Rizopoulos
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: patir
|
|
@@ -16,28 +16,28 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '0.
|
|
19
|
+
version: '0.9'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '0.
|
|
26
|
+
version: '0.9'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: highline
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
33
|
+
version: '2.0'
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
40
|
+
version: '2.0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: rdoc
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -72,7 +72,7 @@ dependencies:
|
|
|
72
72
|
- - "~>"
|
|
73
73
|
- !ruby/object:Gem::Version
|
|
74
74
|
version: '4.6'
|
|
75
|
-
description:
|
|
75
|
+
description: |
|
|
76
76
|
rutema is a test execution tool and a framework for organizing and managing test execution across different tools.
|
|
77
77
|
It enables the combination of different test tools while it takes care of logging, reporting, archiving of results and formalizes execution of automated and manual tests.
|
|
78
78
|
It's purpose is to make testing in heterogeneous environments easier.
|