263 lines
8.2 KiB
Ruby
263 lines
8.2 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'spec_helper'
|
|
|
|
RSpec.describe Gitlab::Database::LoadBalancing::Configuration, :request_store do
|
|
let(:configuration_hash) { {} }
|
|
let(:db_config) { ActiveRecord::DatabaseConfigurations::HashConfig.new('test', 'ci', configuration_hash) }
|
|
let(:model) { double(:model, connection_db_config: db_config) }
|
|
|
|
describe '.for_model' do
|
|
context 'when load balancing is not configured' do
|
|
it 'uses the default settings' do
|
|
config = described_class.for_model(model)
|
|
|
|
expect(config.hosts).to eq([])
|
|
expect(config.max_replication_difference).to eq(8.megabytes)
|
|
expect(config.max_replication_lag_time).to eq(60.0)
|
|
expect(config.replica_check_interval).to eq(60.0)
|
|
expect(config.service_discovery).to eq(
|
|
nameserver: 'localhost',
|
|
port: 8600,
|
|
record: nil,
|
|
record_type: 'A',
|
|
interval: 60,
|
|
disconnect_timeout: 120,
|
|
use_tcp: false
|
|
)
|
|
expect(config.pool_size).to eq(Gitlab::Database.default_pool_size)
|
|
end
|
|
end
|
|
|
|
context 'when load balancing is configured' do
|
|
let(:configuration_hash) do
|
|
{
|
|
pool: 4,
|
|
load_balancing: {
|
|
max_replication_difference: 1,
|
|
max_replication_lag_time: 2,
|
|
replica_check_interval: 3,
|
|
hosts: %w[foo bar],
|
|
discover: {
|
|
'record' => 'foo.example.com'
|
|
}
|
|
}
|
|
}
|
|
end
|
|
|
|
it 'uses the custom configuration settings' do
|
|
config = described_class.for_model(model)
|
|
|
|
expect(config.hosts).to eq(%w[foo bar])
|
|
expect(config.max_replication_difference).to eq(1)
|
|
expect(config.max_replication_lag_time).to eq(2.0)
|
|
expect(config.replica_check_interval).to eq(3.0)
|
|
expect(config.service_discovery).to eq(
|
|
nameserver: 'localhost',
|
|
port: 8600,
|
|
record: 'foo.example.com',
|
|
record_type: 'A',
|
|
interval: 60,
|
|
disconnect_timeout: 120,
|
|
use_tcp: false
|
|
)
|
|
expect(config.pool_size).to eq(4)
|
|
end
|
|
end
|
|
|
|
context 'when the load balancing configuration uses strings as the keys' do
|
|
let(:configuration_hash) do
|
|
{
|
|
pool: 4,
|
|
load_balancing: {
|
|
'max_replication_difference' => 1,
|
|
'max_replication_lag_time' => 2,
|
|
'replica_check_interval' => 3,
|
|
'hosts' => %w[foo bar],
|
|
'discover' => {
|
|
'record' => 'foo.example.com'
|
|
}
|
|
}
|
|
}
|
|
end
|
|
|
|
it 'uses the custom configuration settings' do
|
|
config = described_class.for_model(model)
|
|
|
|
expect(config.hosts).to eq(%w[foo bar])
|
|
expect(config.max_replication_difference).to eq(1)
|
|
expect(config.max_replication_lag_time).to eq(2.0)
|
|
expect(config.replica_check_interval).to eq(3.0)
|
|
expect(config.service_discovery).to eq(
|
|
nameserver: 'localhost',
|
|
port: 8600,
|
|
record: 'foo.example.com',
|
|
record_type: 'A',
|
|
interval: 60,
|
|
disconnect_timeout: 120,
|
|
use_tcp: false
|
|
)
|
|
expect(config.pool_size).to eq(4)
|
|
end
|
|
end
|
|
|
|
it 'calls reuse_primary_connection!' do
|
|
expect_next_instance_of(described_class) do |subject|
|
|
expect(subject).to receive(:reuse_primary_connection!).and_call_original
|
|
end
|
|
|
|
described_class.for_model(model)
|
|
end
|
|
end
|
|
|
|
describe '#load_balancing_enabled?' do
|
|
it 'returns false when running inside a Rake task' do
|
|
config = described_class.new(ActiveRecord::Base, %w[foo bar])
|
|
|
|
allow(Gitlab::Runtime).to receive(:rake?).and_return(true)
|
|
|
|
expect(config.load_balancing_enabled?).to eq(false)
|
|
end
|
|
|
|
it 'returns true when hosts are configured' do
|
|
config = described_class.new(ActiveRecord::Base, %w[foo bar])
|
|
|
|
expect(config.load_balancing_enabled?).to eq(true)
|
|
end
|
|
|
|
it 'returns true when a service discovery record is configured' do
|
|
config = described_class.new(ActiveRecord::Base)
|
|
config.service_discovery[:record] = 'foo'
|
|
|
|
expect(config.load_balancing_enabled?).to eq(true)
|
|
end
|
|
|
|
it 'returns false when no hosts are configured and service discovery is disabled' do
|
|
config = described_class.new(ActiveRecord::Base)
|
|
|
|
expect(config.load_balancing_enabled?).to eq(false)
|
|
end
|
|
end
|
|
|
|
describe '#service_discovery_enabled?' do
|
|
it 'returns false when running inside a Rake task' do
|
|
allow(Gitlab::Runtime).to receive(:rake?).and_return(true)
|
|
|
|
config = described_class.new(ActiveRecord::Base)
|
|
config.service_discovery[:record] = 'foo'
|
|
|
|
expect(config.service_discovery_enabled?).to eq(false)
|
|
end
|
|
|
|
it 'returns true when a record is configured' do
|
|
config = described_class.new(ActiveRecord::Base)
|
|
config.service_discovery[:record] = 'foo'
|
|
|
|
expect(config.service_discovery_enabled?).to eq(true)
|
|
end
|
|
|
|
it 'returns false when no record is configured' do
|
|
config = described_class.new(ActiveRecord::Base)
|
|
|
|
expect(config.service_discovery_enabled?).to eq(false)
|
|
end
|
|
end
|
|
|
|
describe '#pool_size' do
|
|
context 'when a custom pool size is used' do
|
|
let(:configuration_hash) { { pool: 4 } }
|
|
|
|
it 'always reads the value from the model configuration' do
|
|
config = described_class.new(model)
|
|
|
|
expect(config.pool_size).to eq(4)
|
|
|
|
# We can't modify `configuration_hash` as it's only used to populate the
|
|
# internal hash used by ActiveRecord; instead of it being used as-is.
|
|
allow(model.connection_db_config)
|
|
.to receive(:configuration_hash)
|
|
.and_return({ pool: 42 })
|
|
|
|
expect(config.pool_size).to eq(42)
|
|
end
|
|
end
|
|
|
|
context 'when the pool size is nil' do
|
|
let(:configuration_hash) { {} }
|
|
|
|
it 'returns the default pool size' do
|
|
config = described_class.new(model)
|
|
|
|
expect(config.pool_size).to eq(Gitlab::Database.default_pool_size)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#db_config_name' do
|
|
let(:config) { described_class.new(model) }
|
|
|
|
subject { config.db_config_name }
|
|
|
|
it 'returns connection name as symbol' do
|
|
is_expected.to eq(:ci)
|
|
end
|
|
end
|
|
|
|
describe '#replica_db_config' do
|
|
let(:model) { double(:model, connection_db_config: db_config, connection_specification_name: 'Ci::ApplicationRecord') }
|
|
let(:config) { described_class.for_model(model) }
|
|
|
|
it 'returns exactly db_config' do
|
|
expect(config.replica_db_config).to eq(db_config)
|
|
end
|
|
|
|
context 'when GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci=main' do
|
|
it 'does not change replica_db_config' do
|
|
stub_env('GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci', 'main')
|
|
|
|
expect(config.replica_db_config).to eq(db_config)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'reuse_primary_connection!' do
|
|
let(:model) { double(:model, connection_db_config: db_config, connection_specification_name: 'Ci::ApplicationRecord') }
|
|
let(:config) { described_class.for_model(model) }
|
|
|
|
context 'when GITLAB_LOAD_BALANCING_REUSE_PRIMARY_* not configured' do
|
|
it 'the primary connection uses default specification' do
|
|
stub_env('GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci', nil)
|
|
|
|
expect(config.primary_connection_specification_name).to eq('Ci::ApplicationRecord')
|
|
end
|
|
end
|
|
|
|
context 'when GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci=main' do
|
|
before do
|
|
stub_env('GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci', 'main')
|
|
end
|
|
|
|
it 'the primary connection uses main connection' do
|
|
expect(config.primary_connection_specification_name).to eq('ActiveRecord::Base')
|
|
end
|
|
|
|
context 'when force_no_sharing_primary_model feature flag is enabled' do
|
|
before do
|
|
stub_feature_flags(force_no_sharing_primary_model: true)
|
|
end
|
|
|
|
it 'the primary connection uses ci connection' do
|
|
expect(config.primary_connection_specification_name).to eq('Ci::ApplicationRecord')
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci=unknown' do
|
|
it 'raises exception' do
|
|
stub_env('GITLAB_LOAD_BALANCING_REUSE_PRIMARY_ci', 'unknown')
|
|
|
|
expect { config.reuse_primary_connection! }.to raise_error /Invalid value for/
|
|
end
|
|
end
|
|
end
|
|
end
|