From 23547e702313e3e6dec67af84d5e48f1edf4ddfb Mon Sep 17 00:00:00 2001 From: Shaumik-Ashraf Date: Mon, 21 Jul 2025 11:27:29 -0400 Subject: [PATCH] Update to Inferno Core v1.0.0 --- .env.development | 1 + .env.production | 1 + .github/workflows/publish-docs-wiki.yml | 5 +- .gitignore | 1 + .rubocop.yml | 4 +- Dockerfile | 1 - Gemfile.lock | 152 ++++++++++-------- data/igs/.keep | 0 docker-compose.background.yml | 4 +- inferno_template.gemspec | 2 +- lib/inferno_template.rb | 2 +- lib/inferno_template/example_suite.rb | 127 +++++++++++++++ .../example_suite/patient_group.rb | 141 ++++++++++++++++ lib/inferno_template/metadata.rb | 68 +++++++- lib/inferno_template/suite.rb | 4 +- lib/inferno_template/version.rb | 1 + spec/inferno_template/patient_group_spec.rb | 21 +-- 17 files changed, 446 insertions(+), 89 deletions(-) create mode 100644 data/igs/.keep create mode 100644 lib/inferno_template/example_suite.rb create mode 100644 lib/inferno_template/example_suite/patient_group.rb diff --git a/.env.development b/.env.development index 38b28b3..ff94bd7 100644 --- a/.env.development +++ b/.env.development @@ -1,3 +1,4 @@ FHIR_RESOURCE_VALIDATOR_URL=http://localhost/hl7validatorapi REDIS_URL=redis://localhost:6379/0 FHIRPATH_URL=http://localhost/fhirpath +INFERNO_HOST=http://localhost:4567 diff --git a/.env.production b/.env.production index 727c9ae..afb38e7 100644 --- a/.env.production +++ b/.env.production @@ -1,3 +1,4 @@ REDIS_URL=redis://redis:6379/0 FHIR_RESOURCE_VALIDATOR_URL=http://hl7_validator_service:3500 FHIRPATH_URL=http://fhirpath:6789 +INFERNO_HOST=http://localhost diff --git a/.github/workflows/publish-docs-wiki.yml b/.github/workflows/publish-docs-wiki.yml index 57b2e6e..3914253 100644 --- a/.github/workflows/publish-docs-wiki.yml +++ b/.github/workflows/publish-docs-wiki.yml @@ -28,4 +28,7 @@ jobs: - uses: Andrew-Chen-Wang/github-wiki-action@86138cbd6328b21d759e89ab6e6dd6a139b22270 with: path: docs - strategy: init \ No newline at end of file + strategy: init + continue-on-error: true # Make this workflow optional. + - run: echo "Failed to deploy wiki" # If you want to require publishing docs to wiki + if: job.steps.bad.status == failure() # then comment out these 3 lines. diff --git a/.gitignore b/.gitignore index 7c4f988..98ab88f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /data/*.db +/data/igs/*.tgz /data/redis/**/*.rdb /data/redis/**/*.aof /data/redis/**/*.manifest diff --git a/.rubocop.yml b/.rubocop.yml index 27c65cf..23f1717 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,6 +1,6 @@ -require: +plugins: - rubocop-rspec - + AllCops: NewCops: enable SuggestExtensions: false diff --git a/Dockerfile b/Dockerfile index d6fa75c..20980ce 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,6 @@ RUN mkdir -p $INSTALL_PATH WORKDIR $INSTALL_PATH -ADD lib/inferno_template/metadata.rb $INSTALL_PATH/lib/inferno_template/metadata.rb ADD lib/inferno_template/version.rb $INSTALL_PATH/lib/inferno_template/version.rb ADD *.gemspec $INSTALL_PATH ADD Gemfile* $INSTALL_PATH diff --git a/Gemfile.lock b/Gemfile.lock index 528ac58..edc78a0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,7 +2,7 @@ PATH remote: . specs: inferno_template (0.0.0) - inferno_core (~> 0.6.2) + inferno_core (~> 1.0.0) GEM remote: https://rubygems.org/ @@ -15,30 +15,31 @@ GEM zeitwerk (~> 2.3) addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) - ast (2.4.2) + ast (2.4.3) base62-rb (0.3.1) - base64 (0.2.0) + base64 (0.3.0) bcp47 (0.3.3) i18n - bigdecimal (3.1.9) + bigdecimal (3.2.2) blueprinter (0.25.2) - byebug (11.1.3) + byebug (12.0.0) coderay (1.1.3) concurrent-ruby (1.3.4) - connection_pool (2.5.0) + connection_pool (2.5.3) crack (1.0.0) bigdecimal rexml + csv (3.3.5) database_cleaner (1.99.0) database_cleaner-sequel (1.99.0) database_cleaner (~> 1.99.0) sequel date (3.4.1) date_time_precision (0.8.1) - debug (1.10.0) + debug (1.11.0) irb (~> 1.10) reline (>= 0.3.8) - diff-lcs (1.5.1) + diff-lcs (1.6.2) docile (1.4.1) domain_name (0.6.20240107) dotenv (2.8.1) @@ -61,7 +62,8 @@ GEM dry-inflector (~> 1.0, < 2) dry-transformer (1.0.1) zeitwerk (~> 2.6) - factory_bot (6.5.1) + erb (5.0.2) + factory_bot (6.5.4) activesupport (>= 6.1.0) faraday (1.10.4) faraday-em_http (~> 1.0) @@ -76,10 +78,10 @@ GEM faraday-retry (~> 1.0) ruby2_keywords (>= 0.0.4) faraday-em_http (1.0.0) - faraday-em_synchrony (1.0.0) + faraday-em_synchrony (1.0.1) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.1.0) + faraday-multipart (1.1.1) multipart-post (~> 2.0) faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) @@ -129,17 +131,18 @@ GEM dry-core (~> 1.0, < 2) dry-transformer (~> 1.0, < 2) hansi (0.2.1) - hashdiff (1.1.2) + hashdiff (1.2.0) http-accept (1.7.0) http-cookie (1.0.8) domain_name (~> 0.5) i18n (1.14.7) concurrent-ruby (~> 1.0) - inferno_core (0.6.2) + inferno_core (1.0.0) activesupport (~> 6.1.7.5) base62-rb (= 0.3.1) blueprinter (= 0.25.2) concurrent-ruby (= 1.3.4) + csv (~> 3.3.5) dotenv (~> 2.7) dry-configurable (= 1.0.0) dry-container (= 0.10.0) @@ -152,37 +155,44 @@ GEM fhir_models (>= 4.2.2) hanami-controller (= 2.0.0) hanami-router (= 2.0.0) + kramdown (~> 2.5.1) + kramdown-parser-gfm (~> 1.1.0) + mutex_m (~> 0.3.0) oj (= 3.11.0) pastel (~> 0.8.0) pry pry-byebug puma (~> 5.6.7) rake (~> 13.0) + roo (~> 2.10.1) sequel (~> 5.42.0) sidekiq (~> 7.2.4) sqlite3 (~> 1.4) thor (~> 1.2.1) tty-markdown (~> 0.7.1) - io-console (0.8.0) - irb (1.15.1) + io-console (0.8.1) + irb (1.15.2) pp (>= 0.6.0) rdoc (>= 4.0.0) reline (>= 0.4.2) - json (2.10.1) - jwt (2.10.1) + json (2.13.0) + jwt (2.10.2) base64 kramdown (2.5.1) rexml (>= 3.3.9) - language_server-protocol (3.17.0.4) - logger (1.6.5) + kramdown-parser-gfm (1.1.0) + kramdown (~> 2.0) + language_server-protocol (3.17.0.5) + lint_roller (1.1.0) + logger (1.7.0) method_source (1.1.0) - mime-types (3.6.0) + mime-types (3.7.0) logger - mime-types-data (~> 3.2015) - mime-types-data (3.2025.0204) - minitest (5.25.4) - multi_json (1.15.0) - multi_xml (0.7.1) + mime-types-data (~> 3.2025, >= 3.2025.0507) + mime-types-data (3.2025.0715) + minitest (5.25.5) + multi_json (1.17.0) + multi_xml (0.7.2) bigdecimal (~> 3.1) multipart-post (2.4.1) mustermann (1.1.2) @@ -190,23 +200,24 @@ GEM mustermann-contrib (1.1.2) hansi (~> 0.2.0) mustermann (= 1.1.2) + mutex_m (0.3.0) netrc (0.11.0) nio4r (2.7.4) - nokogiri (1.18.2-aarch64-linux-gnu) + nokogiri (1.18.9-aarch64-linux-gnu) racc (~> 1.4) - nokogiri (1.18.2-aarch64-linux-musl) + nokogiri (1.18.9-aarch64-linux-musl) racc (~> 1.4) - nokogiri (1.18.2-arm-linux-gnu) + nokogiri (1.18.9-arm-linux-gnu) racc (~> 1.4) - nokogiri (1.18.2-arm-linux-musl) + nokogiri (1.18.9-arm-linux-musl) racc (~> 1.4) - nokogiri (1.18.2-arm64-darwin) + nokogiri (1.18.9-arm64-darwin) racc (~> 1.4) - nokogiri (1.18.2-x86_64-darwin) + nokogiri (1.18.9-x86_64-darwin) racc (~> 1.4) - nokogiri (1.18.2-x86_64-linux-gnu) + nokogiri (1.18.9-x86_64-linux-gnu) racc (~> 1.4) - nokogiri (1.18.2-x86_64-linux-musl) + nokogiri (1.18.9-x86_64-linux-musl) racc (~> 1.4) oauth2 (1.4.11) faraday (>= 0.17.3, < 3.0) @@ -215,8 +226,8 @@ GEM multi_xml (~> 0.5) rack (>= 1.2, < 4) oj (3.11.0) - parallel (1.26.3) - parser (3.3.7.1) + parallel (1.27.0) + parser (3.3.8.0) ast (~> 2.4.1) racc pastel (0.8.0) @@ -224,67 +235,76 @@ GEM pp (0.6.2) prettyprint prettyprint (0.2.0) - pry (0.14.2) + prism (1.4.0) + pry (0.15.2) coderay (~> 1.1) method_source (~> 1.0) - pry-byebug (3.10.1) - byebug (~> 11.0) - pry (>= 0.13, < 0.15) - psych (5.2.3) + pry-byebug (3.11.0) + byebug (~> 12.0) + pry (>= 0.13, < 0.16) + psych (5.2.6) date stringio - public_suffix (6.0.1) + public_suffix (6.0.2) puma (5.6.9) nio4r (~> 2.0) racc (1.8.1) - rack (2.2.10) + rack (2.2.17) rack-test (2.2.0) rack (>= 1.3) rainbow (3.1.1) - rake (13.2.1) - rdoc (6.12.0) + rake (13.3.0) + rdoc (6.14.2) + erb psych (>= 4.0.0) - redis-client (0.23.2) + redis-client (0.25.1) connection_pool regexp_parser (2.10.0) - reline (0.6.0) + reline (0.6.2) io-console (~> 0.5) rest-client (2.1.0) http-accept (>= 1.7.0, < 2.0) http-cookie (>= 1.0.2, < 2.0) mime-types (>= 1.16, < 4.0) netrc (~> 0.8) - rexml (3.4.0) - rouge (4.5.1) - rspec (3.13.0) + rexml (3.4.1) + roo (2.10.1) + nokogiri (~> 1) + rubyzip (>= 1.3.0, < 3.0.0) + rouge (4.5.2) + rspec (3.13.1) rspec-core (~> 3.13.0) rspec-expectations (~> 3.13.0) rspec-mocks (~> 3.13.0) - rspec-core (3.13.3) + rspec-core (3.13.5) rspec-support (~> 3.13.0) - rspec-expectations (3.13.3) + rspec-expectations (3.13.5) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-mocks (3.13.2) + rspec-mocks (3.13.5) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-support (3.13.2) - rubocop (1.71.2) + rspec-support (3.13.4) + rubocop (1.78.0) json (~> 2.3) - language_server-protocol (>= 3.17.0) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 2.9.3, < 3.0) - rubocop-ast (>= 1.38.0, < 2.0) + rubocop-ast (>= 1.45.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 4.0) - rubocop-ast (1.38.0) - parser (>= 3.3.1.0) - rubocop-rspec (3.4.0) - rubocop (~> 1.61) + rubocop-ast (1.46.0) + parser (>= 3.3.7.2) + prism (~> 1.4) + rubocop-rspec (3.6.0) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) + rubyzip (2.4.1) sequel (5.42.0) sidekiq (7.2.4) concurrent-ruby (< 2) @@ -295,21 +315,21 @@ GEM docile (~> 1.1) simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) - simplecov-html (0.13.1) + simplecov-html (0.13.2) simplecov_json_formatter (0.1.4) sqlite3 (1.7.3-aarch64-linux) sqlite3 (1.7.3-arm-linux) sqlite3 (1.7.3-arm64-darwin) sqlite3 (1.7.3-x86_64-darwin) sqlite3 (1.7.3-x86_64-linux) - stringio (3.1.2) + stringio (3.1.7) strings (0.2.1) strings-ansi (~> 0.2) unicode-display_width (>= 1.5, < 3.0) unicode_utils (~> 1.4) strings-ansi (0.2.0) thor (1.2.2) - tilt (2.6.0) + tilt (2.6.1) tty-color (0.6.0) tty-markdown (0.7.2) kramdown (>= 1.16.2, < 3.0) @@ -323,11 +343,11 @@ GEM concurrent-ruby (~> 1.0) unicode-display_width (2.6.0) unicode_utils (1.4.0) - webmock (3.25.0) + webmock (3.25.1) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - zeitwerk (2.7.1) + zeitwerk (2.7.3) PLATFORMS aarch64-linux @@ -355,4 +375,4 @@ DEPENDENCIES webmock (~> 3.11) BUNDLED WITH - 2.5.23 + 2.6.6 diff --git a/data/igs/.keep b/data/igs/.keep new file mode 100644 index 0000000..e69de29 diff --git a/docker-compose.background.yml b/docker-compose.background.yml index 070e641..005d290 100644 --- a/docker-compose.background.yml +++ b/docker-compose.background.yml @@ -7,7 +7,7 @@ services: # Negative values mean sessions never expire, 0 means sessions immediately expire SESSION_CACHE_DURATION: -1 volumes: - - ./lib/inferno_template/igs:/app/igs + - ./data/igs:/app/igs # To let the service share your local FHIR package cache, # uncomment the below line # - ~/.fhir:/home/ktor/.fhir @@ -15,7 +15,7 @@ services: image: infernocommunity/fhir-validator-service # Update this path to match your directory structure volumes: - - ./lib/inferno_template/igs:/home/igs + - ./data/igs:/home/igs fhir_validator_app: image: infernocommunity/fhir-validator-app depends_on: diff --git a/inferno_template.gemspec b/inferno_template.gemspec index c25daa5..3b6230b 100644 --- a/inferno_template.gemspec +++ b/inferno_template.gemspec @@ -11,7 +11,7 @@ Gem::Specification.new do |spec| # DESCRIPTION # spec.homepage = 'TODO' spec.license = 'Apache-2.0' - spec.add_dependency 'inferno_core', '~> 0.6.2' + spec.add_dependency 'inferno_core', '~> 1.0.0' spec.required_ruby_version = Gem::Requirement.new('>= 3.3.6') spec.metadata['inferno_test_kit'] = 'true' # spec.metadata['homepage_uri'] = spec.homepage diff --git a/lib/inferno_template.rb b/lib/inferno_template.rb index 0d0722a..b5e44dd 100644 --- a/lib/inferno_template.rb +++ b/lib/inferno_template.rb @@ -1 +1 @@ -require_relative 'inferno_template/suite' +require_relative 'inferno_template/example_suite' diff --git a/lib/inferno_template/example_suite.rb b/lib/inferno_template/example_suite.rb new file mode 100644 index 0000000..2f274e7 --- /dev/null +++ b/lib/inferno_template/example_suite.rb @@ -0,0 +1,127 @@ +require_relative 'metadata' +require_relative 'example_suite/patient_group' + +module InfernoTemplate + class ExampleSuite < Inferno::TestSuite + id :inferno_template + title 'Inferno Template' + short_title 'Inferno Template' + + # TODO: Update the description below to align with the test suite + description <<~DESCRIPTION + The Example Test Suite is a testing tool for Health Level 7 (HL7®) Fast Healthcare Interoperability Resources (FHIR®) + services seeking to meet the requirements of the API criterion within the Example Certification Program. + + *or* + + The Example Test Suite tests systems for their conformance to the [Example Implementation Guide](https://example.com/example). + + ## Organization + + This test suite is organized into testing scenarios that in sum cover all requirements within the Example criterion. + The scenarios are intended to be run in order during certification, but can be run out of order to support testing + during development or certification preparation. Some scenarios depend on data collected during previous scenarios + to function. In these cases, the scenario description describes these dependencies. + + The first three scenarios require the system under test to demonstrate basic SMART App Launch functionality. + The fourth uses a valid token provided during earlier tests to verify support for the Single Patient API as + described in the criterion. The fifth verifies support for the Multi Patient API, including Backend Services + for authorization. Not all authorization-related requirements are verified in the first three scenarios, + and the 'Additional Authorization Tests' verify these additional requirements. The last scenario contains + a list of 'attestations' and 'visual inspections' for requirements that could not be verified through automated testing. + + *or* + + This test suite is split into three different categories: + - All Patients: FHIR Operation to obtain a detailed set of FHIR resources of diverse resource types pertaining to all patients + - Group of Patients: FHIR Operation to obtain a detailed set of FHIR resources of diverse resource types pertaining to all members of a specified Group + - System Level Export: FHIR Operation to export data from a FHIR server, whether or not it is associated with a patient + + ## Getting Started + + The best way to learn about how to use these tests is the [Example Test Kit walkthrough](https://example.com/Walkthrough), + which demonstrates the tests running against a simulated system. + + To get started with the first group of scenarios, please first register the Inferno client as a SMART App with the following information: + - SMART Launch URI: https://example.com/smart/launch + - OAuth Redirect URI: https://example.com/smart/redirect + + For the multi-patient API, register Inferno with the following JWK Set Url: + - https://example.com/suites/custom/example/.well-known/jwks.json + + *or* + + To get started, if your server supports SMART backend services authorization, please first register Inferno with the following JWK Set URL: + - https://example.com/suites/custom/example/.well-known/jwks.json + + Then, run the full Example test suite containing both the SMART Backend Services test group and the Bulk Data Export Tests test group. + If your server does not support SMART Backend Services authorization, only run the second test group, Bulk Data Export Tests. + + ## Limitations + + Inferno is unable to determine what requests will result in specific kinds of responses from the server under test + (e.g., what will result in Instructions being returned vs. Coverage Information). As a result, the tester must + supply the request bodies which will cause the system under test to return the desired response types. + + The ability of an Example Server to request additional FHIR resources is not tested. + + Hook configuration is not tested. + + ## *if applicable:* Certification Requirements + + Systems must pass all tests to qualify for Example certification. + + DESCRIPTION + + # These inputs will be available to all tests in this suite + input :url, + title: 'FHIR Server Base Url' + + input :credentials, + title: 'OAuth Credentials', + type: :auth_info, + optional: true + + # All FHIR requests in this suite will use this FHIR client + + # All FHIR requests in this suite will use this FHIR client + fhir_client do + url :url + auth_info :credentials + end + + # All FHIR validation requests will use this FHIR validator + fhir_resource_validator do + # igs 'identifier#version' # Use this method for published IGs/versions + # igs 'igs/filename.tgz' # Use this otherwise + + exclude_message do |message| + message.message.match?(/\A\S+: \S+: URL value '.*' does not resolve/) + end + end + + # Tests and TestGroups can be defined inline + group do + id :capability_statement + title 'Capability Statement' + description 'See a sample description in the Patient Test Group' + + test do + id :capability_statement_read + title 'Read CapabilityStatement' + description 'Read CapabilityStatement from /metadata endpoint' + + run do + fhir_get_capability_statement + + assert_response_status(200) + assert_resource_type(:capability_statement) + end + end + end + + # Tests and TestGroups can be written in separate files and then included + # using their id + group from: :patient_group + end +end diff --git a/lib/inferno_template/example_suite/patient_group.rb b/lib/inferno_template/example_suite/patient_group.rb new file mode 100644 index 0000000..88e275e --- /dev/null +++ b/lib/inferno_template/example_suite/patient_group.rb @@ -0,0 +1,141 @@ +module InfernoTemplate + class PatientGroup < Inferno::TestGroup + title 'Patient' + + description <<~DESCRIPTION + This scenario verifies the ability of a system to provide a Patient as described in the Example criterion. + + *or* + + The Example Patient sequence verifies that the system under test is able to provide correct responses for Patient queries. + + ## Requirements + + Patient queries must contain resources conforming to the Example Patient as specified in the Example Implementation Guide. + + *or* + + All Must Support elements must be seen before the test can pass, as well as Data Absent Reason to demonstrate that the server + can properly handle missing data. Note that Organization, Practitioner, and RelatedPerson resources must be accessible as + references in some Example profiles to satisfy must support requirements, and those references will be validated to their Example + profile. These resources will not be tested for FHIR search support. + + ## <*If applicable*> Dependencies + Prior to running this scenario, systems must recieve a verified access token from one of the previous SMART App Launch scenarios. + + *or* + + Prior to running this scenario, first run the Single Patient API tests using resource-level scopes, as this scenario uses content + saved from that scenario as a baseline for comparison when finer-grained scopes are granted. + + ## <*If applicable*> Methodology + + *Only include if different from instructions included in a parent group or suite* + + The test begins by searching by one or more patients, with the expectation that the Bearer token provided to the test grants + access to all Resources. It uses results returned from that query to generate other queries and checks that the results are + consistent with the provided search parameters. It then performs a read on each Resource returned and validates the response + against the relevant profile as currently defined in the Example Implementation Guide. + + *or* + + ### Searching + + This test sequence will first perform each required search associated with this resource. + This sequence will perform searches with the following parameters: + - _id + - identifier + - name + - birthdate + name + - gender + name + + #### Search Parameters + + The first search uses the selected patient(s) from the prior launch sequence. Any subsequent searches will look for its parameter + values from the results of the first search. For example, the `identifier` search in the patient sequence is performed by looking + for an existing `Patient.identifier` from any of the resources returned in the `_id` search. If a value cannot be found this way, + the search is skipped. + + #### Search Validation + + Inferno will retrieve up to the first 20 bundle pages of the reply for Patient resources and save them for subsequent tests. + Each of these resources is then checked to see if it matches the searched parameters in accordance with [FHIR search guidelines](https://www.hl7.org/fhir/search.html). + The test will fail, for example, if a Patient search for gender=male returns a female patient. + + ### Must Support + + Each profile contains elements marked as "must support". This test sequence expects to see each of these elements at least once. + If at least one cannot be found, the test will fail. The test will look through the Patient resources found in the first test + for these elements. + + ### Profile Validation + + Each resource returned from the first search is expected to conform to the [Example Patient Profile](https://www.example.com/patient/profile). + Each element is checked against teminology binding and cardinality requirements. + + Elements with a required binding are validated against their bound ValueSet. If the code/system in the element is not part of the + ValueSet, then the test will fail. + + ### Reference Validation + + At least one instance of each external reference in elements marked as "must support" within the resources provided by the + system must resolve. The test will attempt to read each reference found and will fail if no read succeeds. + + ## <*If applicable*> Running the Tests + + *Only include if different from instructions included in a parent group or suite* + + Register Inferno as an EHR-launched application using patient-level scopes and the following URIs: + - Launch URI: https://inferno.healthit.gov/suites/custom/smart/launch + - Redirect URI: https://inferno.healthit.gov/suites/custom/smart/redirect + + ## <*If top-level group for criteria*> Relevant Specifications + + The following implementation specifications are relevant to this scenario: + - [Specification 1 v1](https://www.example.com/spec1/v1) + - [Specification 1 v2](https://www.example.com/spec1/v2) + - [Specification 2 v5](https://www.example.com/spec1/v1) + + DESCRIPTION + + id :patient_group + + test do + title 'Server returns requested Patient resource from the Patient read interaction' + description %( + Verify that Patient resources can be read from the server. Expects a 200 response that includes a Patient + resource whose ID matches the requested patient ID. + ) + + input :patient_id, + title: 'Patient ID' + + # Named requests can be used by other tests + makes_request :patient + + run do + fhir_read(:patient, patient_id, name: :patient) + + assert_response_status(200) + assert_resource_type(:patient) + assert resource.id == patient_id, + "Requested resource with id #{patient_id}, received resource with id #{resource.id}" + end + end + + test do + title 'Patient resource is valid' + description %( + Verify that the Patient resource returned from the server is a valid FHIR resource. + ) + # This test will use the response from the :patient request in the + # previous test + uses_request :patient + + run do + assert_resource_type(:patient) + assert_valid_resource + end + end + end +end diff --git a/lib/inferno_template/metadata.rb b/lib/inferno_template/metadata.rb index cd8b663..2401c13 100644 --- a/lib/inferno_template/metadata.rb +++ b/lib/inferno_template/metadata.rb @@ -5,11 +5,73 @@ class Metadata < Inferno::TestKit id :inferno_template title 'Inferno Template' description <<~DESCRIPTION - This is a big markdown description of the test kit. + The Example Test Kit is a testing tool for Health IT systems seeking to meet the requirements of API Criterion within the Example Certification Program. + + *or* + + The Example Test Kit validates the conformance of a server implementation to a specific version of the [Example IG](https://example.com/example). + Currently, Inferno can test against implementations of following versions of the Example IG: v1.0.0, v1.3.0, v2.0.0, and v3.0.1. + + + + ## Getting Started + + Please select which approved version of each standard to use, and click ‘Create Test Session’ to begin testing. + + This test kit includes a [simulated conformant FHIR API](https://inferno.healthit.gov/reference-server/) + that can be used to demonstrate success for all tests. This simulated API is open source and is available on GitHub. + Visit the [walkthrough](https://example.com/Walkthrough) for a demonstration + of using these tests against the provided simulated FHIR API. + + ## Status + + The Example Test Kit is actively developed and updates are released monthly. + + *or* + + These tests are a **DRAFT**. Future versions of these tests may verify other requirements and may change how these requirements are tested. + + ## Conformance + + The test kit currently tests all requirements for the + [API Criterion within the Example Certification Program](https://example.com/api-criterion). + This includes: + - The Lorum IG [v1.0.0](https://example.com/lorum/1.0.0) + - The Ipsum IG [v2.0.0](https://example.com/ipsum/2.0.0), [v3.0.1](https://example.com/ipsum/3.0.1) + - The Dolor IG [v2.0.2](https://example.com/dolor/2.0.2) + + *or* + + The test kit currently tests the following requirements: + - Vel mattis erat semper ut + - Suspendisse eget tempor + - Nulla eu cursus turpis + - Praesent orci diam + + + ## Repository + + The Example Kit can be + [downloaded from its GitHub repository](https://example.com/example-test-kit-repo), + where additional resources and documentation are also available to help users get + started with the testing process. The repository [Wiki](https://example.com/example-test-kit-repo/wiki/) + provides a [FAQ](https://example.com/example-test-kit-repo/wiki/FAQ) for testers, + and the [Releases](https://example.com/example-test-kit-repo/releases) page provides information about each new release. + + ## Providing Feedback and Reporting Issues + + We welcome feedback on the tests, including but not limited to the following areas: + + - Validation logic, such as potential bugs, lax checks, and unexpected failures. + - Requirements coverage, such as requirements that have been missed, tests that necessitate features that the IG does not require, or other issues with the interpretation of the IG’s requirements. + - User experience, such as confusing or missing information in the test UI. + + Please report any issues with this set of tests in the [issues section](https://example.com/example-test-kit-repo/issues) of the repository. DESCRIPTION + suite_ids [:inferno_template] - # tags ['SMART App Launch', 'US Core'] - # last_updated '2024-03-07' + tags [] # E.g., ['SMART App Launch', 'US Core'] + last_updated LAST_UPDATED version VERSION maturity 'Low' authors ['Inferno Template'] diff --git a/lib/inferno_template/suite.rb b/lib/inferno_template/suite.rb index d08a2f6..2dc08ac 100644 --- a/lib/inferno_template/suite.rb +++ b/lib/inferno_template/suite.rb @@ -13,13 +13,13 @@ class Suite < Inferno::TestSuite input :credentials, title: 'OAuth Credentials', - type: :oauth_credentials, + type: :auth_info, optional: true # All FHIR requests in this suite will use this FHIR client fhir_client do url :url - oauth_credentials :credentials + auth_info :credentials end # All FHIR validation requests will use this FHIR validator diff --git a/lib/inferno_template/version.rb b/lib/inferno_template/version.rb index f902f6e..6388a10 100644 --- a/lib/inferno_template/version.rb +++ b/lib/inferno_template/version.rb @@ -1,3 +1,4 @@ module InfernoTemplate VERSION = '0.0.0'.freeze + LAST_UPDATED = '2025-07-21'.freeze # TODO: update next release end diff --git a/spec/inferno_template/patient_group_spec.rb b/spec/inferno_template/patient_group_spec.rb index 9c922e8..08b07ff 100644 --- a/spec/inferno_template/patient_group_spec.rb +++ b/spec/inferno_template/patient_group_spec.rb @@ -1,3 +1,4 @@ +# @note includes RSpec shared context 'when testing a runnable' RSpec.describe InfernoTemplate::PatientGroup do let(:suite_id) { 'inferno_template' } let(:group) { suite.groups[1] } @@ -7,7 +8,7 @@ outcomes: [{ issues: [] }], - sessionId: '' + sessionId: test_session.id } end let(:error_outcome) do @@ -19,7 +20,7 @@ level: 'ERROR' }] }], - sessionId: '' + sessionId: test_session.id } end @@ -34,7 +35,7 @@ result = run(test, url: url, patient_id: patient_id) - expect(result.result).to eq('pass') + expect(result.result).to eq('pass'), result.result_message end it 'fails if a 200 is not received' do @@ -44,7 +45,7 @@ result = run(test, url: url, patient_id: patient_id) - expect(result.result).to eq('fail') + expect(result.result).to eq('fail'), result.result_message expect(result.result_message).to match(/200/) end @@ -55,7 +56,7 @@ result = run(test, url: url, patient_id: patient_id) - expect(result.result).to eq('fail') + expect(result.result).to eq('fail'), result.result_message expect(result.result_message).to match(/Patient/) end @@ -66,7 +67,7 @@ result = run(test, url: url, patient_id: patient_id) - expect(result.result).to eq('fail') + expect(result.result).to eq('fail'), result.result_message expect(result.result_message).to match(/resource with id/) end end @@ -75,7 +76,7 @@ let(:test) { group.tests.last } it 'passes if the resource is valid' do - stub_request(:post, "#{ENV.fetch('FHIR_RESOURCE_VALIDATOR_URL')}/validate") + stub_request(:post, validation_url) .with(query: hash_including({})) .to_return(status: 200, body: success_outcome.to_json) @@ -89,11 +90,11 @@ result = run(test, url: url) - expect(result.result).to eq('pass') + expect(result.result).to eq('pass'), result.result_message end it 'fails if the resource is not valid' do - stub_request(:post, "#{ENV.fetch('FHIR_RESOURCE_VALIDATOR_URL')}/validate") + stub_request(:post, validation_url) .with(query: hash_including({})) .to_return(status: 200, body: error_outcome.to_json) @@ -107,7 +108,7 @@ result = run(test, url: url) - expect(result.result).to eq('fail') + expect(result.result).to eq('fail'), result.result_message end end end