Chefspec - writing unit tests for execute resource that include cwd,command and environment - chefspec

I'm trying to figure out how I can write my chefspec unit tests that will check every line on the below piece of code
Execute 'download gz' do
cwd 'my/working/dir'
environment ('environ' => node[:environ])
command 'some commands here'
end
Thanks

The environment map can be accessed in ChefSpec with the following example.
Given we have defined a resource such as
execute 'script.py' do
environment(
PATH: '/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin'
)
command '/path/to/script.py'
end
If we want to test for the environment in ChefSpec, we do the following
it 'Should execute script' do
expect(chef_run).to run_execute('script.py').with(
command: '/path/to/script.py',
environment: { PATH: '/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin' }
)
end

Related

Aruba: Command "seedly-calculator" not found in PATH-variable

So, I am trying to run the test but I am getting an error says.
Aruba::LaunchError:Command "seedly-calculator.rb" not found in PATH-variable
-seedly-calculator
-bin
-src
-seedly-calculator.rb
I have tried to change the path in rake file but it doesn't work.
My seedly-calculator.rb file is in the root directory.
require "rspec/core/rake_task"
namespace :spec do
desc "Run the functional suite against the CLI"
RSpec::Core::RakeTask.new(:functional, [] => [:set_path])
task :set_path do
project_bin_dir = File.join(File.dirname(File.expand_path(__FILE__)), '..', 'bin')
ENV['PATH'] = project_bin_dir + ':'+ ENV['PATH']
end
end
it shows error like:
Failure/Error: let(:command) { run "seedly-calculator.rb" }
Aruba::LaunchError:
Command "seedly-calculator.rb" not found in PATH-variable "/Users/bilaltariq/Desktop/seedly-calculator/functional_spec/bin:/Users/bilaltariq/Desktop/seedly-calculator/functional_spec/exe:/Users/bilaltariq/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/bin:/Users/bilaltariq/Desktop/seedly-calculator/functional_spec/../bin:/Users/bilaltariq/.rbenv/versions/2.6.2/bin:/usr/local/Cellar/rbenv/1.1.1/libexec:/Users/bilaltariq/.rbenv/shims:/Users/bilaltariq/.asdf/shims:/Users/bilaltariq/.asdf/bin:/usr/local/bin:/Users/bilaltariq/.bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/MacGPG2/bin".
I expect it to hit the file so i can write some test.
am i doing something wrong?
require 'spec_helper'
RSpec.describe 'Command Validation', type: :aruba do
let(:command) { run "seedly-calculator.rb" }
it "wrong/missing arguments" do
command.write("lookup\n")
stop_all_commands
expect(command.output).to end_with("Missing bank_name argument.\n")
end
end
seedly-calculator.rb:
#!/usr/bin/env ruby
# Complete bin/setup so that after it is
# run, ruby seedly-calculator.rb can be used to launch
# it.
# frozen_string_literal: true
require_relative './src/runner'
if !ARGV.length.zero?
input = ARGV
Runner.new.send('process_input', input)
else
puts "Arguments required!."
end
Update
To run a ruby script using run you need to make sure your ruby script is executable and contains a shebang so your system knows to run it with ruby. Here's example from this starter example
#!/usr/bin/env ruby
file = ARGV[0]
if file.nil? || file.empty?
abort "aruba-test-cli [file]: Filename is missing"
elsif !File.exist? file
abort "aruba-test-cli [file]: File does not exist"
end
puts File.read(file).chomp
So in your case you'll need to add this to the first line of your seedly-calculator.rb file
#!/usr/bin/env ruby
Then run this from command line to make it executable.
chmod +x #!/usr/bin/env ruby
I made a simple example forked off the one I reffed above. See this commit
Rspec convention is that it should match the same file structure of your project. It is not a good idea to set PATH manually.
Rake tasks are normally put in a tasks folder so you should have in project root a tasks folder
my_project/tasks/something.rake
Then you should have a spec folder that matches
my_project/spec/tasks/something_spec.rb
Then you should be able to get rid of task :set_path do end block and just run the spec without that.
You should also have a Gemfile to load your gems, run bundle install then invoke your test with
bundle exec rspec spec/tasks/sometask_spec.rb

Tests, using Aruba with Rspec, failing with `run` is not available from within an example (e.g. an `it` block)

I need to test a console application and check printed output, using rspec script. Example:
RSpec.describe 'Test Suite', type: :aruba do
it "has aruba set up" do
command = run("echo 'hello world'")
stop_all_commands
expect(command.output).to eq("hello world\n")
end
It fails with:
Failure/Error: command = run("echo 'hello world'")
`run` is not available from within an example (e.g. an `it` block) or from constructs that run in the scope of an example (e.g. `before`, `let`, etc). It is only available on an example group (e.g. a `describe` or `context` block).
Aruba version 0.14.6, Rspec 3.7.0. Will appreciate any help. Thanks.
As the error implies, you cannot call run within the it block. Aruba's documentation can get a bit confusing here because of the various branches, but the run method is still available in the still branch, with documentation found here.
Following the documentation, instead of defining command within the it block, we can instead define it outside the block using let:
RSpec.describe 'Test Suite', type: :aruba do
context "aruba test" do
let(:command) { run("echo 'hello world'") }
it "has aruba set up" do
stop_all_commands
expect(command.output).to eq("hello world\n")
end
end
end

Chef - using powershell_script from within ruby_block

Is it possible to use powershell_script from within a ruby_block?
I want to run the powershell script during the convergence phase and not the compilation phase.
The current code doesn't work:
ruby_block 'ruby block so that code is run during convergence phase and not compilation phase' do
block do
buildNumber = "123"
powershell_script 'run powershell script' do
environment ({'buildNumber' => buildNumber})
code "path/to/script/script.ps1"
end
end
action :run
end
I know you can use a guard on the powershell_script outside the ruby_block to make it run during convergence but I need the local variable buildNumber that is defined inside the ruby block.
the following code worked for me:
x = Chef::Resource::PowershellScript.new('unzipper script',run_context)
x.code 'D:/git/chef/cookbooks/java-8-upgrade/unzipper.ps1'
x.environment ({'buildNumber' => buildNumber})
x.run_action :run
In the simple case, you can probably use the powershell_out helper method. For more complex cases, make a custom resource and use the normal resource. Do not use manual resource invocation (Chef::Resource::Foo.new as we explicitly do not support this and know for a fact that it breaks things).

Capistrano Ruby: Refactoring Reused String Values

I have a couple tasks within my deploy.rb file that execute within my theme folder.
I currently define them as follows:
namespace :deploy do
desc 'NPM Build Production'
task :npm_build_production do
on roles(:app) do
within "#{release_path}/web/app/themes/example" do
execute :npm, "install --silent --no-progress"
execute :npm, "run build:production"
end;
end
end
end
before 'deploy:updated', 'deploy:npm_build_production'
Everything is working correctly with this implementation, but since there are multiple instances where I use this path, I'd like to extract it to a symbol or variable. I am new to Ruby and am running into some issues.
I have tried using the code below, but for some reason the path ends up being wrong when executed in my tasks.
set :theme_path, -> { "#{release_path}/web/app/themes/example" }
These variables are set on different stages of implementation. for example the release_path variable is not defined in the setting variables section. Move your variable to your execution block for tasking and it will work . for example this snipped will work
namespace :deploy do
desc 'NPM Build Production'
task :npm_build_production do
on roles(:app) do
theme_path = "#{release_path}/web/app/themes/example"
within theme_path do
execute :npm, "install --silent --no-progress"
execute :npm, "run build:production"
end;
end
end
end
also you will be able to fetch some variables using this way while setting other variables like fetch(:varible_name) but I am not sure it is feasible for the release_path since it is a scoped variable
here is how you could do it with a function
def theme_path(release_path)
"#{release_path}/web/app/themes/example"
end
just call this function with your release_path variable and you will have the themepath wherever you want. inside your deployment logic.

How to write a RSpec test to compare a string with its expected substring?

I have a RSpec test like this:
context 'test #EnvironmentFile= method' do
it 'compares the command generated with the expected command' do
knife = EnvironmentFromFile.new(#knife_cfg_file)
knife.environment_file=(#environment_file)
expect(knife.chef_cmd_to_s).to eql("C:/blah/blah/bin/knife environment from file MySampleEnvironment.json --config 'knife.rb'")
end
end
Now, to avoid platform dependency, the expected message within the eql() should be a substring without the initial C:/blah/blah/bin/ part.
My expected message should be "knife environment from file MySampleEnvironment.json --config 'knife.rb'"
Which should match with the actual message returned from knife.chef_cmd_to_s method:
"C:/blah/blah/bin/knife environment from file MySampleEnvironment.json --config 'knife.rb'"
How do I do that? What Rspec matcher is used for this?
This is where you would use the include matcher (documentation).
context 'test #EnvironmentFile= method' do
it 'compares the command generated with the expected command' do
knife = EnvironmentFromFile.new(#knife_cfg_file)
knife.environment_file=(#environment_file)
expect(knife.chef_cmd_to_s).to include("knife environment from file MySampleEnvironment.json --config 'knife.rb'")
end
end

Resources