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