Class: Beaker::TestCase

Inherits:
Object
  • Object
show all
Includes:
DSL
Defined in:
lib/beaker/test_case.rb

Overview

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 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 DSL for more information about writing tests using the DSL.

Constant Summary collapse

TEST_EXCEPTION_CLASS =

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

::Minitest::Assertion

Instance Attribute Summary collapse

Attributes included from DSL::Assertions

#assertions

Instance Method Summary collapse

Methods included from DSL

register

Methods included from DSL::TestTagging

#tag

Methods included from DSL::Patterns

#block_on

Methods included from DSL::Helpers::HoconHelpers

#hocon_file_edit_in_place_on, #hocon_file_edit_on, #hocon_file_read_on

Methods included from DSL::Helpers::WebHelpers

#link_exists?, #port_open_within?

Methods included from DSL::Helpers::TestHelpers

#current_step_name, #current_test_filename, #current_test_name, #set_current_step_name, #set_current_test_filename, #set_current_test_name

Methods included from DSL::Helpers::HostHelpers

#add_system32_hosts_entry, #archive_file_from, #backup_the_file, #check_for_package, #create_remote_file, #curl_on, #curl_with_retries, #directory_exists_on, #echo_on, #execute_powershell_script_on, #file_contents_on, #file_exists_on, #install_package, #link_exists_on, #on, #retry_on, #rsync_to, #run_script, #run_script_on, #scp_from, #scp_to, #shell, #uninstall_package, #upgrade_package, #win_ads_path

Methods included from DSL::Wrappers

#encode_command, #powershell

Methods included from DSL::Assertions

#assert_output

Methods included from DSL::Structure

#confine, #confine_block, #expect_failure, #manual_step, #manual_test, #select_hosts, #step, #teardown, #test_name

Methods included from DSL::Outcomes

#export, #fail_test, #pass_test, #pending_test, #skip_test

Methods included from DSL::Roles

#add_role, #add_role_def, #agent_only, #agents, #aio_agent?, #aio_version?, #any_hosts_as?, #dashboard, #database, #default, #find_at_most_one, #find_host_with_role, #find_only_one, #hosts_as, #master, #not_controller

Constructor Details

#initialize(these_hosts, logger, options = {}, path = nil) ⇒ TestCase

Returns a new instance of TestCase.

Parameters:

  • these_hosts (Hosts, Array<Host>)

    The hosts to execute this test against/on.

  • logger (Logger)

    A logger that implements Logger‘s interface.

  • options (Hash{Symbol=>String}) (defaults to: {})

    Parsed command line options.

  • path (String) (defaults to: nil)

    The local path to a test file to be executed.



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# 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

Instance Attribute Details

#exceptionObject (readonly)

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



72
73
74
# File 'lib/beaker/test_case.rb', line 72

def exception
  @exception
end

#exportsObject

Necessary for DSL::Outcomes. Assumed to be an Array.



42
43
44
# File 'lib/beaker/test_case.rb', line 42

def exports
  @exports
end

#fail_flagObject (readonly)

I don’t know why this is here



62
63
64
# File 'lib/beaker/test_case.rb', line 62

def fail_flag
  @fail_flag
end

#hostsObject

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



30
31
32
# File 'lib/beaker/test_case.rb', line 30

def hosts
  @hosts
end

#last_resultObject

The result for the last command run



48
49
50
# File 'lib/beaker/test_case.rb', line 48

def last_result
  @last_result
end

#loggerObject

Necessary for many methods in DSL. Assumed to be an instance of Logger.



34
35
36
# File 'lib/beaker/test_case.rb', line 34

def logger
  @logger
end

#metadataObject

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



38
39
40
# File 'lib/beaker/test_case.rb', line 38

def 
  @metadata
end

#optionsObject (readonly)

Parsed command line options.



56
57
58
# File 'lib/beaker/test_case.rb', line 56

def options
  @options
end

#pathObject (readonly)

The path to the file which contains this test case.



59
60
61
# File 'lib/beaker/test_case.rb', line 59

def path
  @path
end

#runtimeObject (readonly)

The amount of time taken to execute the test



75
76
77
# File 'lib/beaker/test_case.rb', line 75

def runtime
  @runtime
end

#sublogObject

The full log for this test



45
46
47
# File 'lib/beaker/test_case.rb', line 45

def sublog
  @sublog
end

#teardown_procsObject (readonly)

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



79
80
81
# File 'lib/beaker/test_case.rb', line 79

def teardown_procs
  @teardown_procs
end

#test_statusObject (readonly)

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



69
70
71
# File 'lib/beaker/test_case.rb', line 69

def test_status
  @test_status
end

#usr_homeObject (readonly)

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



65
66
67
# File 'lib/beaker/test_case.rb', line 65

def usr_home
  @usr_home
end

#versionObject (readonly)

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.



53
54
55
# File 'lib/beaker/test_case.rb', line 53

def version
  @version
end

Instance Method Details

#to_hashHash

Note:

The visibility and semantics of this method are valid, but the structure of the Hash it returns may change without notice

The TestCase as a hash

Returns:

  • (Hash)

    A Hash representation of this test.



182
183
184
185
186
187
188
189
# 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