beaker 3.22.0 → 3.23.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.gitignore +3 -0
- data/beaker.gemspec +5 -8
- data/docs/how_to/debug_beaker_tests.md +404 -0
- data/docs/how_to/hypervisors/README.md +21 -4
- data/docs/tutorials/creating_a_test_environment.md +1 -10
- data/lib/beaker.rb +1 -1
- data/lib/beaker/dsl/structure.rb +11 -2
- data/lib/beaker/host/unix/pkg.rb +1 -1
- data/lib/beaker/logger_junit.rb +21 -21
- data/lib/beaker/options/command_line_parser.rb +6 -0
- data/lib/beaker/subcommand.rb +1 -0
- data/lib/beaker/test_suite.rb +1 -260
- data/lib/beaker/test_suite_result.rb +256 -0
- data/lib/beaker/version.rb +1 -1
- data/spec/beaker/logger_junit_spec.rb +3 -5
- data/spec/beaker/test_suite_spec.rb +20 -24
- metadata +44 -29
- data/docs/how_to/access_the_live_test_console_with_pry.md +0 -305
@@ -32,18 +32,23 @@ that are needed for it. An example `.fog` file is below:
|
|
32
32
|
|
33
33
|
# External Hypervisors
|
34
34
|
|
35
|
-
|
35
|
+
Puppet and its community have made several gems that support different
|
36
|
+
hypervisors with beaker, the reason for this is that we're looking to decrease Beaker's
|
36
37
|
dependency footprint, and hypervisors are one of the places where we can often
|
37
38
|
increase the load across all Beaker uses to benefit a small group that uses a
|
38
39
|
particular hypervisor.
|
39
40
|
|
40
|
-
In order to offset this, we've made a listing of gems and community-supported forks
|
41
|
+
In order to offset this, we've made a listing of gems and community-supported forks
|
42
|
+
that support other external hypervisors. Please check them out if you'd like to use
|
43
|
+
those hypervisors, hopefully it'll save you from spending time trying to support a
|
44
|
+
new hypervisor yourself.
|
41
45
|
|
42
|
-
Hypervisor gems made by puppet (pre-included in beaker 3.x):
|
46
|
+
### Hypervisor gems made by puppet (pre-included in beaker 3.x):
|
43
47
|
|
44
48
|
| Hypervisor | Fork |
|
45
49
|
| :----------------------: | :---------------------------------------------------------: |
|
46
50
|
| Vmpooler | [beaker-vmpooler](https://github.com/puppetlabs/beaker-vmpooler) |
|
51
|
+
| Vcloud | [beaker-vcloud](https://github.com/puppetlabs/beaker-vcloud) |
|
47
52
|
| AWS | [beaker-aws](https://github.com/puppetlabs/beaker-aws) |
|
48
53
|
| Vagrant | [beaker-vagrant](https://github.com/puppetlabs/beaker-vagrant) |
|
49
54
|
| VMware/Vsphere | [beaker-vmware](https://github.com/puppetlabs/beaker-vmware) |
|
@@ -51,7 +56,19 @@ Hypervisor gems made by puppet (pre-included in beaker 3.x):
|
|
51
56
|
| Openstack | [beaker-openstack](https://github.com/puppetlabs/beaker-openstack) |
|
52
57
|
| Google Compute | [beaker-google](https://github.com/puppetlabs/beaker-google) |
|
53
58
|
|
54
|
-
|
59
|
+
|
60
|
+
### beaker-abs
|
61
|
+
|
62
|
+
There is another hypervisor made and used internally by puppet,
|
63
|
+
[beaker-abs](https://github.com/puppetlabs/beaker-abs), but it isn't included
|
64
|
+
in beaker 3.x. If you'd like to use beaker-abs, you'll have to include it yourself.
|
65
|
+
|
66
|
+
You do that by requiring beaker-abs in your Gemfile as a sibling to beaker itself
|
67
|
+
and then using `abs` as your hypervisor value in your hosts file. Please check the
|
68
|
+
[beaker-abs README](https://github.com/puppetlabs/beaker-abs/blob/master/README.md)
|
69
|
+
for more information.
|
70
|
+
|
71
|
+
### Hypervisor gems and beaker forks made by community:
|
55
72
|
|
56
73
|
| Hypervisor | Fork |
|
57
74
|
|:------------:|:--------------------------------------------------------------------:|
|
@@ -83,13 +83,4 @@ The platform's format is `/^OSFAMILY-VERSION-ARCH.*$/` where `OSFAMILY` is one o
|
|
83
83
|
|
84
84
|
`VERSION`'s format is not enforced, but should reflect the `OSFAMILY` selected (ie, ubuntu-1204-i386-master, scientific-6-i386-agent, etc). `ARCH`'s format is also not enforced, but should be appropriate to the `OSFAMILY` selected (ie, ubuntu-1204-i386-master, sles-11-x86_64-master, debian-7-amd64-master, etc).
|
85
85
|
|
86
|
-
## Supported Virtualization Providers ##
|
87
|
-
* [AWS](../how_to/hypervisors/aws.md)
|
88
|
-
* [VMWare Fusion](../how_to/hypervisors/vmware_fusion.md)
|
89
|
-
* [EC2](../how_to/hypervisors/ec2.md)
|
90
|
-
* [vSphere](../how_to/hypervisors/vsphere.md)
|
91
|
-
* [Vagrant](../how_to/hypervisors/vagrant.md)
|
92
|
-
* [Google Compute Engine](../how_to/hypervisors/google_compute_engine.md)
|
93
|
-
* [Docker Support](../how_to/hypervisors/docker.md)
|
94
|
-
* [Openstack](../how_to/hypervisors/openstack.md)
|
95
|
-
* [Solaris](../how_to/hypervisors/solaris.md)
|
86
|
+
## [Supported Virtualization Providers](../how_to/hypervisors/README.md#external-hypervisors) ##
|
data/lib/beaker.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'rubygems' unless defined?(Gem)
|
2
2
|
module Beaker
|
3
3
|
|
4
|
-
%w( version platform test_suite result command options network_manager cli perf logger_junit subcommand ).each do |lib|
|
4
|
+
%w( version platform test_suite test_suite_result result command options network_manager cli perf logger_junit subcommand ).each do |lib|
|
5
5
|
begin
|
6
6
|
require "beaker/#{lib}"
|
7
7
|
rescue LoadError
|
data/lib/beaker/dsl/structure.rb
CHANGED
@@ -31,7 +31,7 @@ module Beaker
|
|
31
31
|
# end
|
32
32
|
#
|
33
33
|
module Structure
|
34
|
-
|
34
|
+
require 'pry'
|
35
35
|
# Provides a method to help structure tests into coherent steps.
|
36
36
|
# @param [String] step_name The name of the step to be logged.
|
37
37
|
# @param [Proc] block The actions to be performed in this step.
|
@@ -40,7 +40,16 @@ module Beaker
|
|
40
40
|
set_current_step_name(step_name)
|
41
41
|
if block_given?
|
42
42
|
logger.step_in()
|
43
|
-
|
43
|
+
begin
|
44
|
+
yield
|
45
|
+
rescue Exception => e
|
46
|
+
if(@options.has_key?(:debug_errors) && @options[:debug_errors] == true)
|
47
|
+
logger.info("Exception raised during step execution and debug-errors option is set, entering pry. Exception was: #{e.inspect}")
|
48
|
+
logger.info("HINT: Use the pry 'backtrace' and 'up' commands to navigate to the test code")
|
49
|
+
binding.pry
|
50
|
+
end
|
51
|
+
raise e
|
52
|
+
end
|
44
53
|
logger.step_out()
|
45
54
|
end
|
46
55
|
end
|
data/lib/beaker/host/unix/pkg.rb
CHANGED
@@ -74,7 +74,7 @@ module Unix::Pkg
|
|
74
74
|
def install_package(name, cmdline_args = '', version = nil, opts = {})
|
75
75
|
case self['platform']
|
76
76
|
when /sles-/
|
77
|
-
execute("zypper --non-interactive in #{name}", opts)
|
77
|
+
execute("zypper --non-interactive --gpg-auto-import-keys in #{name}", opts)
|
78
78
|
when /el-4/
|
79
79
|
@logger.debug("Package installation not supported on rhel4")
|
80
80
|
when /fedora-(2[2-9])/
|
data/lib/beaker/logger_junit.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
+
require 'rexml/document'
|
1
2
|
module Beaker
|
2
3
|
# The Beaker JUnit Logger class
|
3
4
|
# This module handles message reporting from Beaker to the JUnit format
|
4
5
|
#
|
5
6
|
# There is a specific pattern for using this class.
|
6
7
|
# Here's a list of example usages:
|
7
|
-
# - {Beaker::
|
8
|
+
# - {Beaker::TestSuiteResult#write_junit_xml}
|
8
9
|
module LoggerJunit
|
9
10
|
|
10
11
|
# writes the xml created in the block to the xml file given
|
@@ -34,14 +35,14 @@ module Beaker
|
|
34
35
|
|
35
36
|
# writes out xml content for a doc
|
36
37
|
#
|
37
|
-
# @param [
|
38
|
+
# @param [REXML::Document] doc doc containing content to write
|
38
39
|
# @param [String] xml_file Path to the xml file to write
|
39
40
|
#
|
40
41
|
# @return nil
|
41
42
|
def self.finish(doc, xml_file)
|
42
43
|
# junit/name.xml will be created in a directory relative to the CWD
|
43
|
-
|
44
|
-
File.open(xml_file, 'w') { |
|
44
|
+
|
45
|
+
File.open(xml_file, 'w') { |f| doc.write(f, 2) }
|
45
46
|
end
|
46
47
|
|
47
48
|
# gets the xml doc & suites in order to build your xml output on top of
|
@@ -50,8 +51,8 @@ module Beaker
|
|
50
51
|
# @param [String] name Name of the testsuite you're writing
|
51
52
|
# @param [String] stylesheet Path to the stylesheet file
|
52
53
|
#
|
53
|
-
# @return [
|
54
|
-
# @return [
|
54
|
+
# @return [REXML::Document] doc to use for your xml content
|
55
|
+
# @return [REXML::Element] suites to add your content to
|
55
56
|
def self.get_xml_contents(xml_file, name, stylesheet)
|
56
57
|
self.copy_stylesheet_into_xml_dir(stylesheet, xml_file)
|
57
58
|
xml_file_already_exists = File.file?(xml_file)
|
@@ -74,24 +75,23 @@ module Beaker
|
|
74
75
|
|
75
76
|
# sets up doc & gives us the suites for the testsuite named
|
76
77
|
#
|
77
|
-
# @param [
|
78
|
+
# @param [REXML::Document] doc Doc that you're getting suites from
|
78
79
|
# @param [String] name Testsuite node name
|
79
80
|
# @param [Boolean] already_existed Whether or not the doc already existed
|
80
81
|
#
|
81
|
-
# @return [
|
82
|
+
# @return [Rexml::Element] testsuites
|
82
83
|
def self.get_testsuites_from_doc(doc, name, already_existed)
|
83
84
|
#check to see if an output file already exists, if it does add or replace test suite data
|
84
85
|
if already_existed
|
85
|
-
suites =
|
86
|
+
suites = REXML::XPath.first(doc, "testsuites")
|
86
87
|
#remove old data
|
87
|
-
|
88
|
-
if
|
89
|
-
|
88
|
+
suites.elements.each("testsuite") do |e|
|
89
|
+
if e.name =~ /#{name}/
|
90
|
+
suites.delete_element e
|
90
91
|
end
|
91
92
|
end
|
92
93
|
else
|
93
|
-
suites
|
94
|
-
suites.parent = doc
|
94
|
+
suites = doc.add_element(REXML::Element.new('testsuites'))
|
95
95
|
end
|
96
96
|
return suites
|
97
97
|
end
|
@@ -102,16 +102,16 @@ module Beaker
|
|
102
102
|
# @param [String] stylesheet Path to the stylesheet for this doc
|
103
103
|
# @param [Boolean] already_exists Whether or not the file already exists
|
104
104
|
#
|
105
|
-
# @return [
|
105
|
+
# @return [REXML::Document] Doc that you want to write in
|
106
106
|
def self.get_doc_for_filename(filename, stylesheet, already_exists)
|
107
107
|
if already_exists
|
108
|
-
doc =
|
108
|
+
doc = REXML::Document.new File.open(filename)
|
109
109
|
else
|
110
110
|
#no existing file, create a new one
|
111
|
-
doc =
|
112
|
-
doc.encoding
|
113
|
-
|
114
|
-
|
111
|
+
doc = REXML::Document.new
|
112
|
+
doc << REXML::XMLDecl.new(version="1.0", encoding="UTF-8")
|
113
|
+
instruction_content = "type='text/xsl' href='#{File.basename(stylesheet)}'"
|
114
|
+
doc << REXML::Instruction.new(target="xml-stylesheet", content=instruction_content)
|
115
115
|
end
|
116
116
|
return doc
|
117
117
|
end
|
@@ -154,4 +154,4 @@ module Beaker
|
|
154
154
|
end
|
155
155
|
|
156
156
|
end
|
157
|
-
end
|
157
|
+
end
|
@@ -88,6 +88,12 @@ module Beaker
|
|
88
88
|
@cmd_options[:preserve_hosts] = mode || 'always'
|
89
89
|
end
|
90
90
|
|
91
|
+
opts.on '--debug-errors',
|
92
|
+
'Enter a pry console if or when a test fails',
|
93
|
+
'(default: false)' do |bool|
|
94
|
+
@cmd_options[:debug_errors] = bool
|
95
|
+
end
|
96
|
+
|
91
97
|
opts.on '--root-keys',
|
92
98
|
'Install puppetlabs pubkeys for superuser',
|
93
99
|
'(default: false)' do |bool|
|
data/lib/beaker/subcommand.rb
CHANGED
@@ -51,6 +51,7 @@ module Beaker
|
|
51
51
|
class_option :tag, :type => :string, :group => 'Beaker run'
|
52
52
|
class_option :'exclude-tags', :type => :string, :group => 'Beaker run'
|
53
53
|
class_option :'xml-time-order', :type => :boolean, :group => 'Beaker run'
|
54
|
+
class_option :'debug-errors', :type => :boolean, :group => 'Beaker run'
|
54
55
|
|
55
56
|
# The following are listed as deprecated in beaker --help, but needed now for
|
56
57
|
# feature parity for beaker 3.x.
|
data/lib/beaker/test_suite.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
-
require 'nokogiri'
|
3
2
|
require 'fileutils'
|
4
|
-
[ 'test_case', 'logger' ].each do |lib|
|
3
|
+
[ 'test_case', 'logger', 'test_suite_result'].each do |lib|
|
5
4
|
require "beaker/#{lib}"
|
6
5
|
end
|
7
6
|
|
@@ -10,264 +9,6 @@ module Beaker
|
|
10
9
|
#Handles executing the set of {TestCase} instances and reporting results as post summary text and JUnit XML.
|
11
10
|
class TestSuite
|
12
11
|
|
13
|
-
#Holds the output of a test suite, formats in plain text or xml
|
14
|
-
class TestSuiteResult
|
15
|
-
attr_accessor :start_time, :stop_time, :total_tests
|
16
|
-
|
17
|
-
#Create a {TestSuiteResult} instance.
|
18
|
-
#@param [Hash{Symbol=>String}] options Options for this object
|
19
|
-
#@option options [Logger] :logger The Logger object to report information to
|
20
|
-
#@param [String] name The name of the {TestSuite} that the results are for
|
21
|
-
def initialize( options, name )
|
22
|
-
@options = options
|
23
|
-
@logger = options[:logger]
|
24
|
-
@name = name
|
25
|
-
@test_cases = []
|
26
|
-
#Set some defaults, just in case you attempt to print without including them
|
27
|
-
start_time = Time.at(0)
|
28
|
-
stop_time = Time.at(1)
|
29
|
-
end
|
30
|
-
|
31
|
-
#Add a {TestCase} to this {TestSuiteResult} instance, used in calculating {TestSuiteResult} data.
|
32
|
-
#@param [TestCase] test_case An individual, completed {TestCase} to be included in this set of {TestSuiteResult}.
|
33
|
-
def add_test_case( test_case )
|
34
|
-
@test_cases << test_case
|
35
|
-
end
|
36
|
-
|
37
|
-
#How many {TestCase} instances are in this {TestSuiteResult}
|
38
|
-
def test_count
|
39
|
-
@test_cases.length
|
40
|
-
end
|
41
|
-
|
42
|
-
#How many passed {TestCase} instances are in this {TestSuiteResult}
|
43
|
-
def passed_tests
|
44
|
-
@test_cases.select { |c| c.test_status == :pass }.length
|
45
|
-
end
|
46
|
-
|
47
|
-
#How many errored {TestCase} instances are in this {TestSuiteResult}
|
48
|
-
def errored_tests
|
49
|
-
@test_cases.select { |c| c.test_status == :error }.length
|
50
|
-
end
|
51
|
-
|
52
|
-
#How many failed {TestCase} instances are in this {TestSuiteResult}
|
53
|
-
def failed_tests
|
54
|
-
@test_cases.select { |c| c.test_status == :fail }.length
|
55
|
-
end
|
56
|
-
|
57
|
-
#How many skipped {TestCase} instances are in this {TestSuiteResult}
|
58
|
-
def skipped_tests
|
59
|
-
@test_cases.select { |c| c.test_status == :skip }.length
|
60
|
-
end
|
61
|
-
|
62
|
-
#How many pending {TestCase} instances are in this {TestSuiteResult}
|
63
|
-
def pending_tests
|
64
|
-
@test_cases.select {|c| c.test_status == :pending}.length
|
65
|
-
end
|
66
|
-
|
67
|
-
#How many {TestCase} instances failed in this {TestSuiteResult}
|
68
|
-
def sum_failed
|
69
|
-
failed_tests + errored_tests
|
70
|
-
end
|
71
|
-
|
72
|
-
#Did all the {TestCase} instances in this {TestSuiteResult} pass?
|
73
|
-
def success?
|
74
|
-
sum_failed == 0
|
75
|
-
end
|
76
|
-
|
77
|
-
#Did one or more {TestCase} instances in this {TestSuiteResult} fail?
|
78
|
-
def failed?
|
79
|
-
!success?
|
80
|
-
end
|
81
|
-
|
82
|
-
#The sum of all {TestCase} runtimes in this {TestSuiteResult}
|
83
|
-
def elapsed_time
|
84
|
-
@test_cases.inject(0.0) {|r, t| r + t.runtime.to_f }
|
85
|
-
end
|
86
|
-
|
87
|
-
#Plain text summay of test suite
|
88
|
-
#@param [Logger] summary_logger The logger we will print the summary to
|
89
|
-
def summarize(summary_logger)
|
90
|
-
|
91
|
-
summary_logger.notify <<-HEREDOC
|
92
|
-
Test Suite: #{@name} @ #{start_time}
|
93
|
-
|
94
|
-
- Host Configuration Summary -
|
95
|
-
HEREDOC
|
96
|
-
|
97
|
-
average_test_time = elapsed_time / test_count
|
98
|
-
|
99
|
-
summary_logger.notify %Q[
|
100
|
-
|
101
|
-
- Test Case Summary for suite '#{@name}' -
|
102
|
-
Total Suite Time: %.2f seconds
|
103
|
-
Average Test Time: %.2f seconds
|
104
|
-
Attempted: #{test_count}
|
105
|
-
Passed: #{passed_tests}
|
106
|
-
Failed: #{failed_tests}
|
107
|
-
Errored: #{errored_tests}
|
108
|
-
Skipped: #{skipped_tests}
|
109
|
-
Pending: #{pending_tests}
|
110
|
-
Total: #{@total_tests}
|
111
|
-
|
112
|
-
- Specific Test Case Status -
|
113
|
-
] % [elapsed_time, average_test_time]
|
114
|
-
|
115
|
-
grouped_summary = @test_cases.group_by{|test_case| test_case.test_status }
|
116
|
-
|
117
|
-
summary_logger.notify "Failed Tests Cases:"
|
118
|
-
(grouped_summary[:fail] || []).each do |test_case|
|
119
|
-
summary_logger.notify print_test_result(test_case)
|
120
|
-
end
|
121
|
-
|
122
|
-
summary_logger.notify "Errored Tests Cases:"
|
123
|
-
(grouped_summary[:error] || []).each do |test_case|
|
124
|
-
summary_logger.notify print_test_result(test_case)
|
125
|
-
end
|
126
|
-
|
127
|
-
summary_logger.notify "Skipped Tests Cases:"
|
128
|
-
(grouped_summary[:skip] || []).each do |test_case|
|
129
|
-
summary_logger.notify print_test_result(test_case)
|
130
|
-
end
|
131
|
-
|
132
|
-
summary_logger.notify "Pending Tests Cases:"
|
133
|
-
(grouped_summary[:pending] || []).each do |test_case|
|
134
|
-
summary_logger.notify print_test_result(test_case)
|
135
|
-
end
|
136
|
-
|
137
|
-
summary_logger.notify("\n\n")
|
138
|
-
end
|
139
|
-
|
140
|
-
#A convenience method for printing the results of a {TestCase}
|
141
|
-
#@param [TestCase] test_case The {TestCase} to examine and print results for
|
142
|
-
def print_test_result(test_case)
|
143
|
-
if test_case.exception
|
144
|
-
test_file_trace = ""
|
145
|
-
test_case.exception.backtrace.each do |line|
|
146
|
-
if line.include?(test_case.path)
|
147
|
-
test_file_trace = "\r\n Test line: #{line}"
|
148
|
-
break
|
149
|
-
end
|
150
|
-
end if test_case.exception.backtrace && test_case.path
|
151
|
-
test_reported = "reported: #{test_case.exception.inspect}#{test_file_trace}"
|
152
|
-
else
|
153
|
-
test_case.test_status
|
154
|
-
end
|
155
|
-
" Test Case #{test_case.path} #{test_reported}"
|
156
|
-
end
|
157
|
-
|
158
|
-
# Writes Junit XML of this {TestSuiteResult}
|
159
|
-
#
|
160
|
-
# @param [String] xml_file Path to the XML file (from Beaker's running directory)
|
161
|
-
# @param [String] file_to_link Path to the paired file that should be linked
|
162
|
-
# from this one (this is relative to the XML
|
163
|
-
# file itself, so it would just be the different
|
164
|
-
# file name if they're in the same directory)
|
165
|
-
# @param [Boolean] time_sort Whether the test results should be output in
|
166
|
-
# order of time spent in the test, or in the
|
167
|
-
# order of test execution (default)
|
168
|
-
#
|
169
|
-
# @return nil
|
170
|
-
# @api private
|
171
|
-
def write_junit_xml(xml_file, file_to_link = nil, time_sort = false)
|
172
|
-
stylesheet = File.join(@options[:project_root], @options[:xml_stylesheet])
|
173
|
-
|
174
|
-
begin
|
175
|
-
LoggerJunit.write_xml(xml_file, stylesheet) do |doc, suites|
|
176
|
-
|
177
|
-
meta_info = Nokogiri::XML::Node.new('meta_test_info', doc)
|
178
|
-
unless file_to_link.nil?
|
179
|
-
meta_info['page_active'] = time_sort ? 'performance' : 'execution'
|
180
|
-
meta_info['link_url'] = file_to_link
|
181
|
-
else
|
182
|
-
meta_info['page_active'] = 'no-links'
|
183
|
-
meta_info['link_url'] = ''
|
184
|
-
end
|
185
|
-
suites.add_child(meta_info)
|
186
|
-
|
187
|
-
suite = Nokogiri::XML::Node.new('testsuite', doc)
|
188
|
-
suite['name'] = @name
|
189
|
-
suite['tests'] = test_count
|
190
|
-
suite['errors'] = errored_tests
|
191
|
-
suite['failures'] = failed_tests
|
192
|
-
suite['skipped'] = skipped_tests
|
193
|
-
suite['pending'] = pending_tests
|
194
|
-
suite['total'] = @total_tests
|
195
|
-
suite['time'] = "%f" % (stop_time - start_time)
|
196
|
-
properties = Nokogiri::XML::Node.new('properties', doc)
|
197
|
-
@options.each_pair do | name, value |
|
198
|
-
property = Nokogiri::XML::Node.new('property', doc)
|
199
|
-
property['name'] = name
|
200
|
-
property['value'] = value
|
201
|
-
properties.add_child(property)
|
202
|
-
end
|
203
|
-
suite.add_child(properties)
|
204
|
-
|
205
|
-
test_cases_to_report = @test_cases
|
206
|
-
test_cases_to_report = @test_cases.sort { |x,y| y.runtime <=> x.runtime } if time_sort
|
207
|
-
test_cases_to_report.each do |test|
|
208
|
-
item = Nokogiri::XML::Node.new('testcase', doc)
|
209
|
-
item['classname'] = File.dirname(test.path)
|
210
|
-
item['name'] = File.basename(test.path)
|
211
|
-
item['time'] = "%f" % test.runtime
|
212
|
-
|
213
|
-
#ugh. nokogiri!!! item can't take a hash, let alone an array.
|
214
|
-
test.exports.each do |export|
|
215
|
-
export.keys.each do |key|
|
216
|
-
item[key] = export[key]
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
# Did we fail? If so, report that.
|
221
|
-
# We need to remove the escape character from colorized text, the
|
222
|
-
# substitution of other entities is handled well by Rexml
|
223
|
-
if test.test_status == :fail || test.test_status == :error then
|
224
|
-
status = Nokogiri::XML::Node.new('failure', doc)
|
225
|
-
status['type'] = test.test_status.to_s
|
226
|
-
if test.exception then
|
227
|
-
status['message'] = test.exception.to_s.gsub(/\e/, '')
|
228
|
-
data = LoggerJunit.format_cdata(test.exception.backtrace.join('\n'))
|
229
|
-
status.add_child(status.document.create_cdata(data))
|
230
|
-
end
|
231
|
-
item.add_child(status)
|
232
|
-
end
|
233
|
-
|
234
|
-
if test.test_status == :skip
|
235
|
-
status = Nokogiri::XML::Node.new('skipped', doc)
|
236
|
-
status['type'] = test.test_status.to_s
|
237
|
-
item.add_child(status)
|
238
|
-
end
|
239
|
-
|
240
|
-
if test.test_status == :pending
|
241
|
-
status = Nokogiri::XML::Node.new('pending', doc)
|
242
|
-
status['type'] = test.test_status.to_s
|
243
|
-
item.add_child(status)
|
244
|
-
end
|
245
|
-
|
246
|
-
if test.sublog then
|
247
|
-
stdout = Nokogiri::XML::Node.new('system-out', doc)
|
248
|
-
data = LoggerJunit.format_cdata(test.sublog)
|
249
|
-
stdout.add_child(stdout.document.create_cdata(data))
|
250
|
-
item.add_child(stdout)
|
251
|
-
end
|
252
|
-
|
253
|
-
if test.last_result and test.last_result.stderr and not test.last_result.stderr.empty? then
|
254
|
-
stderr = Nokogiri::XML::Node.new('system-err', doc)
|
255
|
-
data = LoggerJunit.format_cdata(test.last_result.stderr)
|
256
|
-
stderr.add_child(stderr.document.create_cdata(data))
|
257
|
-
item.add_child(stderr)
|
258
|
-
end
|
259
|
-
|
260
|
-
suite.add_child(item)
|
261
|
-
end
|
262
|
-
suites.add_child(suite)
|
263
|
-
end
|
264
|
-
rescue Exception => e
|
265
|
-
@logger.error "failure in XML output:\n#{e.to_s}\n" + e.backtrace.join("\n")
|
266
|
-
end
|
267
|
-
|
268
|
-
end
|
269
|
-
end
|
270
|
-
|
271
12
|
attr_reader :name, :options, :fail_mode
|
272
13
|
|
273
14
|
#Create {TestSuite} instance
|