mirror of
https://github.com/inspec/inspec
synced 2024-11-10 15:14:23 +00:00
Improvements to the functional helper run_inspec_process (#3603)
* Add run_inspec_process, with JSON handling, to functional helper * Add ability to run a plugin to functional helper * CWD fix for run_inspec_process * Add support for running a plugin within a functional test * Move plugin functional helper code to main func helper file * FuncHelper: Do not send reporter or lock options if command is not exec Signed-off-by: Clinton Wolfe <clintoncwolfe@gmail.com>
This commit is contained in:
parent
82af39e25a
commit
35ad5d5528
2 changed files with 134 additions and 14 deletions
|
@ -4,6 +4,11 @@
|
||||||
|
|
||||||
require 'helper'
|
require 'helper'
|
||||||
require 'rbconfig'
|
require 'rbconfig'
|
||||||
|
require 'byebug'
|
||||||
|
require 'json'
|
||||||
|
require 'fileutils'
|
||||||
|
require 'yaml'
|
||||||
|
require 'tmpdir'
|
||||||
|
|
||||||
require 'minitest/hell'
|
require 'minitest/hell'
|
||||||
class Minitest::Test
|
class Minitest::Test
|
||||||
|
@ -14,6 +19,23 @@ class Module
|
||||||
include Minitest::Spec::DSL
|
include Minitest::Spec::DSL
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module Inspec
|
||||||
|
class FuncTestRunResult
|
||||||
|
attr_reader :train_result
|
||||||
|
attr_reader :payload
|
||||||
|
|
||||||
|
extend Forwardable
|
||||||
|
def_delegator :train_result, :stdout
|
||||||
|
def_delegator :train_result, :stderr
|
||||||
|
def_delegator :train_result, :exit_status
|
||||||
|
|
||||||
|
def initialize(train_result)
|
||||||
|
@train_result = train_result
|
||||||
|
@payload = OpenStruct.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
module FunctionalHelper
|
module FunctionalHelper
|
||||||
let(:repo_path) do
|
let(:repo_path) do
|
||||||
path = File.expand_path(File.join( __FILE__, '..', '..', '..'))
|
path = File.expand_path(File.join( __FILE__, '..', '..', '..'))
|
||||||
|
@ -71,27 +93,68 @@ module FunctionalHelper
|
||||||
convert_windows_output(result.stdout)
|
convert_windows_output(result.stdout)
|
||||||
# remove the CLIXML header trash in windows
|
# remove the CLIXML header trash in windows
|
||||||
result.stderr.gsub!("#< CLIXML\n", '')
|
result.stderr.gsub!("#< CLIXML\n", '')
|
||||||
result
|
Inspec::FuncTestRunResult.new(result)
|
||||||
else
|
else
|
||||||
CMD.run_command("#{prefix} #{exec_inspec} #{commandline}")
|
Inspec::FuncTestRunResult.new(CMD.run_command("#{prefix} #{exec_inspec} #{commandline}"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def inspec_with_env(commandline, env = {})
|
def inspec_with_env(commandline, env = {})
|
||||||
# CMD is a train transport, and does not support anything other than a
|
inspec(commandline, assemble_env_prefix(env))
|
||||||
# single param for the command line.
|
|
||||||
# TODO: what is the intent of using Train here?
|
|
||||||
# HACK: glue together env vars
|
|
||||||
if is_windows?
|
|
||||||
env_prefix = env.to_a.map { |assignment| "set #{assignment[0]}=#{assignment[1]}" }.join('&& ')
|
|
||||||
env_prefix += '&& '
|
|
||||||
else
|
|
||||||
env_prefix = env.to_a.map { |assignment| "#{assignment[0]}=#{assignment[1]}" }.join(' ')
|
|
||||||
env_prefix += ' '
|
|
||||||
end
|
|
||||||
inspec(commandline, env_prefix)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This version allows additional options.
|
||||||
|
# @param String command_line Invocation, without the word 'inspec'
|
||||||
|
# @param Hash opts Additonal options, see below
|
||||||
|
# :env Hash A hash of environment vars to expose to the invocation.
|
||||||
|
# :prefix String A string to prefix to the invocation. Prefix + env + invocation is the order.
|
||||||
|
# :cwd String A directory to change to. Implemented as 'cd CWD && ' + prefix
|
||||||
|
# :lock Boolean Default false. If false, add `--no-create-lockfile`.
|
||||||
|
# :json Boolean Default false. If true, add `--reporter json` and parse the output, which is stored in payload.json .
|
||||||
|
# :tmpdir Boolean default true. If true, wrap execution in a Dir.tmpdir block. Use pre_run and post_run to trigger actions.
|
||||||
|
# :pre_run: Proc(tmp_dir_path) - optional setup block.
|
||||||
|
# tmp_dir will exist and be empty.
|
||||||
|
# :post_run: Proc(FuncTestRunResult, tmp_dir_path) - optional result capture block.
|
||||||
|
# run_result will be populated, but you can add more to the ostruct .payload
|
||||||
|
# tmp_dir will still exist (for a moment!)
|
||||||
|
# @return FuncTestRunResult. Includes attrs exit_status, stderr, stdout, payload (an openstruct which may be used in many ways)
|
||||||
|
def run_inspec_process(command_line, opts)
|
||||||
|
raise 'Do not use tmpdir and cwd in the same invocation' if opts[:cwd] && opts[:tmpdir]
|
||||||
|
prefix = opts[:cwd] ? 'cd ' + opts[:cwd] + ' && ' : ''
|
||||||
|
prefix += opts[:prefix] || ''
|
||||||
|
prefix += assemble_env_prefix(opts[:env])
|
||||||
|
command_line += ' --reporter json ' if opts[:json] && command_line =~ /\bexec\b/
|
||||||
|
command_line += ' --no-create-lockfile ' if (!opts[:lock]) && command_line =~ /\bexec\b/
|
||||||
|
|
||||||
|
run_result = nil
|
||||||
|
if opts[:tmpdir]
|
||||||
|
Dir.mktmpdir do |tmp_dir|
|
||||||
|
opts[:pre_run].call(tmp_dir) if opts[:pre_run]
|
||||||
|
# Do NOT Dir.chdir here - chdir / pwd is per-process, and we are in the
|
||||||
|
# test harness process, which will be multithreaded because we parallelize the tests.
|
||||||
|
# Instead, make the spawned process change dirs using a cd prefix.
|
||||||
|
prefix = 'cd ' + tmp_dir + ' && ' + prefix
|
||||||
|
run_result = inspec(command_line, prefix)
|
||||||
|
opts[:post_run].call(run_result, tmp_dir) if opts[:post_run]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
run_result = inspec(command_line, prefix)
|
||||||
|
end
|
||||||
|
|
||||||
|
if opts[:json]
|
||||||
|
begin
|
||||||
|
run_result.payload.json = JSON.parse(run_result.stdout)
|
||||||
|
rescue JSON::ParserError => e
|
||||||
|
run_result.payload.json = {}
|
||||||
|
run_result.payload.json_error = e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
run_result
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Copy all examples to a temporary directory for functional tests.
|
# Copy all examples to a temporary directory for functional tests.
|
||||||
# You can provide an optional directory which will be handed to your
|
# You can provide an optional directory which will be handed to your
|
||||||
# test block with its absolute path. If nothing is provided you will
|
# test block with its absolute path. If nothing is provided you will
|
||||||
|
@ -106,4 +169,60 @@ module FunctionalHelper
|
||||||
block.call(File.join(tmpdir, bn, dir.to_s))
|
block.call(File.join(tmpdir, bn, dir.to_s))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def assemble_env_prefix(env = {})
|
||||||
|
if is_windows?
|
||||||
|
env_prefix = env.to_a.map { |assignment| "set #{assignment[0]}=#{assignment[1]}" }.join('&& ')
|
||||||
|
env_prefix += '&& '
|
||||||
|
else
|
||||||
|
env_prefix = env.to_a.map { |assignment| "#{assignment[0]}=#{assignment[1]}" }.join(' ')
|
||||||
|
env_prefix += ' '
|
||||||
|
end
|
||||||
|
env_prefix
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#=========================================================================================#
|
||||||
|
# Plugin Support
|
||||||
|
#=========================================================================================#
|
||||||
|
module PluginFunctionalHelper
|
||||||
|
include FunctionalHelper
|
||||||
|
|
||||||
|
def run_inspec_with_plugin(command, opts)
|
||||||
|
pre = Proc.new do |tmp_dir|
|
||||||
|
content = JSON.generate(__make_plugin_file_data_structure_with_path(opts[:plugin_path]))
|
||||||
|
File.write(File.join(tmp_dir, 'plugins.json'), content)
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.merge!({
|
||||||
|
pre_run: pre,
|
||||||
|
tmpdir: true,
|
||||||
|
json: true,
|
||||||
|
env: {
|
||||||
|
"INSPEC_CONFIG_DIR" => '.' # We're in tmpdir
|
||||||
|
}
|
||||||
|
})
|
||||||
|
run_inspec_process(command, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
def __make_plugin_file_data_structure_with_path(path)
|
||||||
|
# TODO: dry this up, refs #3350
|
||||||
|
plugin_name = File.basename(path, '.rb')
|
||||||
|
data = __make_empty_plugin_file_data_structure
|
||||||
|
data['plugins'] << {
|
||||||
|
'name' => plugin_name,
|
||||||
|
'installation_type' => 'path',
|
||||||
|
'installation_path' => path,
|
||||||
|
}
|
||||||
|
data
|
||||||
|
end
|
||||||
|
|
||||||
|
def __make_empty_plugin_file_data_structure
|
||||||
|
# TODO: dry this up, refs #3350
|
||||||
|
{
|
||||||
|
'plugins_config_version' => '1.0.0',
|
||||||
|
'plugins' => [],
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Functional tests related to plugin facility
|
# Functional tests related to plugin facility
|
||||||
require 'functional/helper'
|
require 'functional/helper'
|
||||||
|
|
||||||
|
|
||||||
#=========================================================================================#
|
#=========================================================================================#
|
||||||
# Loader Errors
|
# Loader Errors
|
||||||
#=========================================================================================#
|
#=========================================================================================#
|
||||||
|
|
Loading…
Reference in a new issue