class Beaker::TestCase

This class represents a single test case. A test case is necessarily contained all in one file though may have multiple dependent examples. They are executed in order (save for any teardown procs registered through {Beaker::DSL::Structure#teardown}) and once completed the status of the TestCase is saved. Instance readers/accessors provide the test case access to various details of the environment and suite the test case is running within.

See {Beaker::DSL} for more information about writing tests using the DSL.

Constants

TEST_EXCEPTION_CLASS

The Exception raised by Ruby’s STDLIB’s test framework (Ruby 1.9)

Attributes

exception[R]

The exception that may have stopped this test’s execution.

exports[RW]

Necessary for {Beaker::DSL::Outcomes}. Assumed to be an Array.

fail_flag[R]

I don’t know why this is here

hosts[RW]

Necessary for implementing {Beaker::DSL::Helpers#confine}. Assumed to be an array of valid {Beaker::Host} objects for this test case.

last_result[RW]

The result for the last command run

logger[RW]

Necessary for many methods in {Beaker::DSL}. Assumed to be an instance of {Beaker::Logger}.

metadata[RW]

Necessary for many methods in {Beaker::DSL::Helpers}. Assumed to be a hash.

options[R]

Parsed command line options.

path[R]

The path to the file which contains this test case.

runtime[R]

The amount of time taken to execute the test

sublog[RW]

The full log for this test

teardown_procs[R]

An Array of Procs to be called after test execution has stopped (whether by exception or not).

test_status[R]

A Symbol denoting the status of this test (:fail, :pending, :skipped, :pass).

usr_home[R]

The user that is running this tests home directory, needed by ‘net/ssh’.

version[R]

A Hash of ‘product name’ => ‘version installed’, only set when products are installed via git or PE install steps. See the ‘git’ or ‘pe’ directories within ‘ROOT/setup’ for examples.

Public Class Methods

new(these_hosts, logger, options = {}, path = nil) click to toggle source

@param [Hosts,Array<Host>] these_hosts The hosts to execute this test

against/on.

@param [Logger] logger A logger that implements

{Beaker::Logger}'s interface.

@param [Hash{Symbol=>String}] options Parsed command line options. @param [String] path The local path to a test file to be executed.

# File lib/beaker/test_case.rb, line 87
def initialize(these_hosts, logger, options = {}, path = nil)
  @hosts = these_hosts
  @logger = logger
  @sublog = ""
  @options = options
  @path    = path
  @usr_home = options[:home]
  @test_status = :pass
  @exception = nil
  @runtime = nil
  @teardown_procs = []
  @metadata = {}
  @exports  = []
  set_current_test_filename(@path ? File.basename(@path, '.rb') : nil)

  #
  # We put this on each wrapper (rather than the class) so that methods
  # defined in the tests don't leak out to other tests.
  class << self
    def run_test
      @logger.start_sublog
      @logger.last_result = nil

      set_current_step_name(nil)

      # add arbitrary role methods
      roles = []
      @hosts.each do |host|
        roles << host[:roles]
      end
      add_role_def(roles.flatten.uniq)

      @runtime = Benchmark.realtime do
        begin
          test = File.read(path)
          eval test, nil, path, 1
        rescue FailTest, TEST_EXCEPTION_CLASS => e
          log_and_fail_test(e, :fail)
        rescue PassTest
          @test_status = :pass
        rescue PendingTest
          @test_status = :pending
        rescue SkipTest
          @test_status = :skip
        rescue StandardError, ScriptError, SignalException => e
          log_and_fail_test(e)
        ensure
          @logger.info('Begin teardown')
          @teardown_procs.each do |teardown|
            begin
              teardown.call
            rescue StandardError, SignalException, TEST_EXCEPTION_CLASS => e
              log_and_fail_test(e, :teardown_error)
            end
          end
          @logger.info('End teardown')
        end
      end
      @sublog = @logger.get_sublog
      @last_result = @logger.last_result
      return self
    end

    private

    # Log an error and mark the test as failed, passing through an
    # exception so it can be displayed at the end of the total run.
    #
    # We break out the complete exception backtrace and log each line
    # individually as well.
    #
    # @param exception [Exception] exception to fail with
    # @param exception [Symbol] the test status
    def log_and_fail_test(exception, status = :error)
      logger.error("#{exception.class}: #{exception.message}")
      bt = exception.backtrace
      logger.pretty_backtrace(bt).each_line do |line|
        logger.error(line)
      end
      # If the status is already a test failure or error, don't overwrite with the teardown failure.
      return if status == :teardown_error && (@test_status == :error || @test_status == :fail)

      status = :error if status == :teardown_error
      @test_status = status
      @exception   = exception
    end
  end
end
run_test() click to toggle source
# File lib/beaker/test_case.rb, line 106
def run_test
  @logger.start_sublog
  @logger.last_result = nil

  set_current_step_name(nil)

  # add arbitrary role methods
  roles = []
  @hosts.each do |host|
    roles << host[:roles]
  end
  add_role_def(roles.flatten.uniq)

  @runtime = Benchmark.realtime do
    begin
      test = File.read(path)
      eval test, nil, path, 1
    rescue FailTest, TEST_EXCEPTION_CLASS => e
      log_and_fail_test(e, :fail)
    rescue PassTest
      @test_status = :pass
    rescue PendingTest
      @test_status = :pending
    rescue SkipTest
      @test_status = :skip
    rescue StandardError, ScriptError, SignalException => e
      log_and_fail_test(e)
    ensure
      @logger.info('Begin teardown')
      @teardown_procs.each do |teardown|
        begin
          teardown.call
        rescue StandardError, SignalException, TEST_EXCEPTION_CLASS => e
          log_and_fail_test(e, :teardown_error)
        end
      end
      @logger.info('End teardown')
    end
  end
  @sublog = @logger.get_sublog
  @last_result = @logger.last_result
  return self
end

Private Class Methods

log_and_fail_test(exception, status = :error) click to toggle source

Log an error and mark the test as failed, passing through an exception so it can be displayed at the end of the total run.

We break out the complete exception backtrace and log each line individually as well.

@param exception [Exception] exception to fail with @param exception [Symbol] the test status

# File lib/beaker/test_case.rb, line 160
def log_and_fail_test(exception, status = :error)
  logger.error("#{exception.class}: #{exception.message}")
  bt = exception.backtrace
  logger.pretty_backtrace(bt).each_line do |line|
    logger.error(line)
  end
  # If the status is already a test failure or error, don't overwrite with the teardown failure.
  return if status == :teardown_error && (@test_status == :error || @test_status == :fail)

  status = :error if status == :teardown_error
  @test_status = status
  @exception   = exception
end

Public Instance Methods

to_hash() click to toggle source

The TestCase as a hash @api public @note The visibility and semantics of this method are valid, but the

structure of the Hash it returns may change without notice

@return [Hash] A Hash representation of this test.

# File lib/beaker/test_case.rb, line 182
def to_hash
  hash = {}
  hash['HOSTS'] = {}
  @hosts.each do |host|
    hash['HOSTS'][host.name] = host.overrides
  end
  hash
end