Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
psql: Make cancel test more timing robust
authorPeter Eisentraut <peter@eisentraut.org>
Wed, 25 Aug 2021 09:54:58 +0000 (11:54 +0200)
committerPeter Eisentraut <peter@eisentraut.org>
Wed, 25 Aug 2021 10:02:08 +0000 (12:02 +0200)
The previous coding relied on the PID file appearing and the query
starting "fast enough", which can fail on slow machines.  Also, there
might have been an undocumented interference between alarm and
IPC::Run.  This new coding doesn't rely on any of these concurrency
mechanisms.  Instead, we wait unitl the PID file is complete before
proceeding, and then also wait until the sleep query is registered by
the server.

Discussion: https://www.postgresql.org/message-id/flat/E1mH14Q-0002gh-HS%40gemulon.postgresql.org

src/bin/psql/t/020_cancel.pl

index 7713fff8e4453628245f6285e150f32f03873162..b3edaaf35d01656571180378a0c5fc45e1194a8f 100644 (file)
@@ -7,6 +7,7 @@ use warnings;
 use PostgresNode;
 use TestLib;
 use Test::More tests => 2;
+use Time::HiRes qw(usleep);
 
 my $tempdir = TestLib::tempdir;
 
@@ -28,19 +29,37 @@ SKIP: {
    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).
+   # pre-/non-POSIX shells don't support it (e.g., NetBSD).
    $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;
+   # Now start the real test
+   my $h = IPC::Run::start(['psql', '-X', '-v', 'ON_ERROR_STOP=1'], \$stdin, \$stdout, \$stderr);
 
-   $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);
+   # Get the PID
+   $stdout = '';
+   $stderr = '';
+   $stdin = "\\! echo \$PPID >$tempdir/psql.pid\n";
+   pump $h while length $stdin;
+   my $count;
+   my $psql_pid;
+   until (-s "$tempdir/psql.pid" and ($psql_pid = TestLib::slurp_file("$tempdir/psql.pid")) =~ /^\d+\n/s)
+   {
+       ($count++ < 180 * 100) or die "pid file did not appear";
+       usleep(10_000)
+   }
+
+   # Send sleep command and wait until the server has registered it
+   $stdin = "select pg_sleep(180);\n";
+   pump $h while length $stdin;
+   $node->poll_query_until('postgres', q{SELECT (SELECT count(*) FROM pg_stat_activity WHERE query ~ 'pg_sleep') > 0;})
+     or die "timed out";
+
+   # Send cancel request
+   kill 'INT', $psql_pid;
+
+   my $result = finish $h;
 
    ok(!$result, 'query failed as expected');
    like($stderr, qr/canceling statement due to user request/, 'query was canceled');