spec/command/command_spec.rb in command_exec-0.1.3 vs spec/command/command_spec.rb in command_exec-0.2.0
- old
+ new
@@ -1,125 +1,421 @@
+#encoding: utf-8
+
require 'spec_helper'
describe Command do
- let(:logger) {Logger.new(StringIO.new)}
+ let(:lib_logger) {Logger.new(StringIO.new)}
#let(:logger) {Logger.new($stdout)}
- let(:log_level) {:info}
- let(:command) { Command.new(:echo , :log_level => :silent, :logger => logger, :parameter => "hello world" , :error_keywords => %q[abc def], :working_directory => '/tmp' ) }
+ let(:lib_log_level) {:info}
+ let(:command) { Command.new(:echo , :lib_logger => lib_logger, :parameter => "hello world" , :error_keywords => %q[abc def], :working_directory => '/tmp' ) }
+ context :public_api do
+ test_dir = File.expand_path('test_data', File.dirname(__FILE__))
- it "has a path" do
- command.path.should == '/bin/echo'
- end
+ it "supports relative paths" do
+ Dir.chdir('spec/command') do
+ command = Command.new('test_data/true_test')
+ expect(command.path).to eq(File.join(test_dir, 'true_test'))
+ end
- it "has parameter" do
- command.parameter.should == 'hello world'
- end
+ Dir.chdir test_dir do
+ command = Command.new('./true_test')
+ expect(command.path).to eq(File.join(test_dir, 'true_test'))
+ end
- it "has options" do
- command.options.should == ''
- end
+ Dir.chdir '/tmp/' do
+ command = Command.new('../bin/true')
+ expect(command.path).to eq('/bin/true')
+ end
+ end
- it "offers the possibility to change the working directory of the process" do
- command.working_directory.should == '/tmp'
- Dir.pwd.should == '/tmp'
- end
+ it 'searches $PATH to find the command' do
+ environment({ 'PATH' => '/bin' }) do
+ command = Command.new(:true)
+ expect(command.path).to eq("/bin/true")
+ end
+ end
- it "has special keywords indicating errors in stdout" do
- command.error_keywords.should == %q[abc def]
- end
+ it 'offers an option to change $PATH for the command execution' do
+ command = Command.new(:echo_test, search_paths: [test_dir])
+ expect(command.path).to eq(File.join(test_dir, 'echo_test'))
+ end
- it "can be used to construct a command string, which can be executed" do
- command = Command.new(:pdflatex, :log_level => :silent, :logger => logger, :parameter => "index.tex blub.tex", :options => "-a -b")
- command.send(:build_cmd_string).should == "/usr/bin/pdflatex -a -b index.tex blub.tex"
- end
+ it "checks if exec is executable" do
+ command = Command.new('/bin/true')
+ expect(command.executable?).to eq(true)
- it "runs programms" do
- command.run
- command.result.should == true
- end
+ command = Command.new('/etc/passwd')
+ expect(command.executable?).to eq(false)
+ end
- it "returns the textual rep of a command" do
- command.to_txt.should == '/bin/echo hello world'
- end
+ it "checks if exec exists" do
+ command = Command.new('/bin/true')
+ expect(command.exists?).to eq(true)
- it "execute existing programs" do
- command = Command.execute(:echo, :log_level => :silent, :logger => logger ,:parameter => "index.tex blub.tex", :options => "-- -a -b")
- command.result.should == true
- end
-
- it "does not execute non-existing programs" do
- command = Command.execute(:grep, :log_level => :silent, :logger => logger, :parameter => "index.tex blub.tex", :options => "-- -a -b")
- command.result.should == false
- end
+ command = Command.new('/usr/bin/does_not_exist')
+ expect(command.exists?).to eq(false)
+ end
- it "checks if errors have happend during execution" do
- lambda { Command.new(:echo1, :log_level => :silent, :logger => logger, :parameter => "index.tex blub.tex", :options => "-- -a -b") }.should raise_error CommandNotFound
- end
+ it "checks if exec is valid (exists, executable, type = file)" do
+ #does not exist
+ command = Command.new('/usr/bin/does_not_exist')
+ expect(command.valid?).to eq(false)
- it "decides which output should be returned to the user" do
- logfile = StringIO.new
- logfile << 'Error in ... found'
+ #is a directory not a file
+ command = Command.new('/tmp')
+ expect(command.valid?).to eq(false)
- stderr = StringIO.new
- stderr << 'Error found'
+ #exists and is executable and is a file
+ command = Command.new('/bin/true')
+ expect(command.valid?).to eq(true)
+ end
- stdout = StringIO.new
- stdout << 'Error found'
+ it "has parameter" do
+ command = Command.new(:true, :parameter=>'parameter')
+ expect(command.parameter).to eq('parameter')
+ end
- #result = command.send(:help_logger)({ :error_in_exec => true , :error_in_stdout => false} , { :logfile => logfile, :stderr => stderr , :stdout => stdout })
- result = command.send(:help_output, { :error_in_exec => true , :error_in_stdout => false} , { :logfile => logfile, :stderr => stderr , :stdout => stdout })
- result.should == ["================== LOGFILE ================== ", "Error in ... found", "================== STDOUT ================== ", "Error found", "================== STDERR ================== ", "Error found"]
+ it "has options" do
+ expect(command.options).to eq('')
+ end
- result = command.send(:help_output, { :error_in_exec => false , :error_in_stdout => true} , { :logfile => logfile, :stderr => stderr , :stdout => stdout })
- result.should == ["================== STDOUT ================== ", "Error found"]
+ it "offers the possibility to change the working directory of the process without any side effects" do
+ expect(command.working_directory).to eq('/tmp')
- result = command.send(:help_output, { :error_in_exec => true , :error_in_stdout => true} , { :logfile => logfile, :stderr => stderr , :stdout => stdout })
- result.should == ["================== LOGFILE ================== ", "Error in ... found", "================== STDOUT ================== ", "Error found", "================== STDERR ================== ", "Error found"]
+ #no side effects
+ lambda { command.run }
+ expect(Dir.pwd).to eq(File.expand_path('../..', File.dirname(__FILE__)))
+ end
- result = command.send(:help_output, { :error_in_exec => false , :error_in_stdout => false} , { :logfile => logfile, :stderr => stderr , :stdout => stdout })
- result.should == []
+ it "can be used to construct a command string, which can be executed" do
+ environment('PATH' => '/bin') {
+ command = Command.new(:true, :parameter => "index.tex blub.tex", :options => "-a -b")
+ expect(command.to_s).to eq("/bin/true -a -b index.tex blub.tex")
+ }
+ end
- end
+ it "runs programms" do
+ command = Command.new(:echo, :parameter => "output", :lib_log_level => :silent )
+ command.run
+ expect(command.result.status).to eq(:success)
+ end
- it "finds errors in stdout" do
- command.send(:error_in_string_found?, ['error'] , 'long string witherror inside' ).should == true
- command.send(:error_in_string_found?, ['long', 'inside'] , 'long string witherror inside' ).should == true
- command.send(:error_in_string_found?, ['error'] , 'long string with erro inside' ).should == false
- end
+ it "execute existing programs" do
+ command = Command.execute(:echo, :parameter => "output", :options => "-- -a -b", :lib_log_level => :silent )
+ expect(command.result.status).to eq(:success)
+ end
- it "output a message" do
- command.send(:message, false, 'Hello_world').should == "\e[1m\e[31mFAILED\e[0m\e[0m\nHello_world"
- command.send(:message, true, 'Hello_world').should == "\e[1m\e[32mOK\e[0m\e[0m"
- command.send(:message, true ).should == "\e[1m\e[32mOK\e[0m\e[0m"
- end
+ it "is very verbose and returns a lot of output" do
+ bucket = StringIO.new
+ lib_logger = Logger.new(bucket)
+ Command.execute(:echo, :lib_logger => lib_logger ,:parameter => "output", :lib_log_level => :debug)
- it "is very verbose and returns a lot of output" do
- bucket = StringIO.new
- logger = Logger.new(bucket)
- Command.execute(:echo, :logger => logger ,:parameter => "index.tex blub.tex", :options => "-- -a -b" , :log_level => :debug)
+ expect(bucket.string['DEBUG']).to_not eq(nil)
+ end
- bucket.string.should =~ /OK/
- end
+ it "is silent and returns no output" do
+ # if you choose the system runner output of commands will be not suppressed"
+ bucket = StringIO.new
+ lib_logger = Logger.new(bucket)
+ Command.execute(:echo, :lib_logger => lib_logger ,:parameter => "output", :lib_log_level => :silent)
- it "is silent and returns no output" do
- bucket = StringIO.new
- logger = Logger.new(bucket)
- Command.execute(:echo, :logger => logger ,:parameter => "index.tex blub.tex", :options => "-- -a -b" , :log_level => :silent)
+ expect(bucket.string).to eq("")
+ end
- bucket.string.should == ""
- end
+ it "supports other log levels as well" do
+ bucket = StringIO.new
+ lib_logger = Logger.new(bucket)
- # not completed
- #it "use a log file if given" do
- # application_log_file = Tempfile.new('command_exec_test')
- # application_log_file.write "ERROR"
+ Command.execute(:echo, :lib_logger => lib_logger ,:parameter => "output", :lib_log_level => :info)
+ Command.execute(:echo, :lib_logger => lib_logger ,:parameter => "output", :lib_log_level => :warn)
+ Command.execute(:echo, :lib_logger => lib_logger ,:parameter => "output", :lib_log_level => :error)
+ Command.execute(:echo, :lib_logger => lib_logger ,:parameter => "output", :lib_log_level => :fatal)
+ Command.execute(:echo, :lib_logger => lib_logger ,:parameter => "output", :lib_log_level => :unknown)
+ Command.execute(:echo, :lib_logger => lib_logger ,:parameter => "output", :lib_log_level => :garbage_sasdfasf)
+ end
- # binding.pry
- # Command.execute(:echo, :logger => logger ,:parameter => "index.tex blub.tex", :options => "-- -a -b" , :log_level => :silent, :logfile => application_log_file, :error_keywords => %W[ERROR])
+ it "use a log file if given" do
+ application_log_file = create_temp_file_with('command_exec_test', 'TEXT IN LOG')
- #end
+ bucket = StringIO.new
+ lib_logger = Logger.new(bucket)
+ command = Command.new(:logger_test ,
+ :lib_logger => lib_logger ,
+ :log_file => application_log_file ,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__))).run
+ end
+ it "outputs only warnings when told to output those" do
+ bucket = StringIO.new
+ lib_logger = Logger.new(bucket)
+ command = Command.new(:logger_test ,
+ :lib_logger => lib_logger ,
+ :lib_log_level => :warn,
+ :log_file => '/tmp/i_do_not_exist.log',
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__))).run
+
+ expect(bucket.string['WARN']).to_not eq(nil)
+ end
+
+ it "considers status for error handling (default 0)" do
+ command = Command.new(:exit_status_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :parameter => '1',
+ :lib_log_level => :silent,
+ :error_detection_on => [:return_code],
+ )
+ command.run
+ expect(command.result.status).to eq(:failed)
+ end
+
+ it "considers status for error handling (single value as array)" do
+ command = Command.new(:exit_status_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :parameter => '1',
+ :lib_log_level => :silent,
+ :error_detection_on => [:return_code],
+ :error_indicators => { :allowed_return_code => [0] })
+ command.run
+ expect(command.result.status).to eq(:failed)
+ end
+
+ it "considers status for error handling (single value as symbol)" do
+ command = Command.new(:exit_status_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :parameter => '1',
+ :lib_log_level => :silent,
+ :error_detection_on => :return_code,
+ :error_indicators => { :allowed_return_code => [0] })
+ command.run
+ expect(command.result.status).to eq(:failed)
+ end
+
+ it "considers status for error handling (single value)" do
+ command = Command.new(:exit_status_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :parameter => '0',
+ :lib_log_level => :silent,
+ :error_detection_on => [:return_code],
+ :error_indicators => { :allowed_return_code => [0,2] })
+ command.run
+ expect(command.result.status).to eq(:success)
+
+ command = Command.new(:exit_status_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :parameter => '2',
+ :lib_log_level => :silent,
+ :error_detection_on => [:return_code],
+ :error_indicators => { :allowed_return_code => [0,2] })
+ command.run
+ expect(command.result.status).to eq(:success)
+ end
+
+ it "considers stderr for error handling" do
+ command = Command.new(:stderr_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :lib_log_level => :silent,
+ :error_detection_on => :stderr,
+ :error_indicators => { :forbidden_words_in_stderr => %w{error} })
+ command.run
+ expect(command.result.status).to eq(:failed)
+ end
+
+ it "considers stderr for error handling but can make exceptions" do
+ command = Command.new(:stderr_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :lib_log_level => :silent,
+ :error_detection_on => :stderr,
+ :error_indicators => { :forbidden_words_in_stderr => %w{error}, :allowed_words_in_stderr => ["error. execution failed"]})
+ command.run
+ expect(command.result.status).to eq(:success)
+ end
+
+ it "considers stdout for error handling" do
+ command = Command.new(:stdout_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :lib_log_level => :silent,
+ :error_detection_on => :stdout,
+ :error_indicators => { :forbidden_words_in_stdout => %w{error} })
+ command.run
+ expect(command.result.status).to eq(:failed)
+ end
+
+
+ it "removes newlines from stdout" do
+ #same for stderr
+ command = Command.new(:stdout_multiple_lines_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :lib_log_level => :silent,
+ :error_detection_on => :stdout,
+ :error_indicators => { :forbidden_words_in_stdout => %w{error} })
+ command.run
+ expect(command.result.stdout).to eq(["error. execution failed", "error. execution failed"])
+ end
+
+ it "considers log file for error handling" do
+ temp_file = create_temp_file_with('log_file_test', 'error, huh, what goes on' )
+
+ command = Command.new(:log_file_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :lib_log_level => :silent,
+ :log_file => temp_file,
+ :error_detection_on => :log_file,
+ :error_indicators => { :forbidden_words_in_log_file => %w{error} })
+ command.run
+ expect(command.result.status).to eq(:failed)
+ end
+
+ it "returns the result of command execution as process object (defaults to :return_process_information)" do
+ command = Command.new(:output_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :lib_log_level => :silent,
+ :error_detection_on => :return_code,
+ :error_indicators => { :allowed_return_code => [ 0 ]})
+ command.run
+ expect(command.result.class).to eq(CommandExec::Process)
+ end
+
+ it "returns the result of command execution as process object" do
+ command = Command.new(:output_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :lib_log_level => :silent,
+ :on_error_do => :return_process_information,
+ :error_detection_on => :return_code,
+ :error_indicators => { :allowed_return_code => [ 0 ]})
+ command.run
+ expect(command.result.class).to eq(CommandExec::Process)
+ end
+
+ it "does nothing on error if told so" do
+ command = Command.new(:raise_error_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :lib_log_level => :silent,
+ :on_error_do => :nothing,
+ :error_detection_on => :return_code,
+ :error_indicators => { :allowed_return_code => [ 0 ]})
+ expect{command.run}.to_not raise_error
+ expect{command.run}.to_not throw_symbol
+ end
+
+ it "raises an exception" do
+ command = Command.new(:raise_error_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :lib_log_level => :silent,
+ :on_error_do => :raise_error,
+ :error_detection_on => :return_code,
+ :error_indicators => { :allowed_return_code => [ 0 ]})
+ expect{command.run}.to raise_error(CommandExec::Exceptions::CommandExecutionFailed)
+
+ command = Command.new(:not_raise_error_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :lib_log_level => :silent,
+ :on_error_do => :raise_error,
+ :error_detection_on => :return_code,
+ :error_indicators => { :allowed_return_code => [ 0 ]})
+ expect{command.run}.to_not raise_error
+ end
+
+ it "throws an error" do
+ command = Command.new(:throw_error_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :lib_log_level => :silent,
+ :on_error_do => :throw_error,
+ :error_detection_on => :return_code,
+ :error_indicators => { :allowed_return_code => [ 0 ]})
+ expect{command.run}.to throw_symbol(:command_execution_failed)
+
+ command = Command.new(:not_throw_error_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :lib_log_level => :silent,
+ :on_error_do => :throw_error,
+ :error_detection_on => :return_code,
+ :error_indicators => { :allowed_return_code => [ 0 ]})
+ expect{command.run}.to_not throw_symbol
+ end
+
+ it "support open3 as runner" do
+ #implicit via default value (open3)
+ command = Command.new(:runner_open3_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :lib_log_level => :silent,
+ :error_detection_on => :return_code,
+ :error_indicators => { :allowed_return_code => [ 0 ]})
+ command.run
+ expect(command.result.status).to eq(:success)
+
+ #or explicit
+ command = Command.new(:runner_open3_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :run_via => :open3,
+ :lib_log_level => :silent,
+ :error_detection_on => :return_code,
+ :error_indicators => { :allowed_return_code => [ 0 ]})
+ command.run
+ expect(command.result.status).to eq(:success)
+ end
+
+ it "support system as runner" do
+ command = Command.new(:runner_system_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :run_via => :system,
+ :lib_log_level => :silent,
+ :error_detection_on => :return_code,
+ :error_indicators => { :allowed_return_code => [ 0 ]})
+ command.run
+ expect(command.result.status).to eq(:success)
+ end
+
+ it "has a default runner: open3" do
+ command = Command.new(:runner_system_test,
+ :search_paths => File.expand_path('test_data', File.dirname(__FILE__)),
+ :run_via => :unknown_runner,
+ :lib_log_level => :silent,
+ :error_detection_on => :return_code,
+ :error_indicators => { :allowed_return_code => [ 0 ]})
+ command.run
+ expect(command.result.status).to eq(:success)
+ end
+
+ it "find errors beyond newlines in the string" do
+ command = CommandExec::Command.new( :echo ,
+ :options => '-e',
+ :parameter => "\"wow, a test. That's great.\nBut an error occured in this line\"",
+ :error_detection_on => [:stdout],
+ :error_indicators => {
+ :forbidden_words_in_stdout => %w{ error }
+ },
+ )
+ command.run
+ expect(command.result.status).to eq(:failed)
+ end
+ end
+
+ context :private_api do
+ it "raises an error if command is not executable" do
+ command = Command.new('/etc/passwd', lib_log_level: :silent)
+ expect{command.send(:check_path)}.to raise_error CommandNotExecutable
+ end
+
+ it "raises an error if command does not exist" do
+ command = Command.new('/usr/bin/does_not_exist', lib_log_level: :silent)
+ expect{command.send(:check_path)}.to raise_error CommandNotFound
+ end
+
+ it "raises an error if command is not a file" do
+ command = Command.new('/tmp', lib_log_level: :silent)
+ expect{command.send(:check_path)}.to raise_error CommandIsNotAFile
+ end
+
+ it "finds errors in string" do
+ expect(command.send(:error_occured?, ['error'] , [], ['long string witherrorinside'] )).to eq(true)
+ expect(command.send(:error_occured?, ['error', 'inside'] , [], ['long string with error inside'] )).to eq(true)
+ expect(command.send(:error_occured?, ['error'] , [], ['long string with no erro"r" inside'] )).to eq(false)
+
+ expect(command.send(:error_occured?, ['error'] , ['long string with error inside but an exception defined'], ['long string with error inside but an exception defined'] )).to eq(false)
+ expect(command.send(:error_occured?, ['error'] , ['substring exception defined'], ['long string with error inside but a substring exception defined'] )).to eq(false)
+ end
+ end
end