From 370802ce486464beb8d4e57a596e220293c5de6d Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 7 Nov 2023 10:21:58 -0500 Subject: [PATCH] Add coverage for `CLI::Maintenance#fix_duplicates` command (#25252) --- lib/mastodon/cli/maintenance.rb | 72 ++++++++++++++++------- spec/lib/mastodon/cli/maintenance_spec.rb | 42 +++++++++++++ 2 files changed, 93 insertions(+), 21 deletions(-) diff --git a/lib/mastodon/cli/maintenance.rb b/lib/mastodon/cli/maintenance.rb index 9cc9a3507a..a95b7a30cd 100644 --- a/lib/mastodon/cli/maintenance.rb +++ b/lib/mastodon/cli/maintenance.rb @@ -136,24 +136,24 @@ module Mastodon::CLI Mastodon has to be stopped to run this task, which will take a long time and may be destructive. LONG_DESC def fix_duplicates - if ActiveRecord::Migrator.current_version < MIN_SUPPORTED_VERSION - say 'Your version of the database schema is too old and is not supported by this script.', :red - say 'Please update to at least Mastodon 3.0.0 before running this script.', :red - exit(1) - elsif ActiveRecord::Migrator.current_version > MAX_SUPPORTED_VERSION - say 'Your version of the database schema is more recent than this script, this may cause unexpected errors.', :yellow - exit(1) unless yes?('Continue anyway? (Yes/No)') - end + verify_system_ready! - if Sidekiq::ProcessSet.new.any? - say 'It seems Sidekiq is running. All Mastodon processes need to be stopped when using this script.', :red - exit(1) - end + process_deduplications - say 'This task will take a long time to run and is potentially destructive.', :yellow - say 'Please make sure to stop Mastodon and have a backup.', :yellow - exit(1) unless yes?('Continue? (Yes/No)') + deduplication_cleanup_tasks + say 'Finished!' + end + + private + + def verify_system_ready! + verify_schema_version! + verify_sidekiq_not_active! + verify_backup_warning! + end + + def process_deduplications deduplicate_users! deduplicate_account_domain_blocks! deduplicate_account_identity_proofs! @@ -173,14 +173,44 @@ module Mastodon::CLI deduplicate_webauthn_credentials! deduplicate_webhooks! deduplicate_software_updates! - - Scenic.database.refresh_materialized_view('instances', concurrently: true, cascade: false) if ActiveRecord::Migrator.current_version >= 2020_12_06_004238 - Rails.cache.clear - - say 'Finished!' end - private + def deduplication_cleanup_tasks + refresh_instances_view if schema_has_instances_view? + Rails.cache.clear + end + + def refresh_instances_view + Scenic.database.refresh_materialized_view('instances', concurrently: true, cascade: false) + end + + def schema_has_instances_view? + ActiveRecord::Migrator.current_version >= 2020_12_06_004238 + end + + def verify_schema_version! + if ActiveRecord::Migrator.current_version < MIN_SUPPORTED_VERSION + say 'Your version of the database schema is too old and is not supported by this script.', :red + say 'Please update to at least Mastodon 3.0.0 before running this script.', :red + exit(1) + elsif ActiveRecord::Migrator.current_version > MAX_SUPPORTED_VERSION + say 'Your version of the database schema is more recent than this script, this may cause unexpected errors.', :yellow + exit(1) unless yes?('Continue anyway? (Yes/No)') + end + end + + def verify_sidekiq_not_active! + if Sidekiq::ProcessSet.new.any? + say 'It seems Sidekiq is running. All Mastodon processes need to be stopped when using this script.', :red + exit(1) + end + end + + def verify_backup_warning! + say 'This task will take a long time to run and is potentially destructive.', :yellow + say 'Please make sure to stop Mastodon and have a backup.', :yellow + exit(1) unless yes?('Continue? (Yes/No)') + end def deduplicate_accounts! remove_index_if_exists!(:accounts, 'index_accounts_on_username_and_domain_lower') diff --git a/spec/lib/mastodon/cli/maintenance_spec.rb b/spec/lib/mastodon/cli/maintenance_spec.rb index 12cd9ca8a6..a6789ea5a4 100644 --- a/spec/lib/mastodon/cli/maintenance_spec.rb +++ b/spec/lib/mastodon/cli/maintenance_spec.rb @@ -4,9 +4,51 @@ require 'rails_helper' require 'mastodon/cli/maintenance' describe Mastodon::CLI::Maintenance do + let(:cli) { described_class.new } + describe '.exit_on_failure?' do it 'returns true' do expect(described_class.exit_on_failure?).to be true end end + + describe '#fix_duplicates' do + context 'when the database version is too old' do + before do + allow(ActiveRecord::Migrator).to receive(:current_version).and_return(2000_01_01_000000) # Earlier than minimum + end + + it 'Exits with error message' do + expect { cli.invoke :fix_duplicates }.to output( + a_string_including('is too old') + ).to_stdout.and raise_error(SystemExit) + end + end + + context 'when the database version is too new and the user does not continue' do + before do + allow(ActiveRecord::Migrator).to receive(:current_version).and_return(2100_01_01_000000) # Later than maximum + allow(cli.shell).to receive(:yes?).with('Continue anyway? (Yes/No)').and_return(false).once + end + + it 'Exits with error message' do + expect { cli.invoke :fix_duplicates }.to output( + a_string_including('more recent') + ).to_stdout.and raise_error(SystemExit) + end + end + + context 'when Sidekiq is running' do + before do + allow(ActiveRecord::Migrator).to receive(:current_version).and_return(2022_01_01_000000) # Higher than minimum, lower than maximum + allow(Sidekiq::ProcessSet).to receive(:new).and_return [:process] + end + + it 'Exits with error message' do + expect { cli.invoke :fix_duplicates }.to output( + a_string_including('Sidekiq is running') + ).to_stdout.and raise_error(SystemExit) + end + end + end end