Class: Inferno::TestRunner

Inherits:
Object
  • Object
show all
Includes:
Utils::MarkdownFormatter
Defined in:
lib/inferno/test_runner.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Utils::MarkdownFormatter

#format_markdown

Constructor Details

#initialize(test_session:, test_run:, resume: false) ⇒ TestRunner

Returns a new instance of TestRunner.



10
11
12
13
14
# File 'lib/inferno/test_runner.rb', line 10

def initialize(test_session:, test_run:, resume: false)
  @test_session = test_session
  @test_run = test_run
  @resuming = resume
end

Instance Attribute Details

#resumingObject (readonly)

Returns the value of attribute resuming.



8
9
10
# File 'lib/inferno/test_runner.rb', line 8

def resuming
  @resuming
end

#test_runObject (readonly)

Returns the value of attribute test_run.



8
9
10
# File 'lib/inferno/test_runner.rb', line 8

def test_run
  @test_run
end

#test_sessionObject (readonly)

Returns the value of attribute test_session.



8
9
10
# File 'lib/inferno/test_runner.rb', line 8

def test_session
  @test_session
end

Instance Method Details

#check_inputs(test, _test_instance, inputs) ⇒ Object



117
118
119
120
121
122
123
124
125
# File 'lib/inferno/test_runner.rb', line 117

def check_inputs(test, _test_instance, inputs)
  inputs.each do |key, value|
    optional = test.config.input_optional?(key)
    if value.nil? && !optional
      raise Exceptions::SkipException,
            "Input '#{test.config.input_name(key)}' is nil, skipping test."
    end
  end
end

#existing_test_result(runnable) ⇒ Object



57
58
59
# File 'lib/inferno/test_runner.rb', line 57

def existing_test_result(runnable)
  results_repo.result_for_test_run(runnable.reference_hash.merge(test_run_id: test_run.id))
end

#inputs_as_json(runnable, input_values) ⇒ Object



194
195
196
197
198
199
200
201
202
203
# File 'lib/inferno/test_runner.rb', line 194

def inputs_as_json(runnable, input_values)
  inputs_array = runnable.inputs.map do |input_identifier|
    {
      name: runnable.config.input_name(input_identifier),
      value: input_values[input_identifier],
      type: runnable.config.input_type(input_identifier)
    }
  end
  JSON.generate(inputs_array)
end

#load_inputs(runnable) ⇒ Object



185
186
187
188
189
190
191
192
# File 'lib/inferno/test_runner.rb', line 185

def load_inputs(runnable)
  runnable.inputs.each_with_object({}) do |input_identifier, input_hash|
    input_alias = runnable.config.input_name(input_identifier)
    input_type = runnable.config.input_type(input_identifier)
    input_hash[input_identifier] =
      session_data_repo.load(test_session_id: test_session.id, name: input_alias, type: input_type)
  end
end

#persist_result(params) ⇒ Object



223
224
225
226
227
228
229
# File 'lib/inferno/test_runner.rb', line 223

def persist_result(params)
  result = results_repo.create(
    params.merge(test_run_id: test_run.id, test_session_id: test_session.id)
  )

  run_results[result.runnable.id] = result
end

#results_repoObject



20
21
22
# File 'lib/inferno/test_runner.rb', line 20

def results_repo
  @results_repo ||= Repositories::Results.new
end

#roll_up_result(results) ⇒ Object



231
232
233
# File 'lib/inferno/test_runner.rb', line 231

def roll_up_result(results)
  ResultSummarizer.new(results).summarize
end

#run(runnable, scratch = {}) ⇒ Object



47
48
49
50
51
52
53
54
55
# File 'lib/inferno/test_runner.rb', line 47

def run(runnable, scratch = {})
  if runnable < Entities::Test
    return existing_test_result(runnable) || run_test(runnable, scratch) if resuming

    run_test(runnable, scratch)
  else
    run_group(runnable, scratch)
  end
end

#run_group(group, scratch) ⇒ Object



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
# File 'lib/inferno/test_runner.rb', line 127

def run_group(group, scratch)
  group_inputs_with_values = group.available_inputs.map do |_input_identifier, input|
    {
      name: input.name,
      label: input.title,
      description: input.description,
      value: session_data_repo.load(test_session_id: test_session.id, name: input.name, type: input.type),
      type: input.type
    }
  end

  if group.children.empty?
    group_result = persist_result(group.reference_hash.merge(result: 'omit',
                                                             result_message: 'No tests defined',
                                                             input_json: JSON.generate(group_inputs_with_values),
                                                             output_json: '[]'))
    update_parent_result(group.parent)
    return group_result
  end

  results = []
  group.children(test_session.suite_options).each do |child|
    result = run(child, scratch)
    results << result
    break if results.last.waiting?
  end

  results.flatten!

  group_result = persist_result(group.reference_hash.merge(result: roll_up_result(results),
                                                           input_json: JSON.generate(group_inputs_with_values)))

  update_parent_result(group.parent)

  group_result
end

#run_resultsObject



16
17
18
# File 'lib/inferno/test_runner.rb', line 16

def run_results
  @run_results ||= {}
end

#run_test(test, scratch) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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
# File 'lib/inferno/test_runner.rb', line 61

def run_test(test, scratch)
  inputs = load_inputs(test)
  input_json_string = inputs_as_json(test, inputs)

  test_instance =
    test.new(
      inputs:,
      test_session_id: test_session.id,
      scratch:,
      suite_options: test_session.suite_options_hash
    )

  result = begin
    raise Exceptions::CancelException, 'Test cancelled by user' if test_run_is_cancelling

    check_inputs(test, test_instance, inputs)

    test_instance.load_named_requests
    test_instance.instance_eval(&test.block)
    'pass'
  rescue Exceptions::TestResultException => e
    test_instance.result_message = format_markdown(e.message)
    e.result
  rescue StandardError => e
    Application['logger'].error(e.full_message)
    test_instance.result_message = format_markdown("Error: #{e.message}\n\n#{e.backtrace.first}")
    'error'
  end

  outputs = save_outputs(test_instance)
  output_json_string = JSON.generate(outputs)

  if result == 'wait'
    test_runs_repo.mark_as_waiting(test_run.id, test_instance.identifier, test_instance.wait_timeout)
  end

  test_result = persist_result(
    {
      messages: test_instance.messages,
      requests: test_instance.requests,
      result:,
      result_message: test_instance.result_message,
      input_json: input_json_string,
      output_json: output_json_string
    }.merge(test.reference_hash)
  )

  # If running a single test, update its parents' results. If running a
  # group or suite, #run_group handles updating the parents.
  return test_result if test_run.test_id.blank?

  update_parent_result(test.parent)

  test_result
end

#save_outputs(runnable_instance) ⇒ Object



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/inferno/test_runner.rb', line 205

def save_outputs(runnable_instance)
  outputs =
    runnable_instance.outputs_to_persist.map do |output_identifier, value|
      output_name = runnable_instance.class.config.output_name(output_identifier)
      output_type = runnable_instance.class.config.output_type(output_identifier)
      {
        name: output_name,
        type: output_type,
        value: value.to_s
      }
    end

  outputs.compact!
  outputs.each do |output|
    session_data_repo.save(output.merge(test_session_id: test_session.id))
  end
end

#session_data_repoObject



28
29
30
# File 'lib/inferno/test_runner.rb', line 28

def session_data_repo
  @session_data_repo ||= Repositories::SessionData.new
end

#startObject



37
38
39
40
41
42
43
44
45
# File 'lib/inferno/test_runner.rb', line 37

def start
  test_runs_repo.mark_as_running(test_run.id) unless test_run.status == 'cancelling'

  run(test_run.runnable)

  test_runs_repo.mark_as_done(test_run.id) unless run_results.values.any?(&:waiting?)

  run_results.values
end

#test_run_is_cancellingObject



32
33
34
35
# File 'lib/inferno/test_runner.rb', line 32

def test_run_is_cancelling
  # forces db refetch of the test run status in case it is being cancelled
  test_runs_repo.status_for_test_run(test_run.id) == 'cancelling'
end

#test_runs_repoObject



24
25
26
# File 'lib/inferno/test_runner.rb', line 24

def test_runs_repo
  @test_runs_repo ||= Repositories::TestRuns.new
end

#update_parent_result(parent) ⇒ Object



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/inferno/test_runner.rb', line 164

def update_parent_result(parent)
  return if parent.nil?

  children = parent.children(test_session.suite_options)
  child_results = results_repo.current_results_for_test_session_and_runnables(test_session.id, children)
  required_children = children.select(&:required?)
  required_results = child_results.select(&:required?)
  return if required_children.length != required_results.length

  old_result = results_repo.current_result_for_test_session(test_session.id, parent.reference_hash)&.result
  new_result = roll_up_result(child_results)

  if new_result != old_result
    persist_result(parent.reference_hash.merge(result: new_result))

    update_parent_result(parent.parent)
  end

  new_result
end