spec/lib/gdk/diagnostic/postgresql_spec.rb (263 lines of code) (raw):
# frozen_string_literal: true
RSpec.describe GDK::Diagnostic::Postgresql do
include ShelloutHelper
let(:tmp_path) { Dir.mktmpdir('gdk-path') }
let(:pg_bin_dir) { tmp_path }
let(:psql) { File.join(pg_bin_dir, 'psql') }
before do
@tmp_file = stub_data_version(11)
stub_gdk_yaml("postgresql" => { "bin_dir" => tmp_path })
end
after do
FileUtils.rm_f(@tmp_file) # rubocop:todo RSpec/InstanceVariable
end
describe '#success?' do
let(:psql_success) { true }
before do
stub_psql_version('psql (PostgreSQL) 11.9', success: psql_success)
end
context 'versions testing' do
before do
allow(subject).to receive_messages(can_create_postgres_socket?: true, valid_ldflags?: true)
end
context 'when psql --version matches PG_VERSION' do
it 'returns true' do
expect(subject).to be_success
end
end
context 'when psql --version differs' do
before do
stub_psql_version("#{psql} (PostgreSQL) 12.8", success: psql_success)
end
it 'returns false' do
expect(subject).not_to be_success
end
end
context 'when psql does not succeed' do
let(:psql_success) { false }
it 'returns false' do
expect(subject).not_to be_success
end
end
context 'when psql --version is 9.6' do
before do
stub_psql_version("#{psql} (PostgreSQL) 9.6.18", success: psql_success)
end
it 'returns false' do
expect(subject).not_to be_success
end
context 'when data version is 9.6' do
before do
allow(subject).to receive(:data_dir_version).and_return(9.6)
end
it 'returns false' do
expect(subject).to be_success
end
end
end
end
context 'socket creation testing' do
let(:can_create_socket) { nil }
before do
allow(subject).to receive_messages(versions_ok?: true, valid_ldflags?: true)
stub_can_create_socket.and_return(can_create_socket)
end
context 'when the GDK base directory length is too long' do
let(:can_create_socket) { false }
it 'returns false' do
expect(subject).not_to be_success
end
end
context 'when the GDK base directory length is OK' do
let(:can_create_socket) { true }
it 'returns true' do
expect(subject).to be_success
end
end
end
context 'ldflags testing' do
let(:valid_ldflags) { nil }
let(:pgvector_enabled) { nil }
let(:isysroot_path) { '/Library/Developer/CommandLineTools/SDKs/MacOSX13.3.sdk' }
let(:isysroot_path_exists) { nil }
let(:pg_config_ldflags) { "-isysroot #{isysroot_path}" }
let(:xcrun_sdk_path) { '/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk' }
let(:realpath) { '/expected/isysroot_path' }
before do
allow(subject).to receive_messages(can_create_postgres_socket?: true, data_dir_version: 12, versions_ok?: true, macos?: true)
allow_any_instance_of(GDK::Config).to receive_message_chain('pgvector.enabled').and_return(pgvector_enabled)
stub_isysroot_path_exists?(isysroot_path, isysroot_path_exists)
stub_pg_config_ldflags(pg_config_ldflags)
stub_xcrun_sdk_path(xcrun_sdk_path)
stub_realpath(isysroot_path, realpath)
stub_realpath(xcrun_sdk_path, realpath)
end
context 'when pgvector is enabled' do
let(:pgvector_enabled) { true }
let(:isysroot_path_exists) { true }
context 'when pg_config_ldflags includes -isysroot flag, and matches xcrun_sdk_path' do
it 'returns true' do
expect(subject).to be_success
end
end
context 'when pg_config_ldflags includes -isysroot flag, but does not match xcrun_sdk_path' do
let(:pg_config_ldflags) { '-isysroot /wrong/path' }
let(:isysroot_path) { '/wrong/path' }
let(:isysroot_path_exists) { false }
it 'returns false' do
expect(subject).not_to be_success
end
end
context 'when pg_config_ldflags does not include -isysroot flag' do
let(:pg_config_ldflags) { '-wrong-flag' }
it 'returns false' do
expect(subject).not_to be_success
end
end
context 'when isysroot_path does not exist' do
let(:isysroot_path_exists) { false }
it 'returns false' do
expect(subject).not_to be_success
end
end
context 'when not on macOS' do
before do
allow(subject).to receive(:macos?).and_return(false)
end
it 'returns true' do
expect(subject).to be_success
end
end
context 'when comparing realpaths between isysroot_path and xcrun_sdk_path' do
it 'returns false if realpaths do not match' do
allow(File).to receive(:realpath).with(xcrun_sdk_path).and_return('/wrong/realpath')
expect(subject).not_to be_success
end
end
end
context 'when pgvector is not enabled' do
it 'returns true' do
expect(subject).to be_success
end
end
end
end
describe '#detail' do
context 'when successful' do
before do
allow(subject).to receive(:success?).and_return(true)
end
it 'returns nil' do
expect(subject.detail).to be_nil
end
end
context 'versions testing' do
before do
allow(subject).to receive_messages(can_create_postgres_socket?: true, valid_ldflags?: true)
end
context 'when unsuccessful' do
before do
allow(subject).to receive_messages(success?: false, psql_version: 11.8, data_dir_version: 12)
end
it 'returns help message' do
expected = <<~MESSAGE
`psql` is version 11.8, but your PostgreSQL data dir is using version 12.
Check that your PATH is pointing to the right PostgreSQL version, or see the PostgreSQL upgrade guide:
https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/howto/postgresql.md#upgrade-postgresql
MESSAGE
expect(subject.detail).to eq(expected)
end
end
end
context 'socket creation testing' do
before do
allow(subject).to receive_messages(versions_ok?: true, valid_ldflags?: true)
end
context 'when unsuccessful' do
before do
stub_can_create_socket.and_return(false)
end
it 'returns help message' do
expected = <<~MESSAGE
GDK directory's character length (13) is too long to support the creation
of a UNIX socket for Postgres:
/home/git/gdk
Try using a shorter directory path for GDK or use TCP for Postgres.
MESSAGE
expect(subject.detail).to eq(expected)
end
end
context 'ldflags testing' do
before do
allow(subject).to receive_messages(can_create_postgres_socket?: true, data_dir_version: 12, versions_ok?: true)
end
context 'when unsuccessful' do
let(:error_message) { 'The `-isysroot` value not present in `pg_config --ldflags`.' }
before do
allow(subject).to receive(:asdf?).and_return(true)
allow(subject).to receive_messages(psql_version: 16.8, valid_ldflags?: false)
subject.instance_variable_set(:@pgconfig_error, error_message)
end
it 'returns help message' do
expected = <<~MESSAGE
#{error_message}
This may indicate a potential issue with the PostgreSQL installation, and we recommend reinstalling PostgreSQL.
You can try running the following to reinstall PostgreSQL:
asdf uninstall postgres 16.8 && asdf install postgres 16.8
MESSAGE
expect(subject.detail).to eq(expected)
end
context 'when mise is installed' do
before do
allow(subject).to receive(:asdf?).and_return(false)
end
it 'returns help message' do
expected = <<~MESSAGE
#{error_message}
This may indicate a potential issue with the PostgreSQL installation, and we recommend reinstalling PostgreSQL.
You can try running the following to reinstall PostgreSQL:
mise uninstall postgres 16.8 && mise install postgres 16.8
MESSAGE
expect(subject.detail).to eq(expected)
end
end
end
end
context 'when unhandled' do
before do
stub_can_create_socket.and_raise(ArgumentError.new('something else'))
end
it 'returns help message' do
expect { subject.detail }.to raise_error('something else')
end
end
end
end
def stub_can_create_socket
allow(subject).to receive(:can_create_socket?).with('/home/git/gdk/postgresql_.s.PGSQL.XXXXX')
end
def stub_data_version(version)
tmpfile = Tempfile.new
tmpfile.write(version)
tmpfile.close
allow(subject).to receive(:data_dir_version_filename).and_return(tmpfile.path)
tmpfile.path
end
def stub_isysroot_path_exists?(isysroot_path, exists)
allow(Dir).to receive(:exist?).with(isysroot_path).and_return(exists)
end
def stub_psql_version(result, success: true)
stub_shellout(%W[#{psql} --version], result, success: success)
end
def stub_pg_config_ldflags(result)
stub_shellout('pg_config --ldflags', result)
end
def stub_realpath(path, realpath)
allow(File).to receive(:realpath).with(path).and_return(realpath)
end
def stub_shellout(command, result, success: true)
shellout = gdk_shellout_double(read_stdout: result, success?: success)
allow_gdk_shellout_command(command).and_return(shellout)
allow(shellout).to receive(:execute).and_return(shellout)
end
def stub_xcrun_sdk_path(result)
stub_shellout('xcrun --show-sdk-path', result)
end
end