Fixup behavior and add functional tests

This commit is contained in:
Kartik Null Cating-Subramanian 2016-08-19 18:58:39 -04:00 committed by Dominik Richter
parent 01763d43ed
commit 039c760545
6 changed files with 217 additions and 60 deletions

View file

@ -140,7 +140,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
def detect
o = opts.dup
o[:command] = 'os.params'
res = run_command(o)
(_, res) = run_command(o)
if opts['format'] == 'json'
puts res.to_json
else
@ -162,16 +162,23 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
diagnose
o = opts.dup
log_device = opts['format'] == 'json' ? nil : STDOUT
json_output = ['json', 'json-min'].include?(opts['format'])
log_device = json_output ? nil : STDOUT
o[:logger] = Logger.new(log_device)
o[:logger].level = get_log_level(o.log_level)
if o[:command].nil?
runner = Inspec::Runner.new(o)
return Inspec::Shell.new(runner).start
else
exit run_command(o)
end
run_type, res = run_command(o)
exit res unless run_type == :ruby_eval
# No InSpec tests - just print evaluation output.
res = (res.respond_to?(:to_json) ? res.to_json : JSON.dump(res)) if json_output
puts res
exit 0
rescue RuntimeError, Train::UserError => e
$stderr.puts e.message
end
@ -191,9 +198,13 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
def run_command(opts)
runner = Inspec::Runner.new(opts)
content = { content: opts[:command], ref: nil, line: nil }
runner.add_content(content, [])
runner.run
ctx = runner.create_context(opts)
res = ctx.load(opts[:command])
return :ruby_eval, res if ctx.rules.empty?
runner.register_rules(ctx)
return :rspec_run, runner.run # rubocop:disable Style/RedundantReturn
end
end

View file

@ -298,7 +298,7 @@ module Inspec
def load_dependencies
cwd = @target.is_a?(String) && File.directory?(@target) ? @target : nil
res = Inspec::Dependencies.new(cwd, nil)
res = Inspec::DependencySet.new(cwd, nil)
res.vendor(metadata.dependencies)
res
end

View file

@ -131,11 +131,6 @@ module Inspec
profile.runner_context = ctx
end
append_content(ctx, tests, libs, options)
end
# Returns the profile context used to evaluate the given content.
def append_content(ctx, tests, _libs, options = {})
# evaluate the test content
tests = [tests] unless tests.is_a? Array
tests.each { |t| add_test_to_context(t, ctx) }
@ -151,13 +146,12 @@ module Inspec
ctx
end
def reregister_rules(ctx)
def register_rules(ctx)
new_tests = false
ctx.rules.each do |rule_id, rule|
if yield rule_id, rule
new_tests = true
register_rule(rule_id, rule)
end
next if block_given? && !(yield rule_id, rule)
new_tests = true
register_rule(rule_id, rule)
end
new_tests
end

View file

@ -18,8 +18,7 @@ module Inspec
# Create an in-memory empty runner so that we can add tests to it later.
# This context lasts for the duration of this "start" method call/pry
# session.
c = { content: '', ref: nil, line: nil }
@ctx = @runner.add_content(c, [])
@ctx = @runner.create_context
configure_pry
# This will hold a single evaluation binding context as opened within
@ -27,7 +26,7 @@ module Inspec
# context creates to evaluate each individual test file. We want to
# pretend like we are constantly appending to the same file and want
# to capture the local variable context from inside said class.
@ctx_binding = @ctx.load('binding', nil, nil)
@ctx_binding = @ctx.load('binding')
@ctx_binding.pry
end
@ -62,7 +61,7 @@ module Inspec
# test file, register all the rules it discovered.
Pry.hooks.add_hook(:after_eval, 'inspec_after_eval') do
@current_eval_new_tests =
@runner.reregister_rules(@ctx) do |rule_id, rule|
@runner.register_rules(@ctx) do |rule_id, rule|
@current_eval_rules[rule_id] != Inspec::Rule.merge_count(rule)
end
@runner.run if @current_eval_new_tests

View file

@ -0,0 +1,191 @@
# encoding: utf-8
require 'functional/helper'
describe 'inspec shell tests' do
include FunctionalHelper
describe 'cmd' do
def do_shell_c(code, exit_status, json = false, stderr = '')
json_suffix = " --format 'json'" if json
out = inspec("shell -c '#{code.tr('\'','\\\'')}'#{json_suffix}")
out.stderr.must_equal stderr
out.exit_status.must_equal exit_status
out
end
it 'can run ruby expressions (json output)' do
x = rand
y = rand
out = do_shell_c("#{x} + #{y}", 0, true)
j = JSON.load(out.stdout)
j.must_equal x+y
end
it 'can run ruby expressions' do
x = rand
y = rand
out = do_shell_c("#{x} + #{y}", 0)
out.stdout.must_equal "#{x+y}\n"
end
it 'can run arbitrary ruby (json output)' do
out = do_shell_c('x = [1,2,3].inject(0) {|a,v| a + v*v}; x+10', 0, true)
j = JSON.load(out.stdout)
j.must_equal 24 # 1^2 + 2^2 + 3^2 + 10
end
it 'can run arbitrary ruby' do
out = do_shell_c('x = [1,2,3].inject(0) {|a,v| a + v*v}; x+10', 0)
out.stdout.must_equal "24\n"
end
it 'retrieves resources (json output)' do
out = do_shell_c('os.params', 0, true)
j = JSON.load(out.stdout)
j.keys.must_include 'name'
j.keys.must_include 'family'
j.keys.must_include 'arch'
j.keys.must_include 'release'
end
it 'retrieves resources' do
out = do_shell_c('os.params', 0)
out.stdout.must_include 'name'
out.stdout.must_include 'family'
out.stdout.must_include 'arch'
out.stdout.must_include 'release'
end
it 'runs anonymous tests that succeed (json output)' do
out = do_shell_c("describe file(\"#{__FILE__}\") do it { should exist } end", 0, true)
j = JSON.load(out.stdout)
j.keys.must_include 'version'
j.keys.must_include 'profiles'
j.keys.must_include 'other_checks'
j.keys.must_include 'summary'
j['summary']['example_count'].must_equal 1
j['summary']['failure_count'].must_equal 0
end
it 'runs anonymous tests that succeed' do
out = do_shell_c("describe file(\"#{__FILE__}\") do it { should exist } end", 0)
out.stdout.must_include '1 successful'
out.stdout.must_include '0 failures'
end
it 'runs anonymous tests that fail (json output)' do
out = do_shell_c("describe file(\"foo/bar/baz\") do it { should exist } end", 1, true)
j = JSON.load(out.stdout)
j.keys.must_include 'version'
j.keys.must_include 'profiles'
j.keys.must_include 'other_checks'
j.keys.must_include 'summary'
j['summary']['example_count'].must_equal 1
j['summary']['failure_count'].must_equal 1
end
it 'runs anonymous tests that fail' do
out = do_shell_c("describe file(\"foo/bar/baz\") do it { should exist } end", 1)
out.stdout.must_include '0 successful'
out.stdout.must_include '1 failures'
end
it 'runs controls with tests (json output)' do
out = do_shell_c("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end end", 0, true)
j = JSON.load(out.stdout)
j.keys.must_include 'version'
j.keys.must_include 'profiles'
j.keys.must_include 'other_checks'
j.keys.must_include 'summary'
j['summary']['example_count'].must_equal 1
j['summary']['failure_count'].must_equal 0
end
it 'runs controls with tests' do
out = do_shell_c("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end end", 0)
out.stdout.must_include '1 successful'
out.stdout.must_include '0 failures'
end
it 'runs controls with multiple tests (json output)' do
out = do_shell_c("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end; describe file(\"foo/bar/baz\") do it { should exist } end end", 1, true)
j = JSON.load(out.stdout)
j.keys.must_include 'version'
j.keys.must_include 'profiles'
j.keys.must_include 'other_checks'
j.keys.must_include 'summary'
j['summary']['example_count'].must_equal 2
j['summary']['failure_count'].must_equal 1
end
it 'runs controls with multiple tests' do
out = do_shell_c("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end; describe file(\"foo/bar/baz\") do it { should exist } end end", 1)
out.stdout.must_include '1 successful'
out.stdout.must_include '1 failures'
end
end
describe 'shell' do
def do_shell(code, exit_status = 0, stderr = '')
cmd = "echo '#{code.tr('\'','\\\'')}' | #{exec_inspec} shell"
out = CMD.run_command(cmd)
#out.stderr.must_equal stderr
out.exit_status.must_equal exit_status
out
end
it 'provides a help command' do
out = do_shell('help')
out.stdout.must_include 'Available commands:'
out.stdout.must_include 'You are currently running on:'
end
it 'exposes all resources' do
out = do_shell('os')
out.stdout.must_match /\=> .*Operating.* .*System.* .*Detection/
end
it 'can run ruby expressions' do
x = rand
y = rand
out = do_shell("#{x} + #{y}")
out.stdout.must_include "#{x+y}"
end
it 'can run arbitrary ruby' do
out = do_shell('x = [1,2,3].inject(0) {|a,v| a + v*v}; x+10')
out.stdout.must_include "24"
end
it 'runs anonymous tests that succeed' do
out = do_shell("describe file(\"#{__FILE__}\") do it { should exist } end")
out.stdout.must_include '1 successful'
out.stdout.must_include '0 failures'
end
it 'runs anonymous tests that fail' do
out = do_shell("describe file(\"foo/bar/baz\") do it { should exist } end")
out.stdout.must_include '0 successful'
out.stdout.must_include '1 failures'
end
it 'runs controls with tests' do
out = do_shell("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end end")
out.stdout.must_include '1 successful'
out.stdout.must_include '0 failures'
end
it 'runs controls with multiple tests' do
out = do_shell("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end; describe file(\"foo/bar/baz\") do it { should exist } end end")
out.stdout.must_include '1 successful'
out.stdout.must_include '1 failures'
end
it 'reruns controls when redefined' do
out = do_shell("control \"test\" do describe file(\"#{__FILE__}\") do it { should exist } end end\ncontrol \"test\" do describe file(\"foo/bar/baz\") do it { should exist } end end")
out.stdout.must_include '1 successful'
out.stdout.must_include '1 failures'
end
end
end

View file

@ -34,29 +34,6 @@ describe 'command tests' do
end
end
describe 'cmd' do
it 'can run arbitrary ruby' do
x = rand
y = rand
out = inspec("shell -c '#{x} + #{y}' --format 'json'")
out.stderr.must_equal ''
out.exit_status.must_equal 0
j = JSON.load(out.stdout)
j.must_equal x+y
end
it 'retrieves resources in JSON' do
out = inspec("shell -c 'os.params' --format 'json'")
out.stderr.must_equal ''
out.exit_status.must_equal 0
j = JSON.load(out.stdout)
j.keys.must_include 'name'
j.keys.must_include 'family'
j.keys.must_include 'arch'
j.keys.must_include 'release'
end
end
describe 'version' do
it 'provides the version number on stdout' do
out = inspec('version')
@ -66,21 +43,6 @@ describe 'command tests' do
end
end
describe 'shell' do
it 'provides a help command' do
out = CMD.run_command("echo \"help\nexit\" | #{exec_inspec} shell")
out.exit_status.must_equal 0
out.stdout.must_include 'Available commands:'
out.stdout.must_include 'You are currently running on:'
end
it 'exposes all resources' do
out = CMD.run_command("echo \"os\nexit\" | #{exec_inspec} shell")
out.exit_status.must_equal 0
out.stdout.must_match /^=> .*Operating.* .*System.* .*Detection.*$/
end
end
describe 'check' do
it 'verifies that a profile is ok' do
out = inspec('check ' + example_profile)