beaker 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
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)