Skip to content

Commit

Permalink
Merge pull request #952 from nabertrand/cli_tests
Browse files Browse the repository at this point in the history
Add R10K::CLI tests
  • Loading branch information
adrienthebo authored Apr 21, 2020
2 parents 9c0b9b2 + 5515f6c commit 758564a
Show file tree
Hide file tree
Showing 5 changed files with 424 additions and 17 deletions.
32 changes: 20 additions & 12 deletions lib/r10k/cli/deploy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,6 @@ def self.command
(https://puppet.com/docs/puppet/latest/environments_about.html).
DESCRIPTION

required nil, :cachedir, 'Specify a cachedir, overriding the value in config'
flag nil, :'no-force', 'Prevent the overwriting of local module modifications'
flag nil, :'generate-types', 'Run `puppet generate types` after updating an environment'
option nil, :'puppet-path', 'Path to puppet executable', argument: :required do |value, cmd|
unless File.executable? value
$stderr.puts "The specified puppet executable #{value} is not executable."
puts cmd.help
exit 1
end
end

run do |opts, args, cmd|
puts cmd.help(:verbose => opts[:verbose])
exit 0
Expand Down Expand Up @@ -60,8 +49,18 @@ def self.command
scheduled. On subsequent deployments, Puppetfile deployment will default to off.
DESCRIPTION

flag :p, :puppetfile, 'Deploy modules from a puppetfile'
required nil, :cachedir, 'Specify a cachedir, overriding the value in config'
required nil, :'default-branch-override', 'Specify a branchname to override the default branch in the puppetfile'
flag nil, :'generate-types', 'Run `puppet generate types` after updating an environment'
flag nil, :'no-force', 'Prevent the overwriting of local module modifications'
option nil, :'puppet-path', 'Path to puppet executable', argument: :required do |value, cmd|
unless File.executable? value
$stderr.puts "The specified puppet executable #{value} is not executable."
puts cmd.help
exit 1
end
end
flag :p, :puppetfile, 'Deploy modules from a puppetfile'

runner R10K::Action::CriRunner.wrap(R10K::Action::Deploy::Environment)
end
Expand All @@ -82,6 +81,15 @@ def self.command
DESCRIPTION

required :e, :environment, 'Update the modules in the given environment'
flag nil, :'generate-types', 'Run `puppet generate types` after updating an environment'
flag nil, :'no-force', 'Prevent the overwriting of local module modifications'
option nil, :'puppet-path', 'Path to puppet executable', argument: :required do |value, cmd|
unless File.executable? value
$stderr.puts "The specified puppet executable #{value} is not executable."
puts cmd.help
exit 1
end
end

runner R10K::Action::CriRunner.wrap(R10K::Action::Deploy::Module)
end
Expand Down
27 changes: 27 additions & 0 deletions spec/shared-contexts/cli.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
shared_context 'cli' do
def exit_with_code_and_message(r10k_args, code = 0, message = nil, out = 'stdout')
expect do
expect { r10k.run(r10k_args) }.to exit_with(code)
end.to output(message).send("to_#{out}".to_sym)
end

def filtered_extra_args
extra_args.reject { |arg| arg == '--' }
end

def string_to_module(str)
str.split('::').inject(Object) { |o, c| o.const_get c }
end

def setup_mock_run(command)
command.block = lambda do |opts, args, cmd|
[opts, args.to_a, cmd]
end
end

def setup_mock_runner(command, klass)
command.block = lambda do |opts, args, cmd|
klass.new(opts, args.to_a, cmd)
end
end
end
182 changes: 182 additions & 0 deletions spec/shared-examples/cli.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
shared_examples 'missing argument' do |option, optinfo|
it 'prints error and exits 1' do
["--#{option}", optinfo[:short]].compact.each do |opt|
exit_with_code_and_message(command_args + [opt] + extra_args, 1, %r{option requires an argument}, 'stderr')
end
end
end

shared_examples 'accepts option' do |option, optinfo, value|
it 'accepts the option' do
["--#{option}", optinfo[:short]].compact.each do |opt|
expect(r10k.run(command_args + [opt, value].compact + extra_args)).to eq([{ option.to_sym => value || true }, filtered_extra_args, command])
end
end
end

shared_examples 'help option' do |option, optinfo|
context "when #{option} specified" do
it 'prints command help and exits 0' do
["--#{option}", optinfo[:short]].compact.each do |help_arg|
expect(command).to receive(:help).and_call_original
exit_with_code_and_message(command_args + [help_arg] + extra_args, 0, %r{USAGE\s*r10k #{command_args.join(' ')}})
end
end
end
end

shared_examples 'Cri argument parsing' do |options, include_parent_examples|
context 'Cri argument parsing' do
let!(:prev_run) { command.block }

before(:each) do
setup_mock_run(command)
end

after(:each) do
command.block = prev_run
end

options.each do |option, optinfo|
if optinfo[:custom_cri_examples]
optinfo[:custom_cri_examples].each do |examples|
include_examples examples, option, optinfo
end
next
end

case optinfo[:type]
when :required
context "when #{option} specified without an argument" do
include_examples 'missing argument', option, optinfo
end

context "when #{option} specified with an argument" do
include_examples 'accepts option', option, optinfo, optinfo[:value]
end
when :optional
context "when #{option} specified without an argument" do
include_examples 'accepts option', option, optinfo, nil
end

context "when #{option} specified with an argument" do
include_examples 'accepts option', option, optinfo, optinfo[:value]
end
when :flag
context "when #{option} specified" do
include_examples 'accepts option', option, optinfo, nil
end
else
raise ArgumentError, "Unknown option type #{optinfo} for #{option}"
end
end

include_examples 'parent command examples' if include_parent_examples
end
end

shared_examples 'parent command examples' do
context 'with no arguments' do
it 'prints command help and exits 0' do
command.block = prev_run
expect(command).to receive(:help).and_call_original
exit_with_code_and_message(command_args, 0, %r{USAGE\s*r10k #{command_args.join(' ')}})
end
end

context 'with unknown argument' do
let(:command_args) { super() + ['invalid_arg'] }

it 'prints error to stderr and exits 1' do
exit_with_code_and_message(command_args, 1, %r{unknown command 'invalid_arg'}, 'stderr')
end
end
end

shared_examples 'Action argument parsing' do |options|
context 'Action argument parsing' do
def instance(opts = [])
r10k.run(command_args + opts.compact + extra_args).instance_variable_get(:@runner).instance
end

context 'CriRunner' do
it do
expect(r10k.run(command_args + extra_args)).to be_an_instance_of(R10K::Action::CriRunner)
end
end

context 'Runner' do
it do
expect(r10k.run(command_args + extra_args).instance_variable_get(:@runner)).to be_an_instance_of(R10K::Action::Runner)
end
end

context 'Action' do
it do
expect(instance).to be_an_instance_of(action_class)
end
end

options.each do |option, optinfo|
if optinfo[:custom_action_examples]
optinfo[:custom_action_examples].each do |examples|
include_examples examples, option, optinfo
end
next
end

context "when #{option} specified" do
let(:option_variable) do
"@#{option.to_s.sub(%r{^-*}, '')}".tr('-', '_').to_sym
end

if CRI_RUNNER_OPTIONS.include? option
it 'CriRunner processes the option' do
["--#{option}", optinfo[:short]].compact.each do |opt|
expect(instance([opt, optinfo[:value]]).instance_variable_defined?(option_variable)).to be false
end
end
else
it 'has the option set' do
["--#{option}", optinfo[:short]].compact.each do |opt|
expect(instance([opt, optinfo[:value]]).instance_variable_get(option_variable)).to eq(optinfo[:value] || true)
end
end
end
it 'processes extra args correctly' do
["--#{option}", optinfo[:short]].compact.each do |opt|
expect(instance([opt, optinfo[:value]]).instance_variable_get(:@argv)).to eq(filtered_extra_args)
end
end
end
end

context 'when no options specified' do
it 'processes extra args correctly' do
expect(instance.instance_variable_get(:@argv)).to eq(filtered_extra_args)
end
end
end
end

shared_examples 'deploy examples' do
before(:each) do
allow(File).to receive(:executable?).with('/path/to/puppet').and_return('true')
end
end

shared_examples 'version examples' do
context 'with no arguments' do
it 'prints r10k version' do
exit_with_code_and_message(command_args, 0, "r10k #{R10K::VERSION}\n")
end
end

context 'with -v or --verbose' do
it 'prints verbose version info' do
['-v', '--verbose'].each do |option|
exit_with_code_and_message(command_args + [option], 0, %r{r10k #{Regexp.quote(R10K::VERSION)}\n#{Regexp.quote(RUBY_DESCRIPTION)}})
end
end
end
end
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

Dir.glob(File.expand_path('spec/shared-examples/**/*.rb', PROJECT_ROOT)).each { |file| require file }

require 'shared-contexts/cli'
require 'shared-contexts/git-fixtures'
require 'matchers/exit_with'
require 'matchers/match_realpath'
Expand Down
Loading

0 comments on commit 758564a

Please sign in to comment.