Module: Beaker::LoggerJunit
- Defined in:
- lib/beaker/logger_junit.rb
Overview
The Beaker JUnit Logger class This module handles message reporting from Beaker to the JUnit format
There is a specific pattern for using this class. Here's a list of example usages:
Constant Summary collapse
- INVALID_XML_CHARS =
Every character is_valid_xml rejects, as one pattern. Note that this tracks that method rather than the specification it cites: #xD is absent from both, and both take the last range as 0x100000 rather than the 0x10000 the specification gives. Changing either would change the contents of every junit report, so they are left alone here and the specs walk the whole range to keep the two in step.
/[^\u{9}\u{A}\u{20}-\u{D7FF}\u{E000}-\u{FFFD}\u{100000}-\u{10FFFF}]/
Class Method Summary collapse
-
.copy_stylesheet_into_xml_dir(stylesheet, xml_file) ⇒ Object
copies given stylesheet into the directory of the xml file given.
-
.escape_invalid_xml_chars(string) ⇒ String
Escape invalid XML UTF-8 codes from provided string, see http://www.w3.org/TR/xml/#charsets for valid character specification.
-
.finish(doc, xml_file) ⇒ Object
writes out xml content for a doc.
-
.format_cdata(string) ⇒ String
Remove color codes and invalid XML characters from provided string.
-
.get_doc_for_filename(filename, stylesheet, already_exists) ⇒ REXML::Document
gives the document object for a particular file.
-
.get_testsuites_from_doc(doc, name, already_existed) ⇒ Rexml::Element
sets up doc & gives us the suites for the testsuite named.
-
.get_xml_contents(xml_file, name, stylesheet) ⇒ REXML::Document, REXML::Element
gets the xml doc & suites in order to build your xml output on top of.
-
.is_valid_xml(int) ⇒ Boolean
Determine if the provided number falls in the range of accepted xml unicode values See http://www.w3.org/TR/xml/#charsets for valid for valid character specifications.
-
.write_xml(xml_file, stylesheet, &block) ⇒ Object
writes the xml created in the block to the xml file given.
Class Method Details
.copy_stylesheet_into_xml_dir(stylesheet, xml_file) ⇒ Object
copies given stylesheet into the directory of the xml file given
69 70 71 72 73 |
# File 'lib/beaker/logger_junit.rb', line 69 def self.copy_stylesheet_into_xml_dir(stylesheet, xml_file) return if File.file?(File.join(File.dirname(xml_file), File.basename(stylesheet))) FileUtils.copy(stylesheet, File.join(File.dirname(xml_file), File.basename(stylesheet))) end |
.escape_invalid_xml_chars(string) ⇒ String
Escape invalid XML UTF-8 codes from provided string, see http://www.w3.org/TR/xml/#charsets for valid character specification
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/beaker/logger_junit.rb', line 135 def self.escape_invalid_xml_chars string # Bytes that are not valid in their own encoding cannot be represented in # xml at all, and would make the gsub below raise. Drop them, the same # way Logger#convert does further upstream. Raising matters more here # than it might look: TestSuiteResult calls #format_cdata from inside a # blanket rescue that abandons the whole junit document, so one stray # byte in one sublog loses every test result for the run. string = string.dup.force_encoding(Encoding::UTF_8) unless string.encoding == Encoding::UTF_8 string = string.scrub('') unless string.valid_encoding? # This walked the string a character at a time, unpacking each one into # an array and joining it back into a string just to read its codepoint. # That is around four objects per character, and it runs over the whole # sublog of every test case at the end of a run: 28 million objects, and # 98MB of permanently grown ruby heap, for a 6MB suite. string.gsub(INVALID_XML_CHARS) { |char| "\\#{char.ord}" } end |
.finish(doc, xml_file) ⇒ Object
writes out xml content for a doc
41 42 43 44 45 |
# File 'lib/beaker/logger_junit.rb', line 41 def self.finish(doc, xml_file) # junit/name.xml will be created in a directory relative to the CWD File.open(xml_file, 'w') { |f| doc.write(f, 2) } end |
.format_cdata(string) ⇒ String
Remove color codes and invalid XML characters from provided string
119 120 121 |
# File 'lib/beaker/logger_junit.rb', line 119 def self.format_cdata string self.escape_invalid_xml_chars(Logger.strip_color_codes(string)) end |
.get_doc_for_filename(filename, stylesheet, already_exists) ⇒ REXML::Document
gives the document object for a particular file
103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/beaker/logger_junit.rb', line 103 def self.get_doc_for_filename(filename, stylesheet, already_exists) if already_exists doc = REXML::Document.new File.open(filename) else # no existing file, create a new one doc = REXML::Document.new doc << REXML::XMLDecl.new("1.0", "UTF-8") instruction_content = "type='text/xsl' href='#{File.basename(stylesheet)}'" doc << REXML::Instruction.new("xml-stylesheet", instruction_content) end return doc end |
.get_testsuites_from_doc(doc, name, already_existed) ⇒ Rexml::Element
sets up doc & gives us the suites for the testsuite named
82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/beaker/logger_junit.rb', line 82 def self.get_testsuites_from_doc(doc, name, already_existed) # check to see if an output file already exists, if it does add or replace test suite data if already_existed suites = REXML::XPath.first(doc, "testsuites") # remove old data suites.elements.each("testsuite") do |e| suites.delete_element e if /#{name}/.match?(e.name) end else suites = doc.add_element(REXML::Element.new('testsuites')) end return suites end |
.get_xml_contents(xml_file, name, stylesheet) ⇒ REXML::Document, REXML::Element
gets the xml doc & suites in order to build your xml output on top of
55 56 57 58 59 60 61 |
# File 'lib/beaker/logger_junit.rb', line 55 def self.get_xml_contents(xml_file, name, stylesheet) self.copy_stylesheet_into_xml_dir(stylesheet, xml_file) xml_file_already_exists = File.file?(xml_file) doc = self.get_doc_for_filename(xml_file, stylesheet, xml_file_already_exists) suites = self.get_testsuites_from_doc(doc, name, xml_file_already_exists) return doc, suites end |
.is_valid_xml(int) ⇒ Boolean
Determine if the provided number falls in the range of accepted xml unicode values See http://www.w3.org/TR/xml/#charsets for valid for valid character specifications.
157 158 159 160 161 162 163 164 |
# File 'lib/beaker/logger_junit.rb', line 157 def self.is_valid_xml(int) return (int == 0x9 or int == 0xA or (int >= 0x0020 and int <= 0xD7FF) or (int >= 0xE000 and int <= 0xFFFD) or (int >= 0x100000 and int <= 0x10FFFF) ) end |
.write_xml(xml_file, stylesheet, &block) ⇒ Object
writes the xml created in the block to the xml file given
Note: Error Recovery should take place in the caller of this method in order to recover gracefully
20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/beaker/logger_junit.rb', line 20 def self.write_xml(xml_file, stylesheet, &block) doc, suites = self.get_xml_contents(xml_file, name, stylesheet) if block case block.arity when 2 yield doc, suites else raise ArgumentError.new "write_xml block takes 2 arguments, not #{block.arity}" end end self.finish(doc, xml_file) end |