debian-mirror-gitlab/spec/tasks/gitlab/db/lock_writes_rake_spec.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

194 lines
6.4 KiB
Ruby
Raw Normal View History

2022-07-23 23:45:48 +05:30
# frozen_string_literal: true
require 'rake_helper'
2022-08-27 11:52:29 +05:30
RSpec.describe 'gitlab:db:lock_writes', :silence_stdout, :reestablished_active_record_base,
:suppress_gitlab_schemas_validate_connection do
2022-07-23 23:45:48 +05:30
before :all do
Rake.application.rake_require 'active_record/railties/databases'
Rake.application.rake_require 'tasks/seed_fu'
Rake.application.rake_require 'tasks/gitlab/db/validate_config'
Rake.application.rake_require 'tasks/gitlab/db/lock_writes'
# empty task as env is already loaded
Rake::Task.define_task :environment
end
let!(:project) { create(:project) }
let!(:ci_build) { create(:ci_build) }
let(:main_connection) { ApplicationRecord.connection }
let(:ci_connection) { Ci::ApplicationRecord.connection }
2023-03-04 22:38:38 +05:30
let(:detached_partition_table) { '_test_gitlab_main_part_20220101' }
before do
create_detached_partition_sql = <<~SQL
CREATE TABLE IF NOT EXISTS gitlab_partitions_dynamic._test_gitlab_main_part_20220101 (
id bigserial primary key not null
)
SQL
main_connection.execute(create_detached_partition_sql)
ci_connection.execute(create_detached_partition_sql)
Gitlab::Database::SharedModel.using_connection(main_connection) do
Postgresql::DetachedPartition.create!(
table_name: detached_partition_table,
drop_after: Time.current
)
end
allow(Gitlab::Database::GitlabSchema).to receive(:table_schema).and_call_original
allow(Gitlab::Database::GitlabSchema).to receive(:table_schema)
.with(detached_partition_table).and_return(:gitlab_main)
end
2022-07-23 23:45:48 +05:30
context 'single database' do
before do
skip_if_multiple_databases_are_setup
end
context 'when locking writes' do
it 'does not add any triggers to the main schema tables' do
expect do
run_rake_task('gitlab:db:lock_writes')
end.to change {
number_of_triggers(main_connection)
}.by(0)
end
it 'will be still able to modify tables that belong to the main two schemas' do
run_rake_task('gitlab:db:lock_writes')
expect do
Project.last.touch
Ci::Build.last.touch
end.not_to raise_error
end
end
end
context 'multiple databases' do
before do
skip_if_multiple_databases_not_setup
2023-03-04 22:38:38 +05:30
Gitlab::Database::SharedModel.using_connection(ci_connection) do
Postgresql::DetachedPartition.create!(
table_name: detached_partition_table,
drop_after: Time.current
)
end
2022-07-23 23:45:48 +05:30
end
context 'when locking writes' do
it 'still allows writes on the tables with the correct connections' do
Project.update_all(updated_at: Time.now)
Ci::Build.update_all(updated_at: Time.now)
end
it 'still allows writing to gitlab_shared schema on any connection' do
connections = [main_connection, ci_connection]
connections.each do |connection|
Gitlab::Database::SharedModel.using_connection(connection) do
LooseForeignKeys::DeletedRecord.create!(
fully_qualified_table_name: "public.projects",
primary_key_value: 1,
cleanup_attempts: 0
)
end
end
end
it 'prevents writes on the main tables on the ci database' do
run_rake_task('gitlab:db:lock_writes')
expect do
ci_connection.execute("delete from projects")
end.to raise_error(ActiveRecord::StatementInvalid, /Table: "projects" is write protected/)
end
it 'prevents writes on the ci tables on the main database' do
run_rake_task('gitlab:db:lock_writes')
expect do
main_connection.execute("delete from ci_builds")
end.to raise_error(ActiveRecord::StatementInvalid, /Table: "ci_builds" is write protected/)
end
it 'prevents truncating a ci table on the main database' do
run_rake_task('gitlab:db:lock_writes')
expect do
main_connection.execute("truncate ci_build_needs")
end.to raise_error(ActiveRecord::StatementInvalid, /Table: "ci_build_needs" is write protected/)
end
2023-03-04 22:38:38 +05:30
it 'prevents writes to detached partitions' do
run_rake_task('gitlab:db:lock_writes')
expect do
ci_connection.execute("INSERT INTO gitlab_partitions_dynamic.#{detached_partition_table} DEFAULT VALUES")
end.to raise_error(ActiveRecord::StatementInvalid, /Table: "#{detached_partition_table}" is write protected/)
end
2022-08-27 11:52:29 +05:30
end
2022-07-23 23:45:48 +05:30
2022-11-25 23:54:43 +05:30
context 'when running in dry_run mode' do
before do
stub_env('DRY_RUN', 'true')
end
it 'allows writes on the main tables on the ci database' do
run_rake_task('gitlab:db:lock_writes')
expect do
ci_connection.execute("delete from projects")
end.not_to raise_error
end
it 'allows writes on the ci tables on the main database' do
run_rake_task('gitlab:db:lock_writes')
expect do
main_connection.execute("delete from ci_builds")
end.not_to raise_error
end
end
2022-08-27 11:52:29 +05:30
context 'multiple shared databases' do
before do
allow(::Gitlab::Database).to receive(:db_config_share_with).and_return(nil)
ci_db_config = Ci::ApplicationRecord.connection_db_config
allow(::Gitlab::Database).to receive(:db_config_share_with).with(ci_db_config).and_return('main')
2022-07-23 23:45:48 +05:30
end
2022-08-27 11:52:29 +05:30
it 'does not lock any tables if the ci database is shared with main database' do
run_rake_task('gitlab:db:lock_writes')
2022-07-23 23:45:48 +05:30
expect do
2022-08-27 11:52:29 +05:30
ApplicationRecord.connection.execute("delete from ci_builds")
Ci::ApplicationRecord.connection.execute("delete from users")
end.not_to raise_error
2022-07-23 23:45:48 +05:30
end
end
context 'when unlocking writes' do
before do
run_rake_task('gitlab:db:lock_writes')
end
2022-08-27 11:52:29 +05:30
it 'allows writes again on the gitlab_ci tables on the main database' do
run_rake_task('gitlab:db:unlock_writes')
2022-07-23 23:45:48 +05:30
expect do
main_connection.execute("delete from ci_builds")
end.not_to raise_error
end
2023-03-04 22:38:38 +05:30
it 'allows writes again to detached partitions' do
run_rake_task('gitlab:db:unlock_writes')
expect do
ci_connection.execute("INSERT INTO gitlab_partitions_dynamic._test_gitlab_main_part_20220101 DEFAULT VALUES")
end.not_to raise_error
end
2022-07-23 23:45:48 +05:30
end
end
def number_of_triggers(connection)
connection.select_value("SELECT count(*) FROM information_schema.triggers")
end
end