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