Friendly command-line test runner and matchers for shell scripting in ruby using RSpec.
With Bundler, add the following to your Gemfile:
group :test do gem "blue-shell" end
Then require and configure BlueShell in your
require 'blue-shell' RSpec.configure do |c| c.include BlueShell::Matchers end
Shell commands in BlueShell get executed by creating a new runner instance
Running a command by default times out after 30 seconds or raises a
BlueShell::Runner.run 'sleep 1' # success BlueShell::Runner.run 'sleep 6' # fails with Timeout::Error
Expectations on exit codes
BlueShell::Runner.run 'false' do |runner| runner.should exit_with 1 runner.should have_exit_code 1 # #exit_with and #have_exit_code are aliases end
Expectations on STDOUT
BlueShell::Runner.run 'echo "foo bar baz"' do |runner| runner.should say 'foo' runner.should have_output 'bar' # #say and #have_output are aliases end
#have_output will smartly wait a maximum of 30 seconds.
If you need to increase that timeout, you can do so:
BlueShell::Runner.run 'sleep 35 && echo "foo bar baz"' do |runner| runner.with_timeout(40) do runner.should have_output 'bar' end end
Interacting with STDIN
BlueShell::Runner.run 'read' do |runner| runner.send_keys 'foo' end BlueShell::Runner.run 'read' do |runner| runner.send_return end
Within the run block you can call
if you want to make sure your command finishes within a certain amount
of time. (The default timeout is 30 seconds.)
BlueShell::Runner.run 'sleep 6' do |runner| runner.with_timeout(7) do runner.wait_for_exit end end
It is important to note the difference between calling
.run 'one-off' vs passing in a block:
# raises a Timeout::Error after 30 seconds BlueShell::Runner.run 'sleep 60' # raises a Timeout::Error after 5 seconds BlueShell.with_timeout(5) do BlueShell::Runner.run 'sleep 60' end # succeeds BlueShell::Runner.run 'sleep 60' do |_| # unless #wait_for_exit or #have_exit_code are invoked # your specs do not wait for the command to exit # and also do not fail if it never does end
That being said, in most cases you probably want to invoke
at the end of your block to ensure the command finishes.
Copyright © Pivotal Labs. See LICENSE for details.