inferno_core 0.0.8 → 0.1.1

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 (38) 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/serializers/result.rb +1 -0
  4. data/lib/inferno/apps/web/serializers/test.rb +4 -0
  5. data/lib/inferno/apps/web/serializers/test_group.rb +4 -0
  6. data/lib/inferno/apps/web/serializers/test_suite.rb +3 -0
  7. data/lib/inferno/db/migrations/001_create_initial_structure.rb +54 -53
  8. data/lib/inferno/db/migrations/002_add_wait_support.rb +2 -2
  9. data/lib/inferno/db/migrations/003_update_session_data.rb +7 -7
  10. data/lib/inferno/db/migrations/004_add_request_results_table.rb +2 -2
  11. data/lib/inferno/db/migrations/005_add_updated_at_index_to_results.rb +1 -1
  12. data/lib/inferno/db/migrations/006_remove_unused_tables.rb +38 -0
  13. data/lib/inferno/db/schema.rb +17 -43
  14. data/lib/inferno/dsl/configurable.rb +12 -5
  15. data/lib/inferno/dsl/fhir_client.rb +58 -6
  16. data/lib/inferno/dsl/fhir_client_builder.rb +16 -0
  17. data/lib/inferno/dsl/http_client.rb +62 -0
  18. data/lib/inferno/dsl/oauth_credentials.rb +119 -0
  19. data/lib/inferno/dsl/runnable.rb +87 -9
  20. data/lib/inferno/entities/has_runnable.rb +26 -0
  21. data/lib/inferno/entities/request.rb +7 -1
  22. data/lib/inferno/entities/result.rb +8 -4
  23. data/lib/inferno/entities/test_group.rb +4 -6
  24. data/lib/inferno/entities/test_run.rb +1 -18
  25. data/lib/inferno/entities/test_suite.rb +3 -4
  26. data/lib/inferno/entities.rb +1 -0
  27. data/lib/inferno/exceptions.rb +19 -0
  28. data/lib/inferno/ext/fhir_client.rb +13 -0
  29. data/lib/inferno/public/bundle.js +14 -14
  30. data/lib/inferno/repositories/session_data.rb +40 -6
  31. data/lib/inferno/result_summarizer.rb +40 -0
  32. data/lib/inferno/spec_support.rb +1 -1
  33. data/lib/inferno/test_runner.rb +13 -9
  34. data/lib/inferno/version.rb +1 -1
  35. data/spec/factories/request.rb +1 -1
  36. data/spec/factories/result.rb +2 -2
  37. data/spec/fixtures/basic_test_group.rb +1 -0
  38. metadata +7 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ef5b26a5633a33054fd378a523bc3a768e1a77ef572180db26ea792899cfc86a
4
- data.tar.gz: b08e8c22c830ab2547d02e89d08e97bfc8248ce1fd8705d95b25d25df1925565
3
+ metadata.gz: 4fe39c8c3dfc7f0f12192e065746ab203836ebf93a9f2f6a22a847d0d95fe0a2
4
+ data.tar.gz: 9b10445ccde6d340c35b39450f2cebef2b589b4473b4fe9a9c36ced3c7b20630
5
5
  SHA512:
6
- metadata.gz: a22e65c16f1b80abec1c1e182a91ffa44cdb4e78cfad7ec6233c07cbcbfcdf221a5444aa7bec88c4a6bdb99ad95623926d88f6ed60b3888fa0b7bfc1b5a32793
7
- data.tar.gz: d9717b4a08e8650071bb679ff964f85efd9d771a8f361a4b0a0781d7e9e91ea9ff764e6c8760a34f063e97944fedfb06b86349cd95cb29561844dc20a37401c1
6
+ metadata.gz: a64d50d36b4269fe2449b2e6a25947cd04a1fc963c7fb4ffdfb0bd417d304ec5a5149bdb5cd69bd761ab4471378d13b1dc60d8c961ba6f1729d739c3ad553337
7
+ data.tar.gz: 18a78ac99ac8fe75f6d1715272d6be64c51ae930c1a40cf5453c8aaefcd460739b4b6d817a776576898ffba02df449f07fbd1c7fc3468302b5d7b62f3f64e766
@@ -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
 
@@ -16,6 +16,7 @@ module Inferno
16
16
  field :result_message, if: :field_present?
17
17
  field :created_at
18
18
  field :updated_at
19
+ field :optional?, name: :optional
19
20
 
20
21
  field :outputs do |result, _options|
21
22
  result.output_json.present? ? JSON.parse(result.output_json) : []
@@ -4,10 +4,14 @@ module Inferno
4
4
  class Test < Serializer
5
5
  identifier :id
6
6
  field :title
7
+ field :short_title
7
8
  field :input_definitions, name: :inputs, extractor: HashValueExtractor, blueprint: Input
8
9
  field :output_definitions, name: :outputs, extractor: HashValueExtractor
9
10
  field :description
11
+ field :short_description
12
+ field :input_instructions
10
13
  field :user_runnable?, name: :user_runnable
14
+ field :optional?, name: :optional
11
15
  end
12
16
  end
13
17
  end
@@ -5,10 +5,14 @@ module Inferno
5
5
  identifier :id
6
6
 
7
7
  field :title
8
+ field :short_title
8
9
  field :description
10
+ field :short_description
11
+ field :input_instructions
9
12
  field :test_count
10
13
  field :run_as_group?, name: :run_as_group
11
14
  field :user_runnable?, name: :user_runnable
15
+ field :optional?, name: :optional
12
16
 
13
17
  association :groups, name: :test_groups, blueprint: TestGroup
14
18
  association :tests, blueprint: Test
@@ -5,7 +5,10 @@ module Inferno
5
5
  view :summary do
6
6
  identifier :id
7
7
  field :title
8
+ field :short_title
8
9
  field :description
10
+ field :short_description
11
+ field :input_instructions
9
12
  field :test_count
10
13
  end
11
14
 
@@ -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
- 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,55 +86,29 @@ 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
+ String :"[:test_session_id, :name]"
98
99
  DateTime :created_at, :null=>false
99
100
  DateTime :updated_at, :null=>false
100
101
 
101
102
  index [:id]
102
103
  index [:result_id]
103
104
  index [:test_session_id]
104
- index [:test_session_id, :name]
105
- end
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
105
  end
132
106
 
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
@@ -72,7 +72,7 @@ module Inferno
72
72
  # @param headers [Hash] custom headers for this operation
73
73
  # @return [Inferno::Entities::Request]
74
74
  def fhir_operation(path, body: nil, client: :default, name: nil, headers: {})
75
- store_request('outgoing', name) do
75
+ store_request_and_refresh_token(fhir_client(client), name) do
76
76
  operation_headers = fhir_client(client).fhir_headers
77
77
  operation_headers.merge!('Content-Type' => 'application/fhir+json') if body.present?
78
78
  operation_headers.merge!(headers) if headers.present?
@@ -88,7 +88,7 @@ module Inferno
88
88
  # other tests
89
89
  # @return [Inferno::Entities::Request]
90
90
  def fhir_get_capability_statement(client: :default, name: nil)
91
- store_request('outgoing', name) do
91
+ store_request_and_refresh_token(fhir_client(client), name) do
92
92
  fhir_client(client).conformance_statement
93
93
  fhir_client(client).reply
94
94
  end
@@ -103,7 +103,7 @@ module Inferno
103
103
  # other tests
104
104
  # @return [Inferno::Entities::Request]
105
105
  def fhir_read(resource_type, id, client: :default, name: nil)
106
- store_request('outgoing', name) do
106
+ store_request_and_refresh_token(fhir_client(client), name) do
107
107
  fhir_client(client).read(fhir_class_from_resource_type(resource_type), id)
108
108
  end
109
109
  end
@@ -124,21 +124,73 @@ module Inferno
124
124
  else
125
125
  { parameters: params }
126
126
  end
127
- store_request('outgoing', name) do
127
+
128
+ store_request_and_refresh_token(fhir_client(client), name) do
128
129
  fhir_client(client)
129
130
  .search(fhir_class_from_resource_type(resource_type), { search: search })
130
131
  end
131
132
  end
132
133
 
134
+ # Perform a FHIR delete interaction.
135
+ #
136
+ # @param resource_type [String, Symbol, Class]
137
+ # @param id [String]
138
+ # @param client [Symbol]
139
+ # @param name [Symbol] Name for this request to allow it to be used by
140
+ # other tests
141
+ # @return [Inferno::Entities::Request]
142
+ def fhir_delete(resource_type, id, client: :default, name: nil)
143
+ store_request('outgoing', name) do
144
+ fhir_client(client).destroy(fhir_class_from_resource_type(resource_type), id)
145
+ end
146
+ end
147
+
133
148
  # @todo Make this a FHIR class method? Something like
134
149
  # FHIR.class_for(resource_type)
135
- # @private
150
+ # @api private
136
151
  def fhir_class_from_resource_type(resource_type)
137
152
  FHIR.const_get(resource_type.to_s.camelize)
138
153
  end
139
154
 
155
+ # This method wraps a request to automatically refresh its access token if
156
+ # expired. It's combined with `store_request` so that all of the fhir
157
+ # request methods don't have to be wrapped twice.
158
+ # @api private
159
+ def store_request_and_refresh_token(client, name, &block)
160
+ store_request('outgoing', name) do
161
+ perform_refresh(client) if client.need_to_refresh? && client.able_to_refresh?
162
+ block.call
163
+ end
164
+ end
165
+
166
+ # @api private
167
+ def perform_refresh(client)
168
+ credentials = client.oauth_credentials
169
+
170
+ post(
171
+ credentials.token_url,
172
+ body: credentials.oauth2_refresh_params,
173
+ headers: credentials.oauth2_refresh_headers
174
+ )
175
+
176
+ return if request.status != 200
177
+
178
+ credentials.update_from_response_body(request)
179
+
180
+ if credentials.name.present?
181
+ Inferno::Repositories::SessionData.new.save(
182
+ name: credentials.name,
183
+ value: credentials,
184
+ type: 'oauth_credentials',
185
+ test_session_id: test_session_id
186
+ )
187
+ end
188
+ rescue StandardError => e
189
+ Inferno::Application[:logger].error "Unable to refresh token: #{e.message}"
190
+ end
191
+
140
192
  module ClassMethods
141
- # @private
193
+ # @api private
142
194
  def fhir_client_definitions
143
195
  @fhir_client_definitions ||= {}
144
196
  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]