beaker 2.29.1 → 2.30.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.gitignore +1 -0
- data/HISTORY.md +268 -2
- data/Rakefile +5 -4
- data/docs/How-to-Write-a-Beaker-Test-for-a-Module.md +11 -4
- data/lib/beaker/cli.rb +7 -1
- data/lib/beaker/dsl/install_utils/foss_utils.rb +6 -0
- data/lib/beaker/dsl/roles.rb +15 -12
- data/lib/beaker/hypervisor/vagrant.rb +1 -1
- data/lib/beaker/hypervisor/vcloud.rb +6 -1
- data/lib/beaker/options/command_line_parser.rb +6 -0
- data/lib/beaker/options/presets.rb +1 -0
- data/lib/beaker/platform.rb +8 -0
- data/lib/beaker/runner/mini_test/test_suite.rb +58 -0
- data/lib/beaker/runner/native/test_case.rb +193 -0
- data/lib/beaker/runner/native/test_suite.rb +410 -0
- data/lib/beaker/test_case.rb +2 -176
- data/lib/beaker/test_suite.rb +9 -399
- data/lib/beaker/version.rb +1 -1
- data/spec/beaker/dsl/install_utils/foss_utils_spec.rb +2 -0
- data/spec/beaker/dsl/install_utils/pe_utils_spec.rb +4 -0
- data/spec/beaker/dsl/install_utils/puppet_utils_spec.rb +6 -0
- data/spec/beaker/dsl/roles_spec.rb +118 -0
- data/spec/beaker/hypervisor/vagrant_spec.rb +4 -4
- data/spec/beaker/options/beaker_options_spec.rb +34 -0
- data/spec/beaker/platform_spec.rb +17 -1
- data/spec/beaker/runner/native/test_case_spec.rb +147 -0
- data/spec/beaker/runner/native/test_suite_spec.rb +303 -0
- data/spec/beaker/test_suite_spec.rb +9 -306
- data/spec/helpers.rb +1 -1
- metadata +8 -2
data/lib/beaker/test_case.rb
CHANGED
@@ -1,11 +1,4 @@
|
|
1
|
-
|
2
|
-
require "beaker/#{lib}"
|
3
|
-
end
|
4
|
-
|
5
|
-
require 'tempfile'
|
6
|
-
require 'benchmark'
|
7
|
-
require 'stringio'
|
8
|
-
require 'rbconfig'
|
1
|
+
require 'beaker/runner/native/test_case'
|
9
2
|
|
10
3
|
module Beaker
|
11
4
|
# This class represents a single test case. A test case is necessarily
|
@@ -18,173 +11,6 @@ module Beaker
|
|
18
11
|
#
|
19
12
|
# See {Beaker::DSL} for more information about writing tests
|
20
13
|
# using the DSL.
|
21
|
-
class TestCase
|
22
|
-
include Beaker::DSL
|
23
|
-
|
24
|
-
# The Exception raised by Ruby's STDLIB's test framework (Ruby 1.9)
|
25
|
-
TEST_EXCEPTION_CLASS = ::MiniTest::Assertion
|
26
|
-
|
27
|
-
# Necessary for implementing {Beaker::DSL::Helpers#confine}.
|
28
|
-
# Assumed to be an array of valid {Beaker::Host} objects for
|
29
|
-
# this test case.
|
30
|
-
attr_accessor :hosts
|
31
|
-
|
32
|
-
# Necessary for many methods in {Beaker::DSL}. Assumed to be
|
33
|
-
# an instance of {Beaker::Logger}.
|
34
|
-
attr_accessor :logger
|
35
|
-
|
36
|
-
# Necessary for many methods in {Beaker::DSL::Helpers}. Assumed to be
|
37
|
-
# a hash.
|
38
|
-
attr_accessor :metadata
|
39
|
-
|
40
|
-
#The full log for this test
|
41
|
-
attr_accessor :sublog
|
42
|
-
|
43
|
-
#The result for the last command run
|
44
|
-
attr_accessor :last_result
|
45
|
-
|
46
|
-
# A Hash of 'product name' => 'version installed', only set when
|
47
|
-
# products are installed via git or PE install steps. See the 'git' or
|
48
|
-
# 'pe' directories within 'ROOT/setup' for examples.
|
49
|
-
attr_reader :version
|
50
|
-
|
51
|
-
# Parsed command line options.
|
52
|
-
attr_reader :options
|
53
|
-
|
54
|
-
# The path to the file which contains this test case.
|
55
|
-
attr_reader :path
|
56
|
-
|
57
|
-
# I don't know why this is here
|
58
|
-
attr_reader :fail_flag
|
59
|
-
|
60
|
-
# The user that is running this tests home directory, needed by 'net/ssh'.
|
61
|
-
attr_reader :usr_home
|
62
|
-
|
63
|
-
# A Symbol denoting the status of this test (:fail, :pending,
|
64
|
-
# :skipped, :pass).
|
65
|
-
attr_reader :test_status
|
66
|
-
|
67
|
-
# The exception that may have stopped this test's execution.
|
68
|
-
attr_reader :exception
|
69
|
-
|
70
|
-
# @deprecated
|
71
|
-
# The amount of time taken to execute the test. Unused, probably soon
|
72
|
-
# to be removed or refactored.
|
73
|
-
attr_reader :runtime
|
74
|
-
|
75
|
-
# An Array of Procs to be called after test execution has stopped
|
76
|
-
# (whether by exception or not).
|
77
|
-
attr_reader :teardown_procs
|
78
|
-
|
79
|
-
# @deprecated
|
80
|
-
# Legacy accessor from when test files would only contain one remote
|
81
|
-
# action. Contains the Result of the last call to utilize
|
82
|
-
# {Beaker::DSL::Helpers#on}. Do not use as it is not safe
|
83
|
-
# in test files that use multiple calls to
|
84
|
-
# {Beaker::DSL::Helpers#on}.
|
85
|
-
attr_accessor :result
|
86
|
-
|
87
|
-
# @param [Hosts,Array<Host>] these_hosts The hosts to execute this test
|
88
|
-
# against/on.
|
89
|
-
# @param [Logger] logger A logger that implements
|
90
|
-
# {Beaker::Logger}'s interface.
|
91
|
-
# @param [Hash{Symbol=>String}] options Parsed command line options.
|
92
|
-
# @param [String] path The local path to a test file to be executed.
|
93
|
-
def initialize(these_hosts, logger, options={}, path=nil)
|
94
|
-
@hosts = these_hosts
|
95
|
-
@logger = logger
|
96
|
-
@sublog = ""
|
97
|
-
@options = options
|
98
|
-
@path = path
|
99
|
-
@usr_home = options[:home]
|
100
|
-
@test_status = :pass
|
101
|
-
@exception = nil
|
102
|
-
@runtime = nil
|
103
|
-
@teardown_procs = []
|
104
|
-
@metadata = {}
|
105
|
-
set_current_test_filename(@path ? File.basename(@path, '.rb') : nil)
|
106
|
-
|
107
|
-
|
108
|
-
#
|
109
|
-
# We put this on each wrapper (rather than the class) so that methods
|
110
|
-
# defined in the tests don't leak out to other tests.
|
111
|
-
class << self
|
112
|
-
def run_test
|
113
|
-
@logger.start_sublog
|
114
|
-
@logger.last_result = nil
|
115
|
-
|
116
|
-
set_current_step_name(nil)
|
117
|
-
|
118
|
-
#add arbitrary role methods
|
119
|
-
roles = []
|
120
|
-
@hosts.each do |host|
|
121
|
-
roles << host[:roles]
|
122
|
-
end
|
123
|
-
add_role_def( roles.flatten.uniq )
|
124
|
-
|
125
|
-
@runtime = Benchmark.realtime do
|
126
|
-
begin
|
127
|
-
test = File.read(path)
|
128
|
-
eval test,nil,path,1
|
129
|
-
rescue FailTest, TEST_EXCEPTION_CLASS => e
|
130
|
-
@test_status = :fail
|
131
|
-
@exception = e
|
132
|
-
rescue PendingTest
|
133
|
-
@test_status = :pending
|
134
|
-
rescue SkipTest
|
135
|
-
@test_status = :skip
|
136
|
-
rescue StandardError, ScriptError, SignalException => e
|
137
|
-
log_and_fail_test(e)
|
138
|
-
ensure
|
139
|
-
@teardown_procs.each do |teardown|
|
140
|
-
begin
|
141
|
-
teardown.call
|
142
|
-
rescue StandardError, SignalException, TEST_EXCEPTION_CLASS => e
|
143
|
-
log_and_fail_test(e)
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
@sublog = @logger.get_sublog
|
149
|
-
@last_result = @logger.last_result
|
150
|
-
return self
|
151
|
-
end
|
152
|
-
|
153
|
-
private
|
154
|
-
|
155
|
-
# Log an error and mark the test as failed, passing through an
|
156
|
-
# exception so it can be displayed at the end of the total run.
|
157
|
-
#
|
158
|
-
# We break out the complete exception backtrace and log each line
|
159
|
-
# individually as well.
|
160
|
-
#
|
161
|
-
# @param exception [Exception] exception to fail with
|
162
|
-
def log_and_fail_test(exception)
|
163
|
-
logger.error("#{exception.class}: #{exception.message}")
|
164
|
-
bt = exception.backtrace
|
165
|
-
logger.pretty_backtrace(bt).each_line do |line|
|
166
|
-
logger.error(line)
|
167
|
-
end
|
168
|
-
@test_status = :error
|
169
|
-
@exception = exception
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
# The TestCase as a hash
|
175
|
-
# @api public
|
176
|
-
# @note The visibility and semantics of this method are valid, but the
|
177
|
-
# structure of the Hash it returns may change without notice
|
178
|
-
#
|
179
|
-
# @return [Hash] A Hash representation of this test.
|
180
|
-
def to_hash
|
181
|
-
hash = {}
|
182
|
-
hash['HOSTS'] = {}
|
183
|
-
@hosts.each do |host|
|
184
|
-
hash['HOSTS'][host.name] = host.overrides
|
185
|
-
end
|
186
|
-
hash
|
187
|
-
end
|
188
|
-
|
14
|
+
class TestCase < Beaker::Runner::Native::TestCase
|
189
15
|
end
|
190
16
|
end
|
data/lib/beaker/test_suite.rb
CHANGED
@@ -1,407 +1,17 @@
|
|
1
|
-
|
2
|
-
require '
|
3
|
-
require 'fileutils'
|
4
|
-
[ 'test_case', 'logger' ].each do |lib|
|
5
|
-
require "beaker/#{lib}"
|
6
|
-
end
|
1
|
+
require 'beaker/runner/native/test_suite'
|
2
|
+
require 'beaker/runner/mini_test/test_suite'
|
7
3
|
|
8
4
|
module Beaker
|
9
|
-
#A collection of {TestCase} objects are considered a {TestSuite}.
|
10
|
-
#Handles executing the set of {TestCase} instances and reporting results as post summary text and JUnit XML.
|
11
5
|
class TestSuite
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
print_test_result(test_case)
|
120
|
-
end
|
121
|
-
|
122
|
-
summary_logger.notify "Errored Tests Cases:"
|
123
|
-
(grouped_summary[:error] || []).each do |test_case|
|
124
|
-
print_test_result(test_case)
|
125
|
-
end
|
126
|
-
|
127
|
-
summary_logger.notify "Skipped Tests Cases:"
|
128
|
-
(grouped_summary[:skip] || []).each do |test_case|
|
129
|
-
print_test_result(test_case)
|
130
|
-
end
|
131
|
-
|
132
|
-
summary_logger.notify "Pending Tests Cases:"
|
133
|
-
(grouped_summary[:pending] || []).each do |test_case|
|
134
|
-
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
|
-
test_reported = if test_case.exception
|
144
|
-
"reported: #{test_case.exception.inspect}"
|
145
|
-
else
|
146
|
-
test_case.test_status
|
147
|
-
end
|
148
|
-
@logger.notify " Test Case #{test_case.path} #{test_reported}"
|
149
|
-
end
|
150
|
-
|
151
|
-
# Writes Junit XML of this {TestSuiteResult}
|
152
|
-
#
|
153
|
-
# @param [String] xml_file Path to the XML file (from Beaker's running directory)
|
154
|
-
# @param [String] file_to_link Path to the paired file that should be linked
|
155
|
-
# from this one (this is relative to the XML
|
156
|
-
# file itself, so it would just be the different
|
157
|
-
# file name if they're in the same directory)
|
158
|
-
# @param [Boolean] time_sort Whether the test results should be output in
|
159
|
-
# order of time spent in the test, or in the
|
160
|
-
# order of test execution (default)
|
161
|
-
#
|
162
|
-
# @return nil
|
163
|
-
# @api private
|
164
|
-
def write_junit_xml(xml_file, file_to_link = nil, time_sort = false)
|
165
|
-
stylesheet = File.join(@options[:project_root], @options[:xml_stylesheet])
|
166
|
-
|
167
|
-
begin
|
168
|
-
LoggerJunit.write_xml(xml_file, stylesheet) do |doc, suites|
|
169
|
-
|
170
|
-
meta_info = Nokogiri::XML::Node.new('meta_test_info', doc)
|
171
|
-
unless file_to_link.nil?
|
172
|
-
meta_info['page_active'] = time_sort ? 'performance' : 'execution'
|
173
|
-
meta_info['link_url'] = file_to_link
|
174
|
-
else
|
175
|
-
meta_info['page_active'] = 'no-links'
|
176
|
-
meta_info['link_url'] = ''
|
177
|
-
end
|
178
|
-
suites.add_child(meta_info)
|
179
|
-
|
180
|
-
suite = Nokogiri::XML::Node.new('testsuite', doc)
|
181
|
-
suite['name'] = @name
|
182
|
-
suite['tests'] = test_count
|
183
|
-
suite['errors'] = errored_tests
|
184
|
-
suite['failures'] = failed_tests
|
185
|
-
suite['skip'] = skipped_tests
|
186
|
-
suite['pending'] = pending_tests
|
187
|
-
suite['total'] = @total_tests
|
188
|
-
suite['time'] = "%f" % (stop_time - start_time)
|
189
|
-
properties = Nokogiri::XML::Node.new('properties', doc)
|
190
|
-
@options.each_pair do | name, value |
|
191
|
-
property = Nokogiri::XML::Node.new('property', doc)
|
192
|
-
property['name'] = name
|
193
|
-
property['value'] = value
|
194
|
-
properties.add_child(property)
|
195
|
-
end
|
196
|
-
suite.add_child(properties)
|
197
|
-
|
198
|
-
test_cases_to_report = @test_cases
|
199
|
-
test_cases_to_report = @test_cases.sort { |x,y| y.runtime <=> x.runtime } if time_sort
|
200
|
-
test_cases_to_report.each do |test|
|
201
|
-
item = Nokogiri::XML::Node.new('testcase', doc)
|
202
|
-
item['classname'] = File.dirname(test.path)
|
203
|
-
item['name'] = File.basename(test.path)
|
204
|
-
item['time'] = "%f" % test.runtime
|
205
|
-
|
206
|
-
# Did we fail? If so, report that.
|
207
|
-
# We need to remove the escape character from colorized text, the
|
208
|
-
# substitution of other entities is handled well by Rexml
|
209
|
-
if test.test_status == :fail || test.test_status == :error then
|
210
|
-
status = Nokogiri::XML::Node.new('failure', doc)
|
211
|
-
status['type'] = test.test_status.to_s
|
212
|
-
if test.exception then
|
213
|
-
status['message'] = test.exception.to_s.gsub(/\e/, '')
|
214
|
-
data = LoggerJunit.format_cdata(test.exception.backtrace.join('\n'))
|
215
|
-
status.add_child(status.document.create_cdata(data))
|
216
|
-
end
|
217
|
-
item.add_child(status)
|
218
|
-
end
|
219
|
-
|
220
|
-
if test.test_status == :skip
|
221
|
-
status = Nokogiri::XML::Node.new('skip', doc)
|
222
|
-
status['type'] = test.test_status.to_s
|
223
|
-
item.add_child(status)
|
224
|
-
end
|
225
|
-
|
226
|
-
if test.test_status == :pending
|
227
|
-
status = Nokogiri::XML::Node.new('pending', doc)
|
228
|
-
status['type'] = test.test_status.to_s
|
229
|
-
item.add_child(status)
|
230
|
-
end
|
231
|
-
|
232
|
-
if test.sublog then
|
233
|
-
stdout = Nokogiri::XML::Node.new('system-out', doc)
|
234
|
-
data = LoggerJunit.format_cdata(test.sublog)
|
235
|
-
stdout.add_child(stdout.document.create_cdata(data))
|
236
|
-
item.add_child(stdout)
|
237
|
-
end
|
238
|
-
|
239
|
-
if test.last_result and test.last_result.stderr and not test.last_result.stderr.empty? then
|
240
|
-
stderr = Nokogiri::XML::Node.new('system-err', doc)
|
241
|
-
data = LoggerJunit.format_cdata(test.last_result.stderr)
|
242
|
-
stderr.add_child(stderr.document.create_cdata(data))
|
243
|
-
item.add_child(stderr)
|
244
|
-
end
|
245
|
-
|
246
|
-
suite.add_child(item)
|
247
|
-
end
|
248
|
-
suites.add_child(suite)
|
249
|
-
end
|
250
|
-
rescue Exception => e
|
251
|
-
@logger.error "failure in XML output:\n#{e.to_s}\n" + e.backtrace.join("\n")
|
252
|
-
end
|
253
|
-
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
attr_reader :name, :options, :fail_mode
|
258
|
-
|
259
|
-
#Create {TestSuite} instance
|
260
|
-
#@param [String] name The name of the {TestSuite}
|
261
|
-
#@param [Array<Host>] hosts An Array of Hosts to act upon.
|
262
|
-
#@param [Hash{Symbol=>String}] options Options for this object
|
263
|
-
#@option options [Logger] :logger The Logger object to report information to
|
264
|
-
#@option options [String] :log_dir The directory where text run logs will be written
|
265
|
-
#@option options [String] :xml_dir The directory where JUnit XML file will be written
|
266
|
-
#@option options [String] :xml_file The name of the JUnit XML file to be written to
|
267
|
-
#@option options [String] :project_root The full path to the Beaker lib directory
|
268
|
-
#@option options [String] :xml_stylesheet The path to a stylesheet to be applied to the generated XML output
|
269
|
-
#@param [Symbol] fail_mode One of :slow, :fast
|
270
|
-
#@param [Time] timestamp Beaker execution start time
|
271
|
-
def initialize(name, hosts, options, timestamp, fail_mode=nil)
|
272
|
-
@logger = options[:logger]
|
273
|
-
@test_cases = []
|
274
|
-
@test_files = options[name]
|
275
|
-
@name = name.to_s.gsub(/\s+/, '-')
|
276
|
-
@hosts = hosts
|
277
|
-
@run = false
|
278
|
-
@options = options
|
279
|
-
@fail_mode = fail_mode || @options[:fail_mode] || :slow
|
280
|
-
@test_suite_results = TestSuiteResult.new(@options, name)
|
281
|
-
@timestamp = timestamp
|
282
|
-
|
283
|
-
report_and_raise(@logger, RuntimeError.new("#{@name}: no test files found..."), "TestSuite: initialize") if @test_files.empty?
|
284
|
-
|
285
|
-
rescue => e
|
286
|
-
report_and_raise(@logger, e, "TestSuite: initialize")
|
287
|
-
end
|
288
|
-
|
289
|
-
#Execute all the {TestCase} instances and then report the results as both plain text and xml. The text result
|
290
|
-
#is reported to a newly created run log.
|
291
|
-
#Execution is dependent upon the fail_mode. If mode is :fast then stop running any additional {TestCase} instances
|
292
|
-
#after first failure, if mode is :slow continue execution no matter what {TestCase} results are.
|
293
|
-
def run
|
294
|
-
@run = true
|
295
|
-
start_time = Time.now
|
296
|
-
|
297
|
-
#Create a run log for this TestSuite.
|
298
|
-
run_log = log_path("#{@name}-run.log", @options[:log_dated_dir])
|
299
|
-
@logger.add_destination(run_log)
|
300
|
-
|
301
|
-
# This is an awful hack to maintain backward compatibility until tests
|
302
|
-
# are ported to use logger. Still in use in PuppetDB tests
|
303
|
-
Beaker.const_set(:Log, @logger) unless defined?( Log )
|
304
|
-
|
305
|
-
@test_suite_results.start_time = start_time
|
306
|
-
@test_suite_results.total_tests = @test_files.length
|
307
|
-
|
308
|
-
@test_files.each do |test_file|
|
309
|
-
@logger.info "Begin #{test_file}"
|
310
|
-
start = Time.now
|
311
|
-
test_case = TestCase.new(@hosts, @logger, options, test_file).run_test
|
312
|
-
duration = Time.now - start
|
313
|
-
@test_suite_results.add_test_case(test_case)
|
314
|
-
@test_cases << test_case
|
315
|
-
|
316
|
-
state = test_case.test_status == :skip ? 'skipp' : test_case.test_status
|
317
|
-
msg = "#{test_file} #{state}ed in %.2f seconds" % duration.to_f
|
318
|
-
case test_case.test_status
|
319
|
-
when :pass
|
320
|
-
@logger.success msg
|
321
|
-
when :skip
|
322
|
-
@logger.warn msg
|
323
|
-
when :fail
|
324
|
-
@logger.error msg
|
325
|
-
break if @fail_mode.to_s !~ /slow/ #all failure modes except slow cause us to kick out early on failure
|
326
|
-
when :error
|
327
|
-
@logger.warn msg
|
328
|
-
break if @fail_mode.to_s !~ /slow/ #all failure modes except slow cause us to kick out early on failure
|
329
|
-
end
|
330
|
-
end
|
331
|
-
@test_suite_results.stop_time = Time.now
|
332
|
-
|
333
|
-
# REVISIT: This changes global state, breaking logging in any future runs
|
334
|
-
# of the suite – or, at least, making them highly confusing for anyone who
|
335
|
-
# has not studied the implementation in detail. --daniel 2011-03-14
|
336
|
-
@test_suite_results.summarize( Logger.new(log_path("#{name}-summary.txt", @options[:log_dated_dir]), STDOUT) )
|
337
|
-
|
338
|
-
junit_file_log = log_path(@options[:xml_file], @options[:xml_dated_dir])
|
339
|
-
if @options[:xml_time_enabled]
|
340
|
-
junit_file_time = log_path(@options[:xml_time], @options[:xml_dated_dir])
|
341
|
-
@test_suite_results.write_junit_xml( junit_file_log, @options[:xml_time] )
|
342
|
-
@test_suite_results.write_junit_xml( junit_file_time, @options[:xml_file], true )
|
343
|
-
else
|
344
|
-
@test_suite_results.write_junit_xml( junit_file_log )
|
345
|
-
end
|
346
|
-
#All done with this run, remove run log
|
347
|
-
@logger.remove_destination(run_log)
|
348
|
-
|
349
|
-
# Allow chaining operations...
|
350
|
-
return self
|
351
|
-
end
|
352
|
-
|
353
|
-
#Execute all the TestCases in this suite.
|
354
|
-
#This is a wrapper that catches any failures generated during TestSuite::run.
|
355
|
-
def run_and_raise_on_failure
|
356
|
-
begin
|
357
|
-
run
|
358
|
-
return self if @test_suite_results.success?
|
359
|
-
rescue => e
|
360
|
-
#failed during run
|
361
|
-
report_and_raise(@logger, e, "TestSuite :run_and_raise_on_failure")
|
6
|
+
def self.runner(runner)
|
7
|
+
case runner
|
8
|
+
when "native"
|
9
|
+
::Beaker::Runner::Native::TestSuite
|
10
|
+
when "minitest"
|
11
|
+
::Beaker::Runner::MiniTest::TestSuite
|
362
12
|
else
|
363
|
-
|
364
|
-
report_and_raise(@logger, RuntimeError.new("Failed while running the #{name} suite"), "TestSuite: report_and_raise_on_failure")
|
365
|
-
end
|
366
|
-
end
|
367
|
-
|
368
|
-
# Gives a full file path for output to be written to, maintaining the latest symlink
|
369
|
-
# @param [String] name The file name that we want to write to.
|
370
|
-
# @param [String] log_dir The desired output directory.
|
371
|
-
# A symlink will be made from ./basedir/latest to that.
|
372
|
-
# @example
|
373
|
-
# log_path('output.txt', 'log/2014-06-02_16_31_22')
|
374
|
-
#
|
375
|
-
# This will create the structure:
|
376
|
-
#
|
377
|
-
# ./log/2014-06-02_16_31_22/output.txt
|
378
|
-
# ./log/latest -> 2014-06-02_16_31_22
|
379
|
-
#
|
380
|
-
# @example
|
381
|
-
# log_path('foo.log', 'log/man/date')
|
382
|
-
#
|
383
|
-
# This will create the structure:
|
384
|
-
#
|
385
|
-
# ./log/man/date/foo.log
|
386
|
-
# ./log/latest -> man/date
|
387
|
-
def log_path(name, log_dir)
|
388
|
-
FileUtils.mkdir_p(log_dir) unless File.directory?(log_dir)
|
389
|
-
|
390
|
-
base_dir = log_dir
|
391
|
-
link_dir = ''
|
392
|
-
while File.dirname(base_dir) != '.' do
|
393
|
-
link_dir = link_dir == '' ? File.basename(base_dir) : File.join(File.basename(base_dir), link_dir)
|
394
|
-
base_dir = File.dirname(base_dir)
|
395
|
-
end
|
396
|
-
|
397
|
-
latest = File.join(base_dir, "latest")
|
398
|
-
if !File.exist?(latest) or File.symlink?(latest) then
|
399
|
-
File.delete(latest) if File.exist?(latest) || File.symlink?(latest)
|
400
|
-
File.symlink(link_dir, latest)
|
13
|
+
nil
|
401
14
|
end
|
402
|
-
|
403
|
-
File.join(log_dir, name)
|
404
15
|
end
|
405
|
-
|
406
16
|
end
|
407
17
|
end
|