Author: Noah Misch Commit: Noah Misch Test postmaster with program_options_handling_ok() et al. Most executables already get that testing. To occupy the customary 001_basic.pl name, this renumbers the new-in-October tests of src/test/postmaster/t. Reviewed by FIXME. Discussion: https://postgr.es/m/FIXME diff --git a/src/test/postmaster/meson.build b/src/test/postmaster/meson.build index 2d89adf..5b909fe 100644 --- a/src/test/postmaster/meson.build +++ b/src/test/postmaster/meson.build @@ -6,8 +6,9 @@ tests += { 'bd': meson.current_build_dir(), 'tap': { 'tests': [ - 't/001_connection_limits.pl', - 't/002_start_stop.pl', + 't/001_basic.pl', + 't/002_connection_limits.pl', + 't/003_start_stop.pl', ], }, } diff --git a/src/test/postmaster/t/001_basic.pl b/src/test/postmaster/t/001_basic.pl new file mode 100644 index 0000000..13f411d --- /dev/null +++ b/src/test/postmaster/t/001_basic.pl @@ -0,0 +1,13 @@ + +# Copyright (c) 2021-2024, PostgreSQL Global Development Group + +use strict; +use warnings FATAL => 'all'; +use PostgreSQL::Test::Utils; +use Test::More; + +program_help_ok('postgres'); +program_version_ok('postgres'); +program_options_handling_ok('postgres'); + +done_testing(); diff --git a/src/test/postmaster/t/001_connection_limits.pl b/src/test/postmaster/t/001_connection_limits.pl deleted file mode 100644 index 7e64a82..0000000 --- a/src/test/postmaster/t/001_connection_limits.pl +++ /dev/null @@ -1,123 +0,0 @@ - -# Copyright (c) 2021-2024, PostgreSQL Global Development Group - -# Test connection limits, i.e. max_connections, reserved_connections -# and superuser_reserved_connections. - -use strict; -use warnings FATAL => 'all'; -use PostgreSQL::Test::Cluster; -use PostgreSQL::Test::Utils; -use Test::More; - -# Initialize the server with specific low connection limits -my $node = PostgreSQL::Test::Cluster->new('primary'); -$node->init( - 'auth_extra' => [ - '--create-role', 'regress_regular,regress_reserved,regress_superuser' - ]); -$node->append_conf('postgresql.conf', "max_connections = 6"); -$node->append_conf('postgresql.conf', "reserved_connections = 2"); -$node->append_conf('postgresql.conf', "superuser_reserved_connections = 1"); -$node->append_conf('postgresql.conf', "log_connections = on"); -$node->start; - -$node->safe_psql( - 'postgres', qq{ -CREATE USER regress_regular LOGIN; -CREATE USER regress_reserved LOGIN; -GRANT pg_use_reserved_connections TO regress_reserved; -CREATE USER regress_superuser LOGIN SUPERUSER; -}); - -# With the limits we set in postgresql.conf, we can establish: -# - 3 connections for any user with no special privileges -# - 2 more connections for users belonging to "pg_use_reserved_connections" -# - 1 more connection for superuser - -sub background_psql_as_user -{ - my $user = shift; - - return $node->background_psql( - 'postgres', - on_error_die => 1, - extra_params => [ '-U', $user ]); -} - -my @sessions = (); -my @raw_connections = (); - -push(@sessions, background_psql_as_user('regress_regular')); -push(@sessions, background_psql_as_user('regress_regular')); -push(@sessions, background_psql_as_user('regress_regular')); -$node->connect_fails( - "dbname=postgres user=regress_regular", - "reserved_connections limit", - expected_stderr => - qr/FATAL: remaining connection slots are reserved for roles with privileges of the "pg_use_reserved_connections" role/ -); - -push(@sessions, background_psql_as_user('regress_reserved')); -push(@sessions, background_psql_as_user('regress_reserved')); -$node->connect_fails( - "dbname=postgres user=regress_regular", - "reserved_connections limit", - expected_stderr => - qr/FATAL: remaining connection slots are reserved for roles with the SUPERUSER attribute/ -); - -push(@sessions, background_psql_as_user('regress_superuser')); -$node->connect_fails( - "dbname=postgres user=regress_superuser", - "superuser_reserved_connections limit", - expected_stderr => qr/FATAL: sorry, too many clients already/); - -# We can still open TCP (or Unix domain socket) connections, but -# beyond a certain number (roughly 2x max_connections), they will be -# "dead-end backends". -SKIP: -{ - skip "this test requires working raw_connect()" - unless $node->raw_connect_works(); - - for (my $i = 0; $i <= 20; $i++) - { - my $sock = $node->raw_connect(); - - # On a busy system, the server might reject connections if - # postmaster cannot accept() them fast enough. The exact limit - # and behavior depends on the platform. To make this reliable, - # we attempt SSL negotiation on each connection before opening - # next one. The server will reject the SSL negotiations, but - # when it does so, we know that the backend has been launched - # and we should be able to open another connection. - - # SSLRequest packet consists of packet length followed by - # NEGOTIATE_SSL_CODE. - my $negotiate_ssl_code = pack("Nnn", 8, 1234, 5679); - my $sent = $sock->send($negotiate_ssl_code); - - # Read reply. We expect the server to reject it with 'N' - my $reply = ""; - $sock->recv($reply, 1); - is($reply, "N", "dead-end connection $i"); - - push(@raw_connections, $sock); - } -} - -# TODO: test that query cancellation is still possible. A dead-end -# backend can process a query cancellation packet. - -# Clean up -foreach my $session (@sessions) -{ - $session->quit; -} -foreach my $socket (@raw_connections) -{ - $socket->close(); -} - -done_testing(); diff --git a/src/test/postmaster/t/002_connection_limits.pl b/src/test/postmaster/t/002_connection_limits.pl new file mode 100644 index 0000000..7e64a82 --- /dev/null +++ b/src/test/postmaster/t/002_connection_limits.pl @@ -0,0 +1,123 @@ + +# Copyright (c) 2021-2024, PostgreSQL Global Development Group + +# Test connection limits, i.e. max_connections, reserved_connections +# and superuser_reserved_connections. + +use strict; +use warnings FATAL => 'all'; +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; + +# Initialize the server with specific low connection limits +my $node = PostgreSQL::Test::Cluster->new('primary'); +$node->init( + 'auth_extra' => [ + '--create-role', 'regress_regular,regress_reserved,regress_superuser' + ]); +$node->append_conf('postgresql.conf', "max_connections = 6"); +$node->append_conf('postgresql.conf', "reserved_connections = 2"); +$node->append_conf('postgresql.conf', "superuser_reserved_connections = 1"); +$node->append_conf('postgresql.conf', "log_connections = on"); +$node->start; + +$node->safe_psql( + 'postgres', qq{ +CREATE USER regress_regular LOGIN; +CREATE USER regress_reserved LOGIN; +GRANT pg_use_reserved_connections TO regress_reserved; +CREATE USER regress_superuser LOGIN SUPERUSER; +}); + +# With the limits we set in postgresql.conf, we can establish: +# - 3 connections for any user with no special privileges +# - 2 more connections for users belonging to "pg_use_reserved_connections" +# - 1 more connection for superuser + +sub background_psql_as_user +{ + my $user = shift; + + return $node->background_psql( + 'postgres', + on_error_die => 1, + extra_params => [ '-U', $user ]); +} + +my @sessions = (); +my @raw_connections = (); + +push(@sessions, background_psql_as_user('regress_regular')); +push(@sessions, background_psql_as_user('regress_regular')); +push(@sessions, background_psql_as_user('regress_regular')); +$node->connect_fails( + "dbname=postgres user=regress_regular", + "reserved_connections limit", + expected_stderr => + qr/FATAL: remaining connection slots are reserved for roles with privileges of the "pg_use_reserved_connections" role/ +); + +push(@sessions, background_psql_as_user('regress_reserved')); +push(@sessions, background_psql_as_user('regress_reserved')); +$node->connect_fails( + "dbname=postgres user=regress_regular", + "reserved_connections limit", + expected_stderr => + qr/FATAL: remaining connection slots are reserved for roles with the SUPERUSER attribute/ +); + +push(@sessions, background_psql_as_user('regress_superuser')); +$node->connect_fails( + "dbname=postgres user=regress_superuser", + "superuser_reserved_connections limit", + expected_stderr => qr/FATAL: sorry, too many clients already/); + +# We can still open TCP (or Unix domain socket) connections, but +# beyond a certain number (roughly 2x max_connections), they will be +# "dead-end backends". +SKIP: +{ + skip "this test requires working raw_connect()" + unless $node->raw_connect_works(); + + for (my $i = 0; $i <= 20; $i++) + { + my $sock = $node->raw_connect(); + + # On a busy system, the server might reject connections if + # postmaster cannot accept() them fast enough. The exact limit + # and behavior depends on the platform. To make this reliable, + # we attempt SSL negotiation on each connection before opening + # next one. The server will reject the SSL negotiations, but + # when it does so, we know that the backend has been launched + # and we should be able to open another connection. + + # SSLRequest packet consists of packet length followed by + # NEGOTIATE_SSL_CODE. + my $negotiate_ssl_code = pack("Nnn", 8, 1234, 5679); + my $sent = $sock->send($negotiate_ssl_code); + + # Read reply. We expect the server to reject it with 'N' + my $reply = ""; + $sock->recv($reply, 1); + is($reply, "N", "dead-end connection $i"); + + push(@raw_connections, $sock); + } +} + +# TODO: test that query cancellation is still possible. A dead-end +# backend can process a query cancellation packet. + +# Clean up +foreach my $session (@sessions) +{ + $session->quit; +} +foreach my $socket (@raw_connections) +{ + $socket->close(); +} + +done_testing(); diff --git a/src/test/postmaster/t/002_start_stop.pl b/src/test/postmaster/t/002_start_stop.pl deleted file mode 100644 index 993d855..0000000 --- a/src/test/postmaster/t/002_start_stop.pl +++ /dev/null @@ -1,98 +0,0 @@ - -# Copyright (c) 2021-2024, PostgreSQL Global Development Group - -# Test postmaster start and stop state machine. - -use strict; -use warnings FATAL => 'all'; -use PostgreSQL::Test::Cluster; -use PostgreSQL::Test::Utils; -use Test::More; - -# -# Test that dead-end backends don't prevent the server from shutting -# down. -# -# Dead-end backends can linger until they reach -# authentication_timeout. We use a long authentication_timeout and a -# much shorter timeout for the "pg_ctl stop" operation, to test that -# if dead-end backends are killed at fast shut down. If they're not, -# "pg_ctl stop" will error out before the authentication timeout kicks -# in and cleans up the dead-end backends. -my $authentication_timeout = $PostgreSQL::Test::Utils::timeout_default; -my $stop_timeout = $authentication_timeout / 2; - -# Initialize the server with low connection limits, to test dead-end backends -my $node = PostgreSQL::Test::Cluster->new('main'); -$node->init; -$node->append_conf('postgresql.conf', "max_connections = 5"); -$node->append_conf('postgresql.conf', "max_wal_senders = 0"); -$node->append_conf('postgresql.conf', "autovacuum_max_workers = 1"); -$node->append_conf('postgresql.conf', "max_worker_processes = 1"); -$node->append_conf('postgresql.conf', "log_connections = on"); -$node->append_conf('postgresql.conf', "log_min_messages = debug2"); -$node->append_conf('postgresql.conf', - "authentication_timeout = '$authentication_timeout s'"); -$node->append_conf('postgresql.conf', 'trace_connection_negotiation=on'); -$node->start; - -if (!$node->raw_connect_works()) -{ - plan skip_all => "this test requires working raw_connect()"; -} - -my @raw_connections = (); - -# Open a lot of TCP (or Unix domain socket) connections to use up all -# the connection slots. Beyond a certain number (roughly 2x -# max_connections), they will be "dead-end backends". -for (my $i = 0; $i <= 20; $i++) -{ - my $sock = $node->raw_connect(); - - # On a busy system, the server might reject connections if - # postmaster cannot accept() them fast enough. The exact limit - # and behavior depends on the platform. To make this reliable, - # we attempt SSL negotiation on each connection before opening - # next one. The server will reject the SSL negotations, but - # when it does so, we know that the backend has been launched - # and we should be able to open another connection. - - # SSLRequest packet consists of packet length followed by - # NEGOTIATE_SSL_CODE. - my $negotiate_ssl_code = pack("Nnn", 8, 1234, 5679); - my $sent = $sock->send($negotiate_ssl_code); - - # Read reply. We expect the server to reject it with 'N' - my $reply = ""; - $sock->recv($reply, 1); - is($reply, "N", "dead-end connection $i"); - - push(@raw_connections, $sock); -} - -# When all the connection slots are in use, new connections will fail -# before even looking up the user. Hence you now get "sorry, too many -# clients already" instead of "role does not exist" error. Test that -# to ensure that we have used up all the slots. -$node->connect_fails("dbname=postgres user=invalid_user", - "connect ", - expected_stderr => qr/FATAL: sorry, too many clients already/); - -# Open one more connection, to really ensure that we have at least one -# dead-end backend. -my $sock = $node->raw_connect(); - -# Test that the dead-end backends don't prevent the server from stopping. -$node->stop('fast', timeout => $stop_timeout); - -$node->start(); -$node->connect_ok("dbname=postgres", "works after restart"); - -# Clean up -foreach my $socket (@raw_connections) -{ - $socket->close(); -} - -done_testing(); diff --git a/src/test/postmaster/t/003_start_stop.pl b/src/test/postmaster/t/003_start_stop.pl new file mode 100644 index 0000000..993d855 --- /dev/null +++ b/src/test/postmaster/t/003_start_stop.pl @@ -0,0 +1,98 @@ + +# Copyright (c) 2021-2024, PostgreSQL Global Development Group + +# Test postmaster start and stop state machine. + +use strict; +use warnings FATAL => 'all'; +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; + +# +# Test that dead-end backends don't prevent the server from shutting +# down. +# +# Dead-end backends can linger until they reach +# authentication_timeout. We use a long authentication_timeout and a +# much shorter timeout for the "pg_ctl stop" operation, to test that +# if dead-end backends are killed at fast shut down. If they're not, +# "pg_ctl stop" will error out before the authentication timeout kicks +# in and cleans up the dead-end backends. +my $authentication_timeout = $PostgreSQL::Test::Utils::timeout_default; +my $stop_timeout = $authentication_timeout / 2; + +# Initialize the server with low connection limits, to test dead-end backends +my $node = PostgreSQL::Test::Cluster->new('main'); +$node->init; +$node->append_conf('postgresql.conf', "max_connections = 5"); +$node->append_conf('postgresql.conf', "max_wal_senders = 0"); +$node->append_conf('postgresql.conf', "autovacuum_max_workers = 1"); +$node->append_conf('postgresql.conf', "max_worker_processes = 1"); +$node->append_conf('postgresql.conf', "log_connections = on"); +$node->append_conf('postgresql.conf', "log_min_messages = debug2"); +$node->append_conf('postgresql.conf', + "authentication_timeout = '$authentication_timeout s'"); +$node->append_conf('postgresql.conf', 'trace_connection_negotiation=on'); +$node->start; + +if (!$node->raw_connect_works()) +{ + plan skip_all => "this test requires working raw_connect()"; +} + +my @raw_connections = (); + +# Open a lot of TCP (or Unix domain socket) connections to use up all +# the connection slots. Beyond a certain number (roughly 2x +# max_connections), they will be "dead-end backends". +for (my $i = 0; $i <= 20; $i++) +{ + my $sock = $node->raw_connect(); + + # On a busy system, the server might reject connections if + # postmaster cannot accept() them fast enough. The exact limit + # and behavior depends on the platform. To make this reliable, + # we attempt SSL negotiation on each connection before opening + # next one. The server will reject the SSL negotations, but + # when it does so, we know that the backend has been launched + # and we should be able to open another connection. + + # SSLRequest packet consists of packet length followed by + # NEGOTIATE_SSL_CODE. + my $negotiate_ssl_code = pack("Nnn", 8, 1234, 5679); + my $sent = $sock->send($negotiate_ssl_code); + + # Read reply. We expect the server to reject it with 'N' + my $reply = ""; + $sock->recv($reply, 1); + is($reply, "N", "dead-end connection $i"); + + push(@raw_connections, $sock); +} + +# When all the connection slots are in use, new connections will fail +# before even looking up the user. Hence you now get "sorry, too many +# clients already" instead of "role does not exist" error. Test that +# to ensure that we have used up all the slots. +$node->connect_fails("dbname=postgres user=invalid_user", + "connect ", + expected_stderr => qr/FATAL: sorry, too many clients already/); + +# Open one more connection, to really ensure that we have at least one +# dead-end backend. +my $sock = $node->raw_connect(); + +# Test that the dead-end backends don't prevent the server from stopping. +$node->stop('fast', timeout => $stop_timeout); + +$node->start(); +$node->connect_ok("dbname=postgres", "works after restart"); + +# Clean up +foreach my $socket (@raw_connections) +{ + $socket->close(); +} + +done_testing();