From a320dee565fb17a0ff10aab6538a7692d89490fc Mon Sep 17 00:00:00 2001 From: Stephen MacVicar Date: Tue, 14 Jan 2025 08:54:50 -0500 Subject: [PATCH 1/2] FI-3338: Create common test kit specs (#586) * WIP * WIP * WIP * add test for test kit gem metadata tag * fix linting errors * include shared specs in gem * add test kit spec to require_helpers * Update spec/shared/test_kit_examples.rb Co-authored-by: Rob Scanlon * fix specs * fix linting error * add tests for common suite links --------- Co-authored-by: Rob Scanlon --- inferno_core.gemspec | 1 + lib/inferno/spec_support.rb | 2 + spec/shared/test_kit_examples.rb | 126 +++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 spec/shared/test_kit_examples.rb diff --git a/inferno_core.gemspec b/inferno_core.gemspec index 18d139e12..8e67e459b 100644 --- a/inferno_core.gemspec +++ b/inferno_core.gemspec @@ -57,6 +57,7 @@ Gem::Specification.new do |spec| 'spec/support/factory_bot.rb', Dir['spec/factories/**/*.rb'], Dir['spec/fixtures/**/*.rb'], + Dir['spec/shared/**/*.rb'], Dir['spec/*.rb'] ].flatten diff --git a/lib/inferno/spec_support.rb b/lib/inferno/spec_support.rb index f1f8b8ce7..c11dc68c3 100644 --- a/lib/inferno/spec_support.rb +++ b/lib/inferno/spec_support.rb @@ -7,11 +7,13 @@ module SpecSupport FACTORY_PATH = File.expand_path('../../spec/factories', __dir__).freeze REQUEST_HELPER_PATH = File.expand_path('../../spec/request_helper', __dir__).freeze RUNNABLE_HELPER_PATH = File.expand_path('../../spec/runnable_helper', __dir__).freeze + TEST_KIT_SPEC = File.expand_path('../../spec/shared/test_kit_examples', __dir__).freeze def self.require_helpers require FACTORY_BOT_SUPPORT_PATH require RUNNABLE_HELPER_PATH require REQUEST_HELPER_PATH + require TEST_KIT_SPEC end end end diff --git a/spec/shared/test_kit_examples.rb b/spec/shared/test_kit_examples.rb new file mode 100644 index 000000000..a6fbc6e81 --- /dev/null +++ b/spec/shared/test_kit_examples.rb @@ -0,0 +1,126 @@ +RSpec.shared_examples 'platform_deployable_test_kit' do + let(:test_kit_location) do + Object.const_source_location(described_class.name).first + end + let(:test_kit_gem) do + Bundler.definition.specs.find { |gem| test_kit_location.start_with? gem.full_gem_path } + end + let(:base_path) do + test_kit_gem.full_gem_path + end + let(:test_kit) do + described_class.const_get('Metadata') + rescue NameError + skip 'TestKit must be defined first' + end + let(:suites) do + test_kit.suite_ids.map { |id| Inferno::Repositories::TestSuites.new.find(id) } + end + + describe 'TestKit' do + it 'defines test kit in the Metadata class' do + error_message = + "Define #{described_class.name}::Metadata at " \ + "lib/#{described_class.name.underscore}/metadata.rb and require it in " \ + "lib/#{described_class.name.underscore}.rb\n" + + expect { described_class.const_get('Metadata') }.to_not raise_error(NameError), error_message + + expect(described_class.const_get('Metadata') < Inferno::Entities::TestKit).to be(true) + end + + it 'defines all required fields' do + required_fields = [ + :id, + :title, + :description, + :suite_ids, + :version, + :maturity + ] + + required_fields.each do |field_name| + expect(test_kit.send(field_name)).to be_present + end + end + + it 'has a description with a ' do + error_message = + 'The test kit description must begin with one paragraph followed by "". The portion of the description above the break is displayed ' \ + "on the test kit listing page.\n" + + expect(test_kit.description).to include(''), error_message + end + + it 'has a maturity of "Low", "Medium", or "High"' do + expect(['Low', 'Medium', 'High']).to include(test_kit.maturity) # rubocop:disable RSpec/ExpectActual + end + end + + describe 'suites' do + it 'relies on the test kit version rather than defining the version in the suites' do + suite_paths = suites.map { |suite| Object.const_source_location(suite.name).first } + suite_contents = suite_paths.map { |path| File.read(path) } + + suite_contents.each_with_index do |suite, i| + error_message = + "Suite at #{suite_paths[i]} should not explicitly declare a version, as " \ + 'its version can now be determined by the version of its Test Kit.' \ + "Remove the `version` method call in the suite definition.\n" + + expect(suite).to_not match(/^\s+version(\s|\()\S+\)?/), error_message + end + end + + it 'contains standard links' do + suites.each do |suite| + link_labels = suite.links.map { |link| link[:label] } + + expected_labels = ['Report Issue', 'Open Source', 'Download'] + + error_message = + "Include the standard 'Report Issue', 'Open Source', and 'Download links in " \ + 'each suite.\n' + expect(link_labels).to match_array(expected_labels), error_message + end + end + end + + describe 'presets' do + it 'includes presets in the gem' do + presets = Dir[ + File.join(base_path, 'config', 'presets', '*.json'), + File.join(base_path, 'config', 'presets', '*.json.erb') + ].map { |file_path| file_path.delete_prefix "#{Dir.pwd}/" } + + missing_presets = presets - test_kit_gem.files + + error_message = + "The following presets are not included in the gem: #{missing_presets.join(', ')}\n" \ + "Ensure that config/presets is included in spec.files in #{test_kit_gem.name}.gemspec" + + expect(missing_presets).to be_empty, error_message + end + end + + describe 'gemspec' do + it 'uses git to determine files to include in the gem' do + gemspec_contents = File.read(File.join(base_path, "#{test_kit_gem.name}.gemspec")) + + error_message = + 'Use git to determine which files to include in the gem. In ' \ + "#{test_kit_gem.name}.gemspec, use: " \ + "spec.files = `[ -d .git ] && git ls-files -z lib config/presets LICENSE`.split(\"\\x0\")\n" + + expect(gemspec_contents).to include('[ -d .git ] && git ls-files'), error_message + end + + it 'includes the inferno test kit metadata tag' do + error_message = + %(Add "spec.metadata['inferno_test_kit'] = 'true'" to #{test_kit_gem.name}.gemspec) + + expect(test_kit_gem.metadata['inferno_test_kit']).to eq('true'), error_message + end + end +end From 73929834e3f05b9e59db2ab7c61c168f432daced Mon Sep 17 00:00:00 2001 From: Stephen MacVicar Date: Wed, 15 Jan 2025 10:21:48 -0500 Subject: [PATCH 2/2] FI-3360: Update ruby (#589) * update ruby and tool version files * update ruby version in Gemfile * update required ruby version in gemspec * bundle install * update target ruby version for rubocop * apply rubocop fixes * update ruby version in template * add spec for ruby version in dockerfile * update ruby version in ci --- .github/workflows/ruby.yml | 6 +++--- .rubocop.yml | 2 +- .ruby-version | 2 +- .tool-versions | 2 +- Gemfile | 2 +- Gemfile.lock | 2 +- inferno_core.gemspec | 2 +- lib/inferno/apps/cli/execute/console_outputter.rb | 4 ++-- lib/inferno/apps/cli/new.rb | 4 ++-- lib/inferno/apps/cli/templates/%library_name%.gemspec.tt | 2 +- lib/inferno/apps/cli/templates/.rubocop.yml | 2 +- lib/inferno/apps/cli/templates/.ruby-version | 2 +- lib/inferno/apps/cli/templates/.tool-versions | 2 +- lib/inferno/apps/cli/templates/Dockerfile.tt | 2 +- lib/inferno/dsl/fhir_resource_validation.rb | 4 ++-- lib/inferno/dsl/fhir_validation.rb | 4 ++-- spec/shared/test_kit_examples.rb | 7 +++++++ 17 files changed, 29 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index d651e7633..74c1c830b 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ['3.1.2'] + ruby-version: ['3.3.6'] steps: - uses: actions/checkout@v3 @@ -27,7 +27,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ['3.1.2'] + ruby-version: ['3.3.6'] steps: - uses: actions/checkout@v3 - name: Set up Ruby @@ -49,7 +49,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ['3.1.2'] + ruby-version: ['3.3.6'] steps: - uses: actions/checkout@v3 - name: Set up Ruby diff --git a/.rubocop.yml b/.rubocop.yml index 94e7f2252..19be17725 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -5,7 +5,7 @@ require: AllCops: NewCops: enable - TargetRubyVersion: 3.1 + TargetRubyVersion: 3.3 Exclude: - 'Gemfile' - 'vendor/**/*' diff --git a/.ruby-version b/.ruby-version index ef538c281..9c25013db 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.1.2 +3.3.6 diff --git a/.tool-versions b/.tool-versions index 04d9151ea..aa7a8b552 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -ruby 3.1.2 +ruby 3.3.6 nodejs 20.17.0 \ No newline at end of file diff --git a/Gemfile b/Gemfile index 6f71bc29c..ff14ff9e5 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -ruby '3.1.2' +ruby '3.3.6' gemspec diff --git a/Gemfile.lock b/Gemfile.lock index 99d956fb3..7bc1fc777 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -352,7 +352,7 @@ DEPENDENCIES yard-junk RUBY VERSION - ruby 3.1.2p20 + ruby 3.3.6p108 BUNDLED WITH 2.4.22 diff --git a/inferno_core.gemspec b/inferno_core.gemspec index 8e67e459b..c92b925d8 100644 --- a/inferno_core.gemspec +++ b/inferno_core.gemspec @@ -37,7 +37,7 @@ Gem::Specification.new do |spec| spec.add_dependency 'sqlite3', '~> 1.4' spec.add_dependency 'thor', '~> 1.2.1' spec.add_dependency 'tty-markdown', '~> 0.7.1' - spec.required_ruby_version = Gem::Requirement.new('~> 3.1.2') + spec.required_ruby_version = Gem::Requirement.new('~> 3.3.6') spec.metadata['homepage_uri'] = spec.homepage spec.metadata['source_code_uri'] = 'https://github.com/inferno-framework/inferno-core' spec.metadata['changelog_uri'] = 'https://github.com/inferno-framework/inferno-core/blob/main/CHANGELOG.md' diff --git a/lib/inferno/apps/cli/execute/console_outputter.rb b/lib/inferno/apps/cli/execute/console_outputter.rb index 6235f1abb..17250f451 100644 --- a/lib/inferno/apps/cli/execute/console_outputter.rb +++ b/lib/inferno/apps/cli/execute/console_outputter.rb @@ -51,8 +51,8 @@ def print_error(_options, exception) # private - def verbose_print(options, *args) - print(color.dim(*args)) if options[:verbose] + def verbose_print(options, *) + print(color.dim(*)) if options[:verbose] end def color diff --git a/lib/inferno/apps/cli/new.rb b/lib/inferno/apps/cli/new.rb index bc1a43259..7ce0432ef 100644 --- a/lib/inferno/apps/cli/new.rb +++ b/lib/inferno/apps/cli/new.rb @@ -124,8 +124,8 @@ def load_igs end end - def say_unless_quiet(*args) - say(*args) unless options['quiet'] + def say_unless_quiet(*) + say(*) unless options['quiet'] end end end diff --git a/lib/inferno/apps/cli/templates/%library_name%.gemspec.tt b/lib/inferno/apps/cli/templates/%library_name%.gemspec.tt index a819c9075..109067244 100644 --- a/lib/inferno/apps/cli/templates/%library_name%.gemspec.tt +++ b/lib/inferno/apps/cli/templates/%library_name%.gemspec.tt @@ -12,7 +12,7 @@ Gem::Specification.new do |spec| # spec.homepage = 'TODO' spec.license = 'Apache-2.0' spec.add_dependency 'inferno_core', '~> <%= Inferno::VERSION %>' - spec.required_ruby_version = Gem::Requirement.new('>= 3.1.2') + spec.required_ruby_version = Gem::Requirement.new('>= 3.3.6') spec.metadata['inferno_test_kit'] = 'true' # spec.metadata['homepage_uri'] = spec.homepage # spec.metadata['source_code_uri'] = 'TODO' diff --git a/lib/inferno/apps/cli/templates/.rubocop.yml b/lib/inferno/apps/cli/templates/.rubocop.yml index c58e740d8..27c65cf60 100644 --- a/lib/inferno/apps/cli/templates/.rubocop.yml +++ b/lib/inferno/apps/cli/templates/.rubocop.yml @@ -4,7 +4,7 @@ require: AllCops: NewCops: enable SuggestExtensions: false - TargetRubyVersion: 3.1 + TargetRubyVersion: 3.3 Exclude: - 'Gemfile' - 'vendor/**/*' diff --git a/lib/inferno/apps/cli/templates/.ruby-version b/lib/inferno/apps/cli/templates/.ruby-version index 6ebad1488..9c25013db 100644 --- a/lib/inferno/apps/cli/templates/.ruby-version +++ b/lib/inferno/apps/cli/templates/.ruby-version @@ -1 +1 @@ -3.1.2 \ No newline at end of file +3.3.6 diff --git a/lib/inferno/apps/cli/templates/.tool-versions b/lib/inferno/apps/cli/templates/.tool-versions index b8ab7eae2..20a18c233 100644 --- a/lib/inferno/apps/cli/templates/.tool-versions +++ b/lib/inferno/apps/cli/templates/.tool-versions @@ -1 +1 @@ -ruby 3.1.2 \ No newline at end of file +ruby 3.3.6 \ No newline at end of file diff --git a/lib/inferno/apps/cli/templates/Dockerfile.tt b/lib/inferno/apps/cli/templates/Dockerfile.tt index 19162984a..f3219bfef 100644 --- a/lib/inferno/apps/cli/templates/Dockerfile.tt +++ b/lib/inferno/apps/cli/templates/Dockerfile.tt @@ -1,4 +1,4 @@ -FROM ruby:3.1.2 +FROM ruby:3.3.6 ENV INSTALL_PATH=/opt/inferno/ ENV APP_ENV=production diff --git a/lib/inferno/dsl/fhir_resource_validation.rb b/lib/inferno/dsl/fhir_resource_validation.rb index a3e9060c4..ee97e4030 100644 --- a/lib/inferno/dsl/fhir_resource_validation.rb +++ b/lib/inferno/dsl/fhir_resource_validation.rb @@ -380,10 +380,10 @@ def fhir_validators # using multiple validators # @param required_suite_options [Hash] suite options that must be # selected in order to use this validator - def fhir_resource_validator(name = :default, required_suite_options: nil, &block) + def fhir_resource_validator(name = :default, required_suite_options: nil, &) current_validators = fhir_validators[name] || [] - new_validator = Inferno::DSL::FHIRResourceValidation::Validator.new(name, id, required_suite_options, &block) + new_validator = Inferno::DSL::FHIRResourceValidation::Validator.new(name, id, required_suite_options, &) current_validators.reject! { |validator| validator.requirements == required_suite_options } current_validators << new_validator diff --git a/lib/inferno/dsl/fhir_validation.rb b/lib/inferno/dsl/fhir_validation.rb index 3a21e1b3b..998777f02 100644 --- a/lib/inferno/dsl/fhir_validation.rb +++ b/lib/inferno/dsl/fhir_validation.rb @@ -254,10 +254,10 @@ def fhir_validators # using multiple validators # @param required_suite_options [Hash] suite options that must be # selected in order to use this validator - def validator(name = :default, required_suite_options: nil, &block) + def validator(name = :default, required_suite_options: nil, &) current_validators = fhir_validators[name] || [] - new_validator = Inferno::DSL::FHIRValidation::Validator.new(required_suite_options, &block) + new_validator = Inferno::DSL::FHIRValidation::Validator.new(required_suite_options, &) current_validators.reject! { |validator| validator.requirements == required_suite_options } current_validators << new_validator diff --git a/spec/shared/test_kit_examples.rb b/spec/shared/test_kit_examples.rb index a6fbc6e81..6f0ea46e3 100644 --- a/spec/shared/test_kit_examples.rb +++ b/spec/shared/test_kit_examples.rb @@ -56,6 +56,13 @@ it 'has a maturity of "Low", "Medium", or "High"' do expect(['Low', 'Medium', 'High']).to include(test_kit.maturity) # rubocop:disable RSpec/ExpectActual end + + it 'uses the correct ruby version in its Dockerfile' do + dockerfile_path = File.join(base_path, 'Dockerfile') + dockerfile_contents = File.read(dockerfile_path) + + expect(dockerfile_contents.lines.first.chomp).to eq('FROM ruby:3.3.6') + end end describe 'suites' do