145 lines
3.9 KiB
Ruby
145 lines
3.9 KiB
Ruby
|
# frozen_string_literal: true
|
||
|
|
||
|
require 'spec_helper'
|
||
|
|
||
|
RSpec.describe 'Database::PreventCrossDatabaseModification' do
|
||
|
let_it_be(:pipeline, refind: true) { create(:ci_pipeline) }
|
||
|
let_it_be(:project, refind: true) { create(:project) }
|
||
|
|
||
|
shared_examples 'succeessful examples' do
|
||
|
context 'outside transaction' do
|
||
|
it { expect { run_queries }.not_to raise_error }
|
||
|
end
|
||
|
|
||
|
context 'within transaction' do
|
||
|
it do
|
||
|
Project.transaction do
|
||
|
expect { run_queries }.not_to raise_error
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
context 'within nested transaction' do
|
||
|
it do
|
||
|
Project.transaction(requires_new: true) do
|
||
|
Project.transaction(requires_new: true) do
|
||
|
expect { run_queries }.not_to raise_error
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
context 'when CI and other tables are read in a transaction' do
|
||
|
def run_queries
|
||
|
pipeline.reload
|
||
|
project.reload
|
||
|
end
|
||
|
|
||
|
include_examples 'succeessful examples'
|
||
|
end
|
||
|
|
||
|
context 'when only CI data is modified' do
|
||
|
def run_queries
|
||
|
pipeline.touch
|
||
|
project.reload
|
||
|
end
|
||
|
|
||
|
include_examples 'succeessful examples'
|
||
|
end
|
||
|
|
||
|
context 'when other data is modified' do
|
||
|
def run_queries
|
||
|
pipeline.reload
|
||
|
project.touch
|
||
|
end
|
||
|
|
||
|
include_examples 'succeessful examples'
|
||
|
end
|
||
|
|
||
|
describe 'with_cross_database_modification_prevented block' do
|
||
|
it 'raises error when CI and other data is modified' do
|
||
|
expect do
|
||
|
with_cross_database_modification_prevented do
|
||
|
Project.transaction do
|
||
|
project.touch
|
||
|
pipeline.touch
|
||
|
end
|
||
|
end
|
||
|
end.to raise_error /Cross-database data modification queries/
|
||
|
end
|
||
|
end
|
||
|
|
||
|
context 'when running tests with prevent_cross_database_modification', :prevent_cross_database_modification do
|
||
|
context 'when both CI and other data is modified' do
|
||
|
def run_queries
|
||
|
project.touch
|
||
|
pipeline.touch
|
||
|
end
|
||
|
|
||
|
context 'outside transaction' do
|
||
|
it { expect { run_queries }.not_to raise_error }
|
||
|
end
|
||
|
|
||
|
context 'when data modification happens in a transaction' do
|
||
|
it 'raises error' do
|
||
|
Project.transaction do
|
||
|
expect { run_queries }.to raise_error /Cross-database data modification queries/
|
||
|
end
|
||
|
end
|
||
|
|
||
|
context 'when data modification happens in nested transactions' do
|
||
|
it 'raises error' do
|
||
|
Project.transaction(requires_new: true) do
|
||
|
project.touch
|
||
|
Project.transaction(requires_new: true) do
|
||
|
expect { pipeline.touch }.to raise_error /Cross-database data modification queries/
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
context 'when CI association is modified through project' do
|
||
|
def run_queries
|
||
|
project.variables.build(key: 'a', value: 'v')
|
||
|
project.save!
|
||
|
end
|
||
|
|
||
|
include_examples 'succeessful examples'
|
||
|
end
|
||
|
|
||
|
describe '#allow_cross_database_modification_within_transaction' do
|
||
|
it 'skips raising error' do
|
||
|
expect do
|
||
|
Gitlab::Database.allow_cross_database_modification_within_transaction(url: 'gitlab-issue') do
|
||
|
Project.transaction do
|
||
|
pipeline.touch
|
||
|
project.touch
|
||
|
end
|
||
|
end
|
||
|
end.not_to raise_error
|
||
|
end
|
||
|
|
||
|
it 'raises error when complex factories are built referencing both databases' do
|
||
|
expect do
|
||
|
ApplicationRecord.transaction do
|
||
|
create(:ci_pipeline)
|
||
|
end
|
||
|
end.to raise_error /Cross-database data modification queries/
|
||
|
end
|
||
|
|
||
|
it 'skips raising error on factory creation' do
|
||
|
expect do
|
||
|
Gitlab::Database.allow_cross_database_modification_within_transaction(url: 'gitlab-issue') do
|
||
|
ApplicationRecord.transaction do
|
||
|
create(:ci_pipeline)
|
||
|
end
|
||
|
end
|
||
|
end.not_to raise_error
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|