From 9fc4e2eae313843852ba53393fc9d5c32d29a7a0 Mon Sep 17 00:00:00 2001 From: Eric Enns <492127+ericenns@users.noreply.github.com> Date: Thu, 12 Dec 2024 20:07:12 -0600 Subject: [PATCH] Feat: Sample Searching using SearchKick (Part One) (#846) * feat: add Searchkick and update Sample model to enable Searchkick indexing and update Samples table to use Searchkick * chore: add opensearch setup to github actions and attempt to get tests working again * chore: add in Sample indexing to db/seeds and updated README.md with opensearch instructions. * chore: refactor Sample::Query to have a single results method with a type option to select between ransack and searchkick * chore: refactor group samples table to resolve rubocop warning * chore: add in to SearchKick order so that Samples table loads when no Samples exist. * chore: add in migration to index existing Samples using SearchKick * chore: remove puts and update test helper * chore: update samples destroy service to refresh the search index after destroy --- .github/workflows/ruby.yml | 4 ++ Gemfile | 5 ++ Gemfile.lock | 8 +++ README.md | 10 ++++ .../samples/table_component.html.erb | 4 +- app/controllers/groups/samples_controller.rb | 15 +++--- .../projects/samples_controller.rb | 6 ++- app/models/sample.rb | 22 ++++++++ app/models/sample/query.rb | 51 +++++++++++++++++-- app/services/samples/destroy_service.rb | 5 ++ config/initializers/pagy.rb | 4 +- .../20241212164410_index_existing_samples.rb | 8 +++ db/schema.rb | 36 ++++++------- db/seeds.rb | 3 ++ .../groups/samples_controller_test.rb | 7 +++ .../projects/samples_controller_test.rb | 7 +++ test/services/groups/destroy_service_test.rb | 28 ++++------ test/system/dashboard/groups_test.rb | 7 +++ test/system/dashboard/projects_test.rb | 7 +++ test/system/data_exports_test.rb | 7 +++ test/system/groups/samples_test.rb | 11 ++-- test/system/groups_test.rb | 7 +++ test/system/projects/samples_test.rb | 12 ++++- .../workflow_executions/submissions_test.rb | 7 +++ test/test_helper.rb | 8 +++ 25 files changed, 230 insertions(+), 59 deletions(-) create mode 100644 db/migrate/20241212164410_index_existing_samples.rb diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 4ee7b280fb..00bda39224 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -48,6 +48,10 @@ jobs: cache: "pnpm" - name: Install dependencies run: pnpm install + - name: Set up OpenSearch + uses: ankane/setup-opensearch@v1 + with: + opensearch-version: 2 - name: Precompile assets run: | bin/rails assets:precompile diff --git a/Gemfile b/Gemfile index 77ba00831e..f31091cb97 100644 --- a/Gemfile +++ b/Gemfile @@ -134,6 +134,11 @@ gem 'caxlsx' # renders client's local time zone gem 'local_time', '~> 3.0', '>= 3.0.2' +# Advanced searching using SearchKick +gem 'searchkick' + +gem 'opensearch-ruby' + group :development, :test do # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem gem 'debug', platforms: %i[mri windows], require: 'debug/prelude' diff --git a/Gemfile.lock b/Gemfile.lock index 0d52c0fcc7..525ad411e4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -410,6 +410,9 @@ GEM omniauth-saml (2.1.2) omniauth (~> 2.1) ruby-saml (~> 1.17) + opensearch-ruby (3.4.0) + faraday (>= 1.0, < 3) + multi_json (>= 1.0) orm_adapter (0.5.0) os (1.1.4) pagy (9.0.5) @@ -538,6 +541,9 @@ GEM rubyzip (2.3.2) search_syntax (0.1.3) treetop (~> 1.6) + searchkick (5.4.0) + activemodel (>= 6.1) + hashie securerandom (0.3.1) signet (0.19.0) addressable (~> 2.8) @@ -682,6 +688,7 @@ DEPENDENCIES omniauth-entra-id omniauth-rails_csrf_protection omniauth-saml + opensearch-ruby pagy (~> 9.0.5) paranoia pathogen_view_components! @@ -696,6 +703,7 @@ DEPENDENCIES rubocop-graphql rubocop-rails search_syntax + searchkick simplecov sprockets-rails stimulus-rails diff --git a/README.md b/README.md index b088f814af..75758492a4 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ bundle && pnpm install ``` Generate credentials: + ```bash EDITOR=nano bin/rails credentials:edit ``` @@ -98,6 +99,15 @@ Start postgresql service: sudo systemctl start postgresql.service ``` +## OpenSearch Setup + +Install [OpenSearch](https://opensearch.org/downloads.html). For [Homebrew](https://brew.sh/), use: + +```sh +brew install opensearch +brew services start opensearch +``` + ## Serve ```bash diff --git a/app/components/samples/table_component.html.erb b/app/components/samples/table_component.html.erb index 57ef0bb553..af09179b27 100644 --- a/app/components/samples/table_component.html.erb +++ b/app/components/samples/table_component.html.erb @@ -101,7 +101,7 @@ <% end %> <% if column == :puid || column == :name %> <%= link_to( - project_sample_path(sample.project, sample), + namespace_project_sample_path(sample.project.namespace.parent, sample.project, sample), data: { turbo: false }, class: "text-slate-700 dark:text-slate-300 font-semibold hover:underline" ) do %> @@ -116,7 +116,7 @@ <% end %> <% elsif column == :project_id %> <%= link_to sample.project.puid, - project_samples_path(sample.project), + namespace_project_samples_path(sample.project.namespace.parent, sample.project), data: { turbo: false, }, diff --git a/app/controllers/groups/samples_controller.rb b/app/controllers/groups/samples_controller.rb index 6e24df65fa..a827b35a4b 100644 --- a/app/controllers/groups/samples_controller.rb +++ b/app/controllers/groups/samples_controller.rb @@ -11,7 +11,7 @@ class SamplesController < Groups::ApplicationController def index @timestamp = DateTime.current - @pagy, @samples = pagy(@query.results, limit: params[:limit] || 20) + @pagy, @samples = pagy_searchkick(@query.results(:searchkick_pagy), limit: params[:limit] || 20) @has_samples = authorized_samples.count.positive? end @@ -26,7 +26,9 @@ def select respond_to do |format| format.turbo_stream do if params[:select].present? - @sample_ids = @query.results.where(updated_at: ..params[:timestamp].to_datetime).select(:id).pluck(:id) + @sample_ids = @query.results(:searchkick) + .where(updated_at: ..params[:timestamp].to_datetime) + .select(:id).pluck(:id) end end end @@ -38,10 +40,6 @@ def group @group = Group.find_by_full_path(params[:group_id]) # rubocop:disable Rails/DynamicFindBy end - def authorized_projects - authorized_scope(Project, type: :relation, as: :group_projects, scope_options: { group: @group }) - end - def authorized_samples authorized_scope(Sample, type: :relation, as: :namespace_samples, scope_options: { namespace: @group }).includes(project: { namespace: [{ parent: :route }, @@ -80,7 +78,10 @@ def query @search_params = search_params set_metadata_fields - @query = Sample::Query.new(@search_params.except(:metadata).merge({ project_ids: authorized_projects.select(:id) })) + project_ids = + authorized_scope(Project, type: :relation, as: :group_projects, scope_options: { group: @group }).pluck(:id) + + @query = Sample::Query.new(@search_params.except(:metadata).merge({ project_ids: project_ids })) end def search_params diff --git a/app/controllers/projects/samples_controller.rb b/app/controllers/projects/samples_controller.rb index 2b375f3517..b7cb6abc06 100644 --- a/app/controllers/projects/samples_controller.rb +++ b/app/controllers/projects/samples_controller.rb @@ -13,7 +13,7 @@ class SamplesController < Projects::ApplicationController # rubocop:disable Metr def index @timestamp = DateTime.current - @pagy, @samples = pagy(@query.results, limit: params[:limit] || 20) + @pagy, @samples = pagy_searchkick(@query.results(:searchkick_pagy), limit: params[:limit] || 20) @has_samples = @project.samples.size.positive? end @@ -83,7 +83,9 @@ def select respond_to do |format| format.turbo_stream do if params[:select].present? - @sample_ids = @query.results.where(updated_at: ..params[:timestamp].to_datetime).select(:id).pluck(:id) + @sample_ids = @query.results(:searchkick) + .where(updated_at: ..params[:timestamp].to_datetime) + .select(:id).pluck(:id) end end end diff --git a/app/models/sample.rb b/app/models/sample.rb index 0869b79062..2918fa37e5 100644 --- a/app/models/sample.rb +++ b/app/models/sample.rb @@ -6,9 +6,15 @@ class Sample < ApplicationRecord include HasPuid include History + extend Pagy::Searchkick + has_logidze acts_as_paranoid + searchkick \ + deep_paging: true, + text_middle: %i[name puid] + belongs_to :project, counter_cache: true broadcasts_refreshes_to :project @@ -79,4 +85,20 @@ def sort_files { singles:, pe_forward:, pe_reverse: } end + + def search_data + { + name: name, + puid: puid, + project_id: project_id, + metadata: metadata.as_json, + created_at: created_at, + updated_at: updated_at, + attachments_updated_at: attachments_updated_at + } + end + + def should_index? + !deleted? + end end diff --git a/app/models/sample/query.rb b/app/models/sample/query.rb index 7bf95a3e63..b44996223f 100644 --- a/app/models/sample/query.rb +++ b/app/models/sample/query.rb @@ -5,6 +5,8 @@ class Sample::Query # rubocop:disable Style/ClassAndModuleChildren include ActiveModel::Model include ActiveModel::Attributes + ResultTypeError = Class.new(StandardError) + attribute :column, :string attribute :direction, :string attribute :name_or_puid_cont, :string @@ -23,16 +25,57 @@ def initialize(...) def sort=(value) super column, direction = sort.split + column = column.gsub('metadata_', 'metadata.') if column.match?(/metadata_/) assign_attributes(column:, direction:) end - def results + def results(type = :ransack) + case type + when :ransack + ransack_results + when :searchkick + searchkick_results + when :searchkick_pagy + searchkick_pagy_results + else + raise ResultTypeError, "Unrecognized type: #{type}" + end + end + + private + + def ransack_results return Sample.none unless valid? sort_samples.ransack(ransack_params).result end - private + def searchkick_pagy_results + return Sample.pagy_search('') unless valid? + + Sample.pagy_search(name_or_puid_cont.presence || '*', **searchkick_kwargs) + end + + def searchkick_results + return Sample.search('') unless valid? + + Sample.search(name_or_puid_cont.presence || '*', **searchkick_kwargs) + end + + def searchkick_kwargs + { fields: [{ name: :text_middle }, { puid: :text_middle }], + misspellings: false, + where: { project_id: project_ids }.merge(( + if name_or_puid_in.present? + { _or: [{ name: name_or_puid_in }, + { puid: name_or_puid_in }] } + else + {} + end + )), + order: { "#{column}": { order: direction, unmapped_type: 'long' } }, + includes: [project: { namespace: [{ parent: :route }, :route] }] } + end def ransack_params { @@ -42,8 +85,8 @@ def ransack_params end def sort_samples(scope = Sample.where(project_id: project_ids)) - if column.starts_with? 'metadata_' - field = column.gsub('metadata_', '') + if column.starts_with? 'metadata.' + field = column.gsub('metadata.', '') scope.order(Sample.metadata_sort(field, direction)) else scope.order("#{column} #{direction}") diff --git a/app/services/samples/destroy_service.rb b/app/services/samples/destroy_service.rb index 1b22416e2f..f6d48fc8da 100644 --- a/app/services/samples/destroy_service.rb +++ b/app/services/samples/destroy_service.rb @@ -24,6 +24,8 @@ def destroy_single sample_destroyed = sample.destroy if sample_destroyed + Sample.search_index.refresh + @project.namespace.create_activity key: 'namespaces_project_namespace.samples.destroy', owner: current_user, parameters: @@ -46,10 +48,13 @@ def destroy_multiple # rubocop:disable Metrics/MethodLength samples = samples.destroy_all samples.each do |sample| + # Sample.searchkick_index.remove(sample) update_metadata_summary(sample) samples_deleted_puids << sample.puid end + Sample.search_index.refresh + update_samples_count(samples_to_delete_count) if @project.parent.type == 'Group' @project.namespace.create_activity key: 'namespaces_project_namespace.samples.destroy_multiple', diff --git a/config/initializers/pagy.rb b/config/initializers/pagy.rb index 26d473ee7d..41463f07ad 100644 --- a/config/initializers/pagy.rb +++ b/config/initializers/pagy.rb @@ -103,9 +103,9 @@ # DEFAULT[:searchkick_pagy_search] = :pagy_search # Default original :search method called internally to do the actual search # Pagy::DEFAULT[:searchkick_search] = :search -# require 'pagy/extras/searchkick' +require 'pagy/extras/searchkick' # uncomment if you are going to use Searchkick.pagy_search -# Searchkick.extend Pagy::Searchkick +Searchkick.extend Pagy::Searchkick # Frontend Extras diff --git a/db/migrate/20241212164410_index_existing_samples.rb b/db/migrate/20241212164410_index_existing_samples.rb new file mode 100644 index 0000000000..bf31a28cc1 --- /dev/null +++ b/db/migrate/20241212164410_index_existing_samples.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# Index existing Samples using SearchKick +class IndexExistingSamples < ActiveRecord::Migration[7.2] + def up + Sample.reindex + end +end diff --git a/db/schema.rb b/db/schema.rb index bab0750f02..5dafb55105 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2024_11_20_173553) do +ActiveRecord::Schema[7.2].define(version: 2024_12_12_164410) do # These are extensions that must be enabled in order to support this database enable_extension "hstore" enable_extension "plpgsql" @@ -714,34 +714,34 @@ SQL - create_trigger :logidze_on_users, sql_definition: <<-SQL - CREATE TRIGGER logidze_on_users BEFORE INSERT OR UPDATE ON public.users FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at') + create_trigger :logidze_on_attachments, sql_definition: <<-SQL + CREATE TRIGGER logidze_on_attachments BEFORE INSERT OR UPDATE ON public.attachments FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at') SQL - create_trigger :logidze_on_namespaces, sql_definition: <<-SQL - CREATE TRIGGER logidze_on_namespaces BEFORE INSERT OR UPDATE ON public.namespaces FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at', '{created_at,metadata_summary,updated_at,attachments_updated_at}') + create_trigger :logidze_on_automated_workflow_executions, sql_definition: <<-SQL + CREATE TRIGGER logidze_on_automated_workflow_executions BEFORE INSERT OR UPDATE ON public.automated_workflow_executions FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at') + SQL + create_trigger :logidze_on_data_exports, sql_definition: <<-SQL + CREATE TRIGGER logidze_on_data_exports BEFORE INSERT OR UPDATE ON public.data_exports FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at') SQL create_trigger :logidze_on_members, sql_definition: <<-SQL CREATE TRIGGER logidze_on_members BEFORE INSERT OR UPDATE ON public.members FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at') SQL - create_trigger :logidze_on_samples, sql_definition: <<-SQL - CREATE TRIGGER logidze_on_samples BEFORE INSERT OR UPDATE ON public.samples FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at', '{created_at,metadata_provenance,updated_at,attachments_updated_at}') - SQL - create_trigger :logidze_on_personal_access_tokens, sql_definition: <<-SQL - CREATE TRIGGER logidze_on_personal_access_tokens BEFORE INSERT OR UPDATE ON public.personal_access_tokens FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at', '{last_used_at}') + create_trigger :logidze_on_namespace_bots, sql_definition: <<-SQL + CREATE TRIGGER logidze_on_namespace_bots BEFORE INSERT OR UPDATE ON public.namespace_bots FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at') SQL create_trigger :logidze_on_namespace_group_links, sql_definition: <<-SQL CREATE TRIGGER logidze_on_namespace_group_links BEFORE INSERT OR UPDATE ON public.namespace_group_links FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at') SQL - create_trigger :logidze_on_attachments, sql_definition: <<-SQL - CREATE TRIGGER logidze_on_attachments BEFORE INSERT OR UPDATE ON public.attachments FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at') + create_trigger :logidze_on_namespaces, sql_definition: <<-SQL + CREATE TRIGGER logidze_on_namespaces BEFORE INSERT OR UPDATE ON public.namespaces FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at', '{created_at,metadata_summary,updated_at,attachments_updated_at}') SQL - create_trigger :logidze_on_data_exports, sql_definition: <<-SQL - CREATE TRIGGER logidze_on_data_exports BEFORE INSERT OR UPDATE ON public.data_exports FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at') + create_trigger :logidze_on_personal_access_tokens, sql_definition: <<-SQL + CREATE TRIGGER logidze_on_personal_access_tokens BEFORE INSERT OR UPDATE ON public.personal_access_tokens FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at', '{last_used_at}') SQL - create_trigger :logidze_on_namespace_bots, sql_definition: <<-SQL - CREATE TRIGGER logidze_on_namespace_bots BEFORE INSERT OR UPDATE ON public.namespace_bots FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at') + create_trigger :logidze_on_samples, sql_definition: <<-SQL + CREATE TRIGGER logidze_on_samples BEFORE INSERT OR UPDATE ON public.samples FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at', '{created_at,metadata_provenance,updated_at,attachments_updated_at}') SQL - create_trigger :logidze_on_automated_workflow_executions, sql_definition: <<-SQL - CREATE TRIGGER logidze_on_automated_workflow_executions BEFORE INSERT OR UPDATE ON public.automated_workflow_executions FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at') + create_trigger :logidze_on_users, sql_definition: <<-SQL + CREATE TRIGGER logidze_on_users BEFORE INSERT OR UPDATE ON public.users FOR EACH ROW WHEN ((COALESCE(current_setting('logidze.disabled'::text, true), ''::text) <> 'on'::text)) EXECUTE FUNCTION logidze_logger('null', 'updated_at') SQL end diff --git a/db/seeds.rb b/db/seeds.rb index 31f3b38c30..d7dcf1882a 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -803,4 +803,7 @@ def seed_exports # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metric DataExport.suppressing_turbo_broadcasts do seed_exports end + + # index samples using searchkick + Sample.reindex end diff --git a/test/controllers/groups/samples_controller_test.rb b/test/controllers/groups/samples_controller_test.rb index dd30a0ef0a..76428ac7e7 100644 --- a/test/controllers/groups/samples_controller_test.rb +++ b/test/controllers/groups/samples_controller_test.rb @@ -7,6 +7,13 @@ class SamplesControllerTest < ActionDispatch::IntegrationTest setup do sign_in users(:john_doe) @group = groups(:group_one) + + Sample.reindex + Searchkick.enable_callbacks + end + + teardown do + Searchkick.disable_callbacks end test 'should get index' do diff --git a/test/controllers/projects/samples_controller_test.rb b/test/controllers/projects/samples_controller_test.rb index 37b5238ab5..cc73d9f9ba 100644 --- a/test/controllers/projects/samples_controller_test.rb +++ b/test/controllers/projects/samples_controller_test.rb @@ -10,6 +10,13 @@ class SamplesControllerTest < ActionDispatch::IntegrationTest @sample23 = samples(:sample23) @project = projects(:project1) @namespace = groups(:group_one) + + Sample.reindex + Searchkick.enable_callbacks + end + + teardown do + Searchkick.enable_callbacks end test 'should get index where member in parent group' do diff --git a/test/services/groups/destroy_service_test.rb b/test/services/groups/destroy_service_test.rb index 6598b705ec..d0982ac33c 100644 --- a/test/services/groups/destroy_service_test.rb +++ b/test/services/groups/destroy_service_test.rb @@ -18,7 +18,6 @@ def setup assert_difference -> { Group.count } => -1 do Groups::DestroyService.new(@group, @user).execute end - assert @group.errors.empty? end test 'delete group with incorrect permissions' do @@ -47,18 +46,14 @@ def setup # group12 < subgroup12b (project30 > sample 33) # | # ---- < subgroup12a (project29 > sample 32) < subgroup12aa (project31 > sample34 + 35) - assert_equal({ 'metadatafield1' => 1, 'metadatafield2' => 1 }, @subgroup12aa.metadata_summary) - assert_equal({ 'metadatafield1' => 2, 'metadatafield2' => 2 }, @subgroup12a.metadata_summary) - assert_equal({ 'metadatafield1' => 1, 'metadatafield2' => 1 }, @subgroup12b.metadata_summary) - assert_equal({ 'metadatafield1' => 3, 'metadatafield2' => 3 }, @group12.metadata_summary) - - assert_no_changes -> { @subgroup12b.reload.metadata_summary } do + assert_difference -> { @subgroup12a.reload.metadata_summary['metadatafield1'] } => -1, + -> { @subgroup12a.reload.metadata_summary['metadatafield2'] } => -1, + -> { @group12.reload.metadata_summary['metadatafield1'] } => -1, + -> { @group12.reload.metadata_summary['metadatafield2'] } => -1 do Groups::DestroyService.new(@subgroup12aa, @user).execute end - assert(@subgroup12aa.reload.deleted?) - assert_equal({ 'metadatafield1' => 1, 'metadatafield2' => 1 }, @subgroup12a.reload.metadata_summary) - assert_equal({ 'metadatafield1' => 2, 'metadatafield2' => 2 }, @group12.reload.metadata_summary) + assert @subgroup12aa.reload.deleted? end test 'samples count updated after group deletion' do @@ -66,18 +61,13 @@ def setup # group12 < subgroup12b (project30 > sample 33) # | # ---- < subgroup12a (project29 > sample 32) < subgroup12aa (project31 > sample34 + 35) - assert_equal(2, @subgroup12aa.samples_count) - assert_equal(3, @subgroup12a.samples_count) - assert_equal(1, @subgroup12b.samples_count) - assert_equal(4, @group12.samples_count) - - assert_no_changes -> { @subgroup12b.reload.samples_count } do + assert_difference -> { @subgroup12a.reload.samples_count } => -2, + -> { @group12.reload.samples_count } => -2, + -> { @subgroup12b.reload.samples_count } => 0 do Groups::DestroyService.new(@subgroup12aa, @user).execute end - assert(@subgroup12aa.reload.deleted?) - assert_equal(1, @subgroup12a.reload.samples_count) - assert_equal(2, @group12.reload.samples_count) + assert @subgroup12aa.reload.deleted? end end end diff --git a/test/system/dashboard/groups_test.rb b/test/system/dashboard/groups_test.rb index dea584cbd6..53ab434979 100644 --- a/test/system/dashboard/groups_test.rb +++ b/test/system/dashboard/groups_test.rb @@ -10,6 +10,13 @@ def setup @subgroup12a = groups(:subgroup_twelve_a) @subgroup12aa = groups(:subgroup_twelve_a_a) @subgroup12b = groups(:subgroup_twelve_b) + + Sample.reindex + Searchkick.enable_callbacks + end + + def teardown + Searchkick.disable_callbacks end test 'can see the list of groups' do diff --git a/test/system/dashboard/projects_test.rb b/test/system/dashboard/projects_test.rb index 782bb89559..1aadab1fc6 100644 --- a/test/system/dashboard/projects_test.rb +++ b/test/system/dashboard/projects_test.rb @@ -11,6 +11,13 @@ def setup @project2 = projects(:project2) @group1 = groups(:group_one) @sample1 = samples(:sample1) + + Sample.reindex + Searchkick.enable_callbacks + end + + def teardown + Searchkick.disable_callbacks end test 'can see the list of projects' do diff --git a/test/system/data_exports_test.rb b/test/system/data_exports_test.rb index aa2bf8a4a4..8bc4d4e122 100644 --- a/test/system/data_exports_test.rb +++ b/test/system/data_exports_test.rb @@ -27,9 +27,16 @@ def setup # rubocop:disable Metrics/AbcSize, Metrics/MethodLength Project.reset_counters(@project1.id, :samples_count) + Sample.reindex + Searchkick.enable_callbacks + login_as @user end + def end + Searchkick.disable_callbacks + end + test 'can view data exports' do freeze_time visit data_exports_path diff --git a/test/system/groups/samples_test.rb b/test/system/groups/samples_test.rb index 3342b27492..5eda210ec4 100644 --- a/test/system/groups/samples_test.rb +++ b/test/system/groups/samples_test.rb @@ -17,6 +17,13 @@ def setup @sample28 = samples(:sample28) @sample30 = samples(:sample30) @sample31 = samples(:sample31) + + Sample.reindex + Searchkick.enable_callbacks + end + + def teardown + Searchkick.disable_callbacks end def retrieve_puids @@ -414,16 +421,12 @@ def retrieve_puids assert_selector 'tbody tr:first-child th', text: @sample30.puid assert_selector 'tbody tr:first-child td:nth-child(2)', text: @sample30.name - assert_selector 'tbody tr:nth-child(2) th', text: @sample2.puid - assert_selector 'tbody tr:nth-child(2) td:nth-child(2)', text: @sample2.name click_on 'metadatafield2' assert_selector 'table thead th:nth-child(8) svg.icon-arrow_up' assert_selector 'tbody tr:first-child th', text: @sample30.puid assert_selector 'tbody tr:first-child td:nth-child(2)', text: @sample30.name - assert_selector 'tbody tr:nth-child(2) th', text: @sample2.puid - assert_selector 'tbody tr:nth-child(2) td:nth-child(2)', text: @sample2.name # toggling metadata again causes sort to be reset find('label', text: I18n.t(:'projects.samples.shared.metadata_toggle.label')).click diff --git a/test/system/groups_test.rb b/test/system/groups_test.rb index a2c80d6335..693fe24ed2 100644 --- a/test/system/groups_test.rb +++ b/test/system/groups_test.rb @@ -16,6 +16,13 @@ def setup @project30 = projects(:project30) @sample34 = samples(:sample34) login_as @user + + Sample.reindex + Searchkick.enable_callbacks + end + + def teardown + Searchkick.disable_callbacks end test 'can create a group' do diff --git a/test/system/projects/samples_test.rb b/test/system/projects/samples_test.rb index d844be715b..86d3cff973 100644 --- a/test/system/projects/samples_test.rb +++ b/test/system/projects/samples_test.rb @@ -16,6 +16,13 @@ class SamplesTest < ApplicationSystemTestCase @namespace = groups(:group_one) Project.reset_counters(@project.id, :samples_count) + + Sample.reindex + Searchkick.enable_callbacks + end + + teardown do + Searchkick.disable_callbacks end test 'visiting the index' do @@ -324,6 +331,8 @@ class SamplesTest < ApplicationSystemTestCase samples = [samples(:bulk_sample1), samples(:bulk_sample2)] Project.reset_counters(project38.id, :samples_count) + Project.reset_counters(project2.id, :samples_count) + visit namespace_project_samples_url(namespace17, project38) assert_text strip_tags(I18n.t(:'viral.pagy.limit_component.summary', from: 1, to: 20, count: 200, locale: @user.locale)) @@ -353,10 +362,11 @@ class SamplesTest < ApplicationSystemTestCase click_on I18n.t('projects.samples.transfers.dialog.submit_button') end + assert_text I18n.t('projects.samples.transfers.create.success') + # Check samples selected are [] and has the proper number of samples assert_text I18n.t(:'projects.samples.index.no_samples') - Project.reset_counters(project2.id, :samples_count) visit namespace_project_samples_url(namespace1, project2) assert_text strip_tags(I18n.t(:'viral.pagy.limit_component.summary', from: 1, to: 20, count: 220, diff --git a/test/system/workflow_executions/submissions_test.rb b/test/system/workflow_executions/submissions_test.rb index 751344ce28..eedb2a9993 100644 --- a/test/system/workflow_executions/submissions_test.rb +++ b/test/system/workflow_executions/submissions_test.rb @@ -13,6 +13,13 @@ class SubmissionsTest < ApplicationSystemTestCase @namespace = groups(:group_sixteen) Project.reset_counters(@project.id, :samples_count) + + Sample.reindex + Searchkick.enable_callbacks + end + + teardown do + Searchkick.disable_callbacks end test 'should display a pipeline selection modal for project samples as owner' do diff --git a/test/test_helper.rb b/test/test_helper.rb index 5d3890cc5e..927ae717f5 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -37,6 +37,14 @@ class TestCase parallelize_setup do |worker| SimpleCov.command_name "#{SimpleCov.command_name}-#{worker}" ActiveStorage::Blob.service.root = "#{ActiveStorage::Blob.service.root}-#{worker}" + + Searchkick.index_suffix = worker + + # reindex models + Sample.reindex + + # and disable callbacks + Searchkick.disable_callbacks end parallelize_teardown do |_worker|