onc_certification_g10_test_kit 5.4.2 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/onc_certification_g10_test_kit/base_token_refresh_stu2_group.rb +49 -0
- data/lib/onc_certification_g10_test_kit/multi_patient_api_stu1.rb +13 -8
- data/lib/onc_certification_g10_test_kit/multi_patient_api_stu2.rb +12 -7
- data/lib/onc_certification_g10_test_kit/onc_program_procedure.yml +448 -468
- data/lib/onc_certification_g10_test_kit/short_id_map.yml +227 -17
- data/lib/onc_certification_g10_test_kit/single_patient_api_group.rb +6 -1
- data/lib/onc_certification_g10_test_kit/single_patient_us_core_4_api_group.rb +6 -1
- data/lib/onc_certification_g10_test_kit/single_patient_us_core_6_api_group.rb +8 -5
- data/lib/onc_certification_g10_test_kit/smart_app_launch_invalid_aud_group.rb +16 -17
- data/lib/onc_certification_g10_test_kit/smart_asymmetric_launch_group.rb +194 -0
- data/lib/onc_certification_g10_test_kit/smart_ehr_patient_launch_group.rb +2 -4
- data/lib/onc_certification_g10_test_kit/smart_ehr_patient_launch_group_stu2.rb +7 -6
- data/lib/onc_certification_g10_test_kit/smart_ehr_practitioner_app_group.rb +23 -7
- data/lib/onc_certification_g10_test_kit/smart_fine_grained_scopes_group.rb +188 -0
- data/lib/onc_certification_g10_test_kit/smart_granular_scope_selection_group.rb +150 -0
- data/lib/onc_certification_g10_test_kit/smart_granular_scope_selection_test.rb +53 -0
- data/lib/onc_certification_g10_test_kit/smart_invalid_pkce_group.rb +6 -7
- data/lib/onc_certification_g10_test_kit/smart_invalid_token_group.rb +8 -10
- data/lib/onc_certification_g10_test_kit/smart_invalid_token_group_stu2.rb +7 -9
- data/lib/onc_certification_g10_test_kit/smart_limited_app_group.rb +5 -3
- data/lib/onc_certification_g10_test_kit/smart_public_standalone_launch_group.rb +14 -16
- data/lib/onc_certification_g10_test_kit/smart_public_standalone_launch_group_stu2.rb +28 -4
- data/lib/onc_certification_g10_test_kit/smart_scopes_test.rb +34 -25
- data/lib/onc_certification_g10_test_kit/smart_standalone_patient_app_group.rb +20 -9
- data/lib/onc_certification_g10_test_kit/smart_v1_scopes_group.rb +241 -0
- data/lib/onc_certification_g10_test_kit/tasks/generate_matrix.rb +75 -51
- data/lib/onc_certification_g10_test_kit/token_introspection_group.rb +110 -0
- data/lib/onc_certification_g10_test_kit/token_revocation_group.rb +1 -1
- data/lib/onc_certification_g10_test_kit/version.rb +1 -1
- data/lib/onc_certification_g10_test_kit/visual_inspection_and_attestations_group.rb +57 -37
- data/lib/onc_certification_g10_test_kit.rb +84 -18
- metadata +13 -6
@@ -1,7 +1,7 @@
|
|
1
1
|
module ONCCertificationG10TestKit
|
2
2
|
class SMARTPublicStandaloneLaunchGroupSTU2 < SMARTAppLaunch::StandaloneLaunchGroupSTU2
|
3
|
-
title '
|
4
|
-
short_title '
|
3
|
+
title 'Public Client Standalone Launch with OpenID Connect'
|
4
|
+
short_title 'Public Client Launch'
|
5
5
|
input_instructions %(
|
6
6
|
Register Inferno as a standalone application using the following information:
|
7
7
|
|
@@ -12,6 +12,27 @@ module ONCCertificationG10TestKit
|
|
12
12
|
fhirUser), refresh tokens (offline_access), and patient context
|
13
13
|
(launch/patient) are required.
|
14
14
|
)
|
15
|
+
description %(
|
16
|
+
|
17
|
+
This scenario verifies the ability of systems to support public clients
|
18
|
+
as described in the SMART App Launch implementation specification. Previous
|
19
|
+
scenarios have not required the system under test to demonstrate this
|
20
|
+
specific type of SMART App Launch client.
|
21
|
+
|
22
|
+
Prior to executing this test, register Inferno as a public standalone
|
23
|
+
application using the following information:
|
24
|
+
|
25
|
+
* Redirect URI: `#{SMARTAppLaunch::AppRedirectTest.config.options[:redirect_uri]}`
|
26
|
+
|
27
|
+
Inferno will act as a public client redirect the tester to the the
|
28
|
+
authorization endpoint so that they may provide any required credentials
|
29
|
+
and authorize the application. Upon successful authorization, Inferno will
|
30
|
+
exchange the authorization code provided for an access token.
|
31
|
+
|
32
|
+
For more information on the #{title}:
|
33
|
+
|
34
|
+
* [Standalone Launch Sequence](http://hl7.org/fhir/smart-app-launch/1.0.0/index.html#standalone-launch-sequence)
|
35
|
+
)
|
15
36
|
id :g10_public_standalone_launch_stu2
|
16
37
|
run_as_group
|
17
38
|
|
@@ -106,8 +127,7 @@ module ONCCertificationG10TestKit
|
|
106
127
|
:smart_authorization_url,
|
107
128
|
:smart_token_url,
|
108
129
|
:authorization_method,
|
109
|
-
:public_client_auth_type
|
110
|
-
:client_auth_encryption_method
|
130
|
+
:public_client_auth_type
|
111
131
|
|
112
132
|
test from: :g10_patient_context,
|
113
133
|
config: {
|
@@ -134,5 +154,9 @@ module ONCCertificationG10TestKit
|
|
134
154
|
assert id_token.present?, 'Token response did not provide an id_token as required.'
|
135
155
|
end
|
136
156
|
end
|
157
|
+
|
158
|
+
children.each do |child|
|
159
|
+
child.inputs.delete(:client_auth_encryption_method)
|
160
|
+
end
|
137
161
|
end
|
138
162
|
end
|
@@ -69,6 +69,8 @@ module ONCCertificationG10TestKit
|
|
69
69
|
V6_PATIENT_COMPARTMENT_RESOURCE_TYPES =
|
70
70
|
(V5_PATIENT_COMPARTMENT_RESOURCE_TYPES + ['Coverage', 'MedicationDispense', 'Specimen']).freeze
|
71
71
|
|
72
|
+
attr_accessor :received_or_requested
|
73
|
+
|
72
74
|
def patient_compartment_resource_types
|
73
75
|
return V5_PATIENT_COMPARTMENT_RESOURCE_TYPES if using_us_core_5?
|
74
76
|
|
@@ -94,36 +96,43 @@ module ONCCertificationG10TestKit
|
|
94
96
|
end
|
95
97
|
|
96
98
|
def scope_version
|
97
|
-
|
99
|
+
case received_or_requested
|
100
|
+
when 'received'
|
101
|
+
config.options[:received_scope_version] || config.options[:scope_version]
|
102
|
+
when 'requested'
|
103
|
+
config.options[:requested_scope_version] || config.options[:scope_version]
|
104
|
+
else
|
105
|
+
config.options[:scope_version]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def requested_scope_version
|
110
|
+
config.options[:requested_scope_version]
|
98
111
|
end
|
99
112
|
|
100
113
|
def read_format
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
[v1_read_format, v2_read_format, '*'].join(' | ')
|
113
|
-
end
|
114
|
-
end
|
114
|
+
v1_read_format = 'read'
|
115
|
+
v2_read_format = 'c?ru?d?s?'
|
116
|
+
|
117
|
+
case scope_version
|
118
|
+
when :v1
|
119
|
+
"#{v1_read_format} | *"
|
120
|
+
when :v2
|
121
|
+
"#{v2_read_format} | *"
|
122
|
+
else
|
123
|
+
[v1_read_format, v2_read_format, '*'].join(' | ')
|
124
|
+
end
|
115
125
|
end
|
116
126
|
|
117
127
|
def access_level_regex
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
end
|
128
|
+
case scope_version
|
129
|
+
when :v1
|
130
|
+
/\A(\*|read)\b/
|
131
|
+
when :v2
|
132
|
+
/\A(\*|c?ru?d?s?)\b/
|
133
|
+
else
|
134
|
+
/\A(\*|read|c?ru?d?s?)\b/
|
135
|
+
end
|
127
136
|
end
|
128
137
|
|
129
138
|
def bad_format_message(scope, scope_direction = 'Requested')
|
@@ -229,7 +238,7 @@ module ONCCertificationG10TestKit
|
|
229
238
|
}
|
230
239
|
].each do |metadata|
|
231
240
|
scopes = metadata[:scopes].split
|
232
|
-
received_or_requested = metadata[:received_or_requested]
|
241
|
+
self.received_or_requested = metadata[:received_or_requested]
|
233
242
|
|
234
243
|
missing_scopes = required_scopes - scopes
|
235
244
|
assert missing_scopes.empty?,
|
@@ -24,16 +24,25 @@ module ONCCertificationG10TestKit
|
|
24
24
|
)
|
25
25
|
|
26
26
|
description %(
|
27
|
-
This scenario
|
27
|
+
This scenario verifies the ability of a system to perform a single
|
28
|
+
SMART App Launch. Specifically, this scenario performs a Patient
|
28
29
|
Standalone Launch to a SMART on FHIR confidential client with a patient
|
29
30
|
context, refresh token, OpenID Connect (OIDC) identity token, and use
|
30
|
-
the GET HTTP method for code exchange.
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
31
|
+
the GET HTTP method for code exchange.
|
32
|
+
|
33
|
+
After launch, a simple Patient resource read is performed on the patient
|
34
|
+
in context. The access token is then refreshed, and the Patient resource
|
35
|
+
is read using the new access token to ensure that the refresh was
|
36
|
+
successful. The authentication information provided by OpenID Connect is
|
37
|
+
decoded and validated, and simple queries are performed to ensure that
|
38
|
+
access is granted to all USCDI data elements.
|
39
|
+
|
40
|
+
Prior to running the scenario, register Inferno as a confidential client
|
41
|
+
with the following information:
|
42
|
+
|
43
|
+
* Redirect URI: `#{SMARTAppLaunch::AppRedirectTest.config.options[:redirect_uri]}`
|
44
|
+
|
45
|
+
The following implementation specifications are relevant to this scenario:
|
37
46
|
|
38
47
|
* [SMART on FHIR
|
39
48
|
(STU1)](http://www.hl7.org/fhir/smart-app-launch/1.0.0/)
|
@@ -93,12 +102,14 @@ module ONCCertificationG10TestKit
|
|
93
102
|
'launch-standalone',
|
94
103
|
'client-public',
|
95
104
|
'client-confidential-symmetric',
|
105
|
+
'client-confidential-asymmetric',
|
96
106
|
'sso-openid-connect',
|
97
107
|
'context-standalone-patient',
|
98
108
|
'permission-offline',
|
99
109
|
'permission-patient',
|
100
110
|
'authorize-post',
|
101
|
-
'permission-v2'
|
111
|
+
'permission-v2',
|
112
|
+
'permission-v1'
|
102
113
|
]
|
103
114
|
}
|
104
115
|
}
|
@@ -0,0 +1,241 @@
|
|
1
|
+
require_relative 'base_token_refresh_group'
|
2
|
+
require_relative 'patient_context_test'
|
3
|
+
require_relative 'smart_invalid_token_refresh_test'
|
4
|
+
require_relative 'smart_scopes_test'
|
5
|
+
require_relative 'unauthorized_access_test'
|
6
|
+
require_relative 'unrestricted_resource_type_access_group'
|
7
|
+
require_relative 'well_known_capabilities_test'
|
8
|
+
require_relative 'incorrectly_permitted_tls_versions_messages_setup_test'
|
9
|
+
|
10
|
+
module ONCCertificationG10TestKit
|
11
|
+
class SmartV1ScopesGroup < Inferno::TestGroup
|
12
|
+
title 'App Launch with SMART v1 scopes'
|
13
|
+
short_title 'Launch with v1 Scopes'
|
14
|
+
|
15
|
+
input_instructions %(
|
16
|
+
Register Inferno as a standalone application using the following information:
|
17
|
+
|
18
|
+
* Redirect URI: `#{SMARTAppLaunch::AppRedirectTest.config.options[:redirect_uri]}`
|
19
|
+
|
20
|
+
Enter in the appropriate v1 scopes to enable patient-level access to all
|
21
|
+
relevant resources. In addition, support for the OpenID Connect (openid
|
22
|
+
fhirUser), refresh tokens (offline_access), and patient context
|
23
|
+
(launch/patient) are required.
|
24
|
+
)
|
25
|
+
|
26
|
+
description %(
|
27
|
+
This scenario verifies the ability of a system to support a
|
28
|
+
Standalone Launch when v1 scopes are requested by the client.
|
29
|
+
It verifies that systems implement the `permission-v1` capability as required.
|
30
|
+
Previous scenarios focus on the use of the `permission-v2` capability,
|
31
|
+
and thus a dedicated launch is required to verify that systems
|
32
|
+
can support a client that requests `permission-v1` style scopes.
|
33
|
+
|
34
|
+
This scenario does not place any constraints on the form of scopes
|
35
|
+
granted. Systems are free to grant v1-style scopes in response to the
|
36
|
+
request for v1-style scopes, as recommended in the [SMART App Launch Guide STU2](http://hl7.org/fhir/smart-app-launch/scopes-and-launch-context.html#scopes-for-requesting-fhir-resources).
|
37
|
+
Or they can upgrade them to v2-style scopes. The scenario only ensures
|
38
|
+
that systems can grant access to clients that request v1-style scopes
|
39
|
+
and that the client has access to resources as expected.
|
40
|
+
|
41
|
+
All relevant resource types must be granted, in a similar manner to the
|
42
|
+
'Standalone Patient App' scenario.
|
43
|
+
|
44
|
+
This scenario expects Inferno to be registered as a 'Confidential
|
45
|
+
Symmetric' client. Systems may either reuse a `client_id` associated
|
46
|
+
with Inferno used in a previous scenario, or register Inferno with a new
|
47
|
+
`client_id` as a standalone client with the following information:
|
48
|
+
|
49
|
+
* Redirect URI: `#{SMARTAppLaunch::AppRedirectTest.config.options[:redirect_uri]}`
|
50
|
+
|
51
|
+
)
|
52
|
+
|
53
|
+
id :g10_smart_v1_scopes
|
54
|
+
run_as_group
|
55
|
+
|
56
|
+
config(
|
57
|
+
inputs: {
|
58
|
+
client_secret: {
|
59
|
+
optional: false,
|
60
|
+
name: :standalone_client_secret
|
61
|
+
},
|
62
|
+
requested_scopes: {
|
63
|
+
name: :v1_requested_scopes,
|
64
|
+
default: %(
|
65
|
+
launch/patient openid fhirUser offline_access
|
66
|
+
patient/Medication.read patient/AllergyIntolerance.read
|
67
|
+
patient/CarePlan.read patient/CareTeam.read patient/Condition.read
|
68
|
+
patient/Device.read patient/DiagnosticReport.read
|
69
|
+
patient/DocumentReference.read patient/Encounter.read
|
70
|
+
patient/Goal.read patient/Immunization.read patient/Location.read
|
71
|
+
patient/MedicationRequest.read patient/Observation.read
|
72
|
+
patient/Organization.read patient/Patient.read
|
73
|
+
patient/Practitioner.read patient/Procedure.read
|
74
|
+
patient/Provenance.read patient/PractitionerRole.read
|
75
|
+
patient/Specimen.read patient/Coverage.read
|
76
|
+
patient/MedicationDispense.read patient/ServiceRequest.read
|
77
|
+
).gsub(/\s{2,}/, ' ').strip
|
78
|
+
},
|
79
|
+
received_scopes: { name: :v1_received_scopes },
|
80
|
+
smart_credentials: { name: :v1_smart_credentials }
|
81
|
+
},
|
82
|
+
outputs: {
|
83
|
+
received_scopes: { name: :v1_received_scopes },
|
84
|
+
patient_id: { name: :v1_patient_id }
|
85
|
+
}
|
86
|
+
)
|
87
|
+
|
88
|
+
input_order :url,
|
89
|
+
:standalone_client_id,
|
90
|
+
:standalone_client_secret,
|
91
|
+
:v1_requested_scopes,
|
92
|
+
:use_pkce,
|
93
|
+
:pkce_code_challenge_method,
|
94
|
+
:standalone_authorization_method,
|
95
|
+
:client_auth_type,
|
96
|
+
:client_auth_encryption_method
|
97
|
+
|
98
|
+
group from: :smart_discovery_stu2 do
|
99
|
+
test from: 'g10_smart_well_known_capabilities',
|
100
|
+
config: {
|
101
|
+
options: {
|
102
|
+
required_capabilities: [
|
103
|
+
'launch-standalone',
|
104
|
+
'client-public',
|
105
|
+
'client-confidential-symmetric',
|
106
|
+
'client-confidential-asymmetric',
|
107
|
+
'sso-openid-connect',
|
108
|
+
'context-standalone-patient',
|
109
|
+
'permission-offline',
|
110
|
+
'permission-patient',
|
111
|
+
'authorize-post',
|
112
|
+
'permission-v2',
|
113
|
+
'permission-v1'
|
114
|
+
]
|
115
|
+
}
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
group from: :smart_standalone_launch_stu2,
|
120
|
+
config: {
|
121
|
+
inputs: {
|
122
|
+
use_pkce: {
|
123
|
+
default: 'true',
|
124
|
+
locked: true
|
125
|
+
},
|
126
|
+
pkce_code_challenge_method: {
|
127
|
+
locked: true
|
128
|
+
},
|
129
|
+
authorization_method: {
|
130
|
+
name: :standalone_authorization_method,
|
131
|
+
default: 'get',
|
132
|
+
locked: true
|
133
|
+
},
|
134
|
+
client_auth_type: {
|
135
|
+
locked: true,
|
136
|
+
default: 'confidential_symmetric'
|
137
|
+
}
|
138
|
+
},
|
139
|
+
outputs: {
|
140
|
+
smart_credentials: { name: :v1_smart_credentials }
|
141
|
+
}
|
142
|
+
} do
|
143
|
+
title 'Standalone Launch With Patient Scope'
|
144
|
+
description %(
|
145
|
+
# Background
|
146
|
+
|
147
|
+
The [Standalone
|
148
|
+
Launch Sequence](http://hl7.org/fhir/smart-app-launch/STU2/app-launch.html#launch-app-standalone-launch)
|
149
|
+
allows an app, like Inferno, to be launched independent of an
|
150
|
+
existing EHR session. It is one of the two launch methods described in
|
151
|
+
the SMART App Launch Framework alongside EHR Launch. The app will
|
152
|
+
request authorization for the provided scope from the authorization
|
153
|
+
endpoint, ultimately receiving an authorization token which can be used
|
154
|
+
to gain access to resources on the FHIR server.
|
155
|
+
|
156
|
+
# Test Methodology
|
157
|
+
|
158
|
+
Inferno will redirect the user to the the authorization endpoint so that
|
159
|
+
they may provide any required credentials and authorize the application.
|
160
|
+
Upon successful authorization, Inferno will exchange the authorization
|
161
|
+
code provided for an access token.
|
162
|
+
|
163
|
+
For more information on the #{title}:
|
164
|
+
|
165
|
+
* [Standalone Launch
|
166
|
+
Sequence](http://hl7.org/fhir/smart-app-launch/STU2/app-launch.html#launch-app-standalone-launch)
|
167
|
+
)
|
168
|
+
|
169
|
+
test from: :g10_smart_scopes do
|
170
|
+
config(
|
171
|
+
options: {
|
172
|
+
requested_scope_version: :v1,
|
173
|
+
received_scope_version: :any,
|
174
|
+
required_scope_type: 'patient',
|
175
|
+
required_scopes: ['openid', 'fhirUser', 'launch/patient', 'offline_access']
|
176
|
+
}
|
177
|
+
)
|
178
|
+
end
|
179
|
+
|
180
|
+
test from: :g10_unauthorized_access,
|
181
|
+
config: {
|
182
|
+
inputs: {
|
183
|
+
patient_id: { name: :v1_patient_id }
|
184
|
+
}
|
185
|
+
}
|
186
|
+
|
187
|
+
test from: :g10_patient_context,
|
188
|
+
config: {
|
189
|
+
inputs: {
|
190
|
+
patient_id: { name: :v1_patient_id },
|
191
|
+
smart_credentials: { name: :v1_smart_credentials }
|
192
|
+
}
|
193
|
+
}
|
194
|
+
|
195
|
+
tests[0].config(
|
196
|
+
outputs: {
|
197
|
+
incorrectly_permitted_tls_versions_messages: {
|
198
|
+
name: :auth_incorrectly_permitted_tls_versions_messages
|
199
|
+
}
|
200
|
+
}
|
201
|
+
)
|
202
|
+
|
203
|
+
tests[3].config(
|
204
|
+
outputs: {
|
205
|
+
incorrectly_permitted_tls_versions_messages: {
|
206
|
+
name: :token_incorrectly_permitted_tls_versions_messages
|
207
|
+
}
|
208
|
+
}
|
209
|
+
)
|
210
|
+
end
|
211
|
+
|
212
|
+
group from: :g10_unrestricted_resource_type_access,
|
213
|
+
config: {
|
214
|
+
inputs: {
|
215
|
+
received_scopes: { name: :v1_received_scopes },
|
216
|
+
patient_id: { name: :v1_patient_id },
|
217
|
+
smart_credentials: { name: :v1_smart_credentials }
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|
221
|
+
test from: :g10_incorrectly_permitted_tls_versions_messages_setup,
|
222
|
+
id: :g10_auth_incorrectly_permitted_tls_versions_messages_setup,
|
223
|
+
config: {
|
224
|
+
inputs: {
|
225
|
+
incorrectly_permitted_tls_versions_messages: {
|
226
|
+
name: :auth_incorrectly_permitted_tls_versions_messages
|
227
|
+
}
|
228
|
+
}
|
229
|
+
}
|
230
|
+
|
231
|
+
test from: :g10_incorrectly_permitted_tls_versions_messages_setup,
|
232
|
+
id: :g10_token_incorrectly_permitted_tls_versions_messages_setup,
|
233
|
+
config: {
|
234
|
+
inputs: {
|
235
|
+
incorrectly_permitted_tls_versions_messages: {
|
236
|
+
name: :token_incorrectly_permitted_tls_versions_messages
|
237
|
+
}
|
238
|
+
}
|
239
|
+
}
|
240
|
+
end
|
241
|
+
end
|
@@ -9,6 +9,8 @@ module ONCCertificationG10TestKit
|
|
9
9
|
class GenerateMatrix
|
10
10
|
include ONCCertificationG10TestKit
|
11
11
|
|
12
|
+
attr_accessor :row
|
13
|
+
|
12
14
|
FILE_NAME = 'onc_certification_g10_matrix.xlsx'.freeze
|
13
15
|
|
14
16
|
def inferno_to_procedure_map
|
@@ -35,6 +37,10 @@ module ONCCertificationG10TestKit
|
|
35
37
|
@workbook ||= RubyXL::Workbook.new
|
36
38
|
end
|
37
39
|
|
40
|
+
def next_row
|
41
|
+
self.row += 1
|
42
|
+
end
|
43
|
+
|
38
44
|
def run
|
39
45
|
generate_matrix_worksheet
|
40
46
|
generate_test_procedure_worksheet
|
@@ -44,6 +50,10 @@ module ONCCertificationG10TestKit
|
|
44
50
|
workbook.write(FILE_NAME)
|
45
51
|
end
|
46
52
|
|
53
|
+
def all_descendant_tests(runnable)
|
54
|
+
runnable.tests + runnable.groups.flat_map { |group| all_descendant_tests(group) }
|
55
|
+
end
|
56
|
+
|
47
57
|
def generate_matrix_worksheet # rubocop:disable Metrics/CyclomaticComplexity
|
48
58
|
matrix_worksheet = workbook.worksheets[0]
|
49
59
|
matrix_worksheet.sheet_name = 'Matrix'
|
@@ -64,11 +74,15 @@ module ONCCertificationG10TestKit
|
|
64
74
|
next if group.short_id == '6' # Skip US Core 5
|
65
75
|
|
66
76
|
matrix_worksheet.add_cell(1, col, group.title).change_text_wrap(true)
|
67
|
-
matrix_worksheet.merge_cells(1, col, 1, col + group.groups.length - 1)
|
77
|
+
matrix_worksheet.merge_cells(1, col, 1, col + group.groups.length - 1) if group.groups.length.positive?
|
68
78
|
matrix_worksheet.change_column_border(col, :left, 'medium')
|
69
79
|
matrix_worksheet.change_column_border_color(col, :left, '000000')
|
70
80
|
column_borders << col
|
71
81
|
|
82
|
+
group.tests.each do |test|
|
83
|
+
column_map[test.short_id] = col
|
84
|
+
end
|
85
|
+
|
72
86
|
group.groups.each do |test_case|
|
73
87
|
matrix_worksheet.change_column_width(col, 4.2)
|
74
88
|
|
@@ -80,11 +94,7 @@ module ONCCertificationG10TestKit
|
|
80
94
|
matrix_worksheet.change_column_border(col, :right, 'thin')
|
81
95
|
matrix_worksheet.change_column_border_color(col, :right, '666666')
|
82
96
|
|
83
|
-
test_case.
|
84
|
-
# tests << { test_case: test_case, test: test }
|
85
|
-
# full_test_id = "#{test_case.prefix}#{test.id}"
|
86
|
-
column_map[test.short_id] = col
|
87
|
-
end
|
97
|
+
all_descendant_tests(test_case).each { |test| column_map[test.short_id] = col }
|
88
98
|
col += 1
|
89
99
|
end
|
90
100
|
end
|
@@ -94,7 +104,7 @@ module ONCCertificationG10TestKit
|
|
94
104
|
matrix_worksheet.change_row_horizontal_alignment(0, 'center')
|
95
105
|
|
96
106
|
matrix_worksheet.add_cell(2, total_width + 2, 'Supported?')
|
97
|
-
row = 3
|
107
|
+
self.row = 3
|
98
108
|
|
99
109
|
test_procedure.sections.each do |section|
|
100
110
|
section.steps.each do |step|
|
@@ -120,7 +130,7 @@ module ONCCertificationG10TestKit
|
|
120
130
|
|
121
131
|
matrix_worksheet.add_cell(row, total_width + 2, step.inferno_supported.upcase)
|
122
132
|
|
123
|
-
|
133
|
+
next_row
|
124
134
|
end
|
125
135
|
end
|
126
136
|
matrix_worksheet.change_column_horizontal_alignment(1, 'right')
|
@@ -161,14 +171,14 @@ module ONCCertificationG10TestKit
|
|
161
171
|
'Inferno Notes',
|
162
172
|
'Alternate Test Methodology'].each_with_index { |text, index| tp_worksheet.add_cell(0, index, text) }
|
163
173
|
|
164
|
-
row = 2
|
174
|
+
self.row = 2
|
165
175
|
|
166
176
|
test_procedure.sections.each do |section|
|
167
177
|
tp_worksheet.add_cell(row, 0, section.name)
|
168
|
-
|
178
|
+
next_row
|
169
179
|
section.steps.group_by(&:group).each do |group_name, steps|
|
170
180
|
tp_worksheet.add_cell(row, 1, group_name)
|
171
|
-
|
181
|
+
next_row
|
172
182
|
steps.each do |step|
|
173
183
|
longest_line = [step.s_u_t, step.t_l_v, step.inferno_notes, step.alternate_test].map do |text|
|
174
184
|
text&.lines&.count || 0
|
@@ -183,10 +193,10 @@ module ONCCertificationG10TestKit
|
|
183
193
|
tp_worksheet.add_cell(row, 7, step.inferno_tests.join(', ')).change_text_wrap(true)
|
184
194
|
tp_worksheet.add_cell(row, 8, step.inferno_notes).change_text_wrap(true)
|
185
195
|
tp_worksheet.add_cell(row, 9, step.alternate_test).change_text_wrap(true)
|
186
|
-
|
196
|
+
next_row
|
187
197
|
end
|
188
198
|
end
|
189
|
-
|
199
|
+
next_row
|
190
200
|
end
|
191
201
|
end
|
192
202
|
|
@@ -198,61 +208,75 @@ module ONCCertificationG10TestKit
|
|
198
208
|
runnable_and_parents.map(&:suite_option_requirements).compact.flatten
|
199
209
|
end
|
200
210
|
|
201
|
-
def
|
202
|
-
workbook.
|
203
|
-
|
211
|
+
def inferno_worksheet
|
212
|
+
workbook.worksheets[2]
|
213
|
+
end
|
204
214
|
|
205
|
-
|
215
|
+
def columns # rubocop:disable Metrics/CyclomaticComplexity
|
216
|
+
@columns ||= [
|
206
217
|
['', 3, ->(_test) { '' }],
|
207
218
|
['', 3, ->(_test) { '' }],
|
208
219
|
['Inferno Test ID', 22, ->(test) { test.short_id.to_s }],
|
209
220
|
['Inferno Test Name', 65, ->(test) { test.title }],
|
210
221
|
['Inferno Test Description', 65, lambda do |test|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
222
|
+
description = test.description || ''
|
223
|
+
natural_indent =
|
224
|
+
description
|
225
|
+
.lines
|
226
|
+
.collect { |l| l.index(/[^ ]/) }
|
227
|
+
.select { |l| !l.nil? && l.positive? }
|
228
|
+
.min || 0
|
229
|
+
description.lines.map { |l| l[natural_indent..] || "\n" }.join.strip
|
230
|
+
end],
|
220
231
|
['Test Procedure Steps', 30, ->(test) { inferno_to_procedure_map[test.short_id].join(', ') }],
|
221
232
|
['Standard Version Filter', 30, lambda do |test|
|
222
|
-
|
223
|
-
|
224
|
-
|
233
|
+
applicable_options(test).map(&:value).uniq.join(', ')
|
234
|
+
end]
|
225
235
|
]
|
236
|
+
end
|
237
|
+
|
238
|
+
def add_test(test)
|
239
|
+
this_row = columns.map do |column|
|
240
|
+
column[2].call(test)
|
241
|
+
end
|
242
|
+
|
243
|
+
this_row.each_with_index do |value, index|
|
244
|
+
inferno_worksheet.add_cell(row, index, value).change_text_wrap(true)
|
245
|
+
end
|
246
|
+
inferno_worksheet
|
247
|
+
.change_row_height(row, [26, ((test.description || '').strip.lines.count * 10) + 10].max)
|
248
|
+
inferno_worksheet.change_row_vertical_alignment(row, 'top')
|
249
|
+
next_row
|
250
|
+
end
|
251
|
+
|
252
|
+
def add_group_title(group, column: 1)
|
253
|
+
inferno_worksheet.add_cell(row, column, "#{group.short_id}: #{group.title}")
|
254
|
+
inferno_worksheet.add_cell(row, 6, applicable_options(group).map(&:value).uniq.join(', '))
|
255
|
+
next_row
|
256
|
+
end
|
257
|
+
|
258
|
+
def add_group(group)
|
259
|
+
add_group_title(group)
|
260
|
+
|
261
|
+
group.tests.each { |test| add_test(test) }
|
262
|
+
|
263
|
+
group.groups.each { |nested_group| add_group(nested_group) }
|
264
|
+
end
|
265
|
+
|
266
|
+
def generate_inferno_test_worksheet
|
267
|
+
workbook.add_worksheet('Inferno Tests')
|
226
268
|
|
227
269
|
columns.each_with_index do |row_name, index|
|
228
270
|
inferno_worksheet.add_cell(0, index, row_name.first)
|
229
271
|
end
|
230
272
|
|
231
|
-
row = 1
|
273
|
+
self.row = 1
|
232
274
|
|
233
275
|
test_suite.groups.each do |group|
|
234
|
-
|
235
|
-
inferno_worksheet.add_cell(row, 0, "#{group.short_id}: #{group.title}")
|
236
|
-
inferno_worksheet.add_cell(row, 6, applicable_options(group).map(&:value).uniq.join(', '))
|
237
|
-
row += 1
|
238
|
-
group.groups.each do |test_case|
|
239
|
-
inferno_worksheet.add_cell(row, 1, "#{test_case.short_id}: #{test_case.title}")
|
240
|
-
inferno_worksheet.add_cell(row, 6, applicable_options(test_case).map(&:value).uniq.join(', '))
|
241
|
-
|
242
|
-
row += 1
|
243
|
-
test_case.tests.each do |test|
|
244
|
-
this_row = columns.map do |column|
|
245
|
-
column[2].call(test)
|
246
|
-
end
|
276
|
+
next if group.short_id == '6' # Skip US Core 5
|
247
277
|
|
248
|
-
|
249
|
-
|
250
|
-
end
|
251
|
-
inferno_worksheet.change_row_height(row, [26, ((test.description || '').strip.lines.count * 10) + 10].max)
|
252
|
-
inferno_worksheet.change_row_vertical_alignment(row, 'top')
|
253
|
-
row += 1
|
254
|
-
end
|
255
|
-
end
|
278
|
+
next_row
|
279
|
+
add_group(group)
|
256
280
|
end
|
257
281
|
|
258
282
|
columns.each_with_index do |column, index|
|