Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Functional JUnit reporter #1454

Merged
merged 4 commits into from
Feb 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ habitat/results
www/source/index.html.slim

www/source/index.html.slim

meta-profile-0.2.0.tar.gz
profile-1.0.0.tar.gz
3 changes: 1 addition & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.2.2')
end

gem 'ffi', '>= 1.9.14'
gem 'rspec_junit_formatter', '~> 0.2.3'
gem 'nokogiri', '~> 1.6'

group :test do
gem 'bundler', '~> 1.5'
Expand All @@ -19,7 +19,6 @@ group :test do
gem 'concurrent-ruby', '~> 0.9'
gem 'mocha', '~> 1.1'
gem 'ruby-progressbar', '~> 1.8'
gem 'nokogiri', '~> 1.6'
gem 'webmock', '~> 2.3.2'
end

Expand Down
68 changes: 64 additions & 4 deletions lib/inspec/rspec_json_formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -748,13 +748,73 @@ def status_type(example)
end
end

class InspecRspecJUnit < RSpecJUnitFormatter
class InspecRspecJUnit < InspecRspecJson
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is so good to see that this is now based on our InSpec JSON generator. Awesome @jkerry

RSpec::Core::Formatters.register self, :close

def initialize(*args)
super(*args)
#
# This is the last method is invoked through the formatter interface.
# Converts the junit formatter constructed output_hash into nokogiri generated
# XML and writes it to output.
#
def close(_notification)
require 'nokogiri'
xml_output = Nokogiri::XML::Builder.new { |xml|
xml.testsuites do
@output_hash[:profiles].each do |profile|
build_profile_xml(xml, profile)
end
end
}.to_xml
output.puts xml_output
end

def close(_notification)
private

def build_profile_xml(xml, profile)
xml.testsuite(
name: profile[:name],
tests: count_profile_tests(profile),
failed: count_profile_failed_tests(profile),
) do
profile[:controls].each do |control|
build_control_xml(xml, control)
end
end
end

def build_control_xml(xml, control)
return if control[:results].nil?
control[:results].each do |result|
build_result_xml(xml, control, result)
end
end

def build_result_xml(xml, control, result)
test_class = control[:title].nil? ? 'Anonymous' : control[:id]
xml.testcase(name: result[:code_desc], class: test_class, time: result[:run_time]) do
if result[:status] == 'failed'
xml.failure(message: result[:message])
elsif result[:status] == 'skipped'
xml.skipped
end
end
end

def count_profile_tests(profile)
profile[:controls].reduce(0) { |acc, elem|
acc + (elem[:results].nil? ? 0 : elem[:results].count)
}
end

def count_profile_failed_tests(profile)
profile[:controls].reduce(0) { |acc, elem|
if elem[:results].nil?
acc
else
acc + elem[:results].reduce(0) { |fail_test_total, test_case|
test_case[:status] == 'failed' ? fail_test_total + 1 : fail_test_total
}
end
}
end
end
15 changes: 3 additions & 12 deletions test/functional/inspec_exec_junit_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,7 @@
end
end
describe 'the test suite' do
let(:suite) { doc.xpath("//testsuite").first}

it 'has a single properties element with no children' do
suite.xpath("//properties").length.must_equal 1
suite.xpath("//properties").children.length.must_equal 0
end
let(:suite) { doc.xpath("//testsuites/testsuite").first}

it 'must have 5 testcase children' do
suite.xpath("//testcase").length.must_equal 5
Expand All @@ -48,19 +43,15 @@
end

it 'has the failures attribute with 0 total tests' do
suite["failures"].must_equal "0"
end

it 'has the errors attribute with 0 total tests' do
suite["errors"].must_equal "0"
suite["failed"].must_equal "0"
end

it 'has 2 elements named "File /tmp should be directory"' do
suite.xpath("//testcase[@name='File /tmp should be directory']").length.must_equal 2
end

describe 'the testcase named "gordon_config Can\'t find file ..."' do
let(:gordon_yml_tests) { suite.xpath("//testcase[@classname='lib.inspec.runner']") }
let(:gordon_yml_tests) { suite.xpath("//testcase[@class='gordon-1.0' and @name='gordon_config']") }
let(:first_gordon_test) {gordon_yml_tests.first}

it 'should be unique' do
Expand Down