Class: Inferno::DSL::SuiteEndpoint

Inherits:
Hanami::Action
  • Object
show all
Defined in:
lib/inferno/dsl/suite_endpoint.rb

Overview

A base class for creating endpoints to test client requests. This class is based on Hanami::Action, and may be used similarly to [a normal Hanami endpoint](github.com/hanami/controller/tree/v2.0.0).

class AuthorizedEndpoint < Inferno::DSL::SuiteEndpoint

# Identify the incoming request based on a bearer token
def test_run_identifier
  request.header['authorization']&.delete_prefix('Bearer ')
end

# Return a json FHIR Patient resource
def make_response
  response.status = 200
  response.body = FHIR::Patient.new(id: 'abcdef').to_json
  response.format = :json
end

# Update the waiting test to pass when the incoming request is received.
# This will resume the test run.
def update_result
  results_repo.update(result.id, result: 'pass')
end

# Apply the 'authorized' tag to the incoming request so that it may be
# used by later tests.
def tags
  ['authorized']
end

end

class AuthorizedRequestSuite < Inferno::TestSuite

id :authorized_suite
suite_endpoint :get, '/authorized_endpoint', AuthorizedEndpoint

group do
  title 'Authorized Request Group'

  test do
    title 'Wait for authorized request'

    input :bearer_token

    run do
      wait(
        identifier: bearer_token,
        message: "Waiting to receive a request with bearer_token: #{bearer_token}" \
                 "at `#{Inferno::Application['base_url']}/custom/authorized_suite/authorized_endpoint`"
      )
    end
  end
end

end

Instance Attribute Summary collapse

Overrides These methods should be overridden by subclasses to define the behavior of the endpoint collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config: self.class.config) ⇒ SuiteEndpoint

Returns a new instance of SuiteEndpoint.



159
160
161
# File 'lib/inferno/dsl/suite_endpoint.rb', line 159

def initialize(config: self.class.config) # rubocop:disable Lint/MissingSuper
  @config = config
end

Instance Attribute Details

#reqObject (readonly)

Returns the value of attribute req.



61
62
63
# File 'lib/inferno/dsl/suite_endpoint.rb', line 61

def req
  @req
end

#resObject (readonly)

Returns the value of attribute res.



61
62
63
# File 'lib/inferno/dsl/suite_endpoint.rb', line 61

def res
  @res
end

Class Method Details

.callObject



134
135
136
# File 'lib/inferno/dsl/suite_endpoint.rb', line 134

def self.call(...)
  new.call(...)
end

Instance Method Details

#add_persistence_callbackObject



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
# File 'lib/inferno/dsl/suite_endpoint.rb', line 277

def add_persistence_callback # rubocop:disable Metrics/CyclomaticComplexity
  logger = Application['logger']
  env = req.env
  env['rack.after_reply'] ||= []
  env['rack.after_reply'] << proc do
    repo = Inferno::Repositories::Requests.new

    uri = URI('http://example.com')
    uri.scheme = env['rack.url_scheme']
    uri.host = env['SERVER_NAME']
    uri.port = env['SERVER_PORT']
    uri.path = env['REQUEST_PATH'] || ''
    uri.query = env['rack.request.query_string'] if env['rack.request.query_string'].present?
    url = uri&.to_s
    verb = env['REQUEST_METHOD']
    request_body = env['rack.input']
    request_body.rewind if env['rack.input'].respond_to? :rewind
    request_body = request_body.instance_of?(Puma::NullIO) ? nil : request_body.string

    request_headers = ::Rack::Request.new(env).headers.to_h.map { |name, value| { name:, value: } }

    status, response_headers, response_body = env['inferno.response']

    response_headers = response_headers.map { |name, value| { name:, value: } }

    repo.create(
      verb:,
      url:,
      direction: 'incoming',
      name: env['inferno.name'],
      status:,
      request_body:,
      response_body: response_body.join,
      result_id: env['inferno.result_id'],
      test_session_id: env['inferno.test_session_id'],
      request_headers:,
      response_headers:,
      tags: env['inferno.tags']
    )

    if env['inferno.resume_test_run']
      test_run_id = env['inferno.test_run_id']
      Inferno::Repositories::TestRuns.new.mark_as_no_longer_waiting(test_run_id)

      Inferno::Jobs.perform(Jobs::ResumeTestRun, test_run_id)
    end
  rescue StandardError => e
    logger.error(e.full_message)
  end
end

#find_resultObject



227
228
229
# File 'lib/inferno/dsl/suite_endpoint.rb', line 227

def find_result
  results_repo.find_waiting_result(test_run_id: test_run.id)
end

#find_test_run_identifierObject



220
221
222
223
224
# File 'lib/inferno/dsl/suite_endpoint.rb', line 220

def find_test_run_identifier
  @test_run_identifier ||= test_run_identifier
rescue StandardError => e
  halt 500, "Unable to determine test run identifier:\n#{e.full_message}"
end

#handle(req, res) ⇒ Object



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# File 'lib/inferno/dsl/suite_endpoint.rb', line 260

def handle(req, res)
  @req = req
  @res = res
  test_run

  persist_request if persist_request?

  update_result

  resume if resume_test_run?

  make_response
rescue StandardError => e
  halt 500, e.full_message
end

#loggerLogger

Returns Inferno’s logger.

Returns:

  • (Logger)

    Inferno’s logger



215
216
217
# File 'lib/inferno/dsl/suite_endpoint.rb', line 215

def logger
  @logger ||= Application['logger']
end

#make_responseVoid

Override this method to build the response.

def make_response

response.status = 200
response.body = { abc: 123 }.to_json
response.format = :json

end

Returns:

  • (Void)


91
92
93
# File 'lib/inferno/dsl/suite_endpoint.rb', line 91

def make_response
  nil
end

#nameString

Override this method to assign a name to the request

Returns:

  • (String)


106
107
108
# File 'lib/inferno/dsl/suite_endpoint.rb', line 106

def name
  result&.runnable&.incoming_request_name
end

#persist_requestObject

The actual persisting happens in Inferno::Utils::Middleware::RequestRecorder, which allows the response to include response headers added by other parts of the rack stack rather than only the response headers explicitly added in the endpoint.



236
237
238
239
240
241
242
243
# File 'lib/inferno/dsl/suite_endpoint.rb', line 236

def persist_request
  req.env['inferno.test_session_id'] = test_run.test_session_id
  req.env['inferno.result_id'] = result.id
  req.env['inferno.tags'] = tags
  req.env['inferno.name'] = name if name.present?

  add_persistence_callback
end

#persist_request?Boolean

Override this method to specify whether this request should be persisted. Defaults to true.

Returns:

  • (Boolean)


127
128
129
# File 'lib/inferno/dsl/suite_endpoint.rb', line 127

def persist_request?
  true
end

#requestHanami::Action::Request

The incoming request as a ‘Hanami::Action::Request`

request.params # Get url/query params request.body.read # Get body request.headers # Get Accept header

Returns:

  • (Hanami::Action::Request)


171
172
173
# File 'lib/inferno/dsl/suite_endpoint.rb', line 171

def request
  req
end

#requests_repoInferno::Repositories::Requests



139
140
141
# File 'lib/inferno/dsl/suite_endpoint.rb', line 139

def requests_repo
  @requests_repo ||= Inferno::Repositories::Requests.new
end

#responseHanami::Action::Response

The response as a ‘Hanami::Action::Response`. Modify this to build the response to the incoming request.

response.status = 200 # Set the status response.body = ‘Ok’ # Set the body # Set headers response.headers.merge!(‘X-Custom-Header’ => ‘CUSTOM_HEADER_VALUE’)

Returns:

  • (Hanami::Action::Response)


185
186
187
# File 'lib/inferno/dsl/suite_endpoint.rb', line 185

def response
  res
end

#resultInferno::Entities::Result

The result which is waiting for incoming requests for the current test run



203
204
205
# File 'lib/inferno/dsl/suite_endpoint.rb', line 203

def result
  @result ||= find_result
end

#results_repoInferno::Repositories::Results



144
145
146
# File 'lib/inferno/dsl/suite_endpoint.rb', line 144

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

#resumeObject

Inferno::Utils::Middleware::RequestRecorder actually resumes the TestRun. If it were resumed here, it would be resuming prior to the Request being persisted.



254
255
256
257
# File 'lib/inferno/dsl/suite_endpoint.rb', line 254

def resume
  req.env['inferno.resume_test_run'] = true
  req.env['inferno.test_run_id'] = test_run.id
end

#resume_test_run?Boolean

Returns:

  • (Boolean)


246
247
248
# File 'lib/inferno/dsl/suite_endpoint.rb', line 246

def resume_test_run?
  find_result&.result != 'wait'
end

#tagsArray<String>

Override this method to define the tags which will be applied to the request.

Returns:

  • (Array<String>)


99
100
101
# File 'lib/inferno/dsl/suite_endpoint.rb', line 99

def tags
  @tags ||= []
end

#testInferno::Entities::Test

The test which is currently waiting for incoming requests



210
211
212
# File 'lib/inferno/dsl/suite_endpoint.rb', line 210

def test
  @test ||= tests_repo.find(result.test_id)
end

#test_runInferno::Entities::TestRun

The test run which is waiting for incoming requests



192
193
194
195
196
197
# File 'lib/inferno/dsl/suite_endpoint.rb', line 192

def test_run
  @test_run ||=
    test_runs_repo.find_latest_waiting_by_identifier(find_test_run_identifier).tap do |test_run|
      halt 500, "Unable to find test run with identifier '#{test_run_identifier}'." if test_run.nil?
    end
end

#test_run_identifierString

Override this method to determine a test run’s identifier based on an incoming request.

def test_run_identifier

# Identify the test session of an incoming request based on the bearer
# token
request.headers['authorization']&.delete_prefix('Bearer ')

end

Returns:

  • (String)


77
78
79
# File 'lib/inferno/dsl/suite_endpoint.rb', line 77

def test_run_identifier
  nil
end

#test_runs_repoInferno::Repositories::TestRuns



149
150
151
# File 'lib/inferno/dsl/suite_endpoint.rb', line 149

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

#tests_repoInferno::Repositories::Tests



154
155
156
# File 'lib/inferno/dsl/suite_endpoint.rb', line 154

def tests_repo
  @tests_repo ||= Inferno::Repositories::Tests.new
end

#update_resultVoid

Override this method to update the current waiting result. To resume the test run, set the result to something other than ‘waiting’.

def update_result

results_repo.update(result.id, result: 'pass')

end

Returns:

  • (Void)


119
120
121
# File 'lib/inferno/dsl/suite_endpoint.rb', line 119

def update_result
  nil
end