Files
gitlab-foss/gems/gitlab-backup-cli/spec/gitlab/backup/cli/targets/database_spec.rb
2025-03-05 06:17:11 +00:00

152 lines
4.2 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Backup::Cli::Targets::Database do
let(:context) { build_test_context }
let(:database) { described_class.new(context) }
let(:pipeline_success) { instance_double(Gitlab::Backup::Cli::Shell::Pipeline::Result, success?: true) }
after do
context.cleanup!
end
describe '#dump', :silence_output do
let(:destination) { Pathname(Dir.mktmpdir('database-target', temp_path)) }
after do
FileUtils.rm_rf(destination)
end
it 'creates the destination directory' do
mock_database_dump!
expect(destination).to be_directory
database.dump(destination)
end
it 'triggers a database snapshot' do
mock_database_dump!
expect_next_instance_of(Gitlab::Backup::Cli::Services::Database) do |db|
expect(db).to receive(:export_snapshot!).and_call_original
end.at_least(:once)
database.dump(destination)
end
it 'dumps the database' do
database.dump(destination)
database_dump_files = Dir.glob(destination.join('*.sql.gz'))
expect(database_dump_files).not_to be_empty
end
it 'releases the snapshot after dumping' do
mock_database_dump!
expect_next_instance_of(Gitlab::Backup::Cli::Services::Database) do |db|
expect(db).to receive(:release_snapshot!).and_call_original
end.at_least(:once)
database.dump(destination)
end
it 'restores timeout after dumping' do
mock_database_dump!
expect_next_instance_of(Gitlab::Backup::Cli::Services::Database) do |db|
expect(db).to receive(:restore_timeouts!).and_call_original
end.at_least(:once)
database.dump(destination)
end
it 'raises an error if the dump fails' do
false_command = Gitlab::Backup::Cli::Shell::Command.new(%q(false))
replace_database_dump_command!(false_command)
expect { database.dump(destination) }.to raise_error(Gitlab::Backup::Cli::Errors::DatabaseBackupError)
end
end
describe '#restore' do
let(:source) { Pathname(Dir.mktmpdir('database-target', temp_path)) }
after do
FileUtils.rm_rf(source)
end
context 'with an invalid backup source' do
it 'raises an error when main database backup file is missing' do
mock_databases_collection('main')
expect { database.restore(source) }.to raise_error(Gitlab::Backup::Cli::Error).with_message(
/Database backup file '[^']*' for the main database does not exist/
)
end
it 'raises an warning when other database backup files are missing' do
mock_databases_collection('ci')
expect { database.restore(source) }.to output(
/Database backup file '[^']*' for the ci database does not exist/
).to_stderr
end
end
context 'with a valid backup file' do
it 'drops all tables before restoring' do
allow(database).to receive(:restore_tables).and_return(
pipeline_success
)
mock_databases_collection('main') do |_|
FileUtils.touch(source.join('database.sql.gz'))
end
expect(database).to receive(:drop_tables!)
database.restore(source)
end
it 'restores the database' do
mock_databases_collection('main') do |db|
filepath = source.join('database.sql.gz')
FileUtils.touch(filepath)
expect(database).to receive(:restore_tables).with(database: db, filepath: filepath).and_return(
pipeline_success
)
end
database.restore(source)
end
end
end
def mock_databases_collection(dbname)
allow_next_instance_of(Gitlab::Backup::Cli::Services::Postgres) do |databases|
entry = databases.send(:entries).find { |db| db.configuration.name == dbname }
allow(databases).to receive(:each).and_yield(entry)
yield entry if block_given?
end
end
def mock_database_dump!
echo_command = Gitlab::Backup::Cli::Shell::Command.new(%q(echo ''))
replace_database_dump_command!(echo_command)
end
def replace_database_dump_command!(new_command)
allow_next_instance_of(::Gitlab::Backup::Cli::Utils::PgDump) do |pg_dump|
allow(pg_dump).to receive(:build_command).and_return(new_command)
end
end
end