From 98753c29da00612ccbefd6d47c23adde33cc91fd Mon Sep 17 00:00:00 2001 From: Daniel Gustafsson Date: Mon, 23 Aug 2021 13:04:32 +0200 Subject: [PATCH] Refactor psql query cancellation test to use interactive_psql Utilize the interactive_psql client to inject query cancellation. Discussion: https://www.postgresql.org/message-id/flat/E1mH14Q-0002gh-HS%40gemulon.postgresql.org --- src/bin/psql/t/020_cancel.pl | 66 ++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/src/bin/psql/t/020_cancel.pl b/src/bin/psql/t/020_cancel.pl index 7713fff8e4..ed654869d4 100644 --- a/src/bin/psql/t/020_cancel.pl +++ b/src/bin/psql/t/020_cancel.pl @@ -6,42 +6,48 @@ use warnings; use PostgresNode; use TestLib; -use Test::More tests => 2; +use IPC::Run qw(pump finish timer); +use Test::More tests => 4; -my $tempdir = TestLib::tempdir; +plan skip_all => "Testsuite requires a Unix shell" if ($windows_os); my $node = PostgresNode->new('main'); $node->init; $node->start; # Test query canceling by sending SIGINT to a running psql -# +my $in; +my $out; +my $timer = timer(5); +my $h = $node->interactive_psql('postgres', \$in, \$out, $timer); + # There is, as of this writing, no documented way to get the PID of # the process from IPC::Run. As a workaround, we have psql print its -# own PID (which is the parent of the shell launched by psql) to a -# file. -SKIP: { - skip "cancel test requires a Unix shell", 2 if $windows_os; - - local %ENV = $node->_get_env(); - - my ($stdin, $stdout, $stderr); - - # Test whether shell supports $PPID. It's part of POSIX, but some - # pre-/non-POSIX shells don't support it (e.g., NetBSD, Solaris). - $stdin = "\\! echo \$PPID"; - IPC::Run::run(['psql', '-X', '-v', 'ON_ERROR_STOP=1'], '<', \$stdin, '>', \$stdout, '2>', \$stderr); - $stdout =~ /^\d+$/ or skip "shell apparently does not support \$PPID", 2; - - local $SIG{ALRM} = sub { - my $psql_pid = TestLib::slurp_file("$tempdir/psql.pid"); - kill 'INT', $psql_pid; - }; - alarm 1; - - $stdin = "\\! echo \$PPID >$tempdir/psql.pid\nselect pg_sleep(3);"; - my $result = IPC::Run::run(['psql', '-X', '-v', 'ON_ERROR_STOP=1'], '<', \$stdin, '>', \$stdout, '2>', \$stderr); - - ok(!$result, 'query failed as expected'); - like($stderr, qr/canceling statement due to user request/, 'query was canceled'); -} +# own PID (which is the parent of the shell launched by psql) +$out = ''; +$timer->start(5); +$in = "\\! echo \"\$PPID\"\"x\"\n"; +pump $h until ($out =~ /[^\D]+x/ || $timer->is_expired); +ok(!$timer->is_expired, "PPID timer expired"); + +# Grab PID from the output and clear the output buffer. If no PID was found +# then skip the rest of the tests as the platform doesn't support PPID. +(my $psql_pid = $out) =~ s/[^\d]//g; +$out = ''; +scalar($psql_pid > 0) or skip "shell apparently does not support \$PPID", 3; + +# Put the interactive client to sleep. Pumping on the output is tricky so for +# now allow the timer to expire and assume we are at sleep by then. +$timer->start(2); +$in .= "SELECT pg_sleep(15);\n"; +pump $h until $timer->is_expired; + +# Signal the client and await the expected output +$timer->start(10); +my $killed = kill 'INT', $psql_pid; +ok($killed eq '1', "psql was signaled"); +pump $h until ($out =~ /request/ || $timer->is_expired); +like($out, qr/canceling statement due to user request/, 'query was canceled'); +ok(!$timer->is_expired, "Sleep query timer expired"); + +$node->stop; -- 2.24.3 (Apple Git-128)