spec/lib/gdk/postgresql_spec.rb (225 lines of code) (raw):
# frozen_string_literal: true
RSpec.describe GDK::Postgresql do
include ShelloutHelper
let(:yaml) { {} }
let(:shellout_mock) { double('GDK::Shellout', run: nil, try_run: '', success?: true) } # rubocop:todo RSpec/VerifiedDoubles
let(:config) { GDK::Config.new(yaml: yaml) }
let(:pg_data_dir) { Pathname.new('/home/git/gdk/postgresql/data') }
let(:pg_version_file) { pg_data_dir.join('PG_VERSION') }
let(:postgresql_config) { double('GDK::Config', data_dir: pg_data_dir) } # rubocop:todo RSpec/VerifiedDoubles
subject { described_class.new(config) }
before do
stub_pg_bindir
end
describe '.target_version' do
it 'is 16.8 by default' do
expect(described_class.target_version).to be_instance_of(Gem::Version)
expect(described_class.target_version).to eq(Gem::Version.new('16.8'))
end
end
describe '.target_version_major' do
it 'is 16 by default' do
expect(described_class.target_version_major).to eq(16)
end
end
describe '#current_data_dir' do
it 'returns the computed data dir' do
stub_pg_data_dir
expect(subject.current_data_dir).to eq(pg_data_dir)
end
end
describe '#psql_cmd' do
it 'calls pg_cmd' do
expect(subject).to receive(:pg_cmd).with('--version', database: 'gitlabhq_development').and_call_original
subject.psql_cmd('--version')
end
end
describe '#ready?' do
let(:error_msg) { nil }
let(:success) { nil }
let(:shellout_double) { gdk_shellout_double(read_stderr: error_msg, success?: success) }
before do
allow_gdk_shellout_command(%w[/usr/local/bin/psql --host=/home/git/gdk/postgresql --port=5432 --dbname=template1]).and_return(shellout_double)
allow(shellout_double).to receive(:try_run).and_return(shellout_double)
allow(subject).to receive(:sleep)
end
context 'when DB is not ready' do
let(:error_msg) { 'an error has occurred' }
let(:success) { false }
it 'has defaults' do
interval = 1
retries = 10
expect(GDK::Output).to receive(:error).with(error_msg)
expect(subject).to receive(:sleep).with(interval).exactly(retries - 1).times
expect(subject.ready?).to be_falsey
end
it 'accepts quiet parameter to silence output' do
expect(GDK::Output).not_to receive(:error)
expect(subject.ready?(quiet: true)).to be_falsey
end
it 'accepts custom interval parameter', :hide_output do
interval = 0.5
retries = 3
expect(subject).to receive(:sleep).with(interval).exactly(retries - 1).times
expect(subject.ready?(try_times: retries, interval: interval)).to be_falsey
end
end
context 'when DB is ready' do
let(:success) { true }
it 'returns true' do
expect(subject.ready?(try_times: 1)).to be_truthy
end
end
end
describe '#installed?' do
let(:pg_version_file_exists) { nil }
before do
stub_pg_version_file(exists: pg_version_file_exists)
end
context 'when postgresql/data/PG_VERSION does not exist' do
let(:pg_version_file_exists) { false }
it 'returns false' do
expect(subject.installed?).to be(false)
end
end
context 'when postgresql/data/PG_VERSION exists' do
let(:pg_version_file_exists) { true }
it 'returns true' do
expect(subject.installed?).to be(true)
end
end
end
describe '#use_tcp?' do
context 'with host defined to a path' do
let(:yaml) do
{
'postgresql' => {
'host' => '/home/git/gdk/postgresql'
}
}
end
it 'returns false' do
expect(subject).not_to be_use_tcp
end
end
context 'with host defined to a hostname' do
let(:yaml) do
{
'postgresql' => {
'host' => 'localhost'
}
}
end
it 'returns true' do
expect(subject).to be_use_tcp
end
end
end
describe '#db_exists?' do
it 'calls psql with the correct arguments' do
expect_gdk_shellout.with(array_including('/usr/local/bin/psql', '--dbname=blaat'), any_args).and_return(shellout_mock)
expect(subject.db_exists?('blaat')).to be_truthy
end
end
describe '#createdb' do
it 'calls createdb' do
expect_gdk_shellout.with(array_including('/usr/local/bin/createdb', 'blaat'), any_args).and_return(shellout_mock)
subject.createdb('blaat')
end
end
describe '#in_recovery?' do
it 'queries pg_is_in_recovery()' do
expect_gdk_shellout.with(array_including('/usr/local/bin/psql', '--command=SELECT pg_is_in_recovery();'), any_args).and_return(shellout_mock)
subject.in_recovery?
end
it 'returns true when psql query returned true' do
expect(shellout_mock).to receive(:try_run).and_return('t')
expect_gdk_shellout.and_return(shellout_mock)
expect(subject).to be_in_recovery
end
it 'returns false when psql query returned false' do
expect(shellout_mock).to receive(:try_run).and_return('f')
expect_gdk_shellout.and_return(shellout_mock)
expect(subject).not_to be_in_recovery
end
it 'returns false when psql failed' do
expect(shellout_mock).to receive(:try_run).and_return('error: could not connect to server')
expect_gdk_shellout.and_return(shellout_mock)
expect(subject).not_to be_in_recovery
end
end
describe '#current_version' do
it 'returns the PostgreSQL version set within postgresql/data/PG_VERSION' do
stub_pg_version_file('12')
expect(subject.current_version).to eq(12)
end
end
describe '#upgrade_needed?' do
context 'when current version is 16' do
before do
stub_pg_version_file('16')
end
context 'and target version is 9.6' do
it 'returns false' do
expect(subject.upgrade_needed?(9.6)).to be(false)
expect(subject.upgrade_needed?('9.6')).to be(false)
end
end
context 'and target version is 11' do
it 'returns false' do
expect(subject.upgrade_needed?(11)).to be(false)
expect(subject.upgrade_needed?('11')).to be(false)
end
end
context 'and target version is 12' do
it 'returns false' do
expect(subject.upgrade_needed?(12)).to be(false)
expect(subject.upgrade_needed?('12')).to be(false)
end
end
context 'and target version is 13' do
it 'returns false' do
expect(subject.upgrade_needed?(13)).to be(false)
expect(subject.upgrade_needed?('13')).to be(false)
end
end
context 'and target version is 14' do
it 'returns false' do
expect(subject.upgrade_needed?(14)).to be(false)
expect(subject.upgrade_needed?('14')).to be(false)
end
end
context 'and target version is the default' do
it 'returns false' do
expect(subject.upgrade_needed?).to be(false)
end
end
context 'and target version is 17' do
it 'returns true' do
expect(subject.upgrade_needed?(17)).to be(true)
expect(subject.upgrade_needed?('17')).to be(true)
end
end
end
end
describe '#upgrade' do
let(:cmd) { 'support/upgrade-postgresql' }
let(:shellout_double) { gdk_shellout_double(success?: true) }
before do
allow_gdk_shellout_command(cmd).and_return(shellout_double)
allow(shellout_double).to receive(:stream)
end
it 'runs the upgrade script' do
expect(shellout_double).to receive(:stream)
subject.upgrade
end
end
def stub_pg_data_dir
allow(config).to receive(:postgresql).and_return(postgresql_config)
allow(pg_data_dir).to receive(:join).with('PG_VERSION').and_return(pg_version_file)
end
def stub_pg_version_file(version = nil, exists: true)
stub_pg_data_dir
allow(pg_version_file).to receive(:exist?).and_return(exists)
allow(pg_version_file).to receive(:read).and_return(version) if version
end
end