diff options
Diffstat (limited to 'src/bin/pg_ctl/t')
-rw-r--r-- | src/bin/pg_ctl/t/001_start_stop.pl | 103 | ||||
-rw-r--r-- | src/bin/pg_ctl/t/002_status.pl | 29 | ||||
-rw-r--r-- | src/bin/pg_ctl/t/003_promote.pl | 66 | ||||
-rw-r--r-- | src/bin/pg_ctl/t/004_logrotate.pl | 140 |
4 files changed, 338 insertions, 0 deletions
diff --git a/src/bin/pg_ctl/t/001_start_stop.pl b/src/bin/pg_ctl/t/001_start_stop.pl new file mode 100644 index 0000000..f019fe1 --- /dev/null +++ b/src/bin/pg_ctl/t/001_start_stop.pl @@ -0,0 +1,103 @@ + +# Copyright (c) 2021-2023, PostgreSQL Global Development Group + +use strict; +use warnings; + +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; + +my $tempdir = PostgreSQL::Test::Utils::tempdir; +my $tempdir_short = PostgreSQL::Test::Utils::tempdir_short; + +program_help_ok('pg_ctl'); +program_version_ok('pg_ctl'); +program_options_handling_ok('pg_ctl'); + +command_exit_is([ 'pg_ctl', 'start', '-D', "$tempdir/nonexistent" ], + 1, 'pg_ctl start with nonexistent directory'); + +command_ok([ 'pg_ctl', 'initdb', '-D', "$tempdir/data", '-o', '-N' ], + 'pg_ctl initdb'); +command_ok([ $ENV{PG_REGRESS}, '--config-auth', "$tempdir/data" ], + 'configure authentication'); +my $node_port = PostgreSQL::Test::Cluster::get_free_port(); +open my $conf, '>>', "$tempdir/data/postgresql.conf"; +print $conf "fsync = off\n"; +print $conf "port = $node_port\n"; +print $conf PostgreSQL::Test::Utils::slurp_file($ENV{TEMP_CONFIG}) + if defined $ENV{TEMP_CONFIG}; + +if ($use_unix_sockets) +{ + print $conf "listen_addresses = ''\n"; + $tempdir_short =~ s!\\!/!g if $PostgreSQL::Test::Utils::windows_os; + print $conf "unix_socket_directories = '$tempdir_short'\n"; +} +else +{ + print $conf "listen_addresses = '127.0.0.1'\n"; +} +close $conf; +my $ctlcmd = [ + 'pg_ctl', 'start', '-D', "$tempdir/data", '-l', + "$PostgreSQL::Test::Utils::log_path/001_start_stop_server.log" +]; +command_like($ctlcmd, qr/done.*server started/s, 'pg_ctl start'); + +# sleep here is because Windows builds can't check postmaster.pid exactly, +# so they may mistake a pre-existing postmaster.pid for one created by the +# postmaster they start. Waiting more than the 2 seconds slop time allowed +# by wait_for_postmaster() prevents that mistake. +sleep 3 if ($windows_os); +command_fails([ 'pg_ctl', 'start', '-D', "$tempdir/data" ], + 'second pg_ctl start fails'); +command_ok([ 'pg_ctl', 'stop', '-D', "$tempdir/data" ], 'pg_ctl stop'); +command_fails([ 'pg_ctl', 'stop', '-D', "$tempdir/data" ], + 'second pg_ctl stop fails'); + +# Log file for default permission test. The permissions won't be checked on +# Windows but we still want to do the restart test. +my $logFileName = "$tempdir/data/perm-test-600.log"; + +command_ok([ 'pg_ctl', 'restart', '-D', "$tempdir/data", '-l', $logFileName ], + 'pg_ctl restart with server not running'); + +# Permissions on log file should be default +SKIP: +{ + skip "unix-style permissions not supported on Windows", 2 + if ($windows_os); + + ok(-f $logFileName); + ok(check_mode_recursive("$tempdir/data", 0700, 0600)); +} + +# Log file for group access test +$logFileName = "$tempdir/data/perm-test-640.log"; + +SKIP: +{ + skip "group access not supported on Windows", 3 if ($windows_os); + + system_or_bail 'pg_ctl', 'stop', '-D', "$tempdir/data"; + + # Change the data dir mode so log file will be created with group read + # privileges on the next start + chmod_recursive("$tempdir/data", 0750, 0640); + + command_ok( + [ 'pg_ctl', 'start', '-D', "$tempdir/data", '-l', $logFileName ], + 'start server to check group permissions'); + + ok(-f $logFileName); + ok(check_mode_recursive("$tempdir/data", 0750, 0640)); +} + +command_ok([ 'pg_ctl', 'restart', '-D', "$tempdir/data" ], + 'pg_ctl restart with server running'); + +system_or_bail 'pg_ctl', 'stop', '-D', "$tempdir/data"; + +done_testing(); diff --git a/src/bin/pg_ctl/t/002_status.pl b/src/bin/pg_ctl/t/002_status.pl new file mode 100644 index 0000000..f5c50f6 --- /dev/null +++ b/src/bin/pg_ctl/t/002_status.pl @@ -0,0 +1,29 @@ + +# Copyright (c) 2021-2023, PostgreSQL Global Development Group + +use strict; +use warnings; + +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; + +my $tempdir = PostgreSQL::Test::Utils::tempdir; + +command_exit_is([ 'pg_ctl', 'status', '-D', "$tempdir/nonexistent" ], + 4, 'pg_ctl status with nonexistent directory'); + +my $node = PostgreSQL::Test::Cluster->new('main'); +$node->init; + +command_exit_is([ 'pg_ctl', 'status', '-D', $node->data_dir ], + 3, 'pg_ctl status with server not running'); + +system_or_bail 'pg_ctl', '-l', "$tempdir/logfile", '-D', + $node->data_dir, '-w', 'start'; +command_exit_is([ 'pg_ctl', 'status', '-D', $node->data_dir ], + 0, 'pg_ctl status with server running'); + +system_or_bail 'pg_ctl', 'stop', '-D', $node->data_dir; + +done_testing(); diff --git a/src/bin/pg_ctl/t/003_promote.pl b/src/bin/pg_ctl/t/003_promote.pl new file mode 100644 index 0000000..0e83933 --- /dev/null +++ b/src/bin/pg_ctl/t/003_promote.pl @@ -0,0 +1,66 @@ + +# Copyright (c) 2021-2023, PostgreSQL Global Development Group + +use strict; +use warnings; + +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; + +my $tempdir = PostgreSQL::Test::Utils::tempdir; + +command_fails_like( + [ 'pg_ctl', '-D', "$tempdir/nonexistent", 'promote' ], + qr/directory .* does not exist/, + 'pg_ctl promote with nonexistent directory'); + +my $node_primary = PostgreSQL::Test::Cluster->new('primary'); +$node_primary->init(allows_streaming => 1); + +command_fails_like( + [ 'pg_ctl', '-D', $node_primary->data_dir, 'promote' ], + qr/PID file .* does not exist/, + 'pg_ctl promote of not running instance fails'); + +$node_primary->start; + +command_fails_like( + [ 'pg_ctl', '-D', $node_primary->data_dir, 'promote' ], + qr/not in standby mode/, + 'pg_ctl promote of primary instance fails'); + +my $node_standby = PostgreSQL::Test::Cluster->new('standby'); +$node_primary->backup('my_backup'); +$node_standby->init_from_backup($node_primary, 'my_backup', + has_streaming => 1); +$node_standby->start; + +is($node_standby->safe_psql('postgres', 'SELECT pg_is_in_recovery()'), + 't', 'standby is in recovery'); + +command_ok([ 'pg_ctl', '-D', $node_standby->data_dir, '-W', 'promote' ], + 'pg_ctl -W promote of standby runs'); + +ok( $node_standby->poll_query_until( + 'postgres', 'SELECT NOT pg_is_in_recovery()'), + 'promoted standby is not in recovery'); + +# same again with default wait option +$node_standby = PostgreSQL::Test::Cluster->new('standby2'); +$node_standby->init_from_backup($node_primary, 'my_backup', + has_streaming => 1); +$node_standby->start; + +is($node_standby->safe_psql('postgres', 'SELECT pg_is_in_recovery()'), + 't', 'standby is in recovery'); + +command_ok([ 'pg_ctl', '-D', $node_standby->data_dir, 'promote' ], + 'pg_ctl promote of standby runs'); + +# no wait here + +is($node_standby->safe_psql('postgres', 'SELECT pg_is_in_recovery()'), + 'f', 'promoted standby is not in recovery'); + +done_testing(); diff --git a/src/bin/pg_ctl/t/004_logrotate.pl b/src/bin/pg_ctl/t/004_logrotate.pl new file mode 100644 index 0000000..8d48e56 --- /dev/null +++ b/src/bin/pg_ctl/t/004_logrotate.pl @@ -0,0 +1,140 @@ + +# Copyright (c) 2021-2023, PostgreSQL Global Development Group + +use strict; +use warnings; + +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; +use Time::HiRes qw(usleep); + +# Extract the file name of a $format from the contents of +# current_logfiles. +sub fetch_file_name +{ + my $logfiles = shift; + my $format = shift; + my @lines = split(/\n/, $logfiles); + my $filename = undef; + foreach my $line (@lines) + { + if ($line =~ /$format (.*)$/gm) + { + $filename = $1; + } + } + + return $filename; +} + +# Check for a pattern in the logs associated to one format. +sub check_log_pattern +{ + local $Test::Builder::Level = $Test::Builder::Level + 1; + + my $format = shift; + my $logfiles = shift; + my $pattern = shift; + my $node = shift; + my $lfname = fetch_file_name($logfiles, $format); + + my $max_attempts = 10 * $PostgreSQL::Test::Utils::timeout_default; + + my $logcontents; + for (my $attempts = 0; $attempts < $max_attempts; $attempts++) + { + $logcontents = slurp_file($node->data_dir . '/' . $lfname); + last if $logcontents =~ m/$pattern/; + usleep(100_000); + } + + like($logcontents, qr/$pattern/, + "found expected log file content for $format"); + + # While we're at it, test pg_current_logfile() function + is( $node->safe_psql('postgres', "SELECT pg_current_logfile('$format')"), + $lfname, + "pg_current_logfile() gives correct answer with $format"); + return; +} + +# Set up node with logging collector +my $node = PostgreSQL::Test::Cluster->new('primary'); +$node->init(); +$node->append_conf( + 'postgresql.conf', qq( +logging_collector = on +log_destination = 'stderr, csvlog, jsonlog' +# these ensure stability of test results: +log_rotation_age = 0 +lc_messages = 'C' +)); + +$node->start(); + +# Verify that log output gets to the file + +$node->psql('postgres', 'SELECT 1/0'); + +# might need to retry if logging collector process is slow... +my $max_attempts = 10 * $PostgreSQL::Test::Utils::timeout_default; + +my $current_logfiles; +for (my $attempts = 0; $attempts < $max_attempts; $attempts++) +{ + eval { + $current_logfiles = slurp_file($node->data_dir . '/current_logfiles'); + }; + last unless $@; + usleep(100_000); +} +die $@ if $@; + +note "current_logfiles = $current_logfiles"; + +like( + $current_logfiles, + qr|^stderr log/postgresql-.*log +csvlog log/postgresql-.*csv +jsonlog log/postgresql-.*json$|, + 'current_logfiles is sane'); + +check_log_pattern('stderr', $current_logfiles, 'division by zero', $node); +check_log_pattern('csvlog', $current_logfiles, 'division by zero', $node); +check_log_pattern('jsonlog', $current_logfiles, 'division by zero', $node); + +# Sleep 2 seconds and ask for log rotation; this should result in +# output into a different log file name. +sleep(2); +$node->logrotate(); + +# pg_ctl logrotate doesn't wait for rotation request to be completed. +# Allow a bit of time for it to happen. +my $new_current_logfiles; +for (my $attempts = 0; $attempts < $max_attempts; $attempts++) +{ + $new_current_logfiles = slurp_file($node->data_dir . '/current_logfiles'); + last if $new_current_logfiles ne $current_logfiles; + usleep(100_000); +} + +note "now current_logfiles = $new_current_logfiles"; + +like( + $new_current_logfiles, + qr|^stderr log/postgresql-.*log +csvlog log/postgresql-.*csv +jsonlog log/postgresql-.*json$|, + 'new current_logfiles is sane'); + +# Verify that log output gets to this file, too +$node->psql('postgres', 'fee fi fo fum'); + +check_log_pattern('stderr', $new_current_logfiles, 'syntax error', $node); +check_log_pattern('csvlog', $new_current_logfiles, 'syntax error', $node); +check_log_pattern('jsonlog', $new_current_logfiles, 'syntax error', $node); + +$node->stop(); + +done_testing(); |