Ensure resources are visible inside its blocks

The recent changes to provide isolated views of the available resources
was not extended to Rspec::ExampleGroups. This ensures that
ExampleGroups have access to the same resources as the enclosing
Inspec::Rule.

Signed-off-by: Steven Danna <steve@chef.io>
This commit is contained in:
Steven Danna 2016-09-14 14:57:26 +01:00
parent ee2cbafc6e
commit 8024eea8b7
No known key found for this signature in database
GPG key ID: 94DFB46E861A7DAE
5 changed files with 107 additions and 18 deletions

View file

@ -23,7 +23,7 @@ module Inspec
require 'rspec/core/dsl'
Class.new(Inspec::Rule) do
include RSpec::Core::DSL
include resources_dsl
with_resource_dsl resources_dsl
end
end

View file

@ -122,10 +122,12 @@ module Inspec
@rules.delete(full_id(@profile_id, id))
end
attr_reader :current_load
def register_rule(r)
# get the full ID
r.instance_variable_set(:@__file, @current_load[:file])
r.instance_variable_set(:@__group_title, @current_load[:title])
r.instance_variable_set(:@__file, current_load[:file])
r.instance_variable_set(:@__group_title, current_load[:title])
# add the rule to the registry
fid = full_id(Inspec::Rule.profile_id(r), Inspec::Rule.rule_id(r))

View file

@ -12,6 +12,24 @@ module Inspec
class Rule # rubocop:disable Metrics/ClassLength
include ::RSpec::Matchers
#
# Include any resources from the given resource DSL. The passed
# resource_dsl will also be included in any Inspec::Expect objects
# we make.
#
# @params resource_dsl [Module]
# @returns [TrueClass]
#
def self.with_resource_dsl(resource_dsl)
include resource_dsl
@resource_dsl = resource_dsl
true
end
def self.resource_dsl # rubocop:disable Style/TrivialAccessors
@resource_dsl
end
def initialize(id, profile_id, _opts, &block)
@impact = nil
@title = nil
@ -106,12 +124,12 @@ module Inspec
include dsl
end.new(method(:__add_check))
else
__add_check('describe', values, block)
__add_check('describe', values, with_dsl(block))
end
end
def expect(value, &block)
target = Inspec::Expect.new(value, &block)
target = Inspec::Expect.new(value, &with_dsl(block))
__add_check('expect', [value], target)
target
end
@ -188,6 +206,31 @@ module Inspec
@__checks.push([describe_or_expect, values, block])
end
#
# Takes a block and returns a block that will run the given block
# with access to the resource_dsl of the current class. This is to
# ensure that inside the constructed Rspec::ExampleGroup users
# have access to DSL methods. Previous this was done in
# Inspec::Runner before sending the example groups to rspec. It
# was moved here to ensure that code inside `its` blocks hae the
# same visibility into resources as code outside its blocks.
#
# @param [Proc] block
# @return [Proc]
#
def with_dsl(block)
return nil if block.nil?
if self.class.resource_dsl
dsl = self.class.resource_dsl
proc do |*args|
include dsl
instance_exec(*args, &block)
end
else
block
end
end
# Idio(ma)tic unindent
# TODO: replace this
#

View file

@ -231,21 +231,11 @@ module Inspec
Inspec::Log.debug "Registering rule #{rule}"
@rules << rule
checks = ::Inspec::Rule.prepare_checks(rule)
examples = checks.map do |m, a, b|
examples = checks.flat_map do |m, a, b|
get_check_example(m, a, b)
end.flatten.compact
end.compact
examples.each do |example|
# TODO: Remove this!! It is very dangerous to do this here.
# The goal of this is to make the audit DSL available to all
# describe blocks. Right now, these blocks are executed outside
# the scope of this run, thus not gaining ony of the DSL pieces.
# To circumvent this, the full DSL is attached to the example's
# scope.
dsl = Inspec::Resource.create_dsl(backend)
example.send(:include, dsl)
@test_collector.add_test(example, rule)
end
examples.each { |e| @test_collector.add_test(e, rule) }
end
end
end

View file

@ -0,0 +1,54 @@
# encoding: utf-8
# author: Steven Danna
require 'helper'
require 'rspec/core'
require 'inspec/control_eval_context'
describe Inspec::ControlEvalContext do
module FakeDSL
def foobar
"wombat"
end
end
Inspec::Log.level = :debug
let(:control_content) { <<EOF
control 'foo' do
describe foobar do
end
end
control 'bar' do
describe "wombat" do
it { should_equal foobar }
end
end
EOF
}
let(:resource_dsl) { FakeDSL }
let(:backend) { mock() }
let(:profile_context) { Inspec::ProfileContext.new('test-profile', backend, {}) }
let(:eval_context) do
c = Inspec::ControlEvalContext.create(profile_context, resource_dsl)
# A lot of mocking here :(
c.new(backend, mock(), mock(), mock())
end
it 'accepts a context and a resource_dsl' do
Inspec::ControlEvalContext.create(profile_context, resource_dsl)
end
it 'provides rules with access to the given DSL' do
profile_context.stubs(:current_load).returns({file: "<test content>"})
eval_context.instance_eval(control_content)
profile_context.all_rules.each do |rule|
# Turn each rule into an example group and run it, none of the example content should raise an
# exception
Inspec::Rule.prepare_checks(rule).each do |m, a, b|
RSpec::Core::ExampleGroup.describe(*a, &b).run
end
end
end
end