Last active
September 23, 2020 09:11
-
-
Save wellavelino/1ef7b638f71b2da5eeef27e512db9882 to your computer and use it in GitHub Desktop.
report join
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'nokogiri' | |
require 'find' | |
class JunitMerge | |
FAILURES_DIR = 'artifacts/composer-output/failures/'.freeze | |
REPORT_DIRECTORY = 'artifacts/composer-output/'.freeze | |
COLLATED_REPORT = 'artifacts/composer-output/junit4-reports/collated_report.xml'.freeze | |
OUTDATED_REPORTS = 'artifacts/composer-output/junit4-reports'.freeze | |
def run | |
if report_list.size > 1 | |
join_original_report(report_list) | |
collated_report = find_collated_report(REPORT_DIRECTORY) | |
handle_failure_path(collated_report.join) if File.directory?(FAILURES_DIR) | |
else | |
handle_failure_path(report_list) if File.directory?(FAILURES_DIR) | |
end | |
end | |
def handle_failure_path(report_path) | |
failures_path(FAILURES_DIR).each do |source| | |
merge_files(source, report_path) | |
end | |
end | |
# noinspection RubyModifiedFrozenObject | |
def join_original_report(reports) | |
path1 = File.read(reports[0]).encode!('UTF-8', invalid: :replace) | |
path2 = File.read(reports[1]).encode!('UTF-8', invalid: :replace) | |
first_path = Nokogiri::XML::Document.parse(path1) | |
second_path = Nokogiri::XML::Document.parse(path2) | |
first_path.xpath('//testcase/..').map do |node| | |
second_path.xpath('//testcase/..').map do |second_report| | |
%w[tests failures errors skipped retries].each do |attribute| | |
if (value = node[attribute]) | |
node[attribute] = value.to_i + second_report.attributes[attribute].value.to_i | |
end | |
end | |
node.add_child(second_report.children) | |
open(COLLATED_REPORT, 'w+') {|f| f.write(node.to_s)} | |
end | |
end | |
delete_outdated_reports(OUTDATED_REPORTS) | |
end | |
# noinspection RubyModifiedFrozenObject | |
def merge_files(source_path, original_report) | |
source_text = File.read(source_path).encode!('UTF-8', invalid: :replace) | |
target_text = File.read(original_report).encode!('UTF-8', invalid: :replace) | |
return if target_text =~ /\A\s*\z/m | |
if source_text =~ /\A\s*\z/m | |
FileUtils.cp source_path, original_report | |
return | |
end | |
source = Nokogiri::XML::Document.parse(source_text) | |
target = Nokogiri::XML::Document.parse(target_text) | |
append_failures_diff(source, target) | |
open(original_report, 'w') {|f| f.write(target.to_s)} | |
end | |
def append_failures_diff(source, target) | |
source.xpath('//testsuite/testcase').each do |node| | |
summary_diff = SummaryDiff.new | |
predicates = build_predicates(node) | |
original = target.xpath("testsuite/testcase[#{predicates}]").first | |
modify_report(summary_diff, node, original) if original | |
modify_node_ancestors(node, summary_diff) | |
end | |
end | |
def build_predicates(node) | |
[attribute_predicate('classname', node['classname']), | |
attribute_predicate('name', node['name'])].join(' and ') | |
end | |
def modify_report(summary_diff, node, original) | |
summary_diff.add(node, 1) | |
summary_diff.add(original, -1) | |
# Uncomment when figure out dynamic retries | |
# node.set_attribute('retries', index += 1) | |
original.replace(node) | |
end | |
def modify_node_ancestors(node, summary_diff) | |
node.ancestors.select {|a| a.name =~ /\Atestsuite?\z/}.each do |suite| | |
summary_diff.apply_to(suite) | |
end | |
end | |
def attribute_predicate(name, value) | |
# XPath doesn't let you escape the delimiting quotes. Need concat() here | |
# to support the general case. | |
escaped = value.to_s.gsub('"', '", \'"\', "') | |
"@#{name}=concat('', \"#{escaped}\")" | |
end | |
def failures_path(sources_path) | |
# finding recursivly in folders and subfolders to find all xml | |
# files available | |
Find.find(sources_path).select {|p| /.*\.xml$/ =~ p} | |
end | |
def report_list | |
# obtain target report as String | |
Dir.glob('artifacts/composer-output/junit4-reports/**/*\.xml') | |
end | |
def find_collated_report(pwd = Dir.pwd) | |
files = [] | |
begin | |
Find.find(pwd) do |path| | |
next if path.include? 'emulator' | |
next unless File.file?(path) | |
files << path if path.include? 'collated_report.xml' | |
end | |
rescue StandardError => e | |
puts 'Error reading files.', e | |
end | |
files | |
end | |
def delete_outdated_reports(path) | |
Dir.glob("#{path}/*").each do |file| | |
File.delete(file) if file.include? 'emulator' | |
end | |
end | |
SummaryDiff = Struct.new(:tests, :failures, :errors, :skipped, :retries) do | |
def initialize | |
self.tests = self.failures = self.errors = self.skipped = self.retries = 0 | |
end | |
def add(test_node, delta) | |
self.tests += delta | |
self.failures += delta unless test_node.xpath('failure').empty? | |
self.errors += delta unless test_node.xpath('error').empty? | |
self.skipped += delta unless test_node.xpath('skipped').empty? | |
self.retries += delta unless test_node.xpath('retries').empty? | |
end | |
def apply_to(node) | |
%w[tests failures errors skipped retries].each do |attribute| | |
if (value = node[attribute]) | |
node[attribute] = value.to_i + send(attribute) | |
end | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment