inferno_core 0.0.7 → 0.1.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/lib/inferno/apps/web/controllers/test_runs/create.rb +2 -1
  3. data/lib/inferno/apps/web/index.html.erb +1 -0
  4. data/lib/inferno/db/migrations/001_create_initial_structure.rb +54 -53
  5. data/lib/inferno/db/migrations/002_add_wait_support.rb +2 -2
  6. data/lib/inferno/db/migrations/003_update_session_data.rb +7 -7
  7. data/lib/inferno/db/migrations/004_add_request_results_table.rb +2 -2
  8. data/lib/inferno/db/migrations/005_add_updated_at_index_to_results.rb +1 -1
  9. data/lib/inferno/db/migrations/006_remove_unused_tables.rb +38 -0
  10. data/lib/inferno/db/schema.rb +16 -42
  11. data/lib/inferno/dsl/configurable.rb +12 -5
  12. data/lib/inferno/dsl/fhir_client.rb +62 -20
  13. data/lib/inferno/dsl/fhir_client_builder.rb +16 -0
  14. data/lib/inferno/dsl/fhir_validation.rb +104 -0
  15. data/lib/inferno/dsl/oauth_credentials.rb +119 -0
  16. data/lib/inferno/dsl/runnable.rb +20 -8
  17. data/lib/inferno/entities/request.rb +7 -1
  18. data/lib/inferno/exceptions.rb +19 -0
  19. data/lib/inferno/ext/fhir_client.rb +13 -0
  20. data/lib/inferno/public/217.bundle.js +1 -1
  21. data/lib/inferno/public/bundle.js +154 -1
  22. data/lib/inferno/public/bundle.js.LICENSE.txt +15 -0
  23. data/lib/inferno/repositories/session_data.rb +40 -6
  24. data/lib/inferno/spec_support.rb +1 -1
  25. data/lib/inferno/test_runner.rb +8 -3
  26. data/lib/inferno/utils/middleware/request_logger.rb +8 -2
  27. data/lib/inferno/version.rb +1 -1
  28. data/spec/factories/request.rb +1 -1
  29. data/spec/factories/result.rb +2 -2
  30. data/spec/fixtures/basic_test_group.rb +1 -0
  31. metadata +11 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 86c8b0374d22ea35f07944360943d2a1240f8ef7365b97d625b32facde4a2eaa
4
- data.tar.gz: '0258752a8738b7e9c1da7d9112d0ee4f15bac0a8c7b2acac5f9973bb35d8146c'
3
+ metadata.gz: 9f5cad35764c687097e9021a08a03d64c9acc38f10db6b608cc43a60cf3102c8
4
+ data.tar.gz: 9318cd4c0479930c398902d8770be2590da72d40194b580d92288f3737938c4a
5
5
  SHA512:
6
- metadata.gz: 76cd8133722b109ed66f9b79eea46279c177fdac68cfe9abea4d0e9caaa76b861e533909923a94121d17e15483be5254f8e36e67cf6abb6121bc12f1e37f5fd7
7
- data.tar.gz: 9be9f363e78e653b33818a8e8eee7fc74474ec2ca019b715054b7926d7e5675c46b290e138c0ee020e586d91eecef2759ead3272b6087461af89afeb8fdd7e94
6
+ metadata.gz: aa5f6c1c8e3dbd640b5ac4d371f7a304da34bca8d7b247e0521098cb525063c59cd8c1e8621d41173b3b9e2f4aff4d359303c326c2989bcd27d0d77ce052a71c
7
+ data.tar.gz: ba59fb57dd37e52eb41b309e807d0d8405a76b415c1980bfb368b6208a770de3840d70041ac973523027c3fec72bb6cf94d4730bea317446c262fe6b7b097766
@@ -33,7 +33,8 @@ module Inferno
33
33
  session_data_repo.save(
34
34
  test_session_id: test_session.id,
35
35
  name: input[:name],
36
- value: input[:value]
36
+ value: input[:value],
37
+ type: input[:type]
37
38
  )
38
39
  end
39
40
 
@@ -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" />
@@ -11,81 +11,81 @@ Sequel.migration do
11
11
  # end
12
12
 
13
13
  create_table :test_sessions do
14
- column :id, String, primary_key: true, null: false
15
- column :test_suite_id, String
14
+ column :id, String, primary_key: true, null: false, size: 36
15
+ column :test_suite_id, String, size: 255
16
16
 
17
17
  column :created_at, DateTime, null: false
18
18
  column :updated_at, DateTime, null: false
19
19
  end
20
20
 
21
21
  create_table :test_runs do
22
- column :id, String, primary_key: true, null: false
23
- column :status, String
24
- foreign_key :test_session_id, :test_sessions, index: true, type: String
22
+ column :id, String, primary_key: true, null: false, size: 36
23
+ column :status, String, size: 255
24
+ foreign_key :test_session_id, :test_sessions, index: true, type: String, size: 36, key: [:id]
25
25
  index [:test_session_id, :status] # Searching by unfinished test runs seems like it will be a likely query
26
26
 
27
- column :test_suite_id, String, index: true
28
- column :test_group_id, String, index: true
29
- column :test_id, String, index: true
27
+ column :test_suite_id, String, index: true, size: 255
28
+ column :test_group_id, String, index: true, size: 255
29
+ column :test_id, String, index: true, size: 255
30
30
 
31
31
  column :created_at, DateTime, null: false
32
32
  column :updated_at, DateTime, null: false
33
33
  end
34
34
 
35
35
  create_table :test_run_inputs do
36
- column :id, String, primary_key: true, null: false
37
- foreign_key :test_run_id, :test_runs, index: true, type: String
38
- column :test_input_id, String
39
- column :value, String
36
+ column :id, String, primary_key: true, null: false, size: 36
37
+ foreign_key :test_run_id, :test_runs, index: true, type: String, key: [:id]
38
+ column :test_input_id, String, size: 255
39
+ column :value, String, text: true
40
40
 
41
41
  column :created_at, DateTime, null: false
42
42
  column :updated_at, DateTime, null: false
43
43
  end
44
44
 
45
45
  create_table :results do
46
- column :id, String, primary_key: true, null: false
46
+ column :id, String, primary_key: true, null: false, size: 36
47
47
 
48
- foreign_key :test_run_id, :test_runs, index: true, type: String
49
- foreign_key :test_session_id, :test_sessions, index: true, type: String
48
+ foreign_key :test_run_id, :test_runs, index: true, type: String, size: 36, key: [:id]
49
+ foreign_key :test_session_id, :test_sessions, index: true, type: String, size: 36, key: [:id]
50
50
 
51
- column :result, String
52
- column :result_message, String
51
+ column :result, String, size: 255
52
+ column :result_message, String, text: true
53
53
 
54
- column :test_suite_id, String
55
- column :test_group_id, String
56
- column :test_id, String
54
+ column :test_suite_id, String, size: 255
55
+ column :test_group_id, String, size: 255
56
+ column :test_id, String, size: 255
57
57
 
58
58
  column :created_at, DateTime, null: false
59
59
  column :updated_at, DateTime, null: false
60
60
  end
61
61
 
62
62
  create_table :result_inputs do
63
- column :id, String, primary_key: true, null: false
64
- foreign_key :result_id, :results, index: true, type: String
65
- column :test_input_id, String
66
- column :value, String
63
+ column :id, String, primary_key: true, null: false, size: 36
64
+ foreign_key :result_id, :results, index: true, type: String, size: 36, key: [:id]
65
+ column :test_input_id, String, size: 255
66
+ column :value, String, text: true
67
67
 
68
68
  column :created_at, DateTime, null: false
69
69
  column :updated_at, DateTime, null: false
70
70
  end
71
71
 
72
72
  create_table :result_outputs do
73
- column :id, String, primary_key: true, null: false
74
- foreign_key :result_id, :results, index: true, type: String
75
- column :test_output_id, String
76
- column :value, String
73
+ column :id, String, primary_key: true, null: false, size: 36
74
+ foreign_key :result_id, :results, index: true, type: String, size: 36, key: [:id]
75
+ column :test_output_id, String, size: 255
76
+ column :value, String, text: true
77
77
 
78
78
  column :created_at, DateTime, null: false
79
79
  column :updated_at, DateTime, null: false
80
80
  end
81
81
 
82
82
  create_table :result_prompt_values do
83
- column :id, String, primary_key: true, null: false
83
+ column :id, String, primary_key: true, null: false, size: 36
84
84
 
85
- foreign_key :result_id, :results, index: true, type: String
85
+ foreign_key :result_id, :results, index: true, type: String, size: 36, key: [:id]
86
86
 
87
- column :test_prompt_id, String, null: false
88
- column :value, String, null: false
87
+ column :test_prompt_id, String, null: false, size: 255
88
+ column :value, String, null: false, text: true
89
89
 
90
90
  column :created_at, DateTime, null: false
91
91
  column :updated_at, DateTime, null: false
@@ -93,10 +93,10 @@ Sequel.migration do
93
93
 
94
94
  create_table :messages do
95
95
  primary_key :index
96
- column :id, String, index: true, null: false
97
- foreign_key :result_id, :results, index: true, type: String
98
- column :type, String
99
- column :message, String
96
+ column :id, String, index: true, null: false, size: 36
97
+ foreign_key :result_id, :results, index: true, type: String, size: 36, key: [:id]
98
+ column :type, String, size: 255
99
+ column :message, String, text: true
100
100
 
101
101
  column :created_at, DateTime, null: false
102
102
  column :updated_at, DateTime, null: false
@@ -104,40 +104,41 @@ Sequel.migration do
104
104
 
105
105
  create_table :requests do
106
106
  primary_key :index
107
- column :id, String, index: true, null: false
108
- column :verb, String
109
- column :url, String
110
- column :direction, String
107
+ column :id, String, null: false, size: 36
108
+ column :verb, String, size: 255
109
+ column :url, String, text: true
110
+ column :direction, String, size: 255
111
111
  column :status, Integer
112
- column :name, String
112
+ column :name, String, size: 255
113
113
  column :request_body, String, text: true
114
114
  column :response_body, String, text: true # It would be nice if we could store this on disk
115
+ index [:id], unique: true
115
116
 
116
117
  # Requires requests to be a part of tests now.
117
- foreign_key :result_id, :results, index: true, type: String
118
- foreign_key :test_session_id, :test_sessions, index: true, type: String
119
- add_index [:test_session_id, :name], concurrently: true
118
+ foreign_key :result_id, :results, index: true, type: String, size: 36, key: [:id]
119
+ foreign_key :test_session_id, :test_sessions, index: true, type: String, size: 36, key: [:id]
120
+ index [:test_session_id, :name]
120
121
 
121
122
  column :created_at, DateTime, null: false
122
123
  column :updated_at, DateTime, null: false
123
124
  end
124
125
 
125
126
  create_table :headers do
126
- column :id, String, index: true, null: false
127
- foreign_key :request_id, :requests, index: true, type: String
128
- column :type, String # request / response
129
- column :name, String
130
- column :value, String
127
+ column :id, String, index: true, null: false, size: 36
128
+ foreign_key :request_id, :requests, index: true, type: Integer, key: [:index]
129
+ column :type, String, size: 255 # request / response
130
+ column :name, String, size: 255
131
+ column :value, String, text: true
131
132
 
132
133
  column :created_at, DateTime, null: false
133
134
  column :updated_at, DateTime, null: false
134
135
  end
135
136
 
136
137
  create_table :session_data do
137
- column :id, String, index: true, null: false
138
- foreign_key :test_session_id, :test_sessions, index: true, type: String
139
- column :name, String
140
- column :value, String
138
+ column :id, String, index: true, null: false, size: 255
139
+ foreign_key :test_session_id, :test_sessions, index: true, type: String, size: 36, key: [:id]
140
+ column :name, String, size: 255
141
+ column :value, String, text: true
141
142
  index [:test_session_id, :name]
142
143
  end
143
144
  end
@@ -1,7 +1,7 @@
1
1
  Sequel.migration do
2
2
  change do
3
- add_column :test_runs, :identifier, String, text: true
3
+ add_column :test_runs, :identifier, String, text: true, size: 255
4
4
  add_column :test_runs, :wait_timeout, DateTime
5
- add_index :test_runs, [:status, :identifier, :wait_timeout, :updated_at], concurrently: true
5
+ add_index :test_runs, [:status, :identifier, :wait_timeout, :updated_at]
6
6
  end
7
7
  end
@@ -4,15 +4,15 @@ Sequel.migration do
4
4
  drop_table :result_inputs
5
5
 
6
6
  set_column_type :session_data, :value, String, text: true
7
- drop_index :session_data, [:test_session_id, :name], concurrently: true
8
- add_index :session_data, [:test_session_id, :name], unique: true, concurrently: true
9
- drop_index :session_data, :id, concurrently: true
10
- add_index :session_data, :id, unique: true, concurrently: true
7
+ drop_index :session_data, [:test_session_id, :name]
8
+ add_index :session_data, [:test_session_id, :name], unique: true
9
+ drop_index :session_data, :id
10
+ add_index :session_data, :id, unique: true
11
11
 
12
12
  add_column :results, :input_json, String, text: true
13
13
  add_column :results, :output_json, String, text: true
14
- add_index :results, [:test_session_id, :test_id], concurrently: true
15
- add_index :results, [:test_session_id, :test_group_id], concurrently: true
16
- add_index :results, [:test_session_id, :test_suite_id], concurrently: true
14
+ add_index :results, [:test_session_id, :test_id]
15
+ add_index :results, [:test_session_id, :test_group_id]
16
+ add_index :results, [:test_session_id, :test_suite_id]
17
17
  end
18
18
  end
@@ -2,8 +2,8 @@ Sequel.migration do
2
2
  change do
3
3
  create_table :requests_results do
4
4
  # using results_id instead of result_id to avoid ambiguous column error
5
- foreign_key :results_id, :results, index: true, type: String, null: false
6
- foreign_key :requests_id, :requests, index: true, type: String, null: false
5
+ foreign_key :results_id, :results, index: true, type: String, null: false, size: 36, key: [:id]
6
+ foreign_key :requests_id, :requests, index: true, type: Integer, null: false, size: 36, key: [:index]
7
7
  end
8
8
  end
9
9
  end
@@ -1,5 +1,5 @@
1
1
  Sequel.migration do
2
2
  change do
3
- add_index :results, [:test_run_id, :updated_at], concurrently: true
3
+ add_index :results, [:test_run_id, :updated_at]
4
4
  end
5
5
  end
@@ -0,0 +1,38 @@
1
+ Sequel.migration do
2
+ change do
3
+ drop_table :result_outputs
4
+ drop_table :result_prompt_values
5
+
6
+ alter_table(:test_sessions) { set_column_not_null :test_suite_id }
7
+
8
+ alter_table(:results) do
9
+ set_column_not_null :test_run_id
10
+ set_column_not_null :test_session_id
11
+ end
12
+
13
+ alter_table(:messages) do
14
+ set_column_not_null :result_id
15
+ set_column_not_null :type
16
+ set_column_not_null :message
17
+ end
18
+
19
+ alter_table(:requests) do
20
+ set_column_not_null :verb
21
+ set_column_not_null :url
22
+ set_column_not_null :direction
23
+ set_column_not_null :result_id
24
+ set_column_not_null :test_session_id
25
+ end
26
+
27
+ alter_table(:headers) do
28
+ set_column_not_null :request_id
29
+ set_column_not_null :type
30
+ set_column_not_null :name
31
+ end
32
+
33
+ alter_table(:session_data) do
34
+ set_column_not_null :test_session_id
35
+ set_column_not_null :name
36
+ end
37
+ end
38
+ end
@@ -6,7 +6,7 @@ Sequel.migration do
6
6
 
7
7
  create_table(:test_sessions) do
8
8
  String :id, :size=>255, :null=>false
9
- String :test_suite_id, :size=>255
9
+ String :test_suite_id, :size=>255, :null=>false
10
10
  DateTime :created_at, :null=>false
11
11
  DateTime :updated_at, :null=>false
12
12
 
@@ -15,8 +15,8 @@ Sequel.migration do
15
15
 
16
16
  create_table(:session_data, :ignore_index_errors=>true) do
17
17
  String :id, :size=>255, :null=>false
18
- foreign_key :test_session_id, :test_sessions, :type=>String, :size=>255
19
- String :name, :size=>255
18
+ foreign_key :test_session_id, :test_sessions, :type=>String, :size=>255, :null=>false
19
+ String :name, :size=>255, :null=>false
20
20
  String :value, :text=>true
21
21
 
22
22
  index [:id], :unique=>true
@@ -48,8 +48,8 @@ Sequel.migration do
48
48
 
49
49
  create_table(:results, :ignore_index_errors=>true) do
50
50
  String :id, :size=>255, :null=>false
51
- foreign_key :test_run_id, :test_runs, :type=>String, :size=>255
52
- foreign_key :test_session_id, :test_sessions, :type=>String, :size=>255
51
+ foreign_key :test_run_id, :test_runs, :type=>String, :size=>255, :null=>false
52
+ foreign_key :test_session_id, :test_sessions, :type=>String, :size=>255, :null=>false
53
53
  String :result, :size=>255
54
54
  String :result_message, :size=>255
55
55
  String :test_suite_id, :size=>255
@@ -73,9 +73,9 @@ Sequel.migration do
73
73
  create_table(:messages, :ignore_index_errors=>true) do
74
74
  primary_key :index
75
75
  String :id, :size=>255, :null=>false
76
- foreign_key :result_id, :results, :type=>String, :size=>255
77
- String :type, :size=>255
78
- String :message, :size=>255
76
+ foreign_key :result_id, :results, :type=>String, :size=>255, :null=>false
77
+ String :type, :size=>255, :null=>false
78
+ String :message, :size=>255, :null=>false
79
79
  DateTime :created_at, :null=>false
80
80
  DateTime :updated_at, :null=>false
81
81
 
@@ -86,15 +86,15 @@ Sequel.migration do
86
86
  create_table(:requests, :ignore_index_errors=>true) do
87
87
  primary_key :index
88
88
  String :id, :size=>255, :null=>false
89
- String :verb, :size=>255
90
- String :url, :size=>255
91
- String :direction, :size=>255
89
+ String :verb, :size=>255, :null=>false
90
+ String :url, :size=>255, :null=>false
91
+ String :direction, :size=>255, :null=>false
92
92
  Integer :status
93
93
  String :name, :size=>255
94
94
  String :request_body, :text=>true
95
95
  String :response_body, :text=>true
96
- foreign_key :result_id, :results, :type=>String, :size=>255
97
- foreign_key :test_session_id, :test_sessions, :type=>String, :size=>255
96
+ foreign_key :result_id, :results, :type=>String, :size=>255, :null=>false
97
+ foreign_key :test_session_id, :test_sessions, :type=>String, :size=>255, :null=>false
98
98
  String :"[:test_session_id, :name]"
99
99
  DateTime :created_at, :null=>false
100
100
  DateTime :updated_at, :null=>false
@@ -104,37 +104,11 @@ Sequel.migration do
104
104
  index [:test_session_id]
105
105
  end
106
106
 
107
- create_table(:result_outputs, :ignore_index_errors=>true) do
108
- String :id, :size=>255, :null=>false
109
- foreign_key :result_id, :results, :type=>String, :size=>255
110
- String :test_output_id, :size=>255
111
- String :value, :size=>255
112
- DateTime :created_at, :null=>false
113
- DateTime :updated_at, :null=>false
114
-
115
- primary_key [:id]
116
-
117
- index [:result_id]
118
- end
119
-
120
- create_table(:result_prompt_values, :ignore_index_errors=>true) do
121
- String :id, :size=>255, :null=>false
122
- foreign_key :result_id, :results, :type=>String, :size=>255
123
- String :test_prompt_id, :size=>255, :null=>false
124
- String :value, :size=>255, :null=>false
125
- DateTime :created_at, :null=>false
126
- DateTime :updated_at, :null=>false
127
-
128
- primary_key [:id]
129
-
130
- index [:result_id]
131
- end
132
-
133
107
  create_table(:headers, :ignore_index_errors=>true) do
134
108
  String :id, :size=>255, :null=>false
135
- foreign_key :request_id, :requests, :type=>String, :size=>255
136
- String :type, :size=>255
137
- String :name, :size=>255
109
+ foreign_key :request_id, :requests, :type=>String, :size=>255, :null=>false
110
+ String :type, :size=>255, :null=>false
111
+ String :name, :size=>255, :null=>false
138
112
  String :value, :size=>255
139
113
  DateTime :created_at, :null=>false
140
114
  DateTime :updated_at, :null=>false
@@ -65,20 +65,23 @@ module Inferno
65
65
  inputs.dig(identifier, :name) || identifier
66
66
  end
67
67
 
68
+ def input_type(identifier)
69
+ inputs.dig(identifier, :type)
70
+ end
71
+
68
72
  ### Output Configuration ###
69
73
 
70
74
  def outputs
71
75
  configuration[:outputs] ||= {}
72
76
  end
73
77
 
74
- def add_output(identifier)
75
- return if output_config_exists?(identifier)
76
-
77
- outputs[identifier] = default_output_config(identifier)
78
+ def add_output(identifier, new_config = {})
79
+ existing_config = output_config(identifier) || {}
80
+ outputs[identifier] = default_output_config(identifier).merge(existing_config, new_config)
78
81
  end
79
82
 
80
83
  def default_output_config(identifier)
81
- { name: identifier }
84
+ { name: identifier, type: 'text' }
82
85
  end
83
86
 
84
87
  def output_config_exists?(identifier)
@@ -93,6 +96,10 @@ module Inferno
93
96
  outputs.dig(identifier, :name) || identifier
94
97
  end
95
98
 
99
+ def output_type(identifier)
100
+ outputs.dig(identifier, :type)
101
+ end
102
+
96
103
  ### Request Configuration ###
97
104
 
98
105
  def requests
@@ -69,15 +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
- # @option options [Hash] Input headers here - headers are optional and
73
- # must be entered as the last piece of input to this method
72
+ # @param headers [Hash] custom headers for this operation
74
73
  # @return [Inferno::Entities::Request]
75
- def fhir_operation(path, body: nil, client: :default, name: nil, **options)
76
- store_request('outgoing', name) do
77
- headers = fhir_client(client).fhir_headers
78
- headers.merge!('Content-Type' => 'application/fhir+json') if body.present?
79
- headers.merge!(options[:headers]) if options[:headers].present?
80
- fhir_client(client).send(:post, path, body, headers)
74
+ def fhir_operation(path, body: nil, client: :default, name: nil, headers: {})
75
+ store_request_and_refresh_token(fhir_client(client), name) do
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)
81
81
  end
82
82
  end
83
83
 
@@ -86,10 +86,9 @@ module Inferno
86
86
  # @param client [Symbol]
87
87
  # @param name [Symbol] Name for this request to allow it to be used by
88
88
  # other tests
89
- # @param _options [Hash] TODO
90
89
  # @return [Inferno::Entities::Request]
91
- def fhir_get_capability_statement(client: :default, name: nil, **_options)
92
- store_request('outgoing', name) do
90
+ def fhir_get_capability_statement(client: :default, name: nil)
91
+ store_request_and_refresh_token(fhir_client(client), name) do
93
92
  fhir_client(client).conformance_statement
94
93
  fhir_client(client).reply
95
94
  end
@@ -102,10 +101,9 @@ module Inferno
102
101
  # @param client [Symbol]
103
102
  # @param name [Symbol] Name for this request to allow it to be used by
104
103
  # other tests
105
- # @param _options [Hash] TODO
106
104
  # @return [Inferno::Entities::Request]
107
- def fhir_read(resource_type, id, client: :default, name: nil, **_options)
108
- store_request('outgoing', name) do
105
+ def fhir_read(resource_type, id, client: :default, name: nil)
106
+ store_request_and_refresh_token(fhir_client(client), name) do
109
107
  fhir_client(client).read(fhir_class_from_resource_type(resource_type), id)
110
108
  end
111
109
  end
@@ -117,24 +115,68 @@ module Inferno
117
115
  # @param params [Hash] the search params
118
116
  # @param name [Symbol] Name for this request to allow it to be used by
119
117
  # other tests
120
- # @param _options [Hash] TODO
118
+ # @param search_method [Symbol] Use `:post` to search via POST
121
119
  # @return [Inferno::Entities::Request]
122
- def fhir_search(resource_type, client: :default, params: {}, name: nil, **_options)
123
- store_request('outgoing', name) do
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
127
+
128
+ store_request_and_refresh_token(fhir_client(client), name) do
124
129
  fhir_client(client)
125
- .search(fhir_class_from_resource_type(resource_type), search: { parameters: params })
130
+ .search(fhir_class_from_resource_type(resource_type), { search: search })
126
131
  end
127
132
  end
128
133
 
129
134
  # @todo Make this a FHIR class method? Something like
130
135
  # FHIR.class_for(resource_type)
131
- # @private
136
+ # @api private
132
137
  def fhir_class_from_resource_type(resource_type)
133
138
  FHIR.const_get(resource_type.to_s.camelize)
134
139
  end
135
140
 
141
+ # This method wraps a request to automatically refresh its access token if
142
+ # expired. It's combined with `store_request` so that all of the fhir
143
+ # request methods don't have to be wrapped twice.
144
+ # @api private
145
+ def store_request_and_refresh_token(client, name, &block)
146
+ store_request('outgoing', name) do
147
+ perform_refresh(client) if client.need_to_refresh? && client.able_to_refresh?
148
+ block.call
149
+ end
150
+ end
151
+
152
+ # @api private
153
+ def perform_refresh(client)
154
+ credentials = client.oauth_credentials
155
+
156
+ post(
157
+ credentials.token_url,
158
+ body: credentials.oauth2_refresh_params,
159
+ headers: credentials.oauth2_refresh_headers
160
+ )
161
+
162
+ return if request.status != 200
163
+
164
+ credentials.update_from_response_body(request)
165
+
166
+ if credentials.name.present?
167
+ Inferno::Repositories::SessionData.new.save(
168
+ name: credentials.name,
169
+ value: credentials,
170
+ type: 'oauth_credentials',
171
+ test_session_id: test_session_id
172
+ )
173
+ end
174
+ rescue StandardError => e
175
+ Inferno::Application[:logger].error "Unable to refresh token: #{e.message}"
176
+ end
177
+
136
178
  module ClassMethods
137
- # @private
179
+ # @api private
138
180
  def fhir_client_definitions
139
181
  @fhir_client_definitions ||= {}
140
182
  end
@@ -1,4 +1,5 @@
1
1
  require 'fhir_client'
2
+ require_relative '../ext/fhir_client'
2
3
 
3
4
  module Inferno
4
5
  module DSL
@@ -15,6 +16,7 @@ module Inferno
15
16
  client.additional_headers = headers if headers
16
17
  client.default_json
17
18
  client.set_bearer_token bearer_token if bearer_token
19
+ oauth_credentials&.add_to_client(client)
18
20
  end
19
21
  end
20
22
 
@@ -48,6 +50,20 @@ module Inferno
48
50
  end
49
51
  end
50
52
 
53
+ # Define OAuth credentials for a client. These can allow a client to
54
+ # automatically refresh its access token when it expires.
55
+ #
56
+ # @param oauth_credentials [Inferno::DSL::OAuthCredentials, Symbol]
57
+ # @return [void]
58
+ def oauth_credentials(oauth_credentials = nil)
59
+ @oauth_credentials ||=
60
+ if oauth_credentials.is_a? Symbol
61
+ runnable.send(oauth_credentials)
62
+ else
63
+ oauth_credentials
64
+ end
65
+ end
66
+
51
67
  # Define custom headers for a client
52
68
  #
53
69
  # @param headers [Hash]