blob: 2ae6ccf6c6ab7951357a5f10ffb9d6568dee89cf (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
# 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
|