diff --git a/lib/inspec/rspec_json_formatter.rb b/lib/inspec/rspec_json_formatter.rb index 9c705a8ad..b55162a97 100644 --- a/lib/inspec/rspec_json_formatter.rb +++ b/lib/inspec/rspec_json_formatter.rb @@ -164,10 +164,32 @@ class InspecRspecJson < InspecRspecMiniJson [info[:name], info] end + # + # TODO(ssd+vj): We should probably solve this by either ensuring the example has + # the profile_id of the top level profile when it is included as a dependency, or + # by registrying all dependent profiles with the formatter. The we could remove + # this heuristic matching. + # + def example2profile(example, profiles) + profiles.values.find { |p| profile_contains_example?(p, example) } + end + + def profile_contains_example?(profile, example) + # Heuristic for finding the profile an example came from: + # Case 1: The profile_id on the example matches the name of the profile + # Case 2: The profile contains a control that matches the id of the example + if profile[:name] == example[:profile_id] + true + elsif profile[:controls] && profile[:controls].key?(example[:id]) + true + else + false + end + end + def example2control(example, profiles) - profile = profiles[example[:profile_id]] - return nil if profile.nil? || profile[:controls].nil? - profile[:controls][example[:id]] + p = example2profile(example, profiles) + p[:controls][example[:id]] if p && p[:controls] end def format_example(example) diff --git a/test/functional/helper.rb b/test/functional/helper.rb index 6f3a8627c..7db068501 100644 --- a/test/functional/helper.rb +++ b/test/functional/helper.rb @@ -23,6 +23,7 @@ module FunctionalHelper let(:example_control) { File.join(example_profile, 'controls', 'example.rb') } let(:inheritance_profile) { File.join(examples_path, 'profile') } let(:failure_control) { File.join(profile_path, 'failures', 'controls', 'failures.rb') } + let(:simple_inheritance) { File.join(profile_path, 'simple-inheritance') } let(:dst) { # create a temporary path, but we only want an auto-clean helper diff --git a/test/functional/inspec_exec_test.rb b/test/functional/inspec_exec_test.rb index 7b6dbc380..1ae732b38 100644 --- a/test/functional/inspec_exec_test.rb +++ b/test/functional/inspec_exec_test.rb @@ -147,4 +147,27 @@ Summary: \e[32m2 successful\e[0m, \e[31m0 failures\e[0m, \e[37m0 skipped\e[0m out.stdout.must_include "undefined method `should_nota' " end end + + describe 'given an inherited profile that has more that one test per control block' do + let(:out) { inspec('exec ' + simple_inheritance) } + + it 'should print all the results' do + out.stdout.force_encoding(Encoding::UTF_8).must_include "✖ tmp-1.0: Create /tmp directory (1 failed)\e[0m" + out.stdout.force_encoding(Encoding::UTF_8).must_include "✖ should not be directory\e[0m" + out.stdout.force_encoding(Encoding::UTF_8).must_include "✖ undefined method `should_nota'" + out.stdout.force_encoding(Encoding::UTF_8).must_include "✖ expected `File /tmp.directory?` to return false, got true\e[0m" + end + end + + describe 'when passing in two profiles given an inherited profile that has more that one test per control block' do + let(:out) { inspec('exec ' + File.join(profile_path, 'dependencies', 'profile_d') + ' ' + simple_inheritance) } + + it 'should print all the results' do + out.stdout.force_encoding(Encoding::UTF_8).must_include "✖ tmp-1.0: Create /tmp directory (1 failed)\e[0m" + out.stdout.force_encoding(Encoding::UTF_8).must_include "✖ should not be directory\e[0m" + out.stdout.force_encoding(Encoding::UTF_8).must_include "✖ undefined method `should_nota'" + out.stdout.force_encoding(Encoding::UTF_8).must_include "✖ expected `File /tmp.directory?` to return false, got true\e[0m" + out.stdout.force_encoding(Encoding::UTF_8).must_include "✔ profiled-1: Create /tmp directory (profile d)" + end + end end diff --git a/test/unit/mock/profiles/failures/controls/failures.rb b/test/unit/mock/profiles/failures/controls/failures.rb index c778a9336..ca5a70dfd 100644 --- a/test/unit/mock/profiles/failures/controls/failures.rb +++ b/test/unit/mock/profiles/failures/controls/failures.rb @@ -2,10 +2,31 @@ # copyright: 2015, Chef Software, Inc. # license: All rights reserved -title '/tmp profile' +title 'failures /tmp profile' -# you can also use plain tests +# control, first test passes, second fails +control "tmp-1.0" do # A unique ID for this control + impact 0.7 # The criticality, if this control fails. + title "Create /tmp directory" # A human-readable title + desc "An optional description..." # Describe why this is needed + tag data: "temp data" # A tag allows you to associate key information + tag "security" # to the test + ref "Document A-12", url: 'http://...' # Additional references + + describe file('/tmp') do # The actual test + it { should be_directory } + it { should_not be_directory } + end +end + +# anonymous describe block, first passes, second is syntax error describe file('/tmp') do it { should be_directory } it { should_nota be_directory } end + +# anonymous describe block, first fails, second passes +describe file('/tmp') do + it { should_not be_directory } + it { should be_directory } +end diff --git a/test/unit/mock/profiles/failures/inspec.yml b/test/unit/mock/profiles/failures/inspec.yml new file mode 100644 index 000000000..9c6a347aa --- /dev/null +++ b/test/unit/mock/profiles/failures/inspec.yml @@ -0,0 +1,8 @@ +name: failures +title: InSpec Profile +maintainer: The Authors +copyright: The Authors +copyright_email: you@example.com +license: All Rights Reserved +summary: An InSpec Compliance Profile +version: 0.1.0 diff --git a/test/unit/mock/profiles/simple-inheritance/controls/simple-inheritance.rb b/test/unit/mock/profiles/simple-inheritance/controls/simple-inheritance.rb new file mode 100644 index 000000000..4d3f9e943 --- /dev/null +++ b/test/unit/mock/profiles/simple-inheritance/controls/simple-inheritance.rb @@ -0,0 +1,7 @@ +# encoding: utf-8 + +include_controls 'failures' + +describe file('/tmp') do + it { should be_directory } +end diff --git a/test/unit/mock/profiles/simple-inheritance/inspec.yml b/test/unit/mock/profiles/simple-inheritance/inspec.yml new file mode 100644 index 000000000..3916a8021 --- /dev/null +++ b/test/unit/mock/profiles/simple-inheritance/inspec.yml @@ -0,0 +1,10 @@ +name: simple inheritance +title: InSpec example simple inheritance +maintainer: Chef Software, Inc. +copyright: Chef Software, Inc. +copyright_email: support@chef.io +license: Apache 2 license +version: 1.0.0 +depends: + - name: failures + path: ../failures