davinci_plan_net_test_kit 0.10.0 → 0.11.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.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/config/presets/plan_net_reference_server_v110_preset.json +50 -0
  3. data/lib/davinci_plan_net_test_kit/custom_groups/reverse_chain_tests/examples.md +17 -0
  4. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/davinci_plan_net_test_suite.rb +5 -2
  5. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/endpoint/endpoint_forward_chain_organization_address_search_test.rb +1 -1
  6. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/endpoint/endpoint_forward_chain_organization_name_search_test.rb +1 -1
  7. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/endpoint/endpoint_forward_chain_organization_partof_search_test.rb +1 -1
  8. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/endpoint/endpoint_forward_chain_organization_type_search_test.rb +1 -1
  9. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/endpoint/metadata.yml +4 -4
  10. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/endpoint_group.rb +4 -4
  11. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_endpoint_organization_search_test.rb +1 -1
  12. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_location_address_city_search_test.rb +1 -1
  13. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_location_address_postalcode_search_test.rb +1 -1
  14. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_location_address_search_test.rb +1 -1
  15. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_location_address_state_search_test.rb +1 -1
  16. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_location_organization_search_test.rb +1 -1
  17. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_location_type_search_test.rb +1 -1
  18. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_organization_address_search_test.rb +1 -1
  19. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_organization_name_search_test.rb +1 -1
  20. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_organization_partof_search_test.rb +1 -1
  21. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/healthcare_service_forward_chain_organization_type_search_test.rb +1 -1
  22. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service/metadata.yml +11 -11
  23. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/healthcare_service_group.rb +11 -11
  24. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/insurance_plan/insurance_plan_forward_chain_administered_by_name_search_test.rb +1 -1
  25. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/insurance_plan/insurance_plan_forward_chain_administered_by_partof_search_test.rb +1 -1
  26. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/insurance_plan/insurance_plan_forward_chain_owned_by_name_search_test.rb +1 -1
  27. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/insurance_plan/insurance_plan_forward_chain_owned_by_partof_search_test.rb +1 -1
  28. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/insurance_plan/metadata.yml +4 -4
  29. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/insurance_plan_group.rb +4 -4
  30. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/location_forward_chain_endpoint_organization_search_test.rb +1 -1
  31. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/location_forward_chain_organization_address_search_test.rb +1 -1
  32. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/location_forward_chain_organization_name_search_test.rb +1 -1
  33. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/location_forward_chain_organization_partof_search_test.rb +1 -1
  34. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/location_forward_chain_organization_type_search_test.rb +1 -1
  35. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/location_forward_chain_partof_address_search_test.rb +1 -1
  36. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/location_forward_chain_partof_organization_search_test.rb +1 -1
  37. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/location_forward_chain_partof_type_search_test.rb +1 -1
  38. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location/metadata.yml +8 -8
  39. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/location_group.rb +8 -8
  40. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/metadata.yml +6 -6
  41. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/network/metadata.yml +4 -4
  42. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/network/network_forward_chain_endpoint_organization_search_test.rb +1 -1
  43. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/network/network_forward_chain_partof_address_search_test.rb +1 -1
  44. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/network/network_forward_chain_partof_name_search_test.rb +1 -1
  45. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/network/network_forward_chain_partof_type_search_test.rb +1 -1
  46. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/network_group.rb +4 -4
  47. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/metadata.yml +20 -20
  48. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_endpoint_organization_search_test.rb +1 -1
  49. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_location_address_city_search_test.rb +1 -1
  50. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_location_address_postalcode_search_test.rb +1 -1
  51. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_location_address_search_test.rb +1 -1
  52. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_location_address_state_search_test.rb +1 -1
  53. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_location_organization_search_test.rb +1 -1
  54. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_location_type_search_test.rb +1 -1
  55. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_network_name_search_test.rb +1 -1
  56. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_network_partof_search_test.rb +1 -1
  57. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_participating_organization_address_search_test.rb +1 -1
  58. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_participating_organization_name_search_test.rb +1 -1
  59. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_participating_organization_partof_search_test.rb +1 -1
  60. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_participating_organization_type_search_test.rb +1 -1
  61. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_primary_organization_address_search_test.rb +1 -1
  62. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_primary_organization_name_search_test.rb +1 -1
  63. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_primary_organization_partof_search_test.rb +1 -1
  64. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_primary_organization_type_search_test.rb +1 -1
  65. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_service_location_search_test.rb +1 -1
  66. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_service_organization_search_test.rb +1 -1
  67. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil/org_affil_forward_chain_service_service_category_search_test.rb +1 -1
  68. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/org_affil_group.rb +20 -20
  69. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/organization/metadata.yml +4 -4
  70. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/organization/organization_forward_chain_endpoint_organization_search_test.rb +1 -1
  71. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/organization/organization_forward_chain_partof_address_search_test.rb +1 -1
  72. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/organization/organization_forward_chain_partof_name_search_test.rb +1 -1
  73. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/organization/organization_forward_chain_partof_type_search_test.rb +1 -1
  74. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/organization_group.rb +4 -4
  75. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/metadata.yml +25 -25
  76. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_endpoint_organization_search_test.rb +1 -1
  77. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_location_address_city_search_test.rb +1 -1
  78. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_location_address_postalcode_search_test.rb +1 -1
  79. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_location_address_search_test.rb +1 -1
  80. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_location_address_state_search_test.rb +1 -1
  81. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_location_organization_search_test.rb +1 -1
  82. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_location_type_search_test.rb +1 -1
  83. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_network_address_search_test.rb +1 -1
  84. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_network_name_search_test.rb +1 -1
  85. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_network_partof_search_test.rb +1 -1
  86. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_network_type_search_test.rb +1 -1
  87. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_organization_address_search_test.rb +1 -1
  88. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_organization_name_search_test.rb +1 -1
  89. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_organization_partof_search_test.rb +1 -1
  90. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_organization_type_search_test.rb +1 -1
  91. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_practitioner_name_search_test.rb +1 -1
  92. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_service_location_search_test.rb +1 -1
  93. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_service_organization_search_test.rb +1 -1
  94. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role/practitioner_role_forward_chain_service_service_category_search_test.rb +1 -1
  95. data/lib/davinci_plan_net_test_kit/generated/v1.1.0/practitioner_role_group.rb +19 -19
  96. data/lib/davinci_plan_net_test_kit/generator/forward_chain_test_generator.rb +1 -1
  97. data/lib/davinci_plan_net_test_kit/generator/templates/combination_search_test.rb.erb +49 -0
  98. data/lib/davinci_plan_net_test_kit/generator/templates/forward_chain_test.rb.erb +51 -0
  99. data/lib/davinci_plan_net_test_kit/generator/templates/group.rb.erb +24 -0
  100. data/lib/davinci_plan_net_test_kit/generator/templates/include_search.rb.erb +48 -0
  101. data/lib/davinci_plan_net_test_kit/generator/templates/must_support.rb.erb +41 -0
  102. data/lib/davinci_plan_net_test_kit/generator/templates/read.rb.erb +26 -0
  103. data/lib/davinci_plan_net_test_kit/generator/templates/reference_resolution.rb.erb +42 -0
  104. data/lib/davinci_plan_net_test_kit/generator/templates/resource_list.rb.erb +9 -0
  105. data/lib/davinci_plan_net_test_kit/generator/templates/reverse_chain_search.rb.erb +57 -0
  106. data/lib/davinci_plan_net_test_kit/generator/templates/revinclude_search.rb.erb +55 -0
  107. data/lib/davinci_plan_net_test_kit/generator/templates/search.rb.erb +40 -0
  108. data/lib/davinci_plan_net_test_kit/generator/templates/search_no_params.rb.erb +45 -0
  109. data/lib/davinci_plan_net_test_kit/generator/templates/suite.rb.erb +222 -0
  110. data/lib/davinci_plan_net_test_kit/generator/templates/validation.rb.erb +31 -0
  111. data/lib/davinci_plan_net_test_kit/igs/Plan Net Requirements Interpretation.xlsx +0 -0
  112. data/lib/davinci_plan_net_test_kit/igs/README.md +21 -0
  113. data/lib/davinci_plan_net_test_kit/metadata.rb +64 -0
  114. data/lib/davinci_plan_net_test_kit/search_test.rb +12 -60
  115. data/lib/davinci_plan_net_test_kit/version.rb +2 -1
  116. data/lib/davinci_plan_net_test_kit.rb +1 -0
  117. metadata +30 -10
@@ -0,0 +1,40 @@
1
+ require_relative '../../../search_test'
2
+ require_relative '../../../generator/group_metadata'
3
+
4
+ module DaVinciPlanNetTestKit
5
+ module <%= module_name %>
6
+ class <%= class_name %> < Inferno::Test
7
+ include DaVinciPlanNetTestKit::SearchTest
8
+
9
+ title 'Server returns valid results for <%= resource_type %> search by <%= search_param_name_string %>'
10
+ description %(
11
+ <%= description %>
12
+ )
13
+
14
+ id :<%= test_id %><% if optional? %>
15
+ optional
16
+ <% end %><% if needs_resource_id? %>
17
+ input :<%= resource_type %>_ids,
18
+ title: '<%= resource_type %> IDs',
19
+ description: 'Comma separated list of <%= resource_type %> IDs that in sum contain all MUST SUPPORT elements'
20
+ <% end %>
21
+ def self.properties
22
+ @properties ||= SearchTestProperties.new(
23
+ <%= search_test_properties_string %>
24
+ )
25
+ end
26
+
27
+ def self.metadata
28
+ @metadata ||= Generator::GroupMetadata.new(YAML.load_file(File.join(__dir__, 'metadata.yml'), aliases: true))
29
+ end
30
+
31
+ def scratch_resources
32
+ scratch[:<%= profile_identifier %>_resources] ||= {}
33
+ end
34
+
35
+ run do
36
+ run_search_test
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,45 @@
1
+ require_relative '../../../search_test'
2
+ require_relative '../../../generator/group_metadata'
3
+
4
+ module DaVinciPlanNetTestKit
5
+ module <%= module_name %>
6
+ class <%= class_name %> < Inferno::Test
7
+ include DaVinciPlanNetTestKit::SearchTest
8
+
9
+ title 'Client can identify instances of <%= profile_name %> on the server'
10
+ description %(
11
+ <%= description %>
12
+ )
13
+
14
+ id :<%= test_id %><% if optional? %>
15
+ optional
16
+ <% end %>
17
+
18
+ input :<%= test_id %>_ids,
19
+ title: 'ids of <%= profile_name %> instances',
20
+ optional: true,
21
+ description: 'Required if parameterless searches are not being used for instance gathering.'
22
+ input :no_param_search
23
+ input :max_instances
24
+ input :max_pages
25
+
26
+ def self.properties
27
+ @properties ||= SearchTestProperties.new(
28
+ <%= search_test_properties_string %>
29
+ )
30
+ end
31
+
32
+ def self.metadata
33
+ @metadata ||= Generator::GroupMetadata.new(YAML.load_file(File.join(__dir__, 'metadata.yml'), aliases: true))
34
+ end
35
+
36
+ def scratch_resources
37
+ scratch[:<%= profile_identifier %>_resources] ||= {}
38
+ end
39
+
40
+ run do
41
+ run_search_no_params_test(<%= test_id %>_ids)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,222 @@
1
+ require 'inferno/dsl/oauth_credentials'
2
+ require_relative '../../version'
3
+ require_relative '<%= capability_statement_file_name %>'
4
+ <% group_file_list.each do |file_name| %>require_relative '<%= file_name %>'
5
+ <% end %>
6
+ module DaVinciPlanNetTestKit
7
+ module <%= module_name %>
8
+ class <%= class_name %> < Inferno::TestSuite
9
+ title '<%= title %>'
10
+ description %(
11
+ The Plan Net Test Kit tests servers for their conformance to the [Plan Net
12
+ Implementation Guide](<%=ig_link %>).
13
+
14
+ ## Scope
15
+
16
+ These tests are a **DRAFT** intended to allow Plan Net server implementers to perform
17
+ preliminary checks of their servers against Plan Net IG requirements and [provide
18
+ feedback](https://github.com/inferno-framework/davinci-plan-net-test-kit/issues)
19
+ to ONC on the tests. Future versions of these tests may validate other
20
+ requirements and may change the test validation logic.
21
+
22
+ ## Test Methodology
23
+
24
+ Inferno will act as a client and make a series of requests to the
25
+ server under test. The responses will be checked for conformance to the Plan
26
+ Net IG requirements individually and used in aggregate to determine whether
27
+ required features and functionality are present.
28
+
29
+ HL7® FHIR® resources are validated with the Java validator using
30
+ `tx.fhir.org` as the terminology server.
31
+
32
+ ## Running the Tests
33
+
34
+ ### Quick Start
35
+
36
+ The tests are designed to be runnable with a single input from the user:
37
+ the base FHIR URL of the server under test. To run in this mode:
38
+ 1. Click the `RUN ALL TESTS` button in the upper right
39
+ 2. Provide the URL for the server in the first "FHIR Endpoint (required)" input
40
+ 3. Click the `Submit` button in the lower right of the input display
41
+ 4. Wait for Inferno to run the tests (will take several minutes)
42
+ 5. Expand tests with failures to determine the reason
43
+
44
+ If you would like to try out the tests but don't have a Plan Net server implementation,
45
+ you can use the publicly available reference implementation available at URL
46
+ https://plan-net-ri.davinci.hl7.org/fhir. Select this endpoint by using that URL as the
47
+ "FHIR Endpoint (required)" input or prepopulating it by selecting the
48
+ `Da Vinci Plan Net Reference Server` preset in the upper left. Note that this
49
+ system is not currently expected to pass all of the tests.
50
+
51
+ The feedback provided may require
52
+ - Configuration updates (see *Test Configuration Details* below) to better guide Inferno's test execution.
53
+ - Additional data within the system under test, e.g., to demonstrate all Must Support elements.
54
+ - Fixes to the system under test.
55
+
56
+ Note that this mode requires that the server support parameterless searches against
57
+ Plan Net resource types (e.g., `GET [FHIR Endpoint]/InsurancePlan`), which are not required
58
+ by the Plan Net IG. If your server does not support these searches, or some returned instances
59
+ will not conform to Plan Net profiles, see the *Instance Gathering* section under
60
+ *Test Configuration Details* below for how to disable these searches and direct the tests
61
+ toward specific instances of each profile instead.
62
+
63
+ ### Running Groups Individually
64
+
65
+ Each test group listed on the left can be run individually using the `RUN TESTS`
66
+ button in the upper right of the group page. However, note that running
67
+ them individually requires additional inputs so that Inferno can find appropriate values for searches
68
+ (see *Determination of Search Values When Running Single Groups* below for details).
69
+
70
+ ## Test Configuration Details
71
+
72
+ The details provided here supplement the documentation of individual inputs in the input dialog
73
+ that appears when initiating a test run.
74
+
75
+ ### Authentication
76
+
77
+ The Plan Net IG requires that "A conformant Plan-Net service SHALL NOT
78
+ require a directory mobile application to send consumer identifying information
79
+ in order to query content." A simple way to ensure this is to not require authentication,
80
+ which is safe because the information in scope does not include PHI. Thus, the
81
+ tests do not send authentication details by default.
82
+
83
+ If a server under test requires authentication information to be sent, an access token
84
+ may be provided using the "OAuth Credentials - Access Token" input. When populated,
85
+ requests to the server will include an HTTP header of the form `Authorization: Bearer [access token]`.
86
+
87
+ ### Instance Gathering
88
+
89
+ Inferno needs to identify instances of each profile to use to validate conformance to
90
+ structural and search API requirements. Inferno will use one or a combination of the
91
+ following two approaches as directed by the inputs.
92
+
93
+ #### Parameterless searches (default)
94
+
95
+ Inferno will use a search against the base resource type without any search
96
+ parameters (`GET [FHIR Endpoint]/[Resource Type]`) to identify instances of each profile.
97
+ This behavior can be controlled using the following inputs:
98
+ - "Use parameterless searches to identify instances?": if the server under test does not support
99
+ parameterless searches, this can be set to `No` to disable parameterless searches.
100
+ - "Maximum number of instances to gather using parameterless searches (required)" and
101
+ "Maximum pages of results to consider when using parameterless searches (required)": if fewer
102
+ instances (e.g., to improve performance) or more instances (e.g., to improve Must Support
103
+ element coverage) should be gathered, these inputs can be adjusted to tune the number
104
+ of instances that Inferno will gather using parameterless searches.
105
+
106
+ #### Specific instance ids
107
+
108
+ Inputs of the form "ids of [profile] instances" can be used by the user to specify particular
109
+ instances for Inferno to gather for use in testing. Inferno will perform a read on each provided id
110
+ to gather the instances. When parameterless searches are not used, all inputs of this form must be populated.
111
+ When instance ids are provided in addition to parameterless searches, instances provided by the user
112
+ are prioritized for use in determining search values for search tests.
113
+
114
+ ### Determination of Search Values When Running Single Groups
115
+
116
+ Validation of search parameters requires Inferno to identify values that are expected
117
+ to return instances. By default, Inferno does this by examining gathered instances of each profile
118
+ to identify search values that should return results when performed against the server under
119
+ test. For `_revinclude` and reverse chaining tests, Inferno needs access to instances of other profiles
120
+ in order to determine appropriate search values. When test groups are run individually, Inferno will not
121
+ have access to instances identified while running other groups. Thus, when running at the group level,
122
+ two additional inputs are required to allow the tests to identify appropriate search values:
123
+ - "[target profile] instance ids referenced in [referencing profile].[reference element]":
124
+ used by `_revinclude` tests on [target profile] when run as a group to identify
125
+ instances of the [target profile] that have instances of [referencing profile] that reference it.
126
+ - "'[constraining element]' value from a [referencing profile] instance with '[reference element]' populated": used by reverse chaining tests
127
+ on the [target profile] referenced in the [reference element] element when run as a single group
128
+ to identify the value to use when performing the reverse chain search.
129
+ )
130
+ version VERSION
131
+
132
+ VALIDATION_MESSAGE_FILTERS = [
133
+ %r{Sub-extension url 'introspect' is not defined by the Extension http://fhir-registry\.smarthealthit\.org/StructureDefinition/oauth-uris},
134
+ %r{Sub-extension url 'revoke' is not defined by the Extension http://fhir-registry\.smarthealthit\.org/StructureDefinition/oauth-uris},
135
+ /Observation\.effective\.ofType\(Period\): .*us-core-1:/, # Invalid invariant in US Core v3.1.1
136
+ /\A\S+: \S+: URL value '.*' does not resolve/,
137
+ ].freeze
138
+
139
+ VERSION_SPECIFIC_MESSAGE_FILTERS = <%=version_specific_message_filters%>.freeze
140
+
141
+ def self.metadata
142
+ @metadata ||= YAML.load_file(File.join(__dir__, 'metadata.yml'), aliases: true)[:groups].map do |raw_metadata|
143
+ Generator::GroupMetadata.new(raw_metadata)
144
+ end
145
+ end
146
+
147
+ id :<%= suite_id %>
148
+
149
+ fhir_resource_validator do
150
+ igs '<%= ig_identifier %>'
151
+
152
+ message_filters = VALIDATION_MESSAGE_FILTERS + VERSION_SPECIFIC_MESSAGE_FILTERS
153
+
154
+ exclude_message do |message|
155
+
156
+ message_filters.any? { |filter| filter.match? message.message }
157
+ end
158
+
159
+ perform_additional_validation do |resource, profile_url|
160
+ ProvenanceValidator.validate(resource) if resource.instance_of?(FHIR::Provenance)
161
+ end
162
+ end
163
+
164
+ links [
165
+ {
166
+ label: 'Report Issue',
167
+ url: 'https://github.com/inferno-framework/davinci-plan-net-test-kit/issues'
168
+ },
169
+ {
170
+ label: 'Source Code',
171
+ url: 'https://github.com/inferno-framework/davinci-plan-net-test-kit'
172
+ },
173
+ {
174
+ label: 'Implementation Guide',
175
+ url: '<%=ig_link %>'
176
+ }
177
+ ]
178
+
179
+ input :url,
180
+ title: 'FHIR Endpoint',
181
+ description: 'URL of the FHIR endpoint'
182
+ input :smart_credentials,
183
+ title: 'OAuth Credentials',
184
+ type: :oauth_credentials,
185
+ optional: true
186
+ input :no_param_search,
187
+ title: 'Use parameterless searches to identify instances?',
188
+ type: 'radio',
189
+ options: {
190
+ list_options: [
191
+ {
192
+ label: 'Yes',
193
+ value: 'true'
194
+ },
195
+ {
196
+ label: 'No',
197
+ value: 'false'
198
+ }
199
+ ]
200
+ },
201
+ default: 'true',
202
+ description: 'If `Yes`, Inferno will gather instances of each profile using searches of the form `GET [FHIR Endpoint]/[resource type]`. If searches of this form are not supported or some instances on the server will not be expected to conform to Plan Net profiles, select `No` and enter instance ids of each profile in the "ids of [profile] instances" inputs.'
203
+ input :max_instances,
204
+ title: 'Maximum number of instances to gather using parameterless searches',
205
+ default: '200',
206
+ description: 'Only used with parameterless searches. A higher number will gather more instances for the tests, if they are available. The test will stop looking when the page limit has been reached.'
207
+ input :max_pages,
208
+ title: 'Maximum pages of results to consider when using parameterless searches',
209
+ default: '20',
210
+ description: 'Only used with parameterless searches. A higher number will gather more instances for the tests, if they are available. The test will not consider further pages once the maximum number of instances has been reached.'
211
+
212
+ fhir_client do
213
+ url :url
214
+ oauth_credentials :smart_credentials
215
+ end
216
+
217
+ group from: :<%= capability_statement_group_id %>
218
+ <% group_id_list.each do |id| %>
219
+ group from: :<%= id %><% end %>
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,31 @@
1
+ require_relative '../../../validation_test'
2
+
3
+ module DaVinciPlanNetTestKit
4
+ module <%= module_name %>
5
+ class <%= class_name %> < Inferno::Test
6
+ include DaVinciPlanNetTestKit::ValidationTest
7
+
8
+ id :<%= test_id %>
9
+ title '<%= resource_type %> resources returned during previous tests conform to the <%= profile_name %>'
10
+ description %(
11
+ <%= description %>
12
+ )
13
+ output :dar_code_found, :dar_extension_found
14
+
15
+ def resource_type
16
+ '<%= resource_type %>'
17
+ end
18
+
19
+ def scratch_resources
20
+ scratch[:<%= profile_identifier %>_resources] ||= {}
21
+ end
22
+
23
+ run do
24
+ perform_validation_test(scratch_resources[:all] || [],
25
+ '<%= profile_url %>',
26
+ '<%= profile_version %>',
27
+ skip_if_empty: <%= skip_if_empty %>)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,21 @@
1
+ # Note on this IGs folder
2
+
3
+ There are three reasons why it would be necessary to put an IG package.tgz in this folder. If none of these apply, you do not need to put any files here, or can consider removing any existing files to make it clear they are unused.
4
+
5
+ ## 1. Generated Test Suites
6
+ Some test kits use a "generator" to automatically generate the contents of a test suite for an IG. The IG files are required every time the test suites need to be regenerated. Examples of test kits that use this approach are the US Core Test Kit and CARIN IG for Blue Button® Test Kit.
7
+
8
+
9
+ ## 2. Non-published IG
10
+ If your IG, or the specific version of the IG you want to test against, is not published, then the validator service needs to load the IG from file in order to be able to validate resources with it. The IG must be referenced in the `fhir_resource_validator` block in the test suite definition by filename, ie:
11
+
12
+ ```ruby
13
+ fhir_resource_validator do
14
+ igs 'igs/filename.tgz'
15
+
16
+ ...
17
+ end
18
+ ```
19
+
20
+ ## 3. Inferno Validator UI
21
+ The Inferno Validator UI is configured to auto-load any IGs present in the igs folder and include them in all validations. The Inferno Validator UI is currently disabled by default, so this is only relevant if you choose to re-enable it. In general, the Inferno team is currently leaving IGs in this folder even if not otherwise necessary to make it easy to re-enable the validator UI.
@@ -0,0 +1,64 @@
1
+ module DaVinciPlanNetTestKit
2
+ class Metadata < Inferno::TestKit
3
+ id :davinci_plan_net_test_kit
4
+ title 'Da Vinci Plan Net Test Kit'
5
+ suite_ids [ 'davinci_plan_net_server_v110' ]
6
+ tags ['Da Vinci']
7
+ last_updated ::DaVinciPlanNetTestKit::LAST_UPDATED
8
+ version ::DaVinciPlanNetTestKit::VERSION
9
+ maturity 'Low'
10
+ authors ['Karl Naden']
11
+ repo 'https://github.com/inferno-framework/davinci-plan-net-test-kit'
12
+ description <<~DESCRIPTION
13
+ The DaVinci Plan Net Test Kit validates the conformance of a server
14
+ implementation to version 1.1.0 of the
15
+ [DaVinci PDEX Plan Net Implementation Guide](http://hl7.org/fhir/us/davinci-pdex-plan-net/STU1.1).
16
+
17
+ <!-- break -->
18
+
19
+ Inferno will act as a client and make a series of requests to the
20
+ server under test. The responses will be checked for conformance
21
+ to the Plan Net IG requirements individually and used in aggregate
22
+ to determine whether required features and functionality are present.
23
+
24
+ The test kit currently tests the following requirements:
25
+
26
+ - Support for Must Support Elements
27
+ - JSON Support
28
+ - Support for all Plan Net Profiles
29
+ - Read Interaction
30
+ - Individual Search Parameters
31
+ - _include Searches
32
+ - _revinclude Searches
33
+ - Forward Chain Searches
34
+ - Reverse Chain Searches
35
+ - Search Parameters in Combination
36
+
37
+ The DaVinci Plan Net Test Kit is built using the
38
+ [Inferno Framework](https://inferno-framework.github.io/).
39
+ The Inferno Framework is designed for reuse and aims to make it easier
40
+ to build test kits for any FHIR-based data exchange.
41
+
42
+ ### Known Limitations
43
+
44
+ The following areas of the IG are not fully tested in this draft version
45
+ of the test kit:
46
+
47
+ - All search parameter combinations: the tests check for support of only
48
+ specific combinations of search parameters driven by
49
+ [anticipated searches listed in the IG](http://hl7.org/fhir/us/davinci-pdex-plan-net/implementation.html#Representing).
50
+ - Response classes: the Plan Net IG lists HTTP response codes that the
51
+ server needs to be able to return, but does not indicate specific
52
+ criteria for requests that elicit these status codes.
53
+
54
+ Additional details on these and other areas where the tests may not align
55
+ with the IGs requirements, see this requirements analysis spreadsheet.
56
+
57
+ ## Reporting Issues
58
+
59
+ Please report any issues with this set of tests in the
60
+ [GitHub Issues](https://github.com/inferno-framework/davinci-plan-net-test-kit/issues)
61
+ section of this repository.
62
+ DESCRIPTION
63
+ end
64
+ end
@@ -203,7 +203,7 @@ module DaVinciPlanNetTestKit
203
203
 
204
204
  check_search_response
205
205
 
206
- returned_resources = fetch_all_bundled_resources(additional_resource_types: [additional_resource_type])
206
+ returned_resources = fetch_all_bundled_resources(resource_type: self.resource_type, additional_resource_types: [additional_resource_type])
207
207
 
208
208
  base_resources = returned_resources
209
209
  .select { |res| res.resourceType == resource_type }
@@ -238,7 +238,7 @@ module DaVinciPlanNetTestKit
238
238
 
239
239
  check_search_response
240
240
 
241
- matching_resources = fetch_all_bundled_resources(additional_resource_types: [additional_resource_type])
241
+ matching_resources = fetch_all_bundled_resources(resource_type: self.resource_type, additional_resource_types: [additional_resource_type])
242
242
  .select { |res| res.resourceType == additional_resource_type }
243
243
  .reject { |res| res.id == params[:_id] }
244
244
 
@@ -306,7 +306,7 @@ module DaVinciPlanNetTestKit
306
306
  fhir_search additional_resource_type, params: additional_resource_params
307
307
 
308
308
  check_search_response
309
- additional_resources = fetch_all_bundled_resources(additional_resource_types: [additional_resource_type])
309
+ additional_resources = fetch_all_bundled_resources(resource_type: self.resource_type, additional_resource_types: [additional_resource_type])
310
310
  .select { |res| res.resourceType == additional_resource_type }
311
311
 
312
312
  additional_resources.each { |res| check_resource_against_params(res, additional_resource_params) }
@@ -328,7 +328,7 @@ module DaVinciPlanNetTestKit
328
328
 
329
329
  check_search_response
330
330
 
331
- returned_resources = fetch_all_bundled_resources(additional_resource_types: [additional_resource_type])
331
+ returned_resources = fetch_all_bundled_resources(resource_type: self.resource_type, additional_resource_types: [additional_resource_type])
332
332
  assert !returned_resources.empty?, "No #{resource_type} resources returned"
333
333
  base_resources = returned_resources
334
334
  .select { |res| res.resourceType == resource_type }
@@ -356,7 +356,7 @@ module DaVinciPlanNetTestKit
356
356
 
357
357
  check_search_response
358
358
 
359
- returned_resources = fetch_all_bundled_resources(additional_resource_types: [additional_resource_type])
359
+ returned_resources = fetch_all_bundled_resources(resource_type: self.resource_type, additional_resource_types: [additional_resource_type])
360
360
  input_based_skip_assert(returned_resources, "No resources found.")
361
361
  base_resources = returned_resources
362
362
  .select { |res| res.resourceType == resource_type }
@@ -380,7 +380,7 @@ module DaVinciPlanNetTestKit
380
380
 
381
381
  check_search_response
382
382
 
383
- returned_resources = fetch_all_bundled_resources(additional_resource_types: [additional_resource_type])
383
+ returned_resources = fetch_all_bundled_resources(resource_type: self.resource_type, additional_resource_types: [additional_resource_type])
384
384
  assert !returned_resources.empty?, "No #{resource_type} resources found"
385
385
 
386
386
  base_resources = returned_resources
@@ -424,7 +424,7 @@ module DaVinciPlanNetTestKit
424
424
  check_search_response
425
425
 
426
426
  resources_returned =
427
- fetch_all_bundled_resources.select { |resource| resource.resourceType == resource_type }
427
+ fetch_all_bundled_resources(resource_type: self.resource_type).select { |resource| resource.resourceType == resource_type }
428
428
 
429
429
  return [] if resources_returned.blank?
430
430
 
@@ -456,7 +456,7 @@ module DaVinciPlanNetTestKit
456
456
 
457
457
  check_search_response
458
458
 
459
- post_search_resources = fetch_all_bundled_resources.select { |resource| resource.resourceType == resource_type }
459
+ post_search_resources = fetch_all_bundled_resources(resource_type: self.resource_type).select { |resource| resource.resourceType == resource_type }
460
460
 
461
461
  filter_conditions(post_search_resources) if resource_type == 'Condition' && metadata.version == 'v5.0.1'
462
462
  filter_devices(post_search_resources) if resource_type == 'Device'
@@ -562,7 +562,7 @@ module DaVinciPlanNetTestKit
562
562
 
563
563
  search_and_check_response(params_with_comparator)
564
564
 
565
- fetch_all_bundled_resources.each do |resource|
565
+ fetch_all_bundled_resources(resource_type: self.resource_type).each do |resource|
566
566
  check_resource_against_params(resource, params_with_comparator) if resource.resourceType == resource_type
567
567
  end
568
568
  end
@@ -578,7 +578,7 @@ module DaVinciPlanNetTestKit
578
578
  new_search_params = params.merge(resource_type.underscore => "#{resource_type}/#{params['resource']}")
579
579
  search_and_check_response(new_search_params)
580
580
 
581
- reference_with_type_resources = fetch_all_bundled_resources.select { |resource| resource.resourceType == resource_type }
581
+ reference_with_type_resources = fetch_all_bundled_resources(resource_type: self.resource_type).select { |resource| resource.resourceType == resource_type }
582
582
 
583
583
 
584
584
  new_resource_count = reference_with_type_resources.count
@@ -601,7 +601,7 @@ module DaVinciPlanNetTestKit
601
601
  search_and_check_response(search_params)
602
602
 
603
603
  resources_returned =
604
- fetch_all_bundled_resources
604
+ fetch_all_bundled_resources(resource_type: self.resource_type)
605
605
  .select { |resource| resource.resourceType == resource_type }
606
606
 
607
607
  assert resources_returned.present?, "No resources were returned when searching by `system|code`"
@@ -672,7 +672,7 @@ module DaVinciPlanNetTestKit
672
672
  search_and_check_response(search_params)
673
673
 
674
674
  resources_returned =
675
- fetch_all_bundled_resources
675
+ fetch_all_bundled_resources(resource_type: self.resource_type)
676
676
  .select { |resource| resource.resourceType == resource_type }
677
677
 
678
678
  multiple_or_search_params.each do |param_name|
@@ -855,54 +855,6 @@ module DaVinciPlanNetTestKit
855
855
  "#{msg}."
856
856
  end
857
857
 
858
- def fetch_all_bundled_resources(
859
- reply_handler: nil,
860
- max_pages: 0,
861
- additional_resource_types: [],
862
- resource_type: self.resource_type
863
- )
864
- page_count = 1
865
- resources = []
866
- bundle = resource
867
- resources += bundle&.entry&.map { |entry| entry&.resource }
868
-
869
- until bundle.nil? || (page_count == max_pages && max_pages != 0)
870
-
871
- next_bundle_link = bundle&.link&.find { |link| link.relation == 'next' }&.url
872
- reply_handler&.call(response)
873
-
874
- break if next_bundle_link.blank?
875
-
876
- reply = fhir_client.raw_read_url(next_bundle_link)
877
-
878
- store_request('outgoing') { reply }
879
- error_message = cant_resolve_next_bundle_message(next_bundle_link)
880
-
881
- assert_response_status(200)
882
- assert_valid_json(reply.body, error_message)
883
-
884
- bundle = fhir_client.parse_reply(FHIR::Bundle, fhir_client.default_format, reply)
885
- resources += bundle&.entry&.map { |entry| entry&.resource }
886
-
887
- page_count += 1
888
- end
889
-
890
- valid_resource_types = [resource_type, 'OperationOutcome'].concat(additional_resource_types)
891
-
892
- invalid_resource_types =
893
- resources.reject { |entry| valid_resource_types.include? entry.resourceType }
894
- .map(&:resourceType)
895
- .uniq
896
-
897
- if invalid_resource_types.any?
898
- info "Received resource type(s) #{invalid_resource_types.join(', ')} in search bundle, " \
899
- "but only expected resource types #{valid_resource_types.join(', ')}. " + \
900
- "This is unusual but allowed if the server believes additional resource types are relevant."
901
- end
902
-
903
- resources
904
- end
905
-
906
858
  def fetch_matching_bundled_resources(
907
859
  max_pages: 20,
908
860
  max_instances: 200,
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DaVinciPlanNetTestKit
4
- VERSION = '0.10.0'
4
+ VERSION = '0.11.0'
5
+ LAST_UPDATED = '2025-02-25'
5
6
  end
@@ -1 +1,2 @@
1
+ require_relative 'davinci_plan_net_test_kit/metadata.rb'
1
2
  require_relative 'davinci_plan_net_test_kit/generated/v1.1.0/davinci_plan_net_test_suite'