inferno_core 0.0.5 → 0.0.8.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/bin/inferno +7 -0
  3. data/lib/inferno/apps/cli/console.rb +12 -0
  4. data/lib/inferno/apps/cli/main.rb +18 -0
  5. data/lib/inferno/apps/cli/migration.rb +14 -0
  6. data/lib/inferno/apps/cli.rb +8 -0
  7. data/lib/inferno/apps/web/controllers/test_runs/create.rb +15 -2
  8. data/lib/inferno/apps/web/index.html.erb +1 -0
  9. data/lib/inferno/apps/web/serializers/hash_value_extractor.rb +11 -0
  10. data/lib/inferno/apps/web/serializers/test.rb +3 -4
  11. data/lib/inferno/apps/web/serializers/test_group.rb +4 -6
  12. data/lib/inferno/config/application.rb +4 -0
  13. data/lib/inferno/config/boot/db.rb +1 -9
  14. data/lib/inferno/config/boot/logging.rb +2 -0
  15. data/lib/inferno/config/boot/suites.rb +4 -6
  16. data/lib/inferno/db/migrations/001_create_initial_structure.rb +1 -1
  17. data/lib/inferno/db/schema.rb +1 -1
  18. data/lib/inferno/dsl/assertions.rb +85 -0
  19. data/lib/inferno/dsl/configurable.rb +126 -0
  20. data/lib/inferno/dsl/fhir_client.rb +22 -16
  21. data/lib/inferno/dsl/fhir_client_builder.rb +3 -3
  22. data/lib/inferno/dsl/fhir_validation.rb +105 -1
  23. data/lib/inferno/dsl/http_client.rb +14 -12
  24. data/lib/inferno/dsl/http_client_builder.rb +3 -3
  25. data/lib/inferno/dsl/request_storage.rb +26 -17
  26. data/lib/inferno/dsl/results.rb +1 -1
  27. data/lib/inferno/dsl/resume_test_route.rb +10 -10
  28. data/lib/inferno/dsl/runnable.rb +104 -38
  29. data/lib/inferno/entities/header.rb +14 -7
  30. data/lib/inferno/entities/message.rb +16 -8
  31. data/lib/inferno/entities/request.rb +34 -21
  32. data/lib/inferno/entities/result.rb +36 -29
  33. data/lib/inferno/entities/session_data.rb +12 -6
  34. data/lib/inferno/entities/test.rb +29 -2
  35. data/lib/inferno/entities/test_group.rb +8 -0
  36. data/lib/inferno/entities/test_run.rb +29 -6
  37. data/lib/inferno/entities/test_session.rb +16 -10
  38. data/lib/inferno/exceptions.rb +12 -0
  39. data/lib/inferno/public/217.bundle.js +1 -1
  40. data/lib/inferno/public/bundle.js +154 -1
  41. data/lib/inferno/public/bundle.js.LICENSE.txt +15 -0
  42. data/lib/inferno/repositories/in_memory_repository.rb +1 -1
  43. data/lib/inferno/repositories/results.rb +1 -1
  44. data/lib/inferno/repositories/test_runs.rb +15 -0
  45. data/lib/inferno/spec_support.rb +1 -1
  46. data/lib/inferno/test_runner.rb +21 -19
  47. data/lib/inferno/utils/markdown_formatter.rb +15 -0
  48. data/lib/inferno/utils/middleware/request_logger.rb +9 -3
  49. data/lib/inferno/utils/migration.rb +17 -0
  50. data/lib/inferno/version.rb +1 -1
  51. data/lib/inferno.rb +0 -4
  52. data/spec/factories/request.rb +14 -7
  53. metadata +46 -10
  54. data/bin/inferno-console +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9b643b7c720a9c79df5f329a9947110971076db80fe29f0b57928230cf348d1b
4
- data.tar.gz: e03d93994e7ad33e6e131969af5e31449390d36670d256a7d4bf43c1a9f80e4d
3
+ metadata.gz: 323de6e32c25feac594840493d69222a2388bdabef39c36a5d378a1cfeb2b7cc
4
+ data.tar.gz: d08c713be3303b146a40a6316765e017d76a4213e3981c6121fd502e7eb4e577
5
5
  SHA512:
6
- metadata.gz: 4767e5dfd7f469a6eb70892fb9e5402f2a46708655810b91be0b3d1d9d1dfa839c3502678156f763f5e9a7999948a31013fb68e3a1d1605306d5297639f3b3c3
7
- data.tar.gz: 3adbce3ebb0786095826a114e4c6bc6a3ced2f9e560e2eaa6f6e6f6784bbf44c10ef25734f67bb097ee384b4cd6ab3296dc156e2c14cd5085bc64cb4fb27f575
6
+ metadata.gz: 1dfa395166fd30624510ff16f12a216b5580f60265bf8512391fd50d731c9bf7022aec60fa0527aa55e7de48d7fc38c16bb2b4777666c7947c632f6ce4dc2c6a
7
+ data.tar.gz: 207262300f159a2eb75bca71f95c8550169dc19488e826d4a2e97556d3c9722ce9bdf97436c9f862cddde5ab62b9d2be4895703c02da5c8eac6cf24cdb4e4475
data/bin/inferno ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pry'
4
+ require_relative '../lib/inferno/config/application'
5
+ require_relative '../lib/inferno/apps/cli'
6
+
7
+ Inferno::CLI::Main.start
@@ -0,0 +1,12 @@
1
+ module Inferno
2
+ module CLI
3
+ class Console
4
+ def run
5
+ require_relative '../../../inferno'
6
+
7
+ Inferno::Application.finalize!
8
+ Pry.start
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'console'
2
+ require_relative 'migration'
3
+
4
+ module Inferno
5
+ module CLI
6
+ class Main < Thor
7
+ desc 'console', 'Start an interactive console session with Inferno'
8
+ def console
9
+ Console.new.run
10
+ end
11
+
12
+ desc 'migrate', 'Run database migrations'
13
+ def migrate
14
+ Migration.new.run
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ require_relative '../../utils/migration'
2
+
3
+ module Inferno
4
+ module CLI
5
+ class Migration
6
+ def run
7
+ Inferno::Application.start(:logging)
8
+ Inferno::Application['logger'].level = Logger::DEBUG
9
+
10
+ Utils::Migration.new.run
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ require 'thor'
2
+
3
+ require_relative 'cli/main'
4
+
5
+ module Inferno
6
+ module CLI
7
+ end
8
+ end
@@ -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
@@ -1,6 +1,7 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
+ <base href="/">
4
5
  <meta charset="utf-8" />
5
6
  <link rel="icon" href="/public/favicon.ico" />
6
7
  <meta name="viewport" content="width=device-width, initial-scale=1" />
@@ -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
@@ -1,4 +1,7 @@
1
+ require 'active_support/all'
2
+ require 'dotenv'
1
3
  require 'dry/system/container'
4
+ require 'sequel'
2
5
  require_relative 'boot'
3
6
 
4
7
  module Inferno
@@ -9,6 +12,7 @@ module Inferno
9
12
 
10
13
  Application.register('js_host', ENV.fetch('JS_HOST', ''))
11
14
  Application.register('async_jobs', ENV['ASYNC_JOBS'] != 'false')
15
+ Application.register('inferno_host', ENV.fetch('INFERNO_HOST', 'http://localhost:4567'))
12
16
 
13
17
  configure do |config|
14
18
  config.root = File.expand_path('../../..', __dir__)
@@ -12,6 +12,7 @@ Inferno::Application.boot(:db) do
12
12
  config = YAML.load_file(config_path)[ENV['APP_ENV']]
13
13
  .merge(logger: Inferno::Application['logger'])
14
14
  connection = Sequel.connect(config)
15
+ connection.sql_log_level = :debug
15
16
 
16
17
  register('db.config', config)
17
18
  register('db.connection', connection)
@@ -19,14 +20,5 @@ Inferno::Application.boot(:db) do
19
20
 
20
21
  start do
21
22
  Sequel.extension :migration
22
- db = Inferno::Application['db.connection']
23
- migration_path = File.join(Inferno::Application.root, 'lib', 'inferno', 'db', 'migrations')
24
- Sequel::Migrator.run(db, migration_path)
25
-
26
- if ENV['APP_ENV'] == 'development'
27
- schema_path = File.join(Inferno::Application.root, 'lib', 'inferno', 'db', 'schema.rb')
28
- db.extension :schema_dumper
29
- File.open(schema_path, 'w') { |f| f.print(db.dump_schema_migration) }
30
- end
31
23
  end
32
24
  end
@@ -11,6 +11,8 @@ Inferno::Application.boot(:logging) do
11
11
  Logger.new($stdout)
12
12
  end
13
13
 
14
+ logger.level = Logger::INFO
15
+
14
16
  register('logger', logger)
15
17
  end
16
18
  end
@@ -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'
@@ -116,7 +116,7 @@ Sequel.migration do
116
116
  # Requires requests to be a part of tests now.
117
117
  foreign_key :result_id, :results, index: true, type: String
118
118
  foreign_key :test_session_id, :test_sessions, index: true, type: String
119
- add_index [:test_session_id, :name], concurrently: true
119
+ index [:test_session_id, :name], concurrently: true
120
120
 
121
121
  column :created_at, DateTime, null: false
122
122
  column :updated_at, DateTime, null: false
@@ -95,13 +95,13 @@ Sequel.migration do
95
95
  String :response_body, :text=>true
96
96
  foreign_key :result_id, :results, :type=>String, :size=>255
97
97
  foreign_key :test_session_id, :test_sessions, :type=>String, :size=>255
98
- String :"[:test_session_id, :name]"
99
98
  DateTime :created_at, :null=>false
100
99
  DateTime :updated_at, :null=>false
101
100
 
102
101
  index [:id]
103
102
  index [:result_id]
104
103
  index [:test_session_id]
104
+ index [:test_session_id, :name]
105
105
  end
106
106
 
107
107
  create_table(:result_outputs, :ignore_index_errors=>true) do
@@ -3,22 +3,43 @@ require_relative '../exceptions'
3
3
  module Inferno
4
4
  module DSL
5
5
  module Assertions
6
+ # Make an assertion
7
+ #
8
+ # @param test a value whose truthiness will determine whether the
9
+ # assertion passes or fails
10
+ # @param message [String] failure message
6
11
  def assert(test, message = '')
7
12
  raise Exceptions::AssertionException, message unless test
8
13
  end
9
14
 
15
+ # @private
10
16
  def bad_response_status_message(expected, received)
11
17
  "Bad response status: expected #{Array.wrap(expected).join(', ')}, but received #{received}"
12
18
  end
13
19
 
20
+ # Check an response's status
21
+ #
22
+ # @param status [Integer, Array<Integer>] a single integer or an array of
23
+ # integer status codes
24
+ # @param response [Hash]
14
25
  def assert_response_status(status, response: self.response)
15
26
  assert Array.wrap(status).include?(response[:status]), bad_response_status_message(status, response[:status])
16
27
  end
17
28
 
29
+ # @private
18
30
  def bad_resource_type_message(expected, received)
19
31
  "Bad resource type received: expected #{expected}, but received #{received}"
20
32
  end
21
33
 
34
+ # Check a FHIR resource's type
35
+ #
36
+ # @param resource_type [String, Symbol, Class]
37
+ # @param resource [FHIR::Model]
38
+ # @example
39
+ # # The resource type can be a symbol, String, or FHIR::Model class
40
+ # assert_resource_type(:capability_statement)
41
+ # assert_resource_type('CapabilityStatement')
42
+ # assert_resource_type(FHIR::CapabilityStatement)
22
43
  def assert_resource_type(resource_type, resource: self.resource)
23
44
  resource_type_name = normalize_resource_type(resource_type)
24
45
 
@@ -26,15 +47,48 @@ module Inferno
26
47
  bad_resource_type_message(resource_type_name, resource&.resourceType)
27
48
  end
28
49
 
50
+ # @private
29
51
  def invalid_resource_message(profile_url)
30
52
  "Resource does not conform to the profile: #{profile_url}"
31
53
  end
32
54
 
55
+ # Validate a FHIR resource
56
+ #
57
+ # @param resource [FHIR::Model]
58
+ # @param profile_url [String] url of the profile to validate against,
59
+ # defaults to validating against the base FHIR resource
33
60
  def assert_valid_resource(resource: self.resource, profile_url: nil)
34
61
  assert resource_is_valid?(resource: resource, profile_url: profile_url),
35
62
  invalid_resource_message(profile_url)
36
63
  end
37
64
 
65
+ # Validate each entry of a Bundle
66
+ #
67
+ # @param bundle [FHIR::Bundle]
68
+ # @param resource_types
69
+ # [String,Symbol,FHIR::Model,Array<String,Symbol,FHIR::Model>,Hash] If a
70
+ # string, symbol, or FHIR::Model is provided, only that resource type
71
+ # will be validated. If an array of strings is provided, only those
72
+ # resource types will be validated. If a hash is provided with resource
73
+ # types as keys and profile urls (or nil) as values, only those resource
74
+ # types will be validated against the provided profile url or the base
75
+ # resource if nil.
76
+ # @example
77
+ # # Only validate Patient bundle entries
78
+ # assert_valid_bundle_entries(resource_types: 'Patient')
79
+ #
80
+ # # Only valiadte Patient and Condition bundle entries
81
+ # assert_valid_bundle_entries(resource_types: ['Patient', 'Condition'])
82
+ #
83
+ # # Only validate Patient and Condition bundle entries. Validate Patient
84
+ # # resources against the given profile, and Codition resources against the
85
+ # # base FHIR Condition resource.
86
+ # assert_valid_bundle_entries(
87
+ # resource_types: {
88
+ # 'Patient': 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient',
89
+ # 'Condition': nil
90
+ # }
91
+ # )
38
92
  def assert_valid_bundle_entries(bundle: resource, resource_types: {})
39
93
  assert_resource_type('Bundle', resource: bundle)
40
94
 
@@ -56,6 +110,7 @@ module Inferno
56
110
  assert invalid_resources.empty?, invalid_bundle_entries_message(invalid_resources)
57
111
  end
58
112
 
113
+ # @private
59
114
  def invalid_bundle_entries_message(invalid_resources)
60
115
  identifier_strings =
61
116
  invalid_resources
@@ -64,6 +119,7 @@ module Inferno
64
119
  "The following bundle entries are invalid: #{identifier_strings}"
65
120
  end
66
121
 
122
+ # @private
67
123
  def normalize_resource_type(resource_type)
68
124
  if resource_type.is_a? Class
69
125
  resource_type.name.demodulize
@@ -72,6 +128,7 @@ module Inferno
72
128
  end
73
129
  end
74
130
 
131
+ # @private
75
132
  def normalize_types_to_check(resource_types)
76
133
  case resource_types
77
134
  when Hash
@@ -83,11 +140,39 @@ module Inferno
83
140
  end
84
141
  end
85
142
 
143
+ # Check for valid JSON
144
+ #
145
+ # @param maybe_json_string [String]
146
+ # @param message [String] extra failure message
86
147
  def assert_valid_json(maybe_json_string, message = '')
87
148
  assert JSON.parse(maybe_json_string)
88
149
  rescue JSON::ParserError
89
150
  assert false, "Invalid JSON. #{message}"
90
151
  end
152
+
153
+ # Check for a valid http/https uri
154
+ #
155
+ # @param uri [String]
156
+ # @param message [String] custom failure message
157
+ def assert_valid_http_uri(uri, message = '')
158
+ error_message = message.presence || "\"#{uri}\" is not a valid URI"
159
+ assert uri =~ /\A#{URI::DEFAULT_PARSER.make_regexp(['http', 'https'])}\z/, error_message
160
+ end
161
+
162
+ def assert_response_content_type(type, request: self.request)
163
+ header = request.response_header('Content-Type')
164
+ assert header.present?, no_content_type_message
165
+
166
+ assert header.value.start_with?(type), bad_content_type_message(type, header.value)
167
+ end
168
+
169
+ def no_content_type_message
170
+ 'Response did not contain a `Content-Type` header.'
171
+ end
172
+
173
+ def bad_content_type_message(expected, received)
174
+ "Expected `Content-Type` to be `#{expected}`, but found `#{received}`"
175
+ end
91
176
  end
92
177
  end
93
178
  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
+ # @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
@@ -35,7 +35,7 @@ module Inferno
35
35
  # @see Inferno::FHIRClientBuilder Documentation for the client
36
36
  # configuration DSL
37
37
  module FHIRClient
38
- # @api private
38
+ # @private
39
39
  def self.included(klass)
40
40
  klass.extend ClassMethods
41
41
  klass.extend Forwardable
@@ -54,7 +54,7 @@ module Inferno
54
54
  FHIRClientBuilder.new.build(self, self.class.fhir_client_definitions[client])
55
55
  end
56
56
 
57
- # @api private
57
+ # @private
58
58
  def fhir_clients
59
59
  @fhir_clients ||= {}
60
60
  end
@@ -69,13 +69,15 @@ 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
+ # @param headers [Hash] custom headers for this operation
73
73
  # @return [Inferno::Entities::Request]
74
- def fhir_operation(path, body: nil, client: :default, name: nil, **_options)
74
+ def fhir_operation(path, body: nil, client: :default, name: nil, headers: {})
75
75
  store_request('outgoing', name) do
76
- headers = fhir_client(client).fhir_headers
77
- headers.merge!('Content-Type' => 'application/fhir+json') if body.present?
78
- fhir_client(client).send(:post, path, body, headers)
76
+ operation_headers = fhir_client(client).fhir_headers
77
+ operation_headers.merge!('Content-Type' => 'application/fhir+json') if body.present?
78
+ operation_headers.merge!(headers) if headers.present?
79
+
80
+ fhir_client(client).send(:post, path, body, operation_headers)
79
81
  end
80
82
  end
81
83
 
@@ -84,9 +86,8 @@ module Inferno
84
86
  # @param client [Symbol]
85
87
  # @param name [Symbol] Name for this request to allow it to be used by
86
88
  # other tests
87
- # @param _options [Hash] TODO
88
89
  # @return [Inferno::Entities::Request]
89
- def fhir_get_capability_statement(client: :default, name: nil, **_options)
90
+ def fhir_get_capability_statement(client: :default, name: nil)
90
91
  store_request('outgoing', name) do
91
92
  fhir_client(client).conformance_statement
92
93
  fhir_client(client).reply
@@ -100,9 +101,8 @@ module Inferno
100
101
  # @param client [Symbol]
101
102
  # @param name [Symbol] Name for this request to allow it to be used by
102
103
  # other tests
103
- # @param _options [Hash] TODO
104
104
  # @return [Inferno::Entities::Request]
105
- def fhir_read(resource_type, id, client: :default, name: nil, **_options)
105
+ def fhir_read(resource_type, id, client: :default, name: nil)
106
106
  store_request('outgoing', name) do
107
107
  fhir_client(client).read(fhir_class_from_resource_type(resource_type), id)
108
108
  end
@@ -115,24 +115,30 @@ module Inferno
115
115
  # @param params [Hash] the search params
116
116
  # @param name [Symbol] Name for this request to allow it to be used by
117
117
  # other tests
118
- # @param _options [Hash] TODO
118
+ # @param search_method [Symbol] Use `:post` to search via POST
119
119
  # @return [Inferno::Entities::Request]
120
- def fhir_search(resource_type, client: :default, params: {}, name: nil, **_options)
120
+ def fhir_search(resource_type, client: :default, params: {}, name: nil, search_method: :get)
121
+ search =
122
+ if search_method == :post
123
+ { body: params }
124
+ else
125
+ { parameters: params }
126
+ end
121
127
  store_request('outgoing', name) do
122
128
  fhir_client(client)
123
- .search(fhir_class_from_resource_type(resource_type), search: { parameters: params })
129
+ .search(fhir_class_from_resource_type(resource_type), { search: search })
124
130
  end
125
131
  end
126
132
 
127
133
  # @todo Make this a FHIR class method? Something like
128
134
  # FHIR.class_for(resource_type)
129
- # @api private
135
+ # @private
130
136
  def fhir_class_from_resource_type(resource_type)
131
137
  FHIR.const_get(resource_type.to_s.camelize)
132
138
  end
133
139
 
134
140
  module ClassMethods
135
- # @api private
141
+ # @private
136
142
  def fhir_client_definitions
137
143
  @fhir_client_definitions ||= {}
138
144
  end
@@ -6,7 +6,7 @@ module Inferno
6
6
  class FHIRClientBuilder
7
7
  attr_accessor :runnable
8
8
 
9
- # @api private
9
+ # @private
10
10
  def build(runnable, block)
11
11
  self.runnable = runnable
12
12
  instance_exec(self, &block)
@@ -56,14 +56,14 @@ module Inferno
56
56
  @headers ||= headers
57
57
  end
58
58
 
59
- # @api private
59
+ # @private
60
60
  def method_missing(name, *args, &block)
61
61
  return runnable.call(name, *args, &block) if runnable.respond_to? name
62
62
 
63
63
  super
64
64
  end
65
65
 
66
- # @api private
66
+ # @private
67
67
  def respond_to_missing?(name)
68
68
  runnable.respond_to?(name) || super
69
69
  end