cucumber / aruba

Test command-line applications with Cucumber-Ruby, RSpec or Minitest.
MIT License
949 stars 163 forks source link

Aruba run cannot find script file #11

Closed byrnejb closed 14 years ago

byrnejb commented 14 years ago

Perhaps I do not understand the proper way to invoke run from Aruba but when I try do this in a feature:

@announce . . . And run "vendor/plugins/activewarehouse-etl/bin/etl config/etl/client_xml.ctl"

Then I see this: sh: vendor/plugins/activewarehouse-etl/bin/etl: No such file or directory

Yet: $ ll vendor/plugins/activewarehouse-etl/bin/etl -rwxr-xr-x 1 byrnejb byrnejb 1211 May 14 09:11 vendor/plugins/activewarehouse-etl/bin/etl

Any ideas as to what I might be doing wrong?

byrnejb commented 14 years ago

In case it is important, and when is it not, I am using rvm with the following background statement:

And I am using rvm "ruby-1.8.7-p249"

Although the presence or absence of this seems to have no effect.

byrnejb commented 14 years ago

Making the path absolute (/home/byrnejb/projects/. . ./vendor/plugins/etc.)

Allows Aruba.run to work but it is a bit unwieldy.

byrnejb commented 14 years ago

So, I discover that it was my failure to apprehend that the current directory is always switched to ./tmp/aruba before running anything which is the root of my problems. This is an understandable default but it does pose some practical difficulties when dealing with a deep directory structure.

byrnejb commented 14 years ago

I moved the directory strings into the step_definitions files, which is probably where they belonged to begin with.

However, when one uses Aruba to test configuration files for some third party script and that third party script expects and requires that it be run from the rails-root directory then this default behaviour becomes very problematic. This is my case at the moment using activewarehouse-etl. Should Aruba cope with this sort of testing as well or not?

byrnejb commented 14 years ago

I forked aruba to add, among many other things, a rebase api method. This method creates a symbolic link in the tmpdir for any directory specified and thereby addresses my original problem.

cybertk commented 10 years ago

@byrnejb Could you share your solution? I encounter the same issue and I plan to modify ENV['PATH'] in env.rb

byrnejb commented 10 years ago

My solution was to fork Aruba and add a rebase method to the API. I had maintained this as an alternative gem but abandoned that undertaking when the rate of change to Aruba's internals exceeded my capacity to track. You can look at the fork in my git repository here, extract the necessary methods and monkey patch them into the current version if you wish.

I think I read that Aruba now permits a similar sort of thing but I am not conversant with how they do that.

Presently I simply maintain my own Aruba API library and call Aruba thusly. In ./features/support I put a file called, originally enough, cucumber_aruba_api.rb. Because it ends in .rb and is located in features/support cucumber will always load it during cucumber's initialisation. In that I have this:

# Bring in cucumber and supporting players
require 'cucumber'
require 'aruba/api'
require 'aruba/cucumber/hooks'
require 'aruba/reporting'

World( Aruba::Api )

#  require 'aruba/cucumber'

# Make sure this require is after you require cucumber/rails/world.
#require 'email_spec' # add this line if you use spork
#require 'email_spec/cucumber'

# Monkey patch Aruba
module Aruba
  module Api

    def aruba_working_dir_default
      return ['tmp', 'aruba']
    end

    # aruba_working_dir simply returns the value of the current
    # directory that aruba is running its features in. This is
    # set using the aruba_working_dir_set method from within the
    # step definitions or through the environment variable
    # ARUBA_WORKING_DIR
    #
    def aruba_working_dir
      @aruba_working_dir ||= aruba_working_dir_default
    end

    # aruba_working_dir_set allows before hooks to set aruba's
    # working directory relative to user's cwd.
    #
    def aruba_working_dir_set( dir )
      @aruba_working_dir = dir
      dirs_init
    end

    # You can override the default working directory by setting
    # the environment variable ARUBA_WORKING_DIR
    #
    ARUBA_WORKING_DIR_DEFAULT = 'tmp/aruba'

    # aruba_working_dir_init initializes the aruba_working_dir to
    # either the default value specified in ARUBA_WORKING_DIR_DEFAULT
    # or the value of the the environment variable ARUBA_WORKING_DIR
    # if present.
    #
    # This method also rebases the list of comma delimited directories
    # contained in the ARUBA_REBASE environmental variable, if found.
    #
    def aruba_working_dir_init

      @aruba_working_dir = [ARUBA_WORKING_DIR_DEFAULT]

      if ( ENV['ARUBA_WORKING_DIR'] != nil )
        @aruba_working_dir = [ENV['ARUBA_WORKING_DIR']]
      end

      dirs_init
      clean_up
      rebase_dirs_clear

      if ( ENV['ARUBA_REBASE'] != nil )
        rebase( ENV['ARUBA_REBASE'].split( %r{,|;\s*} ) )
      end
    end

    # check_directory_presence(paths, expect_presence) operates on
    # an enumable collection of paths and determines if each exits
    # passes if they do when expect_presence = true and
    # passes if they do not when expect_presence = false.
    #
    # Usage:
    # Then the following directories should exist:
    # | foo/bar |
    # | foo/bla |
    #
    # Then the following directories should not exist:
    # | bar/foo |
    # | bar/none |
    #
    # When /following directories should exist:$/ do |directories|
    # check_directory_presence(directories.raw.map{
    # |directory_row| directory_row[0]}, true)
    #
    def check_directory_presence( paths, expect_presence=true )
      paths = paths_to_array( paths )
      in_current_dir do
        paths.each do |path|
          is_dir = Dir.exists?( path )
          if expect_presence
            fail( "Expected directory #{path} not found" ) unless is_dir
          else
            fail( "Unexpected directory #{path} found" ) if is_dir
          end
        end
      end
    end

    # check_file_presence operates on files in a fashion similar
    # to check_directory_presence. it enumerates on a collection
    # of file names and passes or fails on the first presence or
    # absence in the filesystem according to the expect_presence setting.
    #
    # Usage:
    # When the following files should exist:
    # """
    # blah/file.tst
    # bare/file1.test
    # foor/barnet.tst
    # """
    # When /following files? should exist:$/ do |files|
    # check_file_presence(files.raw.map{|file_row| file_row[0]}, true)
    #
    def check_file_presence( paths, expect_presence=true )
      paths = paths_to_array( paths )
      in_current_dir do
        paths.each do |path|
          if expect_presence
            fail( "Expected file #{path} not found" ) unless File.exists?( path )
          else
            fail( "Unexpected file #{path} found" ) if File.exists?( path )
          end
        end
      end
    end

    # clean_up is an internal helper method that empties the current working
    # directory of all content. It is used in the Aruba before hook to clear
    # out the awd at the start of each scenario.
    #
    # It will not clear any directory that does not contain the directory
    # <tt>/tmp/</tt> somewhere in its path.
    #
    def clean_up( dir = current_dir )
      check_tmp_dir = File.expand_path( dir )
      if File.fnmatch( '**/tmp/**', check_tmp_dir )
        clean_up!
      else
        raise "#{check_tmp_dir} is outside the tmp " +
          "subtree and may not be deleted."
      end
    end

    # clean_up! is an Internal helper method that clears the awd without
    # checking for tmp in the directory path. Do not use this or you will kick yourself at some point.
    #
    def clean_up!( dir = current_dir )
#      FileUtils.rm_rf( dir )
      FileUtils.chmod_R( 0777, dir )
      FileUtils.remove_entry_secure( dir )
      _mkdir( dir )
    end

    # current_dir is an internal helper method that returns the current awd
    # as a path.
    #
    def current_dir
      File.join( *dirs )
    end

    # dirs is an internal helper method that returns the current
    # directory components as an array.
    #
    def dirs
      @dirs ||= dirs_init
    end

    # dirs_init is an internal helper method that intializes the
    # content of the dirs to the value of aruba_working_dir.
    #
    def dirs_init
      @dirs = []
      @dirs << aruba_working_dir
    end

    # in_current_dir is an internal helper method wherein all the magic
    # of Aruba takes place. It uses the value of current_dir to determine
    # what directory to change to before running Aruba steps.
    #
    def in_current_dir( &block )
      _mkdir( current_dir )
      Dir.chdir( current_dir, &block )
    end

    def last_stderr
      @last_stderr  # 'cucumber/aruba' in #run
    end

    def last_stdout
      @last_stderr # 'cucumber/aruba' in #run
    end

    # _mkdir(dir_name) is an internal helper name that does exactly as its
    # stem suggests, performs a mkdir using the provided name.
    #
    def _mkdir( dir_name )
      FileUtils.mkdir_p( dir_name ) unless File.directory?( dir_name )
    end

    def paths_to_array( paths )
      return paths if paths.kind_of?( Array )
      paths = ( paths || "").split( File::PATH_SEPARATOR )
      return paths
    end

    # rebase creates a symbolic link in the awd to each directory
    # contained in the passed array.Each entry is named relative to the user's
    # cwd. It first checks that the awd path contains a directory named
    # <tt>/tmp/</tt> and fails if it does not.
    #
    # Usage:
    # When I rebase the directory named "bar/foo"$
    #
    # When /I rebase the directory named "([^\"]*)"$/ do |dir|
    # rebase(dir)
    #
    def rebase( dirs=nil )

      rebase_dirs_add( dirs ) if dirs
      working_dir = File.expand_path(
        File.join( FileUtils.pwd, aruba_working_dir ) )

      if rebase_dirs and File.fnmatch( '**/tmp/**', working_dir )
        rebase_dirs.each do |dir|
          FileUtils.ln_s( File.join( user_working_dir, dir.to_s ),
            working_dir, :force => true )
        end
      else
        raise "Aruba's working directory, #{working_dir}, \n" +
          "is outside the tmp subtree and may not be rebased."
      end
    end

    # rebase_dirs is an internal helper method that returns the
    # array containing all the directories to be rebased.
    #
    def rebase_dirs
      @aruba_rebase_dirs
    end

    # rebase_dirs_add is an internal helper method that
    # adds directory names to the rebase_dirs array.
    #
    def rebase_dirs_add( dirs=nil )
      return unless dirs
      dirs = dirs.lines.to_a if dirs.respond_to?( 'lines' )
      dirs = dirs.flatten
      @aruba_rebase_dirs ||= []
      @aruba_rebase_dirs = (@aruba_rebase_dirs + dirs).uniq
    end

    # rebase_dirs_clear is an internal helper method that empties
    # the rebase_dirs array.
    #
    def rebase_dirs_clear
      @aruba_rebase_dirs = []
    end

    # user_working_dir is an internal helper method used by the rebase method
    # that initially sets and then returns the user's pwd.
    #
    def user_working_dir
      # This allows us to find the user's original working directory
      @user_working_dir ||= FileUtils.pwd
    end

  end
end

Before do
  aruba_working_dir_init
end

Before( '@aruba-tmpdir' ) do
  aruba_working_dir_init
end

Before( '@no-aruba-tmpdir' ) do
  aruba_working_dir_set( './' )
  dirs_init
end

After do
  @announce_stdout = false
  @announce_stderr = false
  @announce_cmd = false
  @announce_dir = false
  @announce_env = false
end

Note that I do NOT call the cucumber step-def library that ships with Aruba. I provide my own step-defs instead.

jarl-dk commented 10 years ago

When using aruba it executes in a temporary directory created in tmp. You could try to

@announce
...
And run `pwd`

to see the current working directory of a test...

@cybertk , @byrnejb : Do you have any proposals as of how to improve the documentation/behaviour of aruba?

byrnejb commented 10 years ago

On Fri, August 8, 2014 08:55, Jarl Friis wrote:

When using aruba it executes in a temporary directory created in tmp. You could try to

@announce
...
And run `pwd`

to see the current working directory of a test...

@cybertk , @byrnejb : Do you have any proposals as of how to improve the documentation/behaviour of aruba?

I cannot comment on Aruba as distributed in its more recent forms as I forked my API for Aruba some time ago and now only employ Aruba's core API libraries as described above. Initially, as this issue that I opened so long ago states, my main reason for doing so was the need to preserve non-DB test data between scenarios. Now, what mainly keeps me away from using the base Aruba gem and abandoning my own version is the forced inclusion of the default Aruba 'step-defs', whose matcher formulation clashes with our own, together with those step-defs dependency on RSpec, which we do not use. Although, the rebase method and other addons in our Aruba API cannot be discarded at this point regardless.

If you wish a proposal then:

  1. Make inclusion of Aruba's Cucumber step-def library a project level configuration option or, better yet, package the Aruba step-defs as a separate gem and do not make them a dependency for Aruba.
  2. Make RSpec a project level configuration option as well or a dependency of a separate step-def gem as outlined above..
  3. Remove RSpec as a gem dependency for the base Aruba gem since RSpec's presence is detected by Cucumber and changes that gem's behaviour. This in itself is causing me no end of grief due to the recent changes in Minitest (5.0) and ActiveSupport's (4.1) dependency thereon. I will sort out how to work around that combination eventually but at the moment is is a PITA that I would rather not have and it is Aruba that is dragging RSpec into my project.

Regards,

* E-Mail is NOT a SECURE channel * James B. Byrne mailto:ByrneJB@Harte-Lyne.ca Harte & Lyne Limited http://www.harte-lyne.ca 9 Brockley Drive vox: +1 905 561 1241 Hamilton, Ontario fax: +1 905 561 0757 Canada L8E 3C3