beaker 2.3.0 → 2.4.0

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.
Files changed (45) hide show
  1. checksums.yaml +8 -8
  2. data/HISTORY.md +366 -2
  3. data/ext/completion/beaker-completion.bash +1 -1
  4. data/lib/beaker.rb +1 -1
  5. data/lib/beaker/answers.rb +3 -1
  6. data/lib/beaker/answers/version40.rb +42 -0
  7. data/lib/beaker/cli.rb +0 -2
  8. data/lib/beaker/command.rb +10 -2
  9. data/lib/beaker/dsl/ezbake_utils.rb +195 -157
  10. data/lib/beaker/dsl/helpers.rb +9 -6
  11. data/lib/beaker/dsl/install_utils.rb +22 -8
  12. data/lib/beaker/dsl/structure.rb +67 -0
  13. data/lib/beaker/host.rb +14 -4
  14. data/lib/beaker/host/mac.rb +4 -0
  15. data/lib/beaker/host/pswindows.rb +79 -0
  16. data/lib/beaker/host/pswindows/exec.rb +29 -0
  17. data/lib/beaker/host/pswindows/file.rb +15 -0
  18. data/lib/beaker/host/pswindows/group.rb +36 -0
  19. data/lib/beaker/host/pswindows/pkg.rb +47 -0
  20. data/lib/beaker/host/pswindows/user.rb +32 -0
  21. data/lib/beaker/host/unix.rb +16 -6
  22. data/lib/beaker/host/windows.rb +6 -2
  23. data/lib/beaker/host_prebuilt_steps.rb +2 -0
  24. data/lib/beaker/hypervisor.rb +3 -1
  25. data/lib/beaker/hypervisor/aws_sdk.rb +6 -1
  26. data/lib/beaker/hypervisor/docker.rb +6 -1
  27. data/lib/beaker/hypervisor/vagrant.rb +1 -1
  28. data/lib/beaker/hypervisor/vagrant_parallels.rb +18 -0
  29. data/lib/beaker/logger.rb +8 -1
  30. data/lib/beaker/logger_junit.rb +157 -0
  31. data/lib/beaker/network_manager.rb +28 -0
  32. data/lib/beaker/options/presets.rb +6 -0
  33. data/lib/beaker/test_suite.rb +65 -136
  34. data/lib/beaker/version.rb +1 -1
  35. data/spec/beaker/answers_spec.rb +74 -0
  36. data/spec/beaker/dsl/ezbake_utils_spec.rb +167 -126
  37. data/spec/beaker/dsl/install_utils_spec.rb +5 -4
  38. data/spec/beaker/dsl/structure_spec.rb +28 -1
  39. data/spec/beaker/host_prebuilt_steps_spec.rb +2 -1
  40. data/spec/beaker/host_spec.rb +1 -7
  41. data/spec/beaker/hypervisor/docker_spec.rb +19 -1
  42. data/spec/beaker/hypervisor/vagrant_parallels_spec.rb +44 -0
  43. data/spec/beaker/logger_junit_spec.rb +93 -0
  44. data/spec/beaker/network_manager_spec.rb +52 -0
  45. metadata +14 -2
@@ -21,6 +21,8 @@ module Windows
21
21
  'group' => 'Administrators',
22
22
  'puppetservice' => 'pe-httpd',
23
23
  'puppetpath' => '`cygpath -smF 35`/PuppetLabs/puppet/etc',
24
+ 'puppetconfdir' => '`cygpath -smF 35`/PuppetLabs/puppet/etc',
25
+ 'puppetcodedir' => '`cygpath -smF 35`/PuppetLabs/puppet/etc',
24
26
  'hieraconf' => '`cygpath -smF 35`/Puppetlabs/puppet/etc/hiera.yaml',
25
27
  'puppetvardir' => '`cygpath -smF 35`/PuppetLabs/puppet/var',
26
28
  'distmoduledir' => '`cygpath -smF 35`/PuppetLabs/puppet/etc/modules',
@@ -37,14 +39,16 @@ module Windows
37
39
  'user' => 'Administrator',
38
40
  'group' => 'Administrators',
39
41
  'puppetpath' => '`cygpath -smF 35`/PuppetLabs/puppet/etc',
42
+ 'puppetconfdir' => '`cygpath -smF 35`/PuppetLabs/puppet/etc',
43
+ 'puppetcodedir' => '`cygpath -smF 35`/PuppetLabs/puppet/etc',
40
44
  'hieraconf' => '`cygpath -smF 35`/Puppetlabs/puppet/etc/hiera.yaml',
41
45
  'puppetvardir' => '`cygpath -smF 35`/PuppetLabs/puppet/var',
42
46
  'distmoduledir' => '`cygpath -smF 35`/PuppetLabs/puppet/etc/modules',
43
47
  'sitemoduledir' => 'C:/usr/share/puppet/modules',
44
48
  'hieralibdir' => '`cygpath -w /opt/puppet-git-repos/hiera/lib`',
45
49
  'hierapuppetlibdir' => '`cygpath -w /opt/puppet-git-repos/hiera-puppet/lib`',
46
- #let's just add both potential bin dirs to the path
47
- 'puppetbindir' => '/cygdrive/c/Program Files (x86)/Puppet Labs/Puppet/bin:/cygdrive/c/Program Files/Puppet Labs/Puppet/bin',
50
+ #let's just add both potential bin dirs to the path, include ruby too for `gem`, `ruby`, etc
51
+ 'puppetbindir' => '/cygdrive/c/Program Files (x86)/Puppet Labs/Puppet/bin:/cygdrive/c/Program Files/Puppet Labs/Puppet/bin:/cygdrive/c/Program Files (x86)/Puppet Labs/Puppet/sys/ruby/bin:/cygdrive/c/Program Files/Puppet Labs/Puppet/sys/ruby/bin',
48
52
  'hierabindir' => '/opt/puppet-git-repos/hiera/bin',
49
53
  'pathseparator' => ';',
50
54
  })
@@ -517,6 +517,8 @@ module Beaker
517
517
  host.add_env_var(var, value)
518
518
  end
519
519
 
520
+ host.exec(Command.new("cat #{host[:ssh_env_file]}"))
521
+
520
522
  #close the host to re-establish the connection with the new sshd settings
521
523
  host.close
522
524
  end
@@ -46,6 +46,8 @@ module Beaker
46
46
  Beaker::VagrantFusion
47
47
  when /^vagrant_workstation$/
48
48
  Beaker::VagrantWorkstation
49
+ when /^vagrant_parallels$/
50
+ Beaker::VagrantParallels
49
51
  when /^google$/
50
52
  Beaker::GoogleCompute
51
53
  when /^docker$/
@@ -127,6 +129,6 @@ module Beaker
127
129
  end
128
130
  end
129
131
 
130
- [ 'vsphere_helper', 'vagrant', 'vagrant_virtualbox', 'vagrant_libvirt', 'vagrant_fusion', 'vagrant_workstation', 'fusion', 'aws_sdk', 'vsphere', 'vcloud', 'vcloud_pooled', 'aixer', 'solaris', 'docker', 'google_compute', 'openstack' ].each do |lib|
132
+ [ 'vsphere_helper', 'vagrant', 'vagrant_virtualbox', 'vagrant_parallels', 'vagrant_libvirt', 'vagrant_fusion', 'vagrant_workstation', 'fusion', 'aws_sdk', 'vsphere', 'vcloud', 'vcloud_pooled', 'aixer', 'solaris', 'docker', 'google_compute', 'openstack' ].each do |lib|
131
133
  require "beaker/hypervisor/#{lib}"
132
134
  end
@@ -452,7 +452,12 @@ module Beaker
452
452
  # @api private
453
453
  def set_hostnames
454
454
  @hosts.each do |host|
455
- host.exec(Command.new("hostname #{host.name}"))
455
+ if host['platform'] =~ /el-7/
456
+ # on el-7 hosts, the hostname command doesn't "stick" randomly
457
+ host.exec(Command.new("hostnamectl set-hostname #{host.name}"))
458
+ else
459
+ host.exec(Command.new("hostname #{host.name}"))
460
+ end
456
461
  end
457
462
  end
458
463
 
@@ -11,7 +11,12 @@ module Beaker
11
11
  ::Docker.options = { :write_timeout => 300, :read_timeout => 300 }.merge(::Docker.options || {})
12
12
  # assert that the docker-api gem can talk to your docker
13
13
  # enpoint. Will raise if there is a version mismatch
14
- ::Docker.validate_version!
14
+ begin
15
+ ::Docker.validate_version!
16
+ rescue Excon::Errors::SocketError => e
17
+ raise "Docker instance not found.\nif you are on OSX, you might not have Boot2Docker setup correctly\nCheck your DOCKER_HOST variable has been set"
18
+ end
19
+
15
20
  # Pass on all the logging from docker-api to the beaker logger instance
16
21
  ::Docker.logger = @logger
17
22
  end
@@ -37,7 +37,7 @@ module Beaker
37
37
  if /windows/i.match(host['platform'])
38
38
  v_file << " v.vm.network :forwarded_port, guest: 3389, host: 3389\n"
39
39
  v_file << " v.vm.network :forwarded_port, guest: 5985, host: 5985, id: 'winrm', auto_correct: true\n"
40
- v_file << " v.vm.guest = :windows"
40
+ v_file << " v.vm.guest = :windows\n"
41
41
  end
42
42
 
43
43
  if /osx/i.match(host['platform'])
@@ -0,0 +1,18 @@
1
+ require 'beaker/hypervisor/vagrant'
2
+
3
+ class Beaker::VagrantParallels < Beaker::Vagrant
4
+ def provision(provider = 'parallels')
5
+ super
6
+ end
7
+
8
+ def self.provider_vfile_section(host, options)
9
+ provider_section = ""
10
+ provider_section << " v.vm.provider :parallels do |prl|\n"
11
+ provider_section << " prl.optimize_power_consumption = false\n"
12
+ provider_section << " prl.memory = '#{options['vagrant_memsize'] ||= '1024'}'\n"
13
+ provider_section << " prl.update_guest_tools = false\n" if options[:prl_update_guest_tools] == 'disable'
14
+ provider_section << " end\n"
15
+
16
+ provider_section
17
+ end
18
+ end
data/lib/beaker/logger.rb CHANGED
@@ -257,7 +257,7 @@ module Beaker
257
257
  # @return [Array<String>] An array of strings that do not have color codes
258
258
  def strip_colors_from lines
259
259
  Array( lines ).map do |line|
260
- convert(line).gsub(/(\e|\^\[)\[(\d*;)*\d*m/, '')
260
+ Logger.strip_color_codes(convert(line))
261
261
  end
262
262
  end
263
263
 
@@ -312,6 +312,13 @@ module Beaker
312
312
  log_dir
313
313
  end
314
314
 
315
+ #Remove color codes from provided string. Color codes are of the format /(\e\[\d\d;\d\dm)+/.
316
+ #@param [String] text The string to remove color codes from
317
+ #@return [String] The text without color codes
318
+ def Logger.strip_color_codes(text)
319
+ text.gsub(/(\e|\^\[)\[(\d*;)*\d*m/, '')
320
+ end
321
+
315
322
  private
316
323
  # Expand each symlink found to its full path
317
324
  # Lines are assumed to be in the format "String : Integer"
@@ -0,0 +1,157 @@
1
+ module Beaker
2
+ # The Beaker JUnit Logger class
3
+ # This module handles message reporting from Beaker to the JUnit format
4
+ #
5
+ # There is a specific pattern for using this class.
6
+ # Here's a list of example usages:
7
+ # - {Beaker::TestSuite::TestSuiteResult#write_junit_xml}
8
+ module LoggerJunit
9
+
10
+ # writes the xml created in the block to the xml file given
11
+ #
12
+ # Note: Error Recovery should take place in the caller of this
13
+ # method in order to recover gracefully
14
+ #
15
+ # @param [String] xml_file Path to the xml file
16
+ # @param [String] stylesheet Path to the stylesheet file
17
+ # @param [Proc] block XML message construction block
18
+ #
19
+ # @return nil
20
+ def self.write_xml(xml_file, stylesheet, &block)
21
+ doc, suites = self.get_xml_contents(xml_file, name, stylesheet)
22
+
23
+ if block_given?
24
+ case block.arity
25
+ when 2
26
+ yield doc, suites
27
+ else
28
+ raise ArgumentError.new "write_xml block takes 2 arguments, not #{block.arity}"
29
+ end
30
+ end
31
+
32
+ self.finish(doc, xml_file)
33
+ end
34
+
35
+ # writes out xml content for a doc
36
+ #
37
+ # @param [Nokogiri::XML] doc Nokogiri doc containing content to write
38
+ # @param [String] xml_file Path to the xml file to write
39
+ #
40
+ # @return nil
41
+ def self.finish(doc, xml_file)
42
+ # junit/name.xml will be created in a directory relative to the CWD
43
+ # -- JLS 2/12
44
+ File.open(xml_file, 'w') { |fh| fh.write(doc.to_xml) }
45
+ end
46
+
47
+ # gets the xml doc & suites in order to build your xml output on top of
48
+ #
49
+ # @param [String] xml_file Path to the xml file
50
+ # @param [String] name Name of the testsuite you're writing
51
+ # @param [String] stylesheet Path to the stylesheet file
52
+ #
53
+ # @return [Nokogiri::XML] doc to use for your xml content
54
+ # @return [Nokogiri::XML::Node] suites to add your content to
55
+ def self.get_xml_contents(xml_file, name, stylesheet)
56
+ self.copy_stylesheet_into_xml_dir(stylesheet, xml_file)
57
+ xml_file_already_exists = File.file?(xml_file)
58
+ doc = self.get_doc_for_filename(xml_file, stylesheet, xml_file_already_exists)
59
+ suites = self.get_testsuites_from_doc(doc, name, xml_file_already_exists)
60
+ return doc, suites
61
+ end
62
+
63
+ # copies given stylesheet into the directory of the xml file given
64
+ #
65
+ # @param [String] stylesheet Path to the stylesheet file
66
+ # @param [String] xml_file Path to the xml file
67
+ #
68
+ # @return nil
69
+ def self.copy_stylesheet_into_xml_dir(stylesheet, xml_file)
70
+ if not File.file?(File.join(File.dirname(xml_file), File.basename(stylesheet)))
71
+ FileUtils.copy(stylesheet, File.join(File.dirname(xml_file), File.basename(stylesheet)))
72
+ end
73
+ end
74
+
75
+ # sets up doc & gives us the suites for the testsuite named
76
+ #
77
+ # @param [Nokogiri::XML] doc Doc that you're getting suites from
78
+ # @param [String] name Testsuite node name
79
+ # @param [Boolean] already_existed Whether or not the doc already existed
80
+ #
81
+ # @return [Nokogiri::XML::Node] testsuites
82
+ def self.get_testsuites_from_doc(doc, name, already_existed)
83
+ #check to see if an output file already exists, if it does add or replace test suite data
84
+ if already_existed
85
+ suites = doc.at_xpath('testsuites')
86
+ #remove old data
87
+ doc.search("//testsuite").each do |node|
88
+ if node['name'] =~ /#{name}/
89
+ node.unlink
90
+ end
91
+ end
92
+ else
93
+ suites = Nokogiri::XML::Node.new('testsuites', doc)
94
+ suites.parent = doc
95
+ end
96
+ return suites
97
+ end
98
+
99
+ # gives the document object for a particular file
100
+ #
101
+ # @param [String] filename Path to the file that you're opening
102
+ # @param [String] stylesheet Path to the stylesheet for this doc
103
+ # @param [Boolean] already_exists Whether or not the file already exists
104
+ #
105
+ # @return [Nokogiri::XML] Doc that you want to write in
106
+ def self.get_doc_for_filename(filename, stylesheet, already_exists)
107
+ if already_exists
108
+ doc = Nokogiri::XML(File.open(filename, 'r'))
109
+ else
110
+ #no existing file, create a new one
111
+ doc = Nokogiri::XML::Document.new()
112
+ doc.encoding = 'UTF-8'
113
+ pi = Nokogiri::XML::ProcessingInstruction.new(doc, "xml-stylesheet", "type=\"text/xsl\" href=\"#{File.basename(stylesheet)}\"")
114
+ pi.parent = doc
115
+ end
116
+ return doc
117
+ end
118
+
119
+ # Remove color codes and invalid XML characters from provided string
120
+ # @param [String] string The string to format
121
+ # @return [String] the correctly formatted cdata
122
+ def self.format_cdata string
123
+ self.escape_invalid_xml_chars(Logger.strip_color_codes(string))
124
+ end
125
+
126
+ # Escape invalid XML UTF-8 codes from provided string, see http://www.w3.org/TR/xml/#charsets for valid
127
+ # character specification
128
+ # @param [String] string The string to remove invalid codes from
129
+ # @return [String] Properly escaped string
130
+ def self.escape_invalid_xml_chars string
131
+ escaped_string = ""
132
+ string.chars.each do |i|
133
+ char_as_codestring = i.unpack("U*").join
134
+ if self.is_valid_xml(char_as_codestring.to_i)
135
+ escaped_string << i
136
+ else
137
+ escaped_string << "\\#{char_as_codestring}"
138
+ end
139
+ end
140
+ escaped_string
141
+ end
142
+
143
+ # Determine if the provided number falls in the range of accepted xml unicode values
144
+ # See http://www.w3.org/TR/xml/#charsets for valid for valid character specifications.
145
+ # @param [Integer] int The number to check against
146
+ # @return [Boolean] True, if the number corresponds to a valid xml unicode character, otherwise false
147
+ def self.is_valid_xml(int)
148
+ return ( int == 0x9 or
149
+ int == 0xA or
150
+ ( int >= 0x0020 and int <= 0xD7FF ) or
151
+ ( int >= 0xE000 and int <= 0xFFFD ) or
152
+ ( int >= 0x100000 and int <= 0x10FFFF )
153
+ )
154
+ end
155
+
156
+ end
157
+ end
@@ -25,6 +25,11 @@ module Beaker
25
25
  @hosts = []
26
26
  @machines = {}
27
27
  @hypervisors = nil
28
+
29
+ @options[:timestamp] = Time.now unless @options.has_key?(:timestamp)
30
+ @options[:xml_dated_dir] = Beaker::Logger.generate_dated_log_folder(@options[:xml_dir], @options[:timestamp])
31
+ @options[:log_dated_dir] = Beaker::Logger.generate_dated_log_folder(@options[:log_dir], @options[:timestamp])
32
+ @options[:logger_sut] = Beaker::Logger.new(File.join(@options[:log_dated_dir], @options[:log_sut_event]), { :quiet => true })
28
33
  end
29
34
 
30
35
  #Provision all virtual machines. Provision machines according to their set hypervisor, if no hypervisor
@@ -47,6 +52,9 @@ module Beaker
47
52
  @machines.each_key do |type|
48
53
  @hypervisors[type] = Beaker::Hypervisor.create(type, @machines[type], @options)
49
54
  @hosts << @machines[type]
55
+ @machines[type].each do |host|
56
+ log_sut_event host, true
57
+ end
50
58
  end
51
59
  @hosts = @hosts.flatten
52
60
  @hosts
@@ -91,10 +99,30 @@ module Beaker
91
99
  if @hypervisors
92
100
  @hypervisors.each_key do |type|
93
101
  @hypervisors[type].cleanup
102
+ @hypervisors[type].instance_variable_get(:@hosts).each do |host|
103
+ log_sut_event host, false
104
+ end
94
105
  end
95
106
  end
96
107
  @hypervisors = nil
97
108
  end
98
109
 
110
+ # logs provisioning events
111
+ #
112
+ # @param [Host] host The host that the event is happening to
113
+ # @param [Boolean] create Whether the event is creation or cleaning up
114
+ #
115
+ # @return [String] the log line created for this event
116
+ def log_sut_event host, create
117
+ raise ArgumentError.new "log_sut_event called before sut logger created. skipping #{host}, #{create}" unless @options.has_key?(:logger_sut)
118
+ sut_logger = @options[:logger_sut]
119
+ time = Time.new
120
+ stamp = time.strftime('%Y-%m-%d %H:%M:%S')
121
+ verb = create ? '+' : '-'
122
+ line = "#{stamp}\t[#{verb}]\t#{host['hypervisor']}\t#{host['platform']}\t#{host}"
123
+ sut_logger.notify line
124
+ line
125
+ end
126
+
99
127
  end
100
128
  end
@@ -113,6 +113,10 @@ module Beaker
113
113
  :project => 'Beaker',
114
114
  :department => 'unknown',
115
115
  :created_by => ENV['USER'] || ENV['USERNAME'] || 'unknown',
116
+ :openstack_api_key => ENV['OS_PASSWORD'],
117
+ :openstack_username => ENV['OS_USERNAME'],
118
+ :openstack_auth_url => "#{ENV['OS_AUTH_URL']}/tokens",
119
+ :openstack_tenant => ENV['OS_TENANT_NAME'],
116
120
  :jenkins_build_url => nil,
117
121
  :validate => true,
118
122
  :configure => true,
@@ -131,6 +135,7 @@ module Beaker
131
135
  :xml_file => 'beaker_junit.xml',
132
136
  :xml_stylesheet => 'junit.xsl',
133
137
  :log_dir => 'log',
138
+ :log_sut_event => 'sut.log',
134
139
  :color => true,
135
140
  :dry_run => false,
136
141
  :timeout => 300,
@@ -182,6 +187,7 @@ module Beaker
182
187
  :q_rbac_database_user => 'RbhNBklm',
183
188
  :q_rbac_database_name => 'pe-rbac',
184
189
  :q_rbac_database_password => '~!@#$%^*-/ aZ',
190
+ :q_install_update_server => 'y',
185
191
  },
186
192
  :dot_fog => File.join(ENV['HOME'], '.fog'),
187
193
  :ec2_yaml => 'config/image_templates/ec2.yaml',
@@ -148,156 +148,85 @@ module Beaker
148
148
  @logger.notify " Test Case #{test_case.path} #{test_reported}"
149
149
  end
150
150
 
151
- #Remove color codes from provided string. Color codes are of the format /(\e\[\d\d;\d\dm)+/.
152
- #@param [String] text The string to remove color codes from
153
- #@return [String] The text without color codes
154
- def strip_color_codes(text)
155
- text.gsub(/(\e|\^\[)\[(\d*;)*\d*m/, '')
156
- end
157
-
158
- # Determine if the provided number falls in the range of accepted xml unicode values
159
- # See http://www.w3.org/TR/xml/#charsets for valid for valid character specifications.
160
- # @param [Integer] int The number to check against
161
- # @return [Boolean] True, if the number corresponds to a valid xml unicode character, otherwise false
162
- def is_valid_xml(int)
163
- return ( int == 0x9 or
164
- int == 0xA or
165
- ( int >= 0x0020 and int <= 0xD7FF ) or
166
- ( int >= 0xE000 and int <= 0xFFFD ) or
167
- ( int >= 0x100000 and int <= 0x10FFFF )
168
- )
169
- end
170
-
171
- # Escape invalid XML UTF-8 codes from provided string, see http://www.w3.org/TR/xml/#charsets for valid
172
- # character specification
173
- # @param [String] string The string to remove invalid codes from
174
- def escape_invalid_xml_chars string
175
- escaped_string = ""
176
- string.chars.each do |i|
177
- char_as_codestring = i.unpack("U*").join
178
- if is_valid_xml(char_as_codestring.to_i)
179
- escaped_string << i
180
- else
181
- escaped_string << "\\#{char_as_codestring}"
182
- end
183
- end
184
- escaped_string
185
- end
151
+ def write_junit_xml(xml_file)
152
+ stylesheet = File.join(@options[:project_root], @options[:xml_stylesheet])
186
153
 
187
- # Remove color codes and invalid XML characters from provided string
188
- # @param [String] string The string to format
189
- def format_cdata string
190
- escape_invalid_xml_chars(strip_color_codes(string))
191
- end
192
-
193
- #Format and print the {TestSuiteResult} as JUnit XML
194
- #@param [String] xml_file The full path to print the output to.
195
- #@param [String] stylesheet The full path to a JUnit XML stylesheet
196
- def write_junit_xml(xml_file, stylesheet)
197
154
  begin
198
-
199
- #copy stylesheet into xml directory
200
- if not File.file?(File.join(File.dirname(xml_file), File.basename(stylesheet)))
201
- FileUtils.copy(stylesheet, File.join(File.dirname(xml_file), File.basename(stylesheet)))
202
- end
203
- suites = nil
204
- #check to see if an output file already exists, if it does add or replace test suite data
205
- if File.file?(xml_file)
206
- doc = Nokogiri::XML( File.open(xml_file, 'r') )
207
- suites = doc.at_xpath('testsuites')
208
- #remove old data
209
- doc.search("//testsuite").each do |node|
210
- if node['name'] =~ /#{@name}/
211
- node.unlink
212
- end
155
+ LoggerJunit.write_xml(xml_file, stylesheet) do |doc, suites|
156
+
157
+ suite = Nokogiri::XML::Node.new('testsuite', doc)
158
+ suite['name'] = @name
159
+ suite['tests'] = test_count
160
+ suite['errors'] = errored_tests
161
+ suite['failures'] = failed_tests
162
+ suite['skip'] = skipped_tests
163
+ suite['pending'] = pending_tests
164
+ suite['total'] = @total_tests
165
+ suite['time'] = "%f" % (stop_time - start_time)
166
+ properties = Nokogiri::XML::Node.new('properties', doc)
167
+ @options.each_pair do | name, value |
168
+ property = Nokogiri::XML::Node.new('property', doc)
169
+ property['name'] = name
170
+ property['value'] = value
171
+ properties.add_child(property)
213
172
  end
214
- else
215
- #no existing file, create a new one
216
- doc = Nokogiri::XML::Document.new()
217
- doc.encoding = 'UTF-8'
218
- pi = Nokogiri::XML::ProcessingInstruction.new(doc, "xml-stylesheet", "type=\"text/xsl\" href=\"#{File.basename(stylesheet)}\"")
219
- pi.parent = doc
220
- suites = Nokogiri::XML::Node.new('testsuites', doc)
221
- suites.parent = doc
222
- end
173
+ suite.add_child(properties)
174
+
175
+ @test_cases.each do |test|
176
+ item = Nokogiri::XML::Node.new('testcase', doc)
177
+ item['classname'] = File.dirname(test.path)
178
+ item['name'] = File.basename(test.path)
179
+ item['time'] = "%f" % test.runtime
180
+
181
+ # Did we fail? If so, report that.
182
+ # We need to remove the escape character from colorized text, the
183
+ # substitution of other entities is handled well by Rexml
184
+ if test.test_status == :fail || test.test_status == :error then
185
+ status = Nokogiri::XML::Node.new('failure', doc)
186
+ status['type'] = test.test_status.to_s
187
+ if test.exception then
188
+ status['message'] = test.exception.to_s.gsub(/\e/, '')
189
+ data = LoggerJunit.format_cdata(test.exception.backtrace.join('\n'))
190
+ status.add_child(status.document.create_cdata(data))
191
+ end
192
+ item.add_child(status)
193
+ end
223
194
 
224
- suite = Nokogiri::XML::Node.new('testsuite', doc)
225
- suite['name'] = @name
226
- suite['tests'] = test_count
227
- suite['errors'] = errored_tests
228
- suite['failures'] = failed_tests
229
- suite['skip'] = skipped_tests
230
- suite['pending'] = pending_tests
231
- suite['total'] = @total_tests
232
- suite['time'] = "%f" % (stop_time - start_time)
233
- properties = Nokogiri::XML::Node.new('properties', doc)
234
- @options.each_pair do | name, value |
235
- property = Nokogiri::XML::Node.new('property', doc)
236
- property['name'] = name
237
- property['value'] = value
238
- properties.add_child(property)
239
- end
240
- suite.add_child(properties)
241
-
242
- @test_cases.each do |test|
243
- item = Nokogiri::XML::Node.new('testcase', doc)
244
- item['classname'] = File.dirname(test.path)
245
- item['name'] = File.basename(test.path)
246
- item['time'] = "%f" % test.runtime
247
-
248
- # Did we fail? If so, report that.
249
- # We need to remove the escape character from colorized text, the
250
- # substitution of other entities is handled well by Rexml
251
- if test.test_status == :fail || test.test_status == :error then
252
- status = Nokogiri::XML::Node.new('failure', doc)
253
- status['type'] = test.test_status.to_s
254
- if test.exception then
255
- status['message'] = test.exception.to_s.gsub(/\e/, '')
256
- data = format_cdata(test.exception.backtrace.join('\n'))
257
- status.add_child(status.document.create_cdata(data))
195
+ if test.test_status == :skip
196
+ status = Nokogiri::XML::Node.new('skip', doc)
197
+ status['type'] = test.test_status.to_s
198
+ item.add_child(status)
258
199
  end
259
- item.add_child(status)
260
- end
261
200
 
262
- if test.test_status == :skip
263
- status = Nokogiri::XML::Node.new('skip', doc)
264
- status['type'] = test.test_status.to_s
265
- item.add_child(status)
266
- end
201
+ if test.test_status == :pending
202
+ status = Nokogiri::XML::Node.new('pending', doc)
203
+ status['type'] = test.test_status.to_s
204
+ item.add_child(status)
205
+ end
267
206
 
268
- if test.test_status == :pending
269
- status = Nokogiri::XML::Node.new('pending', doc)
270
- status['type'] = test.test_status.to_s
271
- item.add_child(status)
272
- end
207
+ if test.sublog then
208
+ stdout = Nokogiri::XML::Node.new('system-out', doc)
209
+ data = LoggerJunit.format_cdata(test.sublog)
210
+ stdout.add_child(stdout.document.create_cdata(data))
211
+ item.add_child(stdout)
212
+ end
273
213
 
274
- if test.sublog then
275
- stdout = Nokogiri::XML::Node.new('system-out', doc)
276
- data = format_cdata(test.sublog)
277
- stdout.add_child(stdout.document.create_cdata(data))
278
- item.add_child(stdout)
279
- end
214
+ if test.last_result and test.last_result.stderr and not test.last_result.stderr.empty? then
215
+ stderr = Nokogiri::XML::Node.new('system-err', doc)
216
+ data = LoggerJunit.format_cdata(test.last_result.stderr)
217
+ stderr.add_child(stderr.document.create_cdata(data))
218
+ item.add_child(stderr)
219
+ end
280
220
 
281
- if test.last_result and test.last_result.stderr and not test.last_result.stderr.empty? then
282
- stderr = Nokogiri::XML::Node.new('system-err', doc)
283
- data = format_cdata(test.last_result.stderr)
284
- stderr.add_child(stderr.document.create_cdata(data))
285
- item.add_child(stderr)
221
+ suite.add_child(item)
286
222
  end
287
-
288
- suite.add_child(item)
223
+ suites.add_child(suite)
289
224
  end
290
- suites.add_child(suite)
291
-
292
- # junit/name.xml will be created in a directory relative to the CWD
293
- # -- JLS 2/12
294
- File.open(xml_file, 'w') { |fh| fh.write(doc.to_xml) }
295
-
296
225
  rescue Exception => e
297
226
  @logger.error "failure in XML output:\n#{e.to_s}\n" + e.backtrace.join("\n")
298
227
  end
299
- end
300
228
 
229
+ end
301
230
  end
302
231
 
303
232
  attr_reader :name, :options, :fail_mode
@@ -380,7 +309,7 @@ module Beaker
380
309
  # of the suite – or, at least, making them highly confusing for anyone who
381
310
  # has not studied the implementation in detail. --daniel 2011-03-14
382
311
  @test_suite_results.summarize( Logger.new(log_path("#{name}-summary.txt", @options[:log_dated_dir]), STDOUT) )
383
- @test_suite_results.write_junit_xml( log_path(@options[:xml_file], @options[:xml_dated_dir]), File.join(@options[:project_root], @options[:xml_stylesheet]) )
312
+ @test_suite_results.write_junit_xml( log_path(@options[:xml_file], @options[:xml_dated_dir]) )
384
313
 
385
314
  #All done with this run, remove run log
386
315
  @logger.remove_destination(run_log)