diff --git a/.rubocop.yml b/.rubocop.yml index ab85261ef..467cd14a5 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -39,6 +39,7 @@ Metrics/LineLength: Exclude: - lib/aruba/api.rb - lib/aruba/api/deprecated.rb + - aruba.gemspec # Configuration parameters: CountComments. Metrics/MethodLength: diff --git a/Gemfile b/Gemfile index 070b12dd2..2ffd20c4c 100644 --- a/Gemfile +++ b/Gemfile @@ -7,12 +7,17 @@ gemspec group :debug do gem 'pry', '~> 0.10.1' - platform :mri_20, :mri_21, :mri_22 do + platform :ruby_20, :ruby_21, :ruby_22 do gem 'byebug', '~> 4.0.5' gem 'pry-byebug', '~> 3.1.0' end - platform :mri_19, :mri_20, :mri_21, :mri_22 do + platform :ruby_19 do + gem 'debugger', '~> 1.6.8' + gem 'pry-debugger', '~> 0.2.3' + end + + platform :ruby_19, :ruby_20, :ruby_21, :ruby_22 do gem 'pry-stack_explorer', '~> 0.4.9' end @@ -23,7 +28,7 @@ group :development, :test do # Run development tasks gem 'rake', '~> 10.4.2' - platform :mri_19, :mri_20, :mri_21, :mri_22 do + platform :ruby_19, :ruby_20, :ruby_21, :ruby_22 do # Reporting gem 'bcat', '~> 0.6.2' gem 'kramdown', '~> 1.7.0' @@ -37,20 +42,20 @@ group :development, :test do gem 'fuubar', '~> 2.0.0' # Make aruba compliant to ruby community guide - platform :mri_19, :mri_20, :mri_21, :mri_22 do + platform :ruby_19, :ruby_20, :ruby_21, :ruby_22 do gem 'rubocop', '~> 0.32.0' end - platform :mri_19, :mri_20, :mri_21, :mri_22 do + platform :ruby_19, :ruby_20, :ruby_21, :ruby_22 do gem 'cucumber-pro', '~> 0.0' end - platform :mri_19, :mri_20, :mri_21, :mri_22 do + platform :ruby_19, :ruby_20, :ruby_21, :ruby_22 do # License compliance gem 'license_finder', '~> 2.0.4' end - platform :mri_19, :mri_20, :mri_21, :mri_22 do + platform :ruby_19, :ruby_20, :ruby_21, :ruby_22 do # Upload documentation gem 'relish', '~> 0.7.1' end diff --git a/History.md b/History.md index b6995f713..fa20df888 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,17 @@ +## [v0.8.0](https://github.com/cucumber/aruba/compare/v0.7.4...v0.8.0) +* Make aruba compatible with "ruby 1.8.7" and "ruby 1.9.3" again (fixes #279) +* Move more and more documentation to cucumber steps (partly fixes #268) +* Refactoring of test suits, now rspec tests run randomly +* Move Aruba constants to configuration class (fixes #271) +* Added runtime configuration via `aruba.config` which is reset for each test run +* Refactored hooks: now there are `after()` and `before()`-hooks, old + before_cmd-hook is still working, but is deprecated, added new + `after(:command)`-hook. +* Refactored jruby-startup helper +* Cleanup API by moving deprecated methods to separte class +* Cleanup Core API - reduced to `cd`, `expand_path`, `setup_aruba` and use expand_path wherever possible (fixes #253) +* Better isolation for environment variable manipulation - really helpful from 1.0.0 on + ## [v0.7.4](https://github.com/cucumber/aruba/compare/v0.7.2...v0.7.4) * Really Fixed post install message @@ -21,6 +35,7 @@ * Improve development environment (issue #240) * Cleanup process management (issue #257) * Make path content available through matchers and api metchods (issue #250) +* Refactor announcer to support user defined announce channels (fixes #267) ## [v0.6.2](https://github.com/cucumber/aruba/compare/v0.6.1...v0.6.2) * Fixed minor issue #223) diff --git a/aruba.gemspec b/aruba.gemspec index 8a50e19cf..c054aba23 100644 --- a/aruba.gemspec +++ b/aruba.gemspec @@ -24,6 +24,9 @@ With aruba >= 1.0 * "ruby 1.8.7"-support is discontinued * aruba requires "cucumber 2" for the feature steps. The rest of aruba should be usable by whatever testing framework you are using * "aruba/reporting" will be removed. Please use `@debug`-tag + `byebug`, `debugger`, `pry` to troubleshoot your feature tests + * Set environment variables will have only effect on `#run` and the like + `#with_environment { }` + * The process environment will be fully resetted between tests. Sharing state via ENV['VAR'] = 'shared state' between tests will not be possible anymore. Please make that obvious by using explicit steps or use the aruba API for that. + * There will be a major cleanup for command execution. There will be only `run` and `run_simple` left. `run_interactive` is replaced by `run`. EOS s.files = `git ls-files`.split("\n") diff --git a/features/api/environment/append_environment_variable.feature b/features/api/environment/append_environment_variable.feature new file mode 100644 index 000000000..8ba4cd76f --- /dev/null +++ b/features/api/environment/append_environment_variable.feature @@ -0,0 +1,118 @@ +Feature: Append environment variable + + It is quite handy to modify the environment of a process. To make this + possible, `aruba` provides several methods. One of these is + `#append_environment_variable`. Using this variable appends a given value to + an existing one. If the variable does not exist, it is created with the given + value. + + Each variable name and each value is converted to a string. Otherwise `ruby` + would complain about an invalid argument. To make use of a variable you can + either use `#run` and the like or `#with_environment`. + + Background: + Given I use the fixture "cli-app" + + Scenario: Non-existing variable + Given a file named "spec/environment_spec.rb" with: + """ + require 'spec_helper' + + RSpec.describe 'Long running command', :type => :aruba do + before(:each) { append_environment_variable 'LONG_LONG_VARIABLE', 'a' } + before(:each) { run('env') } + + it { expect(last_command.output).to include 'LONG_LONG_VARIABLE=a' } + end + """ + When I run `rspec` + Then the specs should all pass + + Scenario: Existing inner variable + Given a file named "spec/environment_spec.rb" with: + """ + require 'spec_helper' + + RSpec.describe 'Long running command', :type => :aruba do + before(:each) { append_environment_variable 'LONG_LONG_VARIABLE', 'a' } + before(:each) { append_environment_variable 'LONG_LONG_VARIABLE', 'b' } + before(:each) { run('env') } + + it { expect(last_command.output).to include 'LONG_LONG_VARIABLE=ab' } + end + """ + When I run `rspec` + Then the specs should all pass + + + Scenario: Existing outer variable + Given a file named "spec/environment_spec.rb" with: + """ + require 'spec_helper' + + ENV['REALLY_LONG_LONG_VARIABLE'] = 'a' + + RSpec.describe 'Long running command', :type => :aruba do + before(:each) { append_environment_variable 'REALLY_LONG_LONG_VARIABLE', 'b' } + before(:each) { run('env') } + + it { expect(last_command.output).to include 'REALLY_LONG_LONG_VARIABLE=ab' } + + # Has no effect here, is not in block and not a command `run` + it { expect(ENV['REALLY_LONG_LONG_VARIABLE']).to eq 'a' } + end + """ + When I run `rspec` + Then the specs should all pass + + Scenario: Run some ruby code with previously set environment + Given a file named "spec/environment_spec.rb" with: + """ + require 'spec_helper' + + ENV['REALLY_LONG_LONG_VARIABLE'] = 'a' + + RSpec.describe 'Long running command', :type => :aruba do + before(:each) { append_environment_variable 'REALLY_LONG_LONG_VARIABLE', 'b' } + before(:each) { run('env') } + + it do + with_environment do + expect(ENV['REALLY_LONG_LONG_VARIABLE']).to eq 'ab' + end + end + + # Has no effect here, is not in block and not a command `run` + it { expect(ENV['REALLY_LONG_LONG_VARIABLE']).to eq 'a' } + end + """ + When I run `rspec` + Then the specs should all pass + + Scenario: Run some ruby code with local environment + + If you pass the same variable to the block it will not be appended, but + overwrites the variable + + Given a file named "spec/environment_spec.rb" with: + """ + require 'spec_helper' + + ENV['REALLY_LONG_LONG_VARIABLE'] = 'a' + + RSpec.describe 'Long running command', :type => :aruba do + before(:each) { append_environment_variable 'REALLY_LONG_LONG_VARIABLE', 'b' } + before(:each) { run('env') } + + it do + with_environment 'REALLY_LONG_LONG_VARIABLE' => 'a' do + expect(ENV['REALLY_LONG_LONG_VARIABLE']).to eq 'a' + end + end + + # Has no effect here, is not in block and not a command `run` + it { expect(ENV['REALLY_LONG_LONG_VARIABLE']).to eq 'a' } + end + """ + When I run `rspec` + Then the specs should all pass diff --git a/features/api/environment/prepend_environment_variable.feature b/features/api/environment/prepend_environment_variable.feature new file mode 100644 index 000000000..10f8c13cb --- /dev/null +++ b/features/api/environment/prepend_environment_variable.feature @@ -0,0 +1,118 @@ +Feature: Prepend environment variable + + It is quite handy to modify the environment of a process. To make this + possible, `aruba` provides several methods. One of these is + `#prepend_environment_variable`. Using this variable prepends a given value to + an existing one. If the variable does not exist, it is created with the given + value. + + Each variable name and each value is converted to a string. Otherwise `ruby` + would complain about an invalid argument. To make use of a variable you can + either use `#run` and the like or `#with_environment`. + + Background: + Given I use the fixture "cli-app" + + Scenario: Non-existing variable + Given a file named "spec/environment_spec.rb" with: + """ + require 'spec_helper' + + RSpec.describe 'Long running command', :type => :aruba do + before(:each) { prepend_environment_variable 'LONG_LONG_VARIABLE', 'a' } + before(:each) { run('env') } + + it { expect(last_command.output).to include 'LONG_LONG_VARIABLE=a' } + end + """ + When I run `rspec` + Then the specs should all pass + + Scenario: Existing inner variable + Given a file named "spec/environment_spec.rb" with: + """ + require 'spec_helper' + + RSpec.describe 'Long running command', :type => :aruba do + before(:each) { prepend_environment_variable 'LONG_LONG_VARIABLE', 'a' } + before(:each) { prepend_environment_variable 'LONG_LONG_VARIABLE', 'b' } + before(:each) { run('env') } + + it { expect(last_command.output).to include 'LONG_LONG_VARIABLE=ba' } + end + """ + When I run `rspec` + Then the specs should all pass + + + Scenario: Existing outer variable + Given a file named "spec/environment_spec.rb" with: + """ + require 'spec_helper' + + ENV['REALLY_LONG_LONG_VARIABLE'] = 'a' + + RSpec.describe 'Long running command', :type => :aruba do + before(:each) { prepend_environment_variable 'REALLY_LONG_LONG_VARIABLE', 'b' } + before(:each) { run('env') } + + it { expect(last_command.output).to include 'REALLY_LONG_LONG_VARIABLE=ba' } + + # Has no effect here, is not in block and not a command `run` + it { expect(ENV['REALLY_LONG_LONG_VARIABLE']).to eq 'a' } + end + """ + When I run `rspec` + Then the specs should all pass + + Scenario: Run some ruby code with previously set environment + Given a file named "spec/environment_spec.rb" with: + """ + require 'spec_helper' + + ENV['REALLY_LONG_LONG_VARIABLE'] = 'a' + + RSpec.describe 'Long running command', :type => :aruba do + before(:each) { prepend_environment_variable 'REALLY_LONG_LONG_VARIABLE', 'b' } + before(:each) { run('env') } + + it do + with_environment do + expect(ENV['REALLY_LONG_LONG_VARIABLE']).to eq 'ba' + end + end + + # Has no effect here, is not in block and not a command `run` + it { expect(ENV['REALLY_LONG_LONG_VARIABLE']).to eq 'a' } + end + """ + When I run `rspec` + Then the specs should all pass + + Scenario: Run some ruby code with local environment + + If you pass the same variable to the block it will not be prepended, but + overwrites the variable + + Given a file named "spec/environment_spec.rb" with: + """ + require 'spec_helper' + + ENV['REALLY_LONG_LONG_VARIABLE'] = 'a' + + RSpec.describe 'Long running command', :type => :aruba do + before(:each) { prepend_environment_variable 'REALLY_LONG_LONG_VARIABLE', 'b' } + before(:each) { run('env') } + + it do + with_environment 'REALLY_LONG_LONG_VARIABLE' => 'a' do + expect(ENV['REALLY_LONG_LONG_VARIABLE']).to eq 'a' + end + end + + # Has no effect here, is not in block and not a command `run` + it { expect(ENV['REALLY_LONG_LONG_VARIABLE']).to eq 'a' } + end + """ + When I run `rspec` + Then the specs should all pass diff --git a/features/api/environment/set_environment_variable.feature b/features/api/environment/set_environment_variable.feature new file mode 100644 index 000000000..974b23f8a --- /dev/null +++ b/features/api/environment/set_environment_variable.feature @@ -0,0 +1,138 @@ +Feature: Set environment variable via API-method + + It is quite handy to modify the environment of a process. To make this + possible, `aruba` provides several methods. One of these is + `#set_environment_variable`. Using this variable sets the value of a + non-existing variable and overwrites an existing value. Each variable name + and each value is converted to a string. Otherwise `ruby` would complain + about an invalid argument. To make use of a variable you can either use `#run` + and the like or `#with_environment`. Besides setting a variable globally, you + can set one for a block of code only using `#with_environment`. + + Background: + Given I use the fixture "cli-app" + + Scenario: Non-existing variable + Given a file named "spec/environment_spec.rb" with: + """ + require 'spec_helper' + + RSpec.describe 'Long running command', :type => :aruba do + before(:each) { set_environment_variable 'LONG_LONG_VARIABLE', '1' } + before(:each) { run('env') } + + it { expect(last_command.output).to include 'LONG_LONG_VARIABLE=1' } + end + """ + When I run `rspec` + Then the specs should all pass + + Scenario: Existing inner variable + Given a file named "spec/environment_spec.rb" with: + """ + require 'spec_helper' + + RSpec.describe 'Long running command', :type => :aruba do + before(:each) { set_environment_variable 'LONG_LONG_VARIABLE', '1' } + before(:each) { set_environment_variable 'LONG_LONG_VARIABLE', '2' } + before(:each) { run('env') } + + it { expect(last_command.output).to include 'LONG_LONG_VARIABLE=2' } + end + """ + When I run `rspec` + Then the specs should all pass + + + Scenario: Existing outer variable + Given a file named "spec/environment_spec.rb" with: + """ + require 'spec_helper' + + ENV['REALLY_LONG_LONG_VARIABLE'] = '1' + + RSpec.describe 'Long running command', :type => :aruba do + before(:each) { set_environment_variable 'REALLY_LONG_LONG_VARIABLE', '2' } + before(:each) { run('env') } + + it { expect(last_command.output).to include 'REALLY_LONG_LONG_VARIABLE=2' } + it { expect(ENV['REALLY_LONG_LONG_VARIABLE']).to eq '1' } + end + """ + When I run `rspec` + Then the specs should all pass + + Scenario: Run some ruby code with previously set environment + Given a file named "spec/environment_spec.rb" with: + """ + require 'spec_helper' + + ENV['REALLY_LONG_LONG_VARIABLE'] = '1' + + RSpec.describe 'Long running command', :type => :aruba do + before(:each) { set_environment_variable 'REALLY_LONG_LONG_VARIABLE', '2' } + before(:each) { run('env') } + + it do + with_environment do + expect(ENV['REALLY_LONG_LONG_VARIABLE']).to eq '2' + end + end + + it { expect(ENV['REALLY_LONG_LONG_VARIABLE']).to eq '1' } + + end + """ + When I run `rspec` + Then the specs should all pass + + Scenario: Run some ruby code with local environment + Given a file named "spec/environment_spec.rb" with: + """ + require 'spec_helper' + + ENV['REALLY_LONG_LONG_VARIABLE'] = '1' + + RSpec.describe 'Long running command', :type => :aruba do + before(:each) { set_environment_variable 'REALLY_LONG_LONG_VARIABLE', '2' } + before(:each) { run('env') } + + it do + with_environment 'REALLY_LONG_LONG_VARIABLE' => '3' do + expect(ENV['REALLY_LONG_LONG_VARIABLE']).to eq '3' + end + end + + it { expect(ENV['REALLY_LONG_LONG_VARIABLE']).to eq '1' } + end + """ + When I run `rspec` + Then the specs should all pass + + Scenario: When an error occures the ENV is not polluted + Given a file named "spec/environment_spec.rb" with: + """ + require 'spec_helper' + + ENV['REALLY_LONG_LONG_VARIABLE'] = '1' + + RSpec.describe 'Long running command', :type => :aruba do + before(:each) { set_environment_variable 'REALLY_LONG_LONG_VARIABLE', '2' } + before(:each) { run('env') } + + it do + begin + with_environment 'REALLY_LONG_LONG_VARIABLE' => '3' do + fail + end + rescue StandardError + end + + expect(ENV['REALLY_LONG_LONG_VARIABLE']).to eq '1' + end + + it { expect(ENV['REALLY_LONG_LONG_VARIABLE']).to eq '1' } + end + """ + When I run `rspec` + Then the specs should all pass diff --git a/features/commands/exit_statuses.feature b/features/commands/exit_statuses.feature index 7cc275ad3..f5c69f419 100644 --- a/features/commands/exit_statuses.feature +++ b/features/commands/exit_statuses.feature @@ -19,7 +19,6 @@ Feature: Check exit status of commands When I run `cli` Then the exit status should be 0 """ - When I run `env` When I run `cucumber` Then the features should all pass @@ -133,5 +132,5 @@ Feature: Check exit status of commands When I run `cucumber` Then the features should not all pass with: """ - expected that command "cli" has finished in time + expected "cli" to have finished in time """ diff --git a/features/configuration/exit_timeout.feature b/features/configuration/exit_timeout.feature index f69e8eb95..b590e94ec 100644 --- a/features/configuration/exit_timeout.feature +++ b/features/configuration/exit_timeout.feature @@ -39,7 +39,7 @@ Feature: Configure timeout for command execution Given a file named "bin/cli" with: """ #!/usr/bin/env sh - sleep 5 + sleep 2 """ And a file named "features/support/aruba.rb" with: """ diff --git a/features/environment/home_variable.feature b/features/environment/home_variable.feature new file mode 100644 index 000000000..dc04bf068 --- /dev/null +++ b/features/environment/home_variable.feature @@ -0,0 +1,49 @@ +Feature: Mock the HOME variable + + If you develop commandline applications, you might want to give your users + the possibility to configure your program. Normally this is done via + `.your-app-rc` or via `.config/your-app` an systems which comply to the + freedesktop-specifications. + + To prevent to litter the developers HOME-directory `aruba` comes with a step + which mocks the `HOME`-variable. It is set to the + `aruba`-`working-directory`. + + Background: + Given I use the fixture "cli-app" + And a file named "bin/cli" with: + """ + #!/usr/bin/env sh + + echo "HOME: $HOME" + """ + + Scenario: Mocked home directory by using a step + Given a file named "features/home_variable.feature" with: + """ + Feature: Home Variable + Scenario: Run command + Given a mocked home directory + When I run `cli` + Then the output should contain: + \"\"\" + tmp/aruba + \"\"\" + """ + When I run `cucumber` + Then the features should all pass + + Scenario: Mocked home directory by using a tag + Given a file named "features/home_variable.feature" with: + """ + Feature: Home Variable + @mocked-home-directory + Scenario: Run command + When I run `cli` + Then the output should contain: + \"\"\" + tmp/aruba + \"\"\" + """ + When I run `cucumber` + Then the features should all pass diff --git a/features/environment/set_environment_variable.feature b/features/environment/set_environment_variable.feature new file mode 100644 index 000000000..628a8c34b --- /dev/null +++ b/features/environment/set_environment_variable.feature @@ -0,0 +1,35 @@ +@wip +Feature: Set environment variable via "cucumber"-step + + It is quite handy to modify the environment of a process. To make this + possible, `aruba` provides several steps. One of these is + `I set the environment variables to:`-step. Using this step sets the values of a + non-existing variables and overwrites an existing values. Each variable name + and each value is converted to a string. Otherwise `ruby` would complain + about an invalid argument. + + Background: + Given I use the fixture "cli-app" + + Scenario: Set environment variable by using a step + Given a file named "bin/cli" with: + """ + #!/usr/bin/env sh + + echo $LONG_LONG_VARIABLE + """ + And a file named "features/home_variable.feature" with: + """ + Feature: Environment Variable + Scenario: Run command + Given I set the environment variables to: + | variable | value | + | LONG_LONG_VARIABLE | long_value | + When I run `cli` + Then the output should contain: + \"\"\" + long_value + \"\"\" + """ + When I run `cucumber` + Then the features should all pass diff --git a/features/support/env.rb b/features/support/env.rb index 62c8fd09b..5c1640b2e 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -20,14 +20,14 @@ # Used in simplecov_setup so that each scenario has a different name and their coverage results are merged instead # of overwriting each other as 'Cucumber Features' - set_env('SIMPLECOV_COMMAND_NAME', command_name) + ENV['SIMPLECOV_COMMAND_NAME'] = command_name.to_s simplecov_setup_pathname = Pathname.new(__FILE__).expand_path.parent.join('simplecov_setup') # set environment variable so child processes will merge their coverage data with parent process's coverage data. if RUBY_VERSION < '1.9' - set_env('RUBYOPT', "-r rubygems -r#{simplecov_setup_pathname} #{ENV['RUBYOPT']}") + ENV['RUBYOPT'] = "-r rubygems -r#{simplecov_setup_pathname} #{ENV['RUBYOPT']}" else - set_env('RUBYOPT', "-r#{simplecov_setup_pathname} #{ENV['RUBYOPT']}") + ENV['RUBYOPT'] = "-r#{simplecov_setup_pathname} #{ENV['RUBYOPT']}" end end diff --git a/lib/aruba/api.rb b/lib/aruba/api.rb index 19dab8f13..20f60dbb5 100644 --- a/lib/aruba/api.rb +++ b/lib/aruba/api.rb @@ -529,7 +529,12 @@ def append_output_to(message) end def process_monitor - @process_monitor ||= ProcessMonitor.new(announcer) + return @process_monitor if defined? @process_monitor + + @process_monitor = ProcessMonitor.new(announcer) + @process_monitor.use_environment aruba.environment + + @process_monitor end # @private @@ -644,11 +649,8 @@ def fixtures_directory # @param [Integer] timeout # Timeout for execution def run_simple(cmd, fail_on_error = true, timeout = nil) - command = run(cmd, timeout) do |process| - process_monitor.stop_process(process) - - process - end + command = run(cmd, timeout) + @last_exit_status = command.stop(announcer) @timed_out = command.timed_out? @@ -682,13 +684,13 @@ def use_clean_gemset(gemset) run_simple(%{rvm gemset create "#{gemset}"}, true) if all_stdout =~ /'#{gemset}' gemset created \((.*)\)\./ gem_home = Regexp.last_match[1] - set_env('GEM_HOME', gem_home) - set_env('GEM_PATH', gem_home) - set_env('BUNDLE_PATH', gem_home) + set_environment_variable('GEM_HOME', gem_home) + set_environment_variable('GEM_PATH', gem_home) + set_environment_variable('BUNDLE_PATH', gem_home) paths = (ENV['PATH'] || "").split(File::PATH_SEPARATOR) paths.unshift(File.join(gem_home, 'bin')) - set_env('PATH', paths.uniq.join(File::PATH_SEPARATOR)) + set_environment_variable('PATH', paths.uniq.join(File::PATH_SEPARATOR)) run_simple("gem install bundler", true) else @@ -699,7 +701,7 @@ def use_clean_gemset(gemset) # Unset variables used by bundler def unset_bundler_env_vars %w[RUBYOPT BUNDLE_PATH BUNDLE_BIN_PATH BUNDLE_GEMFILE].each do |key| - set_env(key, nil) + set_environment_variable(key, nil) end end @@ -710,41 +712,67 @@ def unset_bundler_env_vars # # @param [String] value # The value of the environment variable. Needs to be a string. - def set_env(key, value) - announcer.announce(:environment, key, value) - original_env[key] = ENV.delete(key) unless original_env.key? key - ENV[key] = value + def set_environment_variable(name, value) + name = name.to_s + value = value.to_s + + announcer.announce(:environment, name, value) + aruba.environment[name] = value + + self end - # Restore original process environment - def restore_env - original_env.each do |key, value| - if value - ENV[key] = value - else - ENV.delete key - end - end + # Append environment variable + # + # @param [String] key + # The name of the environment variable as string, e.g. 'HOME' + # + # @param [String] value + # The value of the environment variable. Needs to be a string. + def append_environment_variable(name, value) + name = name.to_s + value = value.to_s + + aruba.environment.append name, value + announcer.announce(:environment, name, aruba.environment[name]) + + self end - # @private - def original_env - @original_env ||= {} + # Prepend environment variable + # + # @param [String] key + # The name of the environment variable as string, e.g. 'HOME' + # + # @param [String] value + # The value of the environment variable. Needs to be a string. + def prepend_environment_variable(name, value) + name = name.to_s + value = value.to_s + + aruba.environment.prepend name, value + announcer.announce(:environment, name, aruba.environment[name]) + + self end # Run block with environment # - # @param [Hash] env + # @param [Hash] env (optional) # The variables to be used for block. # # @yield # The block of code which should be run with the modified environment variables - def with_env(env = {}, &block) - env.each do |k,v| - set_env k, v - end + def with_environment(env = {}, &block) + old_env = ENV.to_hash + + ENV.update(aruba.environment.to_h) + ENV.update(env) + block.call - restore_env + ensure + ENV.clear + ENV.update old_env end # Access to announcer diff --git a/lib/aruba/api/deprecated.rb b/lib/aruba/api/deprecated.rb index 0a7fd118a..96d60388c 100644 --- a/lib/aruba/api/deprecated.rb +++ b/lib/aruba/api/deprecated.rb @@ -374,6 +374,62 @@ def in_current_dir(*args, &block) in_current_directory end + + # @deprecated + # Run block with environment + # + # @param [Hash] env + # The variables to be used for block. + # + # @yield + # The block of code which should be run with the modified environment variables + def with_env(env = {}, &block) + Aruba::Platform.deprecated('The use of "#with_env" is deprecated. Use "#with_environment {}" instead. But be careful this uses a different implementation') + + env.each do |k,v| + set_env k, v + end + block.call + restore_env + end + + # @deprecated + # Restore original process environment + def restore_env + # No output because we need to reset env on each scenario/spec run + # Aruba::Platform.deprecated('The use of "#restore_env" is deprecated. If you use "set_environment_variable" there\'s no need to restore the environment') + + original_env.each do |key, value| + if value + ENV[key] = value + else + ENV.delete key + end + end + end + + # @deprecated + # Set environment variable + # + # @param [String] key + # The name of the environment variable as string, e.g. 'HOME' + # + # @param [String] value + # The value of the environment variable. Needs to be a string. + def set_env(key, value) + Aruba::Platform.deprecated('The use of "#set_env" is deprecated. Please use "set_environment_variable" instead. But be careful, this method uses a different kind of implementation') + + announcer.announce(:environment, key, value) + original_env[key] = ENV.delete(key) unless original_env.key? key + ENV[key] = value + end + + # @deprecated + def original_env + # Aruba::Platform.deprecated('The use of "#original_env" is deprecated.') + + @original_env ||= {} + end end end end diff --git a/lib/aruba/config.rb b/lib/aruba/config.rb index 9f0a31ed1..3937dabca 100644 --- a/lib/aruba/config.rb +++ b/lib/aruba/config.rb @@ -19,6 +19,8 @@ class Configuration < BasicConfiguration option_accessor :exit_timeout, :contract => { Num => Num }, :default => 3 option_accessor :io_wait_timeout, :contract => { Num => Num }, :default => 0.1 option_accessor :fixtures_directories, :contract => { Array => ArrayOf[String] }, :default => %w(features/fixtures spec/fixtures test/fixtures) + option_accessor :command_runtime_environment, :contract => { Hash => Hash }, :default => ENV.to_hash + option_accessor(:command_search_paths, :contract => { ArrayOf[String] => ArrayOf[String] }) { |config| [File.join(config.root_directory.value, 'bin')] } end end diff --git a/lib/aruba/cucumber.rb b/lib/aruba/cucumber.rb index e31d29bfc..ab7c40cf5 100644 --- a/lib/aruba/cucumber.rb +++ b/lib/aruba/cucumber.rb @@ -54,7 +54,7 @@ end Given /^a mocked home directory$/ do - set_env 'HOME', expand_path('.') + set_environment_variable 'HOME', expand_path('.') end Given /^(?:a|the) directory(?: named)? "([^"]*)" does not exist$/ do |directory_name| @@ -98,16 +98,16 @@ variable = row['variable'].to_s.upcase value = row['value'].to_s - set_env(variable, value) + set_environment_variable(variable, value) end end Given /^I append the value to the environment variable:/ do |table| table.hashes.each do |row| variable = row['variable'].to_s.upcase - value = row['value'].to_s + row['value'].to_s + value = row['value'].to_s - set_env(variable, value) + append_environment_variable(variable, value) end end diff --git a/lib/aruba/cucumber/hooks.rb b/lib/aruba/cucumber/hooks.rb index c3bd9bb5f..dc9af54b8 100644 --- a/lib/aruba/cucumber/hooks.rb +++ b/lib/aruba/cucumber/hooks.rb @@ -2,20 +2,26 @@ require 'aruba/api' World(Aruba::Api) -Around do |_, block| - project_bin = Aruba::ArubaPath.new(Aruba.config.root_directory) - project_bin << 'bin' - - old_path = ENV.fetch 'PATH', '' - - paths = old_path.split(File::PATH_SEPARATOR) - paths.unshift project_bin - - ENV['PATH'] = paths.join(File::PATH_SEPARATOR) - - block.call - - ENV['PATH'] = old_path +# Activate on 1.0.0 +# +# Around do |_, block| +# begin +# if RUBY_VERSION < '1.9' +# old_env = ENV.to_hash +# else +# old_env = ENV.to_h +# end +# +# block.call +# ensure +# ENV.clear +# ENV.update old_env +# end +# end + +Before do + aruba.environment.update aruba.config.command_runtime_environment + aruba.environment.prepend 'PATH', aruba.config.command_search_paths.join(':') + ':' end After do @@ -88,7 +94,13 @@ end Before '@mocked_home_directory' do - set_env 'HOME', expand_path('.') + Aruba::Platform.deprecated('The use of "@mocked_home_directory" is deprecated. Use "@mocked-home-directory" instead') + + set_environment_variable 'HOME', expand_path('.') +end + +Before '@mocked-home-directory' do + set_environment_variable 'HOME', expand_path('.') end Before('@disable-bundler') do diff --git a/lib/aruba/environment.rb b/lib/aruba/environment.rb new file mode 100644 index 000000000..791cd32b6 --- /dev/null +++ b/lib/aruba/environment.rb @@ -0,0 +1,51 @@ +module Aruba + class Environment + private + + attr_reader :env + + public + + def initialize + @env = ENV.to_hash + end + + def update(other_env) + env.update other_env + + self + end + + def [](name) + env[name.to_s] + end + + def []=(name, value) + env[name.to_s] = value.to_s + + self + end + + def append(name, value) + name = name.to_s + env[name] = env[name].to_s + value.to_s + + self + end + + def prepend(name, value) + name = name.to_s + env[name] = value.to_s + env[name].to_s + + self + end + + def to_h + if RUBY_VERSION < '2.0' + env.to_hash + else + env.to_h + end + end + end +end diff --git a/lib/aruba/jruby.rb b/lib/aruba/jruby.rb index 247368de3..a3390bb9d 100644 --- a/lib/aruba/jruby.rb +++ b/lib/aruba/jruby.rb @@ -2,13 +2,13 @@ # ideas taken from: http://blog.headius.com/2010/03/jruby-startup-time-tips.html Aruba.configure do |config| - config.before :cmd do + config.before :command do next unless RUBY_PLATFORM == 'java' # disable JIT since these processes are so short lived - set_env('JRUBY_OPTS', "-X-C #{ENV['JRUBY_OPTS']}") + set_environment_variable('JRUBY_OPTS', "-X-C #{ENV['JRUBY_OPTS']}") # force jRuby to use client JVM for faster startup times - set_env('JAVA_OPTS', "-d32 #{ENV['JAVA_OPTS']}") if RbConfig::CONFIG['host_os'] =~ /solaris|sunos/i + set_environment_variable('JAVA_OPTS', "-d32 #{ENV['JAVA_OPTS']}") if RbConfig::CONFIG['host_os'] =~ /solaris|sunos/i end end diff --git a/lib/aruba/matchers/command/be_successfully_executed.rb b/lib/aruba/matchers/command/be_successfully_executed.rb index a9aa00163..36ecb701b 100644 --- a/lib/aruba/matchers/command/be_successfully_executed.rb +++ b/lib/aruba/matchers/command/be_successfully_executed.rb @@ -1,5 +1,5 @@ require 'aruba/matchers/command/have_exit_status' -require 'aruba/matchers/command/run_too_long' +require 'aruba/matchers/command/have_finished_in_time' # @!method be_successfuly_executed # This matchers checks if execution of was successful @@ -15,12 +15,16 @@ # # RSpec.describe do # it { expect(last_command).to be_successfully_executed } +# it { expect(last_command).not_to be_successfully_executed } +# it { expect(last_command).to have_failed_running } # end RSpec::Matchers.define :be_successfully_executed do match do |actual| @old_actual = actual - @actual = @old_actual.commandline + @actual = @old_actual.commandline expect(@old_actual).to have_exit_status(0) end end + +RSpec::Matchers.define_negated_matcher :have_failed_running, :be_successfully_executed diff --git a/lib/aruba/matchers/command/run_too_long.rb b/lib/aruba/matchers/command/have_finished_in_time.rb similarity index 70% rename from lib/aruba/matchers/command/run_too_long.rb rename to lib/aruba/matchers/command/have_finished_in_time.rb index f2481718e..e336c8725 100644 --- a/lib/aruba/matchers/command/run_too_long.rb +++ b/lib/aruba/matchers/command/have_finished_in_time.rb @@ -16,9 +16,11 @@ # it { expect(last_command).not_to run_too_long } # it { expect(last_command).to finish_its_run_in_time } # end -RSpec::Matchers.define :run_too_long do +# RSpec::Matchers.define :run_too_long do +RSpec::Matchers.define :have_finished_in_time do match do |actual| @old_actual = actual + @actual = @old_actual.commandline @announcer ||= Aruba::Announcer.new( self, @@ -33,16 +35,8 @@ next false unless @old_actual.respond_to? :timed_out? - expect(@old_actual).to be_timed_out - end - - failure_message do |actual| - format %(expected that command "%s" run too long), actual.commandline - end - - failure_message_when_negated do |actual| - format %(expected that command "%s" has finished in time), actual.commandline + @old_actual.timed_out? == false end end -RSpec::Matchers.define_negated_matcher :have_finished_in_time, :run_too_long +RSpec::Matchers.define_negated_matcher :run_too_long, :have_finished_in_time diff --git a/lib/aruba/process_monitor.rb b/lib/aruba/process_monitor.rb index 6868e5dde..464c7f297 100644 --- a/lib/aruba/process_monitor.rb +++ b/lib/aruba/process_monitor.rb @@ -2,13 +2,18 @@ module Aruba class ProcessMonitor private - attr_reader :processes, :announcer + attr_reader :processes, :announcer, :environment public def initialize(announcer) @processes = [] @announcer = announcer + @environment = {} + end + + def use_environment(environment) + @environment = environment.to_h end def last_exit_status @@ -41,6 +46,10 @@ def terminate_processes def register_process(name, process) processes << [name, process] + + process.environment = environment + + [name, process] end def get_process(wanted) diff --git a/lib/aruba/processes/basic_process.rb b/lib/aruba/processes/basic_process.rb index 9627fe8eb..7ef34333f 100644 --- a/lib/aruba/processes/basic_process.rb +++ b/lib/aruba/processes/basic_process.rb @@ -1,8 +1,11 @@ module Aruba module Processes class BasicProcess + attr_accessor :environment + def initialize(cmd, exit_timeout, io_wait, working_directory) @working_directory = working_directory + @environment = ENV.to_hash end # Output stderr and stdout diff --git a/lib/aruba/processes/debug_process.rb b/lib/aruba/processes/debug_process.rb index 532e14340..9e694d6a3 100644 --- a/lib/aruba/processes/debug_process.rb +++ b/lib/aruba/processes/debug_process.rb @@ -34,10 +34,10 @@ def commandline def run! if RUBY_VERSION < '1.9' Dir.chdir do - @exit_status = system(@cmd) ? 0 : 1 + @exit_status = system(environment, @cmd) ? 0 : 1 end else - @exit_status = system(@cmd, :chdir => @working_directory) ? 0 : 1 + @exit_status = system(environment, @cmd, :chdir => @working_directory) ? 0 : 1 end end diff --git a/lib/aruba/processes/in_process.rb b/lib/aruba/processes/in_process.rb index 48d18b841..ac1aff70c 100644 --- a/lib/aruba/processes/in_process.rb +++ b/lib/aruba/processes/in_process.rb @@ -44,7 +44,11 @@ def run! Dir.chdir @working_directory do before_run - self.class.main_class.new(@argv, @stdin, @stdout, @stderr, @kernel).execute! + + with_environment do + self.class.main_class.new(@argv, @stdin, @stdout, @stderr, @kernel).execute! + end + after_run yield self if block_given? @@ -81,6 +85,19 @@ def close_io(name) def terminate stop end + + private + + def with_environment(&block) + old_env = ENV.to_hash + + ENV.update(environment) + + block.call + ensure + ENV.clear + ENV.update old_env + end end end end diff --git a/lib/aruba/processes/spawn_process.rb b/lib/aruba/processes/spawn_process.rb index 736b813fe..28cf8ee6c 100644 --- a/lib/aruba/processes/spawn_process.rb +++ b/lib/aruba/processes/spawn_process.rb @@ -58,6 +58,8 @@ def run! @process.duplex = @duplex @process.cwd = @working_directory + @process.environment.update(environment) + begin @process.start rescue ChildProcess::LaunchError => e diff --git a/lib/aruba/rspec.rb b/lib/aruba/rspec.rb index b1fa4c1e3..3267a234b 100644 --- a/lib/aruba/rspec.rb +++ b/lib/aruba/rspec.rb @@ -63,4 +63,11 @@ announcer.activate(:directory) end end + + config.before :each do + next unless self.class.include? Aruba::Api + + aruba.environment.update aruba.config.command_runtime_environment + aruba.environment.prepend 'PATH', aruba.config.command_search_paths.join(':') + ':' + end end diff --git a/lib/aruba/runtime.rb b/lib/aruba/runtime.rb index f3a005c25..b3b7c76eb 100644 --- a/lib/aruba/runtime.rb +++ b/lib/aruba/runtime.rb @@ -1,12 +1,14 @@ require 'aruba/config' +require 'aruba/environment' module Aruba class Runtime - attr_reader :config, :current_directory + attr_reader :config, :current_directory, :environment def initialize @config = Aruba.config.make_copy @current_directory = ArubaPath.new(@config.working_directory) + @environment = Environment.new end end end diff --git a/spec/aruba/api_spec.rb b/spec/aruba/api_spec.rb index f0368f14a..e3fdd62ca 100644 --- a/spec/aruba/api_spec.rb +++ b/spec/aruba/api_spec.rb @@ -130,7 +130,7 @@ let(:content) { 'asdf' } before :each do - set_env 'HOME', File.expand_path(@aruba.aruba.current_directory) + set_environment_variable 'HOME', File.expand_path(@aruba.aruba.current_directory) end context 'when does not exist' do @@ -184,7 +184,7 @@ let(:path) { File.join(@aruba.aruba.current_directory, name) } before :each do - set_env 'HOME', File.expand_path(@aruba.aruba.current_directory) + set_environment_variable 'HOME', File.expand_path(@aruba.aruba.current_directory) end context 'when does not exist' do @@ -247,7 +247,7 @@ let(:options) { {} } before :each do - set_env 'HOME', File.expand_path(@aruba.aruba.current_directory) + set_environment_variable 'HOME', File.expand_path(@aruba.aruba.current_directory) end context 'when file' do @@ -346,7 +346,7 @@ let(:options) { {} } before :each do - set_env 'HOME', File.expand_path(@aruba.aruba.current_directory) + set_environment_variable 'HOME', File.expand_path(@aruba.aruba.current_directory) end context 'when file' do @@ -778,7 +778,7 @@ def actual_permissions let(:permissions) { '0655' } before :each do - set_env 'HOME', File.expand_path(@aruba.aruba.current_directory) + set_environment_variable 'HOME', File.expand_path(@aruba.aruba.current_directory) end before(:each) do @@ -816,7 +816,7 @@ def actual_permissions let(:permissions) { '0655' } before :each do - set_env 'HOME', File.expand_path(@aruba.aruba.current_directory) + set_environment_variable 'HOME', File.expand_path(@aruba.aruba.current_directory) end before(:each) do @@ -1192,19 +1192,19 @@ def root_directory end end - describe "#set_env" do + describe "#set_environment_variable" do after(:each) do @aruba.stop_processes! @aruba.restore_env end it "set environment variable" do - @aruba.set_env 'LONG_LONG_ENV_VARIABLE', 'true' + @aruba.set_environment_variable 'LONG_LONG_ENV_VARIABLE', 'true' @aruba.run "env" expect(@aruba.all_output).to include("LONG_LONG_ENV_VARIABLE=true") end it "overwrites environment variable" do - @aruba.set_env 'LONG_LONG_ENV_VARIABLE', 'true' - @aruba.set_env 'LONG_LONG_ENV_VARIABLE', 'false' + @aruba.set_environment_variable 'LONG_LONG_ENV_VARIABLE', 'true' + @aruba.set_environment_variable 'LONG_LONG_ENV_VARIABLE', 'false' @aruba.run "env" expect(@aruba.all_output).to include("LONG_LONG_ENV_VARIABLE=false") end @@ -1213,14 +1213,14 @@ def root_directory describe "#restore_env" do after(:each){@aruba.stop_processes!} it "restores environment variable" do - @aruba.set_env 'LONG_LONG_ENV_VARIABLE', 'true' + @aruba.set_environment_variable 'LONG_LONG_ENV_VARIABLE', 'true' @aruba.restore_env @aruba.run "env" expect(@aruba.all_output).not_to include("LONG_LONG_ENV_VARIABLE") end it "restores environment variable that has been set multiple times" do - @aruba.set_env 'LONG_LONG_ENV_VARIABLE', 'true' - @aruba.set_env 'LONG_LONG_ENV_VARIABLE', 'false' + @aruba.set_environment_variable 'LONG_LONG_ENV_VARIABLE', 'true' + @aruba.set_environment_variable 'LONG_LONG_ENV_VARIABLE', 'false' @aruba.restore_env @aruba.run "env" expect(@aruba.all_output).not_to include("LONG_LONG_ENV_VARIABLE")