inferno_core 0.0.5 → 0.0.8.pre2

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.
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