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 }
|
|
|
|
|
|
|
|
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
|
|
|
|
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
|
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
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def number_of_triggers(connection)
|
|
|
|
connection.select_value("SELECT count(*) FROM information_schema.triggers")
|
|
|
|
end
|
|
|
|
end
|