diff --git a/CHANGELOG.md b/CHANGELOG.md index 87ff1ba12..ee61d92be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 0.5.2 +* FI-3366: Fetch report date from test results by @AlyssaWang in https://github.com/inferno-framework/inferno-core/pull/567 +* FI-3019: Add custom blockquote styles by @AlyssaWang in https://github.com/inferno-framework/inferno-core/pull/556 +* FI-2622: Update meta tags for link unfurling by @AlyssaWang in https://github.com/inferno-framework/inferno-core/pull/553 +* FI-2961 execute preset support by @Shaumik-Ashraf in https://github.com/inferno-framework/inferno-core/pull/565 +* FI-3511: Fix json handling by @Jammjammjamm in https://github.com/inferno-framework/inferno-core/pull/568 + ## 0.5.1 * FI-3097: Maintain checkbox label colors on error by @AlyssaWang in https://github.com/inferno-framework/inferno-core/pull/537 * Fi 2962 execute outputters by @Shaumik-Ashraf in https://github.com/inferno-framework/inferno-core/pull/541 diff --git a/Gemfile.lock b/Gemfile.lock index 995ba3f17..432ba6327 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - inferno_core (0.5.1) + inferno_core (0.5.2) activesupport (~> 6.1.7.5) base62-rb (= 0.3.1) blueprinter (= 0.25.2) @@ -239,7 +239,7 @@ GEM http-cookie (>= 1.0.2, < 2.0) mime-types (>= 1.16, < 4.0) netrc (~> 0.8) - rexml (3.3.8) + rexml (3.3.9) rouge (4.4.0) rspec (3.13.0) rspec-core (~> 3.13.0) diff --git a/dev_suites/dev_infrastructure_test/infrastructure_test.rb b/dev_suites/dev_infrastructure_test/infrastructure_test_suite.rb similarity index 97% rename from dev_suites/dev_infrastructure_test/infrastructure_test.rb rename to dev_suites/dev_infrastructure_test/infrastructure_test_suite.rb index cc4340d9b..3a86783dd 100644 --- a/dev_suites/dev_infrastructure_test/infrastructure_test.rb +++ b/dev_suites/dev_infrastructure_test/infrastructure_test_suite.rb @@ -1,8 +1,9 @@ +require_relative 'empty_group' require_relative 'external_outer_group' require_relative 'failing_optional_group' -require_relative 'passing_optional_group' +require_relative 'json_test_endpoint' require_relative 'mixed_optional_group' -require_relative 'empty_group' +require_relative 'passing_optional_group' module InfrastructureTest class Suite < Inferno::TestSuite @@ -29,6 +30,8 @@ class Suite < Inferno::TestSuite } ] + suite_endpoint :post, '/json_test', JSONTestEndpoint + input :suite_input output :suite_output diff --git a/dev_suites/dev_infrastructure_test/json_test_endpoint.rb b/dev_suites/dev_infrastructure_test/json_test_endpoint.rb new file mode 100644 index 000000000..2b74d7ee9 --- /dev/null +++ b/dev_suites/dev_infrastructure_test/json_test_endpoint.rb @@ -0,0 +1,9 @@ +class JSONTestEndpoint < Inferno::DSL::SuiteEndpoint + def test_run_identifier + 'ABC' + end + + def make_response + response.body = req.params[:json_param] + end +end diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 5dd27fe8a..7ee94baa5 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -15,7 +15,7 @@ GEM coffee-script-source (1.11.1) colorator (1.1.0) commonmarker (0.23.10) - concurrent-ruby (1.2.3) + concurrent-ruby (1.3.4) dnsruby (1.72.0) simpleidn (~> 0.2.1) em-websocket (0.5.3) @@ -210,12 +210,12 @@ GEM jekyll (>= 3.5, < 5.0) jekyll-feed (~> 0.9) jekyll-seo-tag (~> 2.1) - minitest (5.22.3) + minitest (5.25.4) net-http (0.4.1) uri - nokogiri (1.16.4-arm64-darwin) + nokogiri (1.16.8-arm64-darwin) racc (~> 1.4) - nokogiri (1.16.4-x86_64-darwin) + nokogiri (1.16.8-x86_64-darwin) racc (~> 1.4) octokit (4.25.1) faraday (>= 1, < 3) @@ -223,11 +223,11 @@ GEM pathutil (0.16.2) forwardable-extended (~> 2.6) public_suffix (4.0.7) - racc (1.7.3) + racc (1.8.1) rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - rexml (3.2.6) + rexml (3.3.9) rouge (3.26.0) rubyzip (2.3.2) safe_yaml (1.0.5) @@ -253,10 +253,11 @@ GEM unf_ext (0.0.9.1) unicode-display_width (1.8.0) uri (0.13.0) - webrick (1.8.1) - zeitwerk (2.6.13) + webrick (1.9.1) + zeitwerk (2.6.18) PLATFORMS + arm64-darwin-21 arm64-darwin-22 x86_64-darwin-22 diff --git a/lib/inferno/apps/cli/templates/%library_name%.gemspec.tt b/lib/inferno/apps/cli/templates/%library_name%.gemspec.tt index 853e4e5f6..cfa1f042c 100644 --- a/lib/inferno/apps/cli/templates/%library_name%.gemspec.tt +++ b/lib/inferno/apps/cli/templates/%library_name%.gemspec.tt @@ -1,11 +1,15 @@ +require_relative 'lib/<%= library_name %>/version' + Gem::Specification.new do |spec| spec.name = '<%= library_name %>' - spec.version = '0.0.1' + spec.version = <%= module_name %>::VERSION spec.authors = <%= authors %> # spec.email = ['TODO'] spec.date = Time.now.utc.strftime('%Y-%m-%d') - spec.summary = '<%= title_name %> Test Kit' - spec.description = '<%= human_name %> Inferno test kit for FHIR' + spec.summary = '<%= title_name %>' + # spec.description = <<~DESCRIPTION + # This is a big markdown description of the test kit. + # DESCRIPTION # spec.homepage = 'TODO' spec.license = 'Apache-2.0' spec.add_runtime_dependency 'inferno_core', '~> <%= Inferno::VERSION %>' diff --git a/lib/inferno/apps/cli/templates/Dockerfile.tt b/lib/inferno/apps/cli/templates/Dockerfile.tt index d32710caf..19162984a 100644 --- a/lib/inferno/apps/cli/templates/Dockerfile.tt +++ b/lib/inferno/apps/cli/templates/Dockerfile.tt @@ -6,12 +6,13 @@ RUN mkdir -p $INSTALL_PATH WORKDIR $INSTALL_PATH +ADD lib/<%= library_name %>/metadata.rb $INSTALL_PATH/lib/<%= library_name %>/metadata.rb ADD *.gemspec $INSTALL_PATH ADD Gemfile* $INSTALL_PATH RUN gem install bundler -# The below RUN line is commented out for development purposes, because any change to the +# The below RUN line is commented out for development purposes, because any change to the # required gems will break the dockerfile build process. -# If you want to run in Deploy mode, just run `bundle install` locally to update +# If you want to run in Deploy mode, just run `bundle install` locally to update # Gemfile.lock, and uncomment the following line. # RUN bundle config set --local deployment 'true' RUN bundle install diff --git a/lib/inferno/apps/cli/templates/lib/%library_name%.rb.tt b/lib/inferno/apps/cli/templates/lib/%library_name%.rb.tt index 12e363228..90b802e92 100644 --- a/lib/inferno/apps/cli/templates/lib/%library_name%.rb.tt +++ b/lib/inferno/apps/cli/templates/lib/%library_name%.rb.tt @@ -1,58 +1 @@ -require_relative '<%= library_name %>/patient_group' - -module <%= module_name %> - class Suite < Inferno::TestSuite - id :<%= test_suite_id %> - title '<%= title_name %> Test Suite' - description '<%= human_name %> test suite.' - - # These inputs will be available to all tests in this suite - input :url, - title: 'FHIR Server Base Url' - - input :credentials, - title: 'OAuth Credentials', - type: :oauth_credentials, - optional: true - - # All FHIR requests in this suite will use this FHIR client - fhir_client do - url :url - oauth_credentials :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 'Verify that the server has a CapabilityStatement' - - 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 +require_relative '<%= library_name %>/suite' diff --git a/lib/inferno/apps/cli/templates/lib/%library_name%/metadata.rb.tt b/lib/inferno/apps/cli/templates/lib/%library_name%/metadata.rb.tt new file mode 100644 index 000000000..1717ff4b3 --- /dev/null +++ b/lib/inferno/apps/cli/templates/lib/%library_name%/metadata.rb.tt @@ -0,0 +1,18 @@ +require_relative 'version' + +module <%= module_name %> + class Metadata < Inferno::TestKit + id :<%= test_kit_id %> + title '<%= title_name %>' + description <<~DESCRIPTION + This is a big markdown description of the test kit. + DESCRIPTION + suite_ids [:<%= test_suite_id %>] + # tags ['SMART App Launch', 'US Core'] + # last_updated '2024-03-07' + version VERSION + maturity 'Low' + authors <%= authors %> + # repo 'TODO' + end +end diff --git a/lib/inferno/apps/cli/templates/lib/%library_name%/suite.rb.tt b/lib/inferno/apps/cli/templates/lib/%library_name%/suite.rb.tt new file mode 100644 index 000000000..a2f3fec08 --- /dev/null +++ b/lib/inferno/apps/cli/templates/lib/%library_name%/suite.rb.tt @@ -0,0 +1,59 @@ +require_relative 'metadata' +require_relative 'patient_group' + +module <%= module_name %> + class Suite < Inferno::TestSuite + id :<%= test_suite_id %> + title '<%= title_name %> Test Suite' + description '<%= human_name %> test suite.' + + # These inputs will be available to all tests in this suite + input :url, + title: 'FHIR Server Base Url' + + input :credentials, + title: 'OAuth Credentials', + type: :oauth_credentials, + optional: true + + # All FHIR requests in this suite will use this FHIR client + fhir_client do + url :url + oauth_credentials :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 'Verify that the server has a CapabilityStatement' + + 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 \ No newline at end of file diff --git a/lib/inferno/apps/cli/templates/lib/%library_name%/version.rb.tt b/lib/inferno/apps/cli/templates/lib/%library_name%/version.rb.tt new file mode 100644 index 000000000..056069ca0 --- /dev/null +++ b/lib/inferno/apps/cli/templates/lib/%library_name%/version.rb.tt @@ -0,0 +1,3 @@ +module <%= module_name %> + VERSION = '0.0.0'.freeze +end diff --git a/lib/inferno/apps/web/application.rb b/lib/inferno/apps/web/application.rb index 158e318ef..1773a5178 100644 --- a/lib/inferno/apps/web/application.rb +++ b/lib/inferno/apps/web/application.rb @@ -1,6 +1,10 @@ require 'hanami/middleware/body_parser' require_relative 'router' +# Only required to monkey patch the JSON parser to support application/fhir+json +require 'hanami/middleware/body_parser/json_parser' +require_relative '../../ext/json_parser' + module Inferno module Web def self.app diff --git a/lib/inferno/entities.rb b/lib/inferno/entities.rb index 3158719b0..23cc87ba1 100644 --- a/lib/inferno/entities.rb +++ b/lib/inferno/entities.rb @@ -8,6 +8,7 @@ require_relative 'entities/session_data' require_relative 'entities/test' require_relative 'entities/test_group' +require_relative 'entities/test_kit' require_relative 'entities/test_run' require_relative 'entities/test_session' require_relative 'entities/test_suite' diff --git a/lib/inferno/entities/test_kit.rb b/lib/inferno/entities/test_kit.rb index cf6adce84..80fcad415 100644 --- a/lib/inferno/entities/test_kit.rb +++ b/lib/inferno/entities/test_kit.rb @@ -6,7 +6,7 @@ module Entities # @example # # module USCoreTestKit - # class TestKit < Inferno::Entities::TestKit + # class Metadata < Inferno::Entities::TestKit # id :us_core # title 'US Core Test Kit' # description <<~DESCRIPTION @@ -156,7 +156,7 @@ def add_self_to_repository # @private def repository - @repository ||= Inferno::Repositories::TestKits + @repository ||= Inferno::Repositories::TestKits.new end # @private @@ -168,4 +168,6 @@ def copy_instance_variables end end end + + TestKit = Entities::TestKit end diff --git a/lib/inferno/entities/test_suite.rb b/lib/inferno/entities/test_suite.rb index 2fe747869..4d6b28bdf 100644 --- a/lib/inferno/entities/test_suite.rb +++ b/lib/inferno/entities/test_suite.rb @@ -84,15 +84,16 @@ def reference_hash } end - # Set/get the version of this test suite. + # Set/get the version of this test suite. Defaults to the TestKit + # version. # # @param version [String] # # @return [String, nil] def version(version = nil) - return @version if version.nil? + @version = version if version.present? - @version = version + @version || test_kit&.version end # @private @@ -186,6 +187,25 @@ def suite_summary(suite_summary = nil) @suite_summary = format_markdown(suite_summary) end + + # Get the TestKit this suite belongs to + # + # @return [Inferno::Entities::TestKit] + def test_kit + return @test_kit if @test_kit + + module_name = name + + while module_name.present? && @test_kit.nil? + module_name = module_name.deconstantize + + next unless const_defined?("#{module_name}::Metadata") + + @test_kit = const_get("#{module_name}::Metadata") + end + + @test_kit + end end end end diff --git a/lib/inferno/ext/json_parser.rb b/lib/inferno/ext/json_parser.rb new file mode 100644 index 000000000..361b6da8e --- /dev/null +++ b/lib/inferno/ext/json_parser.rb @@ -0,0 +1,11 @@ +module Hanami + module Middleware + class BodyParser + class JsonParser + def self.mime_types + ['application/json', 'application/vnd.api+json', 'application/fhir+json'] + end + end + end + end +end diff --git a/lib/inferno/utils/named_thor_actions.rb b/lib/inferno/utils/named_thor_actions.rb index 3fc55fba3..0e9217161 100644 --- a/lib/inferno/utils/named_thor_actions.rb +++ b/lib/inferno/utils/named_thor_actions.rb @@ -25,8 +25,12 @@ def title_name human_name.split.map(&:capitalize).join(' ') end + def test_kit_id + library_name.delete_suffix('_test_kit') + end + def test_suite_id - "#{library_name}_test_suite" + test_kit_id end end end diff --git a/lib/inferno/version.rb b/lib/inferno/version.rb index 7cba0a7eb..fcfe8dd73 100644 --- a/lib/inferno/version.rb +++ b/lib/inferno/version.rb @@ -1,4 +1,4 @@ module Inferno # Standard patterns for gem versions: https://guides.rubygems.org/patterns/ - VERSION = '0.5.1'.freeze + VERSION = '0.5.2'.freeze end diff --git a/spec/inferno/cli/new_spec.rb b/spec/inferno/cli/new_spec.rb index 2641174c4..5ca7a39ef 100644 --- a/spec/inferno/cli/new_spec.rb +++ b/spec/inferno/cli/new_spec.rb @@ -31,12 +31,10 @@ expect(File).to exist('test-fhir-app/test_fhir_app.gemspec') expect(File).to exist('test-fhir-app/lib/test_fhir_app.rb') - if cli_args.include? '--author' - expect(File.read('test-fhir-app/test_fhir_app.gemspec')).to match(/authors\s*=.*ABC/) - end - - if cli_args.count('--author') == 2 - expect(File.read('test-fhir-app/test_fhir_app.gemspec')).to match(/authors\s*=.*ABC.*DEF/) + if cli_args.count('--author') == 1 + expect(File.read('test-fhir-app/lib/test_fhir_app/metadata.rb')).to include('authors ["ABC"]') + elsif cli_args.count('--author') == 2 + expect(File.read('test-fhir-app/lib/test_fhir_app/metadata.rb')).to include('authors ["ABC", "DEF"]') end if cli_args.count('--implementation-guide') == 1 diff --git a/spec/inferno/dsl/suite_endpoint_spec.rb b/spec/inferno/dsl/suite_endpoint_spec.rb new file mode 100644 index 000000000..2f0cc8a0e --- /dev/null +++ b/spec/inferno/dsl/suite_endpoint_spec.rb @@ -0,0 +1,31 @@ +RSpec.describe Inferno::DSL::SuiteEndpoint, :request do + let(:test_run) do + repo_create(:test_run, identifier: 'ABC', status: 'waiting', wait_timeout: Time.now + 5.minutes) + end + + before do + repo_create( + :result, + test_run_id: test_run.id, + result: 'wait', + test_id: InfrastructureTest::Suite.groups.first.groups.first.tests.first.id, + test_suite_id: nil + ) + end + + it 'automatically parses application/json bodies' do + post '/custom/infra_test/json_test', + { json_param: 'EXPECTED_RESPONSE_BODY' }.to_json, + 'CONTENT_TYPE' => 'application/json' + + expect(last_response.body).to eq('EXPECTED_RESPONSE_BODY') + end + + it 'automatically parses application/fhir+json bodies' do + post '/custom/infra_test/json_test', + { json_param: 'EXPECTED_RESPONSE_BODY' }.to_json, + 'CONTENT_TYPE' => 'application/fhir+json' + + expect(last_response.body).to eq('EXPECTED_RESPONSE_BODY') + end +end diff --git a/spec/inferno/entities/test_suite_spec.rb b/spec/inferno/entities/test_suite_spec.rb index 80d0efd22..28f61dbd9 100644 --- a/spec/inferno/entities/test_suite_spec.rb +++ b/spec/inferno/entities/test_suite_spec.rb @@ -1,3 +1,26 @@ +module NoTestKit + class NoTestKitSuite < Inferno::Entities::TestSuite + id :no_test_kit + end +end + +module NestedTestKit + class Metadata < Inferno::Entities::TestKit + id :nested + version 'VERSION' + end + + class TopLevelSuite < Inferno::Entities::TestSuite + id :top_level + end + + module SubModule + class NestedSuite < Inferno::Entities::TestSuite + id :nested + end + end +end + RSpec.describe Inferno::Entities::TestSuite do let!(:suite_class) { Class.new(described_class) } let(:suite_id) { 'basic' } @@ -93,9 +116,17 @@ suite_class end - specify 'it gets/sets the version' do + it 'gets/sets the version' do expect(test_suite.version).to eq('VERSION') end + + it 'defaults to the test kit version' do + expect(NestedTestKit::TopLevelSuite.version).to eq('VERSION') + end + + it 'returns nil if no test kit or version are defined' do + expect(NoTestKit::NoTestKitSuite.version).to be_nil + end end describe '.check_configuration' do @@ -170,11 +201,11 @@ ] end - specify 'it returns an empty array if no links are set' do + it 'returns an empty array if no links are set' do expect(suite_class.links).to eq([]) end - specify 'it can set and retrieve a list of http links for display' do + it 'can set and retrieve a list of http links for display' do suite_class.links links link = suite_class.links.first expect(link[:label]).to eq('One') @@ -184,7 +215,7 @@ end describe '.add_link' do - specify 'it adds a custom link to the list' do + it 'adds a custom link to the list' do suite_class.add_link('custom_type', 'One', 'http://one.com') link = suite_class.links.first expect(link[:type]).to eq('custom_type') @@ -194,7 +225,7 @@ end describe '.source_code_url' do - specify 'it adds a source code link to the list' do + it 'adds a source code link to the list' do suite_class.source_code_url('http://github.com/source_code') link = suite_class.links.first expect(link[:type]).to eq('source_code') @@ -202,7 +233,7 @@ expect(link[:url]).to eq('http://github.com/source_code') end - specify 'it allows overriding the label for source code links' do + it 'allows overriding the label for source code links' do suite_class.source_code_url('http://github.com/source_code', label: 'My Source') link = suite_class.links.first expect(link[:label]).to eq('My Source') @@ -210,7 +241,7 @@ end describe '.ig_url' do - specify 'it adds an implementation guide link to the list' do + it 'adds an implementation guide link to the list' do suite_class.ig_url('http://ig.example.com') link = suite_class.links.first expect(link[:type]).to eq('ig') @@ -218,7 +249,7 @@ expect(link[:url]).to eq('http://ig.example.com') end - specify 'it allows overriding the label for IG links' do + it 'allows overriding the label for IG links' do suite_class.ig_url('http://ig.example.com', label: 'My IG') link = suite_class.links.first expect(link[:label]).to eq('My IG') @@ -226,7 +257,7 @@ end describe '.download_url' do - specify 'it adds a download link to the list' do + it 'adds a download link to the list' do suite_class.download_url('http://example.com/download') link = suite_class.links.first expect(link[:type]).to eq('download') @@ -234,7 +265,7 @@ expect(link[:url]).to eq('http://example.com/download') end - specify 'it allows overriding the label for download links' do + it 'allows overriding the label for download links' do suite_class.download_url('http://example.com/download', label: 'Get Latest Version') link = suite_class.links.first expect(link[:label]).to eq('Get Latest Version') @@ -242,7 +273,7 @@ end describe '.report_issue_url' do - specify 'it adds a report issue link to the list' do + it 'adds a report issue link to the list' do suite_class.report_issue_url('http://example.com/report') link = suite_class.links.first expect(link[:type]).to eq('report_issue') @@ -250,10 +281,24 @@ expect(link[:url]).to eq('http://example.com/report') end - specify 'it allows overriding the label for report issue links' do + it 'allows overriding the label for report issue links' do suite_class.report_issue_url('http://example.com/report', label: 'Report Problem') link = suite_class.links.first expect(link[:label]).to eq('Report Problem') end end + + describe '.test_kit' do + it 'returns nil if no test kit is defined' do + expect(NoTestKit::NoTestKitSuite.test_kit).to be_nil + end + + it 'returns a test kit defined in the same module as the suite' do + expect(NestedTestKit::TopLevelSuite.test_kit).to eq(NestedTestKit::Metadata) + end + + it 'returns a test kit defined in a higher-level module' do + expect(NestedTestKit::SubModule::NestedSuite.test_kit).to eq(NestedTestKit::Metadata) + end + end end diff --git a/spec/inferno/utils/named_thor_actions_spec.rb b/spec/inferno/utils/named_thor_actions_spec.rb index 8e697beb9..0bce1d500 100644 --- a/spec/inferno/utils/named_thor_actions_spec.rb +++ b/spec/inferno/utils/named_thor_actions_spec.rb @@ -36,8 +36,12 @@ expect(dummy.title_name).to eq('Test Fhir App') end + it 'returns proper test kit id' do + expect(dummy.test_kit_id).to eq('test_fhir_app') + end + it 'returns proper test suite id' do - expect(dummy.test_suite_id).to eq('test_fhir_app_test_suite') + expect(dummy.test_suite_id).to eq('test_fhir_app') end end end