Skip to content

Commit

Permalink
(puppetlabsGH-2905) Update BoltSpec functions to allow absolute paths
Browse files Browse the repository at this point in the history
Updates BoltSpec `allow/expect_upload` and `allow/expect_script`
functions to accept an absolute path. The path referred to must still
exist, but that's relatively easy to mock with temporary files.

----

!bug

* **Update BoltSpec functions to allow absolute paths** ([puppetlabs#2905](puppetlabs#2905))

  BoltSpec's `allow_upload`, `expect_upload`, `allow_script`, and
  `expect_script` functions now support passing absolute paths that
  rather than a module reference. The referenced path must refer to a
  real file or upload and script functions will still error.
  • Loading branch information
MikaelSmith committed Aug 27, 2021
1 parent 183cedf commit 036f192
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 21 deletions.
10 changes: 6 additions & 4 deletions lib/bolt_spec/bolt_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,15 @@
#
# Stubs:
# - allow_command(cmd), expect_command(cmd): expect the exact command
# - allow_script(script), expect_script(script): expect the script as <module>/path/to/file
# - allow_script(script), expect_script(script): expect the script as <module>/path/to/file or an absolute path
# - allow_task(task), expect_task(task): expect the named task
# - allow_download(file), expect_download(file): expect the identified source file
# - allow_upload(file), expect_upload(file): expect the identified source file
# - allow_upload(file), expect_upload(file): expect the identified source file as <module>/path/to/file or an absolute path
# - allow_out_message, expect_out_message: expect a message to be passed to out::message (only modifiers are
# be_called_times(n), with_params(params), and not_be_called)
#
# Files with absolute path (for upload and script) must exist or those functions will fail.
#
# Stub modifiers:
# - be_called_times(n): if allowed, fail if the action is called more than 'n' times
# if expected, fail unless the action is called 'n' times
Expand Down Expand Up @@ -211,8 +213,8 @@ def expect_out_verbose
# def allow_script(script_name)
#
# file uploads and downloads have a single destination and no arguments
# def allow_file_upload(source_name)
# def allow_file_download(source_name)
# def allow_upload(source_name)
# def allow_download(source_name)
#
# Most of the information in commands is in the command string itself
# we may need more flexible allows than just the name/command string
Expand Down
6 changes: 3 additions & 3 deletions lib/bolt_spec/plans/mock_executor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def initialize(modulepath)

def module_file_id(file)
modpath = @modulepath.select { |path| file =~ /^#{path}/ }
raise "Could not identify modulepath containing #{file}: #{modpath}" unless modpath.size == 1
return nil unless modpath.size == 1

path = Pathname.new(file)
relative = path.relative_path_from(Pathname.new(modpath.first))
Expand All @@ -66,7 +66,7 @@ def run_command(targets, command, options = {}, _position = [])
end

def run_script(targets, script_path, arguments, options = {}, _position = [])
script = module_file_id(script_path)
script = module_file_id(script_path) || script_path
result = nil
if (doub = @script_doubles[script] || @script_doubles[:default])
result = doub.process(targets, script, arguments, options)
Expand Down Expand Up @@ -116,7 +116,7 @@ def download_file(targets, source, destination, options = {}, _position = [])
end

def upload_file(targets, source_path, destination, options = {}, _position = [])
source = module_file_id(source_path)
source = module_file_id(source_path) || source_path
result = nil
if (doub = @upload_doubles[source] || @upload_doubles[:default])
result = doub.process(targets, source, destination, options)
Expand Down
36 changes: 26 additions & 10 deletions spec/bolt_spec/plan_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
require 'bolt_spec/files'
require 'bolt_spec/plans'

# Requires targets, plan_name, return_expects to be set.
# Requires targets, plan_name, plan_params, return_expects to be set.
# Requires expect_action to be defined.
shared_examples 'action tests' do
it 'runs' do
expect_action
result = run_plan(plan_name, 'nodes' => targets)
result = run_plan(plan_name, plan_params.merge('nodes' => targets))
expect(result).to be_ok
expect(result.value.class).to eq(Bolt::ResultSet)
end
Expand All @@ -18,7 +18,7 @@
expect_action.return do |targets:, **kwargs|
Bolt::ResultSet.new(targets.map { |targ| Bolt::Result.new(targ, value: kwargs) })
end
result = run_plan(plan_name, 'nodes' => targets)
result = run_plan(plan_name, plan_params.merge('nodes' => targets))
expect(result).to be_ok
expect(result.value.class).to eq(Bolt::ResultSet)
results = result.value.result_hash
Expand All @@ -29,18 +29,22 @@

it 'errors' do
expect_action.error_with('msg' => 'failed', 'kind' => 'min')
result = run_plan(plan_name, 'nodes' => targets)
result = run_plan(plan_name, plan_params.merge('nodes' => targets))
expect(result).not_to be_ok
end

it 'fails when not stubbed' do
expect { run_plan(plan_name, 'nodes' => targets) }.to raise_error(RuntimeError, /Unexpected call to/)
expect {
run_plan(plan_name, plan_params.merge('nodes' => targets))
}.to raise_error(RuntimeError, /Unexpected call to/)
end

it 'prints expected parameters when erroring' do
params = Regexp.escape(expect_action.parameters.to_s)
expect_action.not_be_called
expect { run_plan(plan_name, 'nodes' => targets) }.to raise_error(RuntimeError, /#{params}/)
expect {
run_plan(plan_name, plan_params.merge('nodes' => targets))
}.to raise_error(RuntimeError, /#{params}/)
end
end

Expand All @@ -53,6 +57,7 @@ def modulepath
end

let(:targets) { %w[foo bar] }
let(:plan_params) { {} }

it 'prints notice' do
result = run_plan('plans', {})
Expand Down Expand Up @@ -106,8 +111,14 @@ def expect_action
let(:plan_name) { 'plans::script' }
let(:return_expects) { { script: 'plans/script', params: { 'arguments' => ['arg'] } } }

before(:each) do
allow_script('plans/dir/prep').with_targets(targets)
let(:plan_params) { { 'source' => @source } }

around(:each) do |example|
with_tempfile_containing('prep', '') do |file|
@source = file.path
allow_script(@source).with_targets(targets)
example.run
end
end

def expect_action
Expand Down Expand Up @@ -190,9 +201,14 @@ def expect_action
context 'with uploads' do
let(:plan_name) { 'plans::upload' }
let(:return_expects) { { source: 'plans/script', destination: '/d', params: {} } }
let(:plan_params) { { 'source' => @source } }

before(:each) do
allow_upload('plans/dir/prep').with_targets(targets)
around(:each) do |example|
with_tempfile_containing('prep', '') do |file|
@source = file.path
allow_upload(@source).with_targets(targets)
example.run
end
end

def expect_action
Expand Down
4 changes: 2 additions & 2 deletions spec/fixtures/bolt_spec/plans/plans/script.pp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
plan plans::script(TargetSpec $nodes) {
run_script('plans/dir/prep', $nodes)
plan plans::script(TargetSpec $nodes, String $source) {
run_script($source, $nodes)
return run_script('plans/script', $nodes, 'arguments' => ['arg'])
}
4 changes: 2 additions & 2 deletions spec/fixtures/bolt_spec/plans/plans/upload.pp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
plan plans::upload(TargetSpec $nodes) {
upload_file('plans/dir/prep', '/b', $nodes)
plan plans::upload(TargetSpec $nodes, String $source) {
upload_file($source, '/b', $nodes)
return upload_file('plans/script', '/d', $nodes)
}

0 comments on commit 036f192

Please sign in to comment.