debian-mirror-gitlab/spec/lib/gitlab/database/shared_model_spec.rb
2023-04-23 21:23:45 +05:30

135 lines
4.6 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Database::SharedModel, feature_category: :database do
describe 'using an external connection' do
let!(:original_connection) { described_class.connection }
let(:new_connection) { double('connection') }
it 'overrides the connection for the duration of the block', :aggregate_failures do
expect_original_connection_around do
described_class.using_connection(new_connection) do
expect(described_class.connection).to be(new_connection)
end
end
end
it 'does not affect connections in other threads', :aggregate_failures do
expect_original_connection_around do
described_class.using_connection(new_connection) do
expect(described_class.connection).to be(new_connection)
Thread.new do
expect(described_class.connection).not_to be(new_connection)
end.join
end
end
end
it 'raises an error if the connection does not include `:gitlab_shared` schema' do
allow(Gitlab::Database)
.to receive(:gitlab_schemas_for_connection)
.with(new_connection)
.and_return([:gitlab_main])
expect_original_connection_around do
expect do
described_class.using_connection(new_connection) {}
end.to raise_error(/Cannot set `SharedModel` to connection/)
end
end
context 'when multiple connection overrides are nested', :aggregate_failures do
let(:second_connection) { double('connection') }
it 'allows the nesting with the same connection object' do
expect_original_connection_around do
described_class.using_connection(new_connection) do
expect(described_class.connection).to be(new_connection)
described_class.using_connection(new_connection) do
expect(described_class.connection).to be(new_connection)
end
expect(described_class.connection).to be(new_connection)
end
end
end
it 'raises an error if the connection is changed' do
expect_original_connection_around do
described_class.using_connection(new_connection) do
expect(described_class.connection).to be(new_connection)
expect do
described_class.using_connection(second_connection) {}
end.to raise_error(/Cannot change connection for Gitlab::Database::SharedModel/)
expect(described_class.connection).to be(new_connection)
end
end
end
end
context 'when the block raises an error', :aggregate_failures do
it 're-raises the error, removing the overridden connection' do
expect_original_connection_around do
expect do
described_class.using_connection(new_connection) do
expect(described_class.connection).to be(new_connection)
raise 'here comes an error!'
end
end.to raise_error(RuntimeError, 'here comes an error!')
end
end
end
end
describe '#connection_db_config' do
let!(:original_connection) { shared_model_class.connection }
let!(:original_connection_db_config) { shared_model_class.connection_db_config }
let(:shared_model) { shared_model_class.new }
let(:shared_model_class) do
Class.new(described_class) do
self.table_name = 'postgres_async_indexes'
end
end
it 'returns the class connection_db_config' do
expect(shared_model.connection_db_config).to eq(described_class.connection_db_config)
end
context 'when switching the class connection' do
before do
skip_if_multiple_databases_not_setup
end
let(:new_base_model) { Ci::ApplicationRecord }
let(:new_connection) { new_base_model.connection }
it 'returns the db_config of the used connection when using load balancing' do
expect_original_connection_around do
described_class.using_connection(new_connection) do
expect(shared_model.connection_db_config).to eq(new_base_model.connection_db_config)
end
end
# it restores the connection_db_config afterwards
expect(shared_model.connection_db_config).to eq(original_connection_db_config)
end
end
end
def expect_original_connection_around
# For safety, ensure our original connection is distinct from our double
# This should be the case, but in case of something leaking we should verify
expect(original_connection).not_to be(new_connection)
expect(described_class.connection).to be(original_connection)
yield
expect(described_class.connection).to be(original_connection)
end
end