Repository URL to install this package:
|
Version:
2.3.23 ▾
|
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
require 'rspec/core'
require 'rspec/its'
require 'inspec/formatters'
# There be dragons!! Or borgs, or something...
# This file and all its contents cannot be unit-tested. both test-suits
# collide and disable all unit tests that have been added.
module Inspec
class RunnerRspec
def initialize(conf)
@conf = conf
@formatter = nil
reset
end
# Create a new RSpec example group from arguments and block.
#
# @param [Type] *args list of arguments for this example
# @param [Type] &block the block associated with this example group
# @return [RSpecExampleGroup]
def example_group(*args, &block)
RSpec::Core::ExampleGroup.describe(*args, &block)
end
# Add a full profile to the runner. Only pulls in metadata
#
# @param [Inspec::Profile] profile
# @return [nil]
def add_profile(profile)
RSpec.configuration.formatters
.find_all { |c| c.is_a?(Inspec::Formatters::Base) }
.each do |fmt|
fmt.add_profile(profile)
end
end
# Configure the backend of the runner.
#
# @param [Inspec::Backend] backend
# @return [nil]
def backend=(backend)
RSpec.configuration.formatters
.find_all { |c| c.is_a?(Inspec::Formatters::Base) }
.each do |fmt|
fmt.backend = backend
end
end
# Add an example group to the list of registered tests.
#
# @param [RSpecExampleGroup] example test
# @param [String] rule_id the ID associated with this check
# @return [nil]
def add_test(example, rule)
set_rspec_ids(example, rule)
@tests.example_groups.push(example)
end
# Retrieve the list of tests that have been added.
#
# @return [Array] full list of tests
def tests
@tests.ordered_example_groups
end
# Run all registered tests with an optional test runner.
#
# @param [RSpecRunner] with is an optional RSpecRunner
# @return [int] 0 if all went well; otherwise nonzero
def run(with = nil)
with ||= RSpec::Core::Runner.new(nil)
@rspec_exit_code = with.run_specs(tests)
@formatter.results
end
# Return a proper exit code to the runner
#
# @return [int] exit code
def exit_code
return @rspec_exit_code if @formatter.results.empty?
stats = @formatter.results[:statistics][:controls]
if stats[:failed][:total] == 0 && stats[:skipped][:total] == 0
0
elsif stats[:failed][:total] > 0
@conf['distinct_exit'] ? 100 : 1
elsif stats[:skipped][:total] > 0
@conf['distinct_exit'] ? 101 : 0
else
@rspec_exit_code
end
end
# Empty the list of registered tests.
#
# @return [nil]
def reset
@tests = RSpec::Core::World.new
# resets "pending examples" in reporter
RSpec.configuration.reset
configure_output
end
private
# Set optional formatters and output
#
#
def set_optional_formatters
return if @conf['reporter'].nil?
if @conf['reporter'].key?('json-rspec')
# We cannot pass in a nil output path. Rspec only accepts a valid string or a IO object.
if @conf['reporter']['json-rspec']&.[]('file').nil?
RSpec.configuration.add_formatter(Inspec::Formatters::RspecJson)
else
RSpec.configuration.add_formatter(Inspec::Formatters::RspecJson, @conf['reporter']['json-rspec']['file'])
end
@conf['reporter'].delete('json-rspec')
end
formats = @conf['reporter'].select { |k, _v| %w{documentation progress html}.include?(k) }
formats.each do |k, v|
# We cannot pass in a nil output path. Rspec only accepts a valid string or a IO object.
if v&.[]('file').nil?
RSpec.configuration.add_formatter(k.to_sym)
else
RSpec.configuration.add_formatter(k.to_sym, v['file'])
end
@conf['reporter'].delete(k)
end
end
# Configure the output formatter and stream to be used with RSpec.
#
# @return [nil]
def configure_output
RSpec.configuration.output_stream = $stdout
@formatter = RSpec.configuration.add_formatter(Inspec::Formatters::Base)
RSpec.configuration.add_formatter(Inspec::Formatters::ShowProgress, $stderr) if @conf[:show_progress]
set_optional_formatters
RSpec.configuration.color = @conf['color']
end
# Make sure that all RSpec example groups use the provided ID.
# At the time of creation, we didn't yet have full ID support in RSpec,
# which is why they were added to metadata directly. This is evaluated
# by the InSpec adjusted json formatter (rspec_json_formatter).
#
# @param [RSpecExampleGroup] example object which contains a check
# @return [Type] description of returned object
def set_rspec_ids(example, rule)
assign_rspec_ids(example.metadata, rule)
example.filtered_examples.each do |e|
assign_rspec_ids(e.metadata, rule)
end
example.children.each do |child|
set_rspec_ids(child, rule)
end
end
def assign_rspec_ids(metadata, rule)
metadata[:id] = ::Inspec::Rule.rule_id(rule)
metadata[:profile_id] = ::Inspec::Rule.profile_id(rule)
metadata[:impact] = rule.impact
metadata[:title] = rule.title
metadata[:descriptions] = rule.descriptions
metadata[:code] = rule.instance_variable_get(:@__code)
metadata[:source_location] = rule.instance_variable_get(:@__source_location)
end
end
end