inferno_core 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9b643b7c720a9c79df5f329a9947110971076db80fe29f0b57928230cf348d1b
4
- data.tar.gz: e03d93994e7ad33e6e131969af5e31449390d36670d256a7d4bf43c1a9f80e4d
3
+ metadata.gz: 40769c54fd3854730eb080d1bb9e0755ff1551b00761968155d463dd3a6ce3e0
4
+ data.tar.gz: 8bbf5aaa2b09d7d5ff54e56a3ed33ce4e1f4df29fc53e3737f18e9972dc34f1e
5
5
  SHA512:
6
- metadata.gz: 4767e5dfd7f469a6eb70892fb9e5402f2a46708655810b91be0b3d1d9d1dfa839c3502678156f763f5e9a7999948a31013fb68e3a1d1605306d5297639f3b3c3
7
- data.tar.gz: 3adbce3ebb0786095826a114e4c6bc6a3ced2f9e560e2eaa6f6e6f6784bbf44c10ef25734f67bb097ee384b4cd6ab3296dc156e2c14cd5085bc64cb4fb27f575
6
+ metadata.gz: 35fe2518d3856f01b3358da68d862318784f05ab067b579d3ac62053dc1deed2be2895e3cfb5ff8efbc97e71d2495a11ebf66eadf23c5b8b4edb502707334838
7
+ data.tar.gz: 04e37af9daf40c01f0d4182f055e4ddf187d72f0e9d8a43e8858af5c549a4a60900d71f034a8e027e20f53a56f6b5e835bce1fca3a0b98870b07e0681793a2d9
@@ -5,7 +5,8 @@ module Inferno
5
5
  class Create < Controller
6
6
  include Import[
7
7
  test_sessions_repo: 'repositories.test_sessions',
8
- session_data_repo: 'repositories.session_data'
8
+ session_data_repo: 'repositories.session_data',
9
+ test_runs_repo: 'repositories.test_runs'
9
10
  ]
10
11
 
11
12
  PARAMS = [:test_session_id, :test_suite_id, :test_group_id, :test_id].freeze
@@ -14,8 +15,18 @@ module Inferno
14
15
  test_session = test_sessions_repo.find(params[:test_session_id])
15
16
 
16
17
  # if testsession.nil?
18
+ if test_runs_repo.active_test_run_for_session?(test_session.id)
19
+ self.status = 409
20
+ self.body = { error: 'Cannot run new test while another test run is in progress' }.to_json
21
+ return
22
+ end
17
23
 
18
24
  test_run = repo.create(create_params(params).merge(status: 'queued'))
25
+ missing_inputs = test_run.runnable.missing_inputs(params[:inputs])
26
+
27
+ raise Inferno::Exceptions::RequiredInputsNotFound, missing_inputs if missing_inputs.any?
28
+ raise Inferno::Exceptions::NotUserRunnableException unless test_run.runnable.user_runnable?
29
+
19
30
  self.body = serialize(test_run)
20
31
 
21
32
  params[:inputs]&.each do |input|
@@ -27,7 +38,9 @@ module Inferno
27
38
  end
28
39
 
29
40
  Jobs.perform(Jobs::ExecuteTestRun, test_run.id)
30
- rescue Sequel::ValidationFailed, Sequel::ForeignKeyConstraintViolation => e
41
+ rescue Sequel::ValidationFailed, Sequel::ForeignKeyConstraintViolation,
42
+ Inferno::Exceptions::RequiredInputsNotFound,
43
+ Inferno::Exceptions::NotUserRunnableException => e
31
44
  self.body = { errors: e.message }.to_json
32
45
  self.status = 422
33
46
  rescue StandardError => e
@@ -0,0 +1,11 @@
1
+ module Inferno
2
+ module Web
3
+ module Serializers
4
+ class HashValueExtractor < Blueprinter::Extractor
5
+ def extract(field_name, object, _local_options, _options)
6
+ object.send(field_name).values
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -4,11 +4,10 @@ module Inferno
4
4
  class Test < Serializer
5
5
  identifier :id
6
6
  field :title
7
- field :inputs
8
- field :outputs do |test, _options|
9
- test.outputs.map { |output| { name: output } }
10
- end
7
+ field :input_definitions, name: :inputs, extractor: HashValueExtractor, blueprint: Input
8
+ field :output_definitions, name: :outputs, extractor: HashValueExtractor
11
9
  field :description
10
+ field :user_runnable?, name: :user_runnable
12
11
  end
13
12
  end
14
13
  end
@@ -4,18 +4,16 @@ module Inferno
4
4
  class TestGroup < Serializer
5
5
  identifier :id
6
6
 
7
- # TODO: fill out test group
8
7
  field :title
9
8
  field :description
10
9
  field :test_count
11
- # field :run_as_group
10
+ field :run_as_group?, name: :run_as_group
11
+ field :user_runnable?, name: :user_runnable
12
12
 
13
13
  association :groups, name: :test_groups, blueprint: TestGroup
14
14
  association :tests, blueprint: Test
15
- field :inputs
16
- field :outputs do |group, _options|
17
- group.outputs.map { |input| { name: input } }
18
- end
15
+ field :input_definitions, name: :inputs, extractor: HashValueExtractor, blueprint: Input
16
+ field :output_definitions, name: :outputs, extractor: HashValueExtractor
19
17
  end
20
18
  end
21
19
  end
@@ -9,6 +9,7 @@ module Inferno
9
9
 
10
10
  Application.register('js_host', ENV.fetch('JS_HOST', ''))
11
11
  Application.register('async_jobs', ENV['ASYNC_JOBS'] != 'false')
12
+ Application.register('inferno_host', ENV.fetch('INFERNO_HOST', 'http://localhost:4567'))
12
13
 
13
14
  configure do |config|
14
15
  config.root = File.expand_path('../../..', __dir__)
@@ -4,12 +4,10 @@ Inferno::Application.boot(:suites) do
4
4
 
5
5
  files_to_load = Dir.glob(File.join(Dir.pwd, 'lib', '*.rb'))
6
6
 
7
- if ENV['LOAD_DEV_SUITES'] == 'true'
8
- files_to_load.concat Dir.glob(File.join(Inferno::Application.root, 'dev_suites', '**', '*.rb'))
9
- end
10
-
11
- if ENV['LOAD_UI_SUITES'] == 'true'
12
- files_to_load.concat Dir.glob(File.join(Inferno::Application.root, 'ui_suites', '**', '*.rb'))
7
+ if ENV['LOAD_DEV_SUITES'].present?
8
+ ENV['LOAD_DEV_SUITES'].split(',').map(&:strip).reject(&:empty?).each do |suite|
9
+ files_to_load.concat Dir.glob(File.join(Inferno::Application.root, 'dev_suites', suite, '**', '*.rb'))
10
+ end
13
11
  end
14
12
 
15
13
  if ENV['APP_ENV'] == 'test'
@@ -88,6 +88,26 @@ module Inferno
88
88
  rescue JSON::ParserError
89
89
  assert false, "Invalid JSON. #{message}"
90
90
  end
91
+
92
+ def assert_valid_http_uri(uri, message = '')
93
+ error_message = message || "\"#{uri}\" is not a valid URI"
94
+ assert uri =~ /\A#{URI::DEFAULT_PARSER.make_regexp(['http', 'https'])}\z/, error_message
95
+ end
96
+
97
+ def assert_response_content_type(type, request: self.request)
98
+ header = request.response_header('Content-Type')
99
+ assert header.present?, no_content_type_message
100
+
101
+ assert header.value.start_with?(type), bad_content_type_message(type, header.value)
102
+ end
103
+
104
+ def no_content_type_message
105
+ 'Response did not contain a `Content-Type` header.'
106
+ end
107
+
108
+ def bad_content_type_message(expected, received)
109
+ "Expected `Content-Type` to be `#{expected}`, but found `#{received}`"
110
+ end
91
111
  end
92
112
  end
93
113
  end
@@ -0,0 +1,126 @@
1
+ module Inferno
2
+ module DSL
3
+ # This module contains the DSL for managing runnable configuration.
4
+ module Configurable
5
+ def self.extended(klass)
6
+ klass.extend Forwardable
7
+ klass.def_delegator 'self.class', :config
8
+ end
9
+
10
+ def config(new_configuration = {})
11
+ @config ||= Configuration.new
12
+
13
+ return @config if new_configuration.blank?
14
+
15
+ @config.apply(new_configuration)
16
+ end
17
+
18
+ # @api private
19
+ class Configuration
20
+ attr_accessor :configuration
21
+
22
+ def initialize(configuration = {})
23
+ self.configuration = configuration
24
+ end
25
+
26
+ def apply(new_configuration)
27
+ config_to_apply =
28
+ if new_configuration.is_a? Configuration
29
+ new_configuration.configuration
30
+ else
31
+ new_configuration
32
+ end
33
+
34
+ self.configuration = configuration.deep_merge(config_to_apply)
35
+ end
36
+
37
+ def options
38
+ configuration[:options] ||= {}
39
+ end
40
+
41
+ ### Input Configuration ###
42
+
43
+ def inputs
44
+ configuration[:inputs] ||= {}
45
+ end
46
+
47
+ def add_input(identifier, new_config = {})
48
+ existing_config = input_config(identifier) || {}
49
+ inputs[identifier] = default_input_config(identifier).merge(existing_config, new_config)
50
+ end
51
+
52
+ def default_input_config(identifier)
53
+ { name: identifier, type: 'text' }
54
+ end
55
+
56
+ def input_config_exists?(identifier)
57
+ inputs.key? identifier
58
+ end
59
+
60
+ def input_config(identifier)
61
+ inputs[identifier]
62
+ end
63
+
64
+ def input_name(identifier)
65
+ inputs.dig(identifier, :name) || identifier
66
+ end
67
+
68
+ ### Output Configuration ###
69
+
70
+ def outputs
71
+ configuration[:outputs] ||= {}
72
+ end
73
+
74
+ def add_output(identifier)
75
+ return if output_config_exists?(identifier)
76
+
77
+ outputs[identifier] = default_output_config(identifier)
78
+ end
79
+
80
+ def default_output_config(identifier)
81
+ { name: identifier }
82
+ end
83
+
84
+ def output_config_exists?(identifier)
85
+ outputs.key? identifier
86
+ end
87
+
88
+ def output_config(identifier)
89
+ outputs[identifier]
90
+ end
91
+
92
+ def output_name(identifier)
93
+ outputs.dig(identifier, :name) || identifier
94
+ end
95
+
96
+ ### Request Configuration ###
97
+
98
+ def requests
99
+ configuration[:requests] ||= {}
100
+ end
101
+
102
+ def add_request(identifier)
103
+ return if request_config_exists?(identifier)
104
+
105
+ requests[identifier] = default_request_config(identifier)
106
+ end
107
+
108
+ def default_request_config(identifier)
109
+ { name: identifier }
110
+ end
111
+
112
+ def request_config_exists?(identifier)
113
+ requests.key? identifier
114
+ end
115
+
116
+ def request_config(identifier)
117
+ requests[identifier]
118
+ end
119
+
120
+ def request_name(identifier)
121
+ requests.dig(identifier, :name) || identifier
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -69,12 +69,14 @@ module Inferno
69
69
  # @param client [Symbol]
70
70
  # @param name [Symbol] Name for this request to allow it to be used by
71
71
  # other tests
72
- # @param _options [Hash] TODO
72
+ # @option options [Hash] Input headers here - headers are optional and
73
+ # must be entered as the last piece of input to this method
73
74
  # @return [Inferno::Entities::Request]
74
- def fhir_operation(path, body: nil, client: :default, name: nil, **_options)
75
+ def fhir_operation(path, body: nil, client: :default, name: nil, **options)
75
76
  store_request('outgoing', name) do
76
77
  headers = fhir_client(client).fhir_headers
77
78
  headers.merge!('Content-Type' => 'application/fhir+json') if body.present?
79
+ headers.merge!(options[:headers]) if options[:headers].present?
78
80
  fhir_client(client).send(:post, path, body, headers)
79
81
  end
80
82
  end
@@ -60,16 +60,17 @@ module Inferno
60
60
  # @param client [Symbol]
61
61
  # @param name [Symbol] Name for this request to allow it to be used by
62
62
  # other tests
63
- # @param _options [Hash] TODO
63
+ # @option options [Hash] Input headers here - headers are optional and
64
+ # must be entered as the last piece of input to this method
64
65
  # @return [Inferno::Entities::Request]
65
- def get(url = '', client: :default, name: nil, **_options)
66
+ def get(url = '', client: :default, name: nil, **options)
66
67
  store_request('outgoing', name) do
67
68
  client = http_client(client)
68
69
 
69
70
  if client
70
- client.get(url)
71
+ client.get(url, nil, options[:headers])
71
72
  elsif url.match?(%r{\Ahttps?://})
72
- Faraday.get(url)
73
+ Faraday.get(url, nil, options[:headers])
73
74
  else
74
75
  raise StandardError, 'Must use an absolute url or define an HTTP client with a base url'
75
76
  end
@@ -85,16 +86,17 @@ module Inferno
85
86
  # @param client [Symbol]
86
87
  # @param name [Symbol] Name for this request to allow it to be used by
87
88
  # other tests
88
- # @param _options [Hash] TODO
89
+ # @option options [Hash] Input headers here - headers are optional and
90
+ # must be entered as the last piece of input to this method
89
91
  # @return [Inferno::Entities::Request]
90
- def post(url = '', body: nil, client: :default, name: nil, **_options)
92
+ def post(url = '', body: nil, client: :default, name: nil, **options)
91
93
  store_request('outgoing', name) do
92
94
  client = http_client(client)
93
95
 
94
96
  if client
95
- client.post(url, body)
97
+ client.post(url, body, options[:headers])
96
98
  elsif url.match?(%r{\Ahttps?://})
97
- Faraday.post(url, body)
99
+ Faraday.post(url, body, options[:headers])
98
100
  else
99
101
  raise StandardError, 'Must use an absolute url or define an HTTP client with a base url'
100
102
  end
@@ -38,13 +38,14 @@ module Inferno
38
38
 
39
39
  # TODO: do a check in the test runner
40
40
  def named_request(name)
41
- requests.find { |request| request.name == name.to_sym }
41
+ requests.find { |request| request.name == self.class.config.request_name(name.to_sym) }
42
42
  end
43
43
 
44
44
  # @api private
45
45
  def store_request(direction, name = nil, &block)
46
46
  response = block.call
47
47
 
48
+ name = self.class.config.request_name(name)
48
49
  request =
49
50
  if response.is_a? FHIR::ClientReply
50
51
  Entities::Request.from_fhir_client_reply(
@@ -64,8 +65,9 @@ module Inferno
64
65
  def load_named_requests
65
66
  requests_repo = Inferno::Repositories::Requests.new
66
67
  self.class.named_requests_used.map do |request_name|
67
- request = requests_repo.find_named_request(test_session_id, request_name)
68
- raise StandardError, "Unable to find '#{request_name}' request" if request.nil?
68
+ request_alias = self.class.config.request_name(request_name)
69
+ request = requests_repo.find_named_request(test_session_id, request_alias)
70
+ raise StandardError, "Unable to find '#{request_alias}' request" if request.nil?
69
71
 
70
72
  requests << request
71
73
  end
@@ -84,16 +86,20 @@ module Inferno
84
86
 
85
87
  # Specify the named requests made by a test
86
88
  #
87
- # @param *names [Symbol] one or more Symbols
88
- def makes_request(*names)
89
- named_requests_made.concat(names)
89
+ # @param *identifiers [Symbol] one or more Symbols
90
+ def makes_request(*identifiers)
91
+ named_requests_made.concat(identifiers).uniq!
92
+ identifiers.each do |identifier|
93
+ config.add_request(identifier)
94
+ end
90
95
  end
91
96
 
92
97
  # Specify the name for a request received by a test
93
98
  #
94
- # @param *names [Symbol] one or more Symbols
95
- def receives_request(name)
96
- @incoming_request_name = name
99
+ # @param *identifiers [Symbol] one or more Symbols
100
+ def receives_request(identifier)
101
+ config.add_request(identifier)
102
+ @incoming_request_name = identifier
97
103
  end
98
104
 
99
105
  # @api private
@@ -103,9 +109,12 @@ module Inferno
103
109
 
104
110
  # Specify the named requests used by a test
105
111
  #
106
- # @param *names [Symbol] one or more Symbols
107
- def uses_request(*names)
108
- named_requests_used.concat(names)
112
+ # @param *identifiers [Symbol] one or more Symbols
113
+ def uses_request(*identifiers)
114
+ named_requests_used.concat(identifiers).uniq!
115
+ identifiers.each do |identifier|
116
+ config.add_request(identifier)
117
+ end
109
118
  end
110
119
  end
111
120
  end
@@ -48,7 +48,7 @@ module Inferno
48
48
  request.to_hash.merge(
49
49
  test_session_id: test_run.test_session_id,
50
50
  result_id: waiting_result.id,
51
- name: test.incoming_request_name
51
+ name: test.config.request_name(test.incoming_request_name)
52
52
  )
53
53
  )
54
54
  end
@@ -1,4 +1,6 @@
1
+ require_relative 'configurable'
1
2
  require_relative 'resume_test_route'
3
+ require_relative '../utils/markdown_formatter'
2
4
 
3
5
  module Inferno
4
6
  module DSL
@@ -7,6 +9,8 @@ module Inferno
7
9
  module Runnable
8
10
  attr_accessor :parent
9
11
 
12
+ include Inferno::Utils::MarkdownFormatter
13
+
10
14
  # When a class (e.g. TestSuite/TestGroup) uses this module, set it up
11
15
  # so that subclassing it works correctly.
12
16
  # - add the subclass to the relevant repository when it is created
@@ -15,6 +19,7 @@ module Inferno
15
19
  # @api private
16
20
  def self.extended(extending_class)
17
21
  super
22
+ extending_class.extend Configurable
18
23
 
19
24
  extending_class.define_singleton_method(:inherited) do |subclass|
20
25
  copy_instance_variables(subclass)
@@ -39,11 +44,13 @@ module Inferno
39
44
  # @api private
40
45
  def copy_instance_variables(subclass)
41
46
  instance_variables.each do |variable|
42
- next if [:@id, :@groups, :@tests, :@parent, :@children, :@test_count].include?(variable)
47
+ next if [:@id, :@groups, :@tests, :@parent, :@children, :@test_count, :@config].include?(variable)
43
48
 
44
49
  subclass.instance_variable_set(variable, instance_variable_get(variable).dup)
45
50
  end
46
51
 
52
+ subclass.config(config)
53
+
47
54
  child_types.each do |child_type|
48
55
  new_children = send(child_type).map do |child|
49
56
  Class.new(child).tap do |subclass_child|
@@ -126,16 +133,16 @@ module Inferno
126
133
 
127
134
  # @api private
128
135
  def configure_child_class(klass, hash_args) # rubocop:disable Metrics/CyclomaticComplexity
129
- inputs.each do |input_definition|
130
- next if klass.inputs.any? { |input| input[:name] == input_definition[:name] }
136
+ inputs.each do |name|
137
+ next if klass.inputs.any? { |klass_input_name| klass_input_name == name }
131
138
 
132
- klass.input input_definition[:name], input_definition
139
+ klass.input name
133
140
  end
134
141
 
135
- outputs.each do |output_definition|
136
- next if klass.outputs.include? output_definition
142
+ outputs.each do |output_name|
143
+ next if klass.outputs.include? output_name
137
144
 
138
- klass.output output_definition
145
+ klass.output output_name
139
146
  end
140
147
 
141
148
  new_fhir_client_definitions = klass.instance_variable_get(:@fhir_client_definitions) || {}
@@ -154,8 +161,14 @@ module Inferno
154
161
  end
155
162
  klass.instance_variable_set(:@http_client_definitions, new_http_client_definitions)
156
163
 
164
+ klass.config(config)
165
+
157
166
  hash_args.each do |key, value|
158
- klass.send(key, *value)
167
+ if value.is_a? Array
168
+ klass.send(key, *value)
169
+ else
170
+ klass.send(key, value)
171
+ end
159
172
  end
160
173
 
161
174
  klass.children.each do |child_class|
@@ -193,43 +206,48 @@ module Inferno
193
206
  def description(new_description = nil)
194
207
  return @description if new_description.nil?
195
208
 
196
- @description = new_description
209
+ @description = format_markdown(new_description)
197
210
  end
198
211
 
199
212
  # Define inputs
200
213
  #
201
- # @param name [Symbol] name of the input
202
- # @param other_names [Symbol] array of symbols if specifying multiple inputs
214
+ # @param identifier [Symbol] identifier for the input
215
+ # @param other_identifiers [Symbol] array of symbols if specifying multiple inputs
203
216
  # @param input_definition [Hash] options for input such as type, description, or title
204
217
  # @option input_definition [String] :title Human readable title for input
205
218
  # @option input_definition [String] :description Description for the input
206
219
  # @option input_definition [String] :type text | textarea
207
220
  # @option input_definition [String] :default The default value for the input
221
+ # @option input_definition [Boolean] :optional Set to true to not require input for test execution
208
222
  # @return [void]
209
223
  # @example
210
224
  # input :patientid, title: 'Patient ID', description: 'The ID of the patient being searched for',
211
225
  # default: 'default_patient_id'
212
226
  # @example
213
- # input :textarea, title: 'Textarea Input Example', type: 'textarea'
214
- def input(name, *other_names, **input_definition)
215
- if other_names.present?
216
- [name, *other_names].each do |input_name|
217
- inputs.push({ name: input_name, title: nil, description: nil, type: 'text' })
227
+ # input :textarea, title: 'Textarea Input Example', type: 'textarea', optional: true
228
+ def input(identifier, *other_identifiers, **input_definition)
229
+ if other_identifiers.present?
230
+ [identifier, *other_identifiers].compact.each do |input_identifier|
231
+ inputs << input_identifier
232
+ config.add_input(input_identifier)
218
233
  end
219
234
  else
220
- input_definition[:type] = 'text' unless input_definition.key? :type
221
- inputs.push({ name: name }.merge(input_definition))
235
+ inputs << identifier
236
+ config.add_input(identifier, input_definition)
222
237
  end
223
238
  end
224
239
 
225
240
  # Define outputs
226
241
  #
227
- # @param output_definitions [Symbol]
242
+ # @param output_lists [Symbol]
228
243
  # @return [void]
229
244
  # @example
230
245
  # output :patient_id, :bearer_token
231
- def output(*output_definitions)
232
- outputs.concat(output_definitions)
246
+ def output(*output_list)
247
+ output_list.each do |output_identifier|
248
+ outputs << output_identifier
249
+ config.add_output(output_identifier)
250
+ end
233
251
  end
234
252
 
235
253
  # @api private
@@ -242,6 +260,14 @@ module Inferno
242
260
  @inputs ||= []
243
261
  end
244
262
 
263
+ def input_definitions
264
+ config.inputs.slice(*inputs)
265
+ end
266
+
267
+ def output_definitions
268
+ config.outputs.slice(*outputs)
269
+ end
270
+
245
271
  # @api private
246
272
  def outputs
247
273
  @outputs ||= []
@@ -334,6 +360,28 @@ module Inferno
334
360
  def test_count
335
361
  @test_count ||= children&.reduce(0) { |sum, child| sum + child.test_count } || 0
336
362
  end
363
+
364
+ def required_inputs(prior_outputs = [])
365
+ required_inputs = inputs.select do |input|
366
+ !input_definitions[input][:optional] && !prior_outputs.include?(input)
367
+ end
368
+ required_inputs.map! { |input_identifier| input_definitions[input_identifier][:name] }
369
+ children_required_inputs = children.flat_map { |child| child.required_inputs(prior_outputs) }
370
+ prior_outputs.concat(outputs)
371
+ (required_inputs + children_required_inputs).flatten.uniq
372
+ end
373
+
374
+ def missing_inputs(submitted_inputs)
375
+ submitted_inputs = [] if submitted_inputs.nil?
376
+
377
+ required_inputs.map(&:to_s) - submitted_inputs.map { |input| input[:name] }
378
+ end
379
+
380
+ def user_runnable?
381
+ @user_runnable ||= parent.nil? ||
382
+ !parent.respond_to?(:run_as_group?) ||
383
+ (parent.user_runnable? && !parent.run_as_group?)
384
+ end
337
385
  end
338
386
  end
339
387
  end
@@ -46,7 +46,7 @@ module Inferno
46
46
  # @param name [String] the header name
47
47
  # @return [Inferno::Entities::RequestHeader, nil]
48
48
  def response_header(name)
49
- response_headers.find { |header| header.name == name.downcase }
49
+ response_headers.find { |header| header.name.casecmp(name).zero? }
50
50
  end
51
51
 
52
52
  # Find a request header
@@ -54,7 +54,7 @@ module Inferno
54
54
  # @param name [String] the header name
55
55
  # @return [Inferno::Entities::RequestHeader, nil]
56
56
  def request_header(name)
57
- request_headers.find { |header| header.name == name.downcase }
57
+ request_headers.find { |header| header.name.casecmp(name).zero? }
58
58
  end
59
59
 
60
60
  # All of the request headers