Merge pull request #1442 from chef/ap/ortest-negate

Add negate! support for describe.one object
This commit is contained in:
Christoph Hartmann 2017-01-30 13:22:59 +01:00 committed by GitHub
commit a4d230e5ea
3 changed files with 236 additions and 25 deletions

View file

@ -5,15 +5,30 @@ module Inspec
attr_reader :tests
def initialize(tests)
@tests = tests
@negated = false
end
def skip
nil
end
def negate!
@negated = !@negated
end
def to_ruby
all_tests = @tests.map(&:to_ruby).join("\n").gsub("\n", "\n ")
format("describe.one do\n %s\nend", all_tests)
if @negated
# We don't use the describe.one wrapper when negated because:
# !(test1 || test2) same as (!test1 && !test2) where && is implicit in inspec
all_tests = @tests.map { |test|
test.negate!
test
}.map(&:to_ruby).join("\n")
return all_tests
else
all_tests = @tests.map(&:to_ruby).join("\n").gsub("\n", "\n ")
return format("describe.one do\n %s\nend", all_tests)
end
end
def to_hash

View file

@ -67,7 +67,7 @@ module Inspec
itsy = xtra.nil? ? 'it' : 'its(' + xtra.to_s.inspect + ')'
naughty = @negated ? '_not' : ''
xpect = defined?(@expectation) ? expectation.inspect : ''
if matcher == 'match'
if @expectation.class == Regexp
# without this, xpect values like / \/zones\// will not be parsed properly
xpect = "(#{xpect})"
elsif xpect != ''

View file

@ -6,60 +6,256 @@ require 'helper'
require 'inspec/objects'
describe 'Objects' do
describe 'Test' do
describe 'Inspec::Test' do
let(:obj) { Inspec::Test.new }
it 'constructs a simple resource+argument' do
obj.qualifier = [['resource'], ['arg']]
obj.to_ruby.must_equal "
obj.qualifier = [['resource'], ['version']]
obj.matcher = 'cmp >='
obj.expectation = '2.4.2'
obj.to_ruby.must_equal '
describe resource do
its(\"arg\") { should }
its("version") { should cmp >= "2.4.2" }
end
".strip
'.strip
end
it 'constructs a simple resource+argument with to_s' do
obj.qualifier = [['resource'], ['to_s']]
obj.to_ruby.must_equal "
obj.matcher = 'cmp'
obj.expectation = Regexp.new('^Desc.+$')
obj.to_ruby.must_equal '
describe resource.to_s do
it { should }
it { should cmp(/^Desc.+$/) }
end
".strip
'.strip
end
it 'constructs a simple resource+argument with to_i' do
obj.qualifier = [['resource'], ['to_i']]
obj.to_ruby.must_equal "
obj.matcher = 'cmp >'
obj.expectation = 3
obj.to_ruby.must_equal '
describe resource.to_i do
it { should }
it { should cmp > 3 }
end
".strip
'.strip
end
it 'constructs a simple resource+argument with array accessors' do
obj.qualifier = [['resource'], ['name[2]']]
obj.to_ruby.must_equal "
obj.matcher = 'exist'
obj.matcher = 'eq'
obj.expectation = 'mytest'
obj.to_ruby.must_equal '
describe resource.name[2] do
it { should }
it { should eq "mytest" }
end
".strip
'.strip
end
it 'constructs a simple resource+argument with method calls' do
obj.qualifier = [['resource'], ['hello', 'world']]
obj.to_ruby.must_equal "
describe resource.hello(\"world\") do
it { should }
obj.matcher = 'eq'
obj.expectation = 'mytest'
obj.to_ruby.must_equal '
describe resource.hello("world") do
it { should eq "mytest" }
end
".strip
'.strip
end
it 'constructs a simple resource+argument with method calls' do
obj.qualifier = [['resource'], [:world]]
obj.to_ruby.must_equal "
obj.qualifier = [['resource'], [:mode]]
obj.matcher = 'cmp'
obj.expectation = '0755'
obj.to_ruby.must_equal '
describe resource do
its(\"world\") { should }
its("mode") { should cmp "0755" }
end
".strip
'.strip
end
it 'constructs a resource+argument block with method call, matcher and expectation' do
obj.qualifier = [['command','ls /etc'], ['exit_status']]
obj.matcher = 'eq'
obj.expectation = 0
obj.to_ruby.must_equal '
describe command("ls /etc") do
its("exit_status") { should eq 0 }
end
'.strip
end
it 'constructs a simple describe with static data, negated regex matcher and expectation' do
obj.qualifier = [['"aaa"']]
obj.matcher = 'match'
obj.negate!
obj.expectation = Regexp.new('^aa.*')
obj.to_ruby.must_equal '
describe "aaa" do
it { should_not match(/^aa.*/) }
end
'.strip
end
it 'constructs a resource+argument block without a property call' do
obj.qualifier = [['service', 'avahi-daemon']]
obj.qualifier.push(["info['properties']['UnitFileState']"])
obj.expectation = "enabled"
obj.matcher = 'eq'
obj.to_ruby.must_equal '
describe service("avahi-daemon").info[\'properties\'][\'UnitFileState\'] do
it { should eq "enabled" }
end
'.strip
end
end
describe 'Inspec::EachLoop, each_loop' do
it 'constructs an each loop to match listening addresses' do
loop_obj = Inspec::EachLoop.new
loop_obj.qualifier = [['port', 25]]
loop_obj.qualifier.push(['addresses'])
obj = Inspec::Test.new
obj.matcher = 'match'
obj.negate!
obj.expectation = '0.0.0.0'
loop_obj.add_test(obj)
loop_obj.to_ruby.must_equal '
port(25).addresses.each do |entry|
describe entry do
it { should_not match "0.0.0.0" }
end
end
'.strip
end
end
describe 'Inspec::List' do
it 'constructs a list filtering test' do
list_obj = Inspec::List.new([['passwd']])
list_obj.qualifier.push(["where { user =~ /^(?!root|sync|shutdown|halt).*$/ }"])
obj = Inspec::Test.new
obj.qualifier = list_obj.qualifier
obj.matcher = 'be_empty'
obj.qualifier.push(['entries'])
obj.negate!
obj.to_ruby.must_equal '
describe passwd.where { user =~ /^(?!root|sync|shutdown|halt).*$/ } do
its("entries") { should_not be_empty }
end
'.strip
end
end
describe 'Inspec::OrTest and Inspec::Control' do
let(:obj1) do
obj1 = Inspec::Test.new
obj1.qualifier = [['command','ls /etc'], ['exit_status']]
obj1.matcher = 'eq'
obj1.expectation = 0
obj1
end
let(:obj2) do
obj2 = obj1.dup
obj2.negate!
obj2.expectation = 100
obj2
end
it 'constructs a simple describe.one block wrapping two tests' do
or_obj = Inspec::OrTest.new([obj1,obj2])
or_obj.to_ruby.must_equal '
describe.one do
describe command("ls /etc") do
its("exit_status") { should eq 0 }
end
describe command("ls /etc") do
its("exit_status") { should_not eq 100 }
end
end
'.strip
end
it 'negates a describe.one block, wow!' do
or_obj = Inspec::OrTest.new([obj1,obj2])
or_obj.negate!
or_obj.to_ruby.must_equal '
describe command("ls /etc") do
its("exit_status") { should_not eq 0 }
end
describe command("ls /etc") do
its("exit_status") { should eq 100 }
end
'.strip
end
it 'constructs a control' do
control = Inspec::Control.new
control.add_test(obj1)
control.id = 'sample.control.id'
control.title = 'Sample Control Important Title'
control.desc = 'The most critical control the world has ever seen'
control.impact = 1.0
control.to_ruby.must_equal '
control "sample.control.id" do
title "Sample Control Important Title"
desc "The most critical control the world has ever seen"
impact 1.0
describe command("ls /etc") do
its("exit_status") { should eq 0 }
end
end
'.strip
end
end
describe 'Inspec::Variable' do
it 'constructs a control with variable to instantiate a resource only once' do
control = Inspec::Control.new
variable = Inspec::Value.new([['command','which grep']])
variable_id = variable.name_variable.to_s
obj1 = Inspec::Test.new
obj1.variables.push(variable)
obj1.qualifier.push([variable_id])
obj1.qualifier.push(['exit_status'])
obj1.matcher = 'eq'
obj1.expectation = 0
control.add_test(obj1)
obj2 = Inspec::Test.new
obj2.qualifier.push([variable_id.to_s])
obj2.qualifier.push(['stdout'])
obj2.matcher = 'contain'
obj2.expectation = 'grep'
control.add_test(obj2)
control.id = 'variable.control.id'
control.title = 'Variable Control Important Title'
control.desc = 'The most variable control the world has ever seen'
control.impact = 1.0
control.to_ruby.must_equal '
control "variable.control.id" do
title "Variable Control Important Title"
desc "The most variable control the world has ever seen"
impact 1.0
a = command("which grep")
describe a do
its("exit_status") { should eq 0 }
end
describe a do
its("stdout") { should contain "grep" }
end
end
'.strip
end
end
end