mirror of
https://github.com/inspec/inspec
synced 2024-11-10 07:04:15 +00:00
Replace Nokogiri with REXML in the JUnit formatter
In #1454, we welcomed a newly-revamped JUnit formatter which has a dependency on Nokogiri. Unfortunately, this had led us to problems getting InSpec included in Chef omnibus builds (see chef/chef#5937) because Chef is using Ruby 2.4.1 and the Nokogiri maintainers have not yet released a windows binary gem that supports Ruby 2.4.x. This has led to breaking builds in Chef's CI platform and would block the acceptance of chef/chef#5937. This change replaces Nokogiri use with REXML instead. While REXML can be slower than Nokogiri, it does not require native extensions and is supported on all Chef platforms. Signed-off-by: Adam Leff <adam@leff.co>
This commit is contained in:
parent
68a930f141
commit
73d46f9c49
6 changed files with 60 additions and 65 deletions
|
@ -51,18 +51,11 @@ do_build() {
|
|||
local _libxslt_dir
|
||||
|
||||
_bundler_dir="$(pkg_path_for bundler)"
|
||||
_libxml2_dir="$(pkg_path_for libxml2)"
|
||||
_libxslt_dir="$(pkg_path_for libxslt)"
|
||||
|
||||
export GEM_HOME=${pkg_path}/vendor/bundle
|
||||
export GEM_PATH=${_bundler_dir}:${GEM_HOME}
|
||||
export BUNDLE_SILENCE_ROOT_WARNING=1
|
||||
|
||||
# don't let bundler split up the nokogiri config string (it breaks
|
||||
# the build), so specify it as an env var instead
|
||||
export NOKOGIRI_CONFIG="--use-system-libraries --with-zlib-dir=${_zlib_dir} --with-xslt-dir=${_libxslt_dir} --with-xml2-include=${_libxml2_dir}/include/libxml2 --with-xml2-lib=${_libxml2_dir}/lib"
|
||||
bundle config build.nokogiri "${NOKOGIRI_CONFIG}"
|
||||
|
||||
bundle install --jobs "$(nproc)" --retry 5 --standalone \
|
||||
--path "$pkg_prefix/bundle" \
|
||||
--binstubs "$pkg_prefix/bin"
|
||||
|
|
|
@ -39,7 +39,6 @@ Gem::Specification.new do |spec|
|
|||
spec.add_dependency 'mixlib-log'
|
||||
spec.add_dependency 'sslshake', '~> 1'
|
||||
spec.add_dependency 'parallel', '~> 1.9'
|
||||
spec.add_dependency 'nokogiri', '~> 1.6'
|
||||
spec.add_dependency 'faraday', '>=0.9.0'
|
||||
spec.add_dependency 'toml', '~> 0.1'
|
||||
spec.add_dependency 'addressable', '~> 2.5'
|
||||
|
|
|
@ -795,51 +795,61 @@ class InspecRspecJUnit < InspecRspecJson
|
|||
|
||||
#
|
||||
# This is the last method is invoked through the formatter interface.
|
||||
# Converts the junit formatter constructed output_hash into nokogiri generated
|
||||
# Converts the junit formatter constructed output_hash into REXML 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
|
||||
require 'rexml/document'
|
||||
xml_output = REXML::Document.new
|
||||
xml_output.add(REXML::XMLDecl.new)
|
||||
|
||||
testsuites = REXML::Element.new('testsuites')
|
||||
xml_output.add(testsuites)
|
||||
|
||||
@output_hash[:profiles].each do |profile|
|
||||
testsuites.add(build_profile_xml(profile))
|
||||
end
|
||||
|
||||
formatter = REXML::Formatters::Pretty.new
|
||||
formatter.compact = true
|
||||
output.puts formatter.write(xml_output.xml_decl, '')
|
||||
output.puts formatter.write(xml_output.root, '')
|
||||
end
|
||||
|
||||
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)
|
||||
def build_profile_xml(profile)
|
||||
profile_xml = REXML::Element.new('testsuite')
|
||||
profile_xml.add_attribute('name', profile[:name])
|
||||
profile_xml.add_attribute('tests', count_profile_tests(profile))
|
||||
profile_xml.add_attribute('failed', count_profile_failed_tests(profile))
|
||||
|
||||
profile[:controls].each do |control|
|
||||
next if control[:results].nil?
|
||||
|
||||
control[:results].each do |result|
|
||||
profile_xml.add(build_result_xml(control, result))
|
||||
end
|
||||
end
|
||||
|
||||
profile_xml
|
||||
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(control, result)
|
||||
result_xml = REXML::Element.new('testcase')
|
||||
result_xml.add_attribute('name', result[:code_desc])
|
||||
result_xml.add_attribute('class', control[:title].nil? ? 'Anonymous' : control[:id])
|
||||
result_xml.add_attribute('time', result[:run_time])
|
||||
|
||||
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
|
||||
if result[:status] == 'failed'
|
||||
failure_element = REXML::Element.new('failure')
|
||||
failure_element.add_attribute('message', result[:message])
|
||||
result_xml.add(failure_element)
|
||||
elsif result[:status] == 'skipped'
|
||||
result_xml.add_element('skipped')
|
||||
end
|
||||
|
||||
result_xml
|
||||
end
|
||||
|
||||
def count_profile_tests(profile)
|
||||
|
|
|
@ -23,7 +23,6 @@ dependency 'ruby'
|
|||
dependency 'rubygems'
|
||||
dependency 'bundler'
|
||||
dependency 'rb-readline'
|
||||
dependency 'nokogiri'
|
||||
dependency 'appbundler'
|
||||
|
||||
license :project_license
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# author: John Kerry
|
||||
|
||||
require 'functional/helper'
|
||||
require 'nokogiri'
|
||||
require 'rexml/document'
|
||||
|
||||
describe 'inspec exec with junit formatter' do
|
||||
include FunctionalHelper
|
||||
|
@ -11,47 +11,47 @@ describe 'inspec exec with junit formatter' do
|
|||
out = inspec('exec ' + example_control + ' --format junit --no-create-lockfile')
|
||||
out.stderr.must_equal ''
|
||||
out.exit_status.must_equal 0
|
||||
doc = Nokogiri::XML(out.stdout)
|
||||
doc.errors.length.must_equal 0
|
||||
doc = REXML::Document.new(out.stdout)
|
||||
doc.has_elements?.must_equal true
|
||||
end
|
||||
|
||||
it 'can execute the profile with the junit formatter' do
|
||||
out = inspec('exec ' + example_profile + ' --format junit --no-create-lockfile')
|
||||
out.stderr.must_equal ''
|
||||
out.exit_status.must_equal 0
|
||||
doc = Nokogiri::XML(out.stdout)
|
||||
doc.errors.length.must_equal 0
|
||||
doc = REXML::Document.new(out.stdout)
|
||||
doc.has_elements?.must_equal true
|
||||
end
|
||||
|
||||
describe 'execute a profile with junit formatting' do
|
||||
let(:doc) { Nokogiri::XML(inspec('exec ' + example_profile + ' --format junit --no-create-lockfile').stdout) }
|
||||
let(:doc) { REXML::Document.new(inspec('exec ' + example_profile + ' --format junit --no-create-lockfile').stdout) }
|
||||
|
||||
describe 'the document' do
|
||||
it 'has only one testsuite' do
|
||||
doc.xpath("//testsuite").length.must_equal 1
|
||||
doc.elements.to_a("//testsuite").length.must_equal 1
|
||||
end
|
||||
end
|
||||
describe 'the test suite' do
|
||||
let(:suite) { doc.xpath("//testsuites/testsuite").first}
|
||||
let(:suite) { doc.elements.to_a("//testsuites/testsuite").first }
|
||||
|
||||
it 'must have 5 testcase children' do
|
||||
suite.xpath("//testcase").length.must_equal 5
|
||||
suite.elements.to_a("//testcase").length.must_equal 5
|
||||
end
|
||||
|
||||
it 'has the tests attribute with 5 total tests' do
|
||||
suite["tests"].must_equal "5"
|
||||
suite.attribute('tests').value.must_equal "5"
|
||||
end
|
||||
|
||||
it 'has the failures attribute with 0 total tests' do
|
||||
suite["failed"].must_equal "0"
|
||||
suite.attribute('failed').value.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
|
||||
REXML::XPath.match(suite, "//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[@class='gordon-1.0' and @name='gordon_config']") }
|
||||
let(:gordon_yml_tests) { REXML::XPath.match(suite, "//testcase[@class='gordon-1.0' and @name='gordon_config']") }
|
||||
let(:first_gordon_test) {gordon_yml_tests.first}
|
||||
|
||||
it 'should be unique' do
|
||||
|
@ -59,7 +59,7 @@ describe 'inspec exec with junit formatter' do
|
|||
end
|
||||
|
||||
it 'should be skipped' do
|
||||
first_gordon_test.xpath("//skipped").length.must_equal 1
|
||||
first_gordon_test.elements.to_a('//skipped').length.must_equal 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,7 +8,6 @@ PATH
|
|||
json (>= 1.8, < 3.0)
|
||||
method_source (~> 0.8)
|
||||
mixlib-log
|
||||
nokogiri (~> 1.6)
|
||||
parallel (~> 1.9)
|
||||
pry (~> 0)
|
||||
rainbow (~> 2)
|
||||
|
@ -56,7 +55,7 @@ GEM
|
|||
concurrent-ruby (1.0.5)
|
||||
contracts (0.13.0)
|
||||
diff-lcs (1.3)
|
||||
docker-api (1.33.2)
|
||||
docker-api (1.33.3)
|
||||
excon (>= 0.38.0)
|
||||
json
|
||||
dotenv (2.2.0)
|
||||
|
@ -67,13 +66,12 @@ GEM
|
|||
eventmachine (1.2.3)
|
||||
excon (0.55.0)
|
||||
execjs (2.7.0)
|
||||
faraday (0.11.0)
|
||||
faraday (0.12.0.1)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
fast_blank (1.0.0)
|
||||
fastimage (2.1.0)
|
||||
ffi (1.9.18)
|
||||
github-markup (1.5.0)
|
||||
rinku
|
||||
github-markup (1.6.0)
|
||||
gssapi (1.2.0)
|
||||
ffi (>= 1.0.1)
|
||||
gyoku (1.3.1)
|
||||
|
@ -148,7 +146,6 @@ GEM
|
|||
middleman-syntax (3.0.0)
|
||||
middleman-core (>= 3.2)
|
||||
rouge (~> 2.0)
|
||||
mini_portile2 (2.1.0)
|
||||
minitest (5.10.1)
|
||||
mixlib-log (1.7.1)
|
||||
mixlib-shellout (2.2.7)
|
||||
|
@ -157,8 +154,6 @@ GEM
|
|||
net-scp (1.2.1)
|
||||
net-ssh (>= 2.6.5)
|
||||
net-ssh (4.1.0)
|
||||
nokogiri (1.7.1)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
nori (2.6.0)
|
||||
padrino-helpers (0.13.3.3)
|
||||
i18n (~> 0.6, >= 0.6.7)
|
||||
|
@ -183,7 +178,6 @@ GEM
|
|||
rb-inotify (0.9.8)
|
||||
ffi (>= 0.5.0)
|
||||
redcarpet (3.4.0)
|
||||
rinku (2.0.2)
|
||||
rouge (2.0.7)
|
||||
rspec (3.5.0)
|
||||
rspec-core (~> 3.5.0)
|
||||
|
@ -233,7 +227,7 @@ GEM
|
|||
winrm-fs (~> 1.0)
|
||||
tzinfo (1.2.3)
|
||||
thread_safe (~> 0.1)
|
||||
uglifier (3.1.11)
|
||||
uglifier (3.1.13)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
winrm (2.1.3)
|
||||
builder (>= 2.1.2)
|
||||
|
|
Loading…
Reference in a new issue