From de3de0afd7da7b432e219aa38bde248fc5c5206a Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 2 Jul 2017 14:03:41 -0400 Subject: [PATCH] Improve TAP test function PostgresNode::poll_query_until(). Add an optional "expected" argument to override the default assumption that we're waiting for the query to return "t". This allows replacing a handwritten polling loop in recovery/t/007_sync_rep.pl with use of poll_query_until(); AFAICS that's the only remaining ad-hoc polling loop in our TAP tests. Change poll_query_until() to probe ten times per second not once per second. Like some similar changes I've been making recently, the one-second interval seems to be rooted in ancient traditions rather than the actual likely wait duration on modern machines. I'd consider reducing it further if there were a convenient way to spawn just one psql for the whole loop rather than one per probe attempt. Discussion: https://postgr.es/m/12486.1498938782@sss.pgh.pa.us --- src/test/perl/PostgresNode.pm | 29 ++++++++++++++++++----------- src/test/recovery/t/007_sync_rep.pl | 21 ++------------------- 2 files changed, 20 insertions(+), 30 deletions(-) diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm index f4fa600951..4346423a0d 100644 --- a/src/test/perl/PostgresNode.pm +++ b/src/test/perl/PostgresNode.pm @@ -1213,36 +1213,43 @@ sub psql =pod -=item $node->poll_query_until(dbname, query) +=item $node->poll_query_until($dbname, $query [, $expected ]) -Run a query once a second, until it returns 't' (i.e. SQL boolean true). -Continues polling if psql returns an error result. Times out after 180 seconds. +Run B<$query> repeatedly, until it returns the B<$expected> result +('t', or SQL boolean true, by default). +Continues polling if B returns an error result. +Times out after 180 seconds. +Returns 1 if successful, 0 if timed out. =cut sub poll_query_until { - my ($self, $dbname, $query) = @_; + my ($self, $dbname, $query, $expected) = @_; - my $max_attempts = 180; - my $attempts = 0; + $expected = 't' unless defined($expected); # default value + + my $cmd = + [ 'psql', '-XAt', '-c', $query, '-d', $self->connstr($dbname) ]; my ($stdout, $stderr); + my $max_attempts = 180 * 10; + my $attempts = 0; while ($attempts < $max_attempts) { - my $cmd = - [ 'psql', '-XAt', '-c', $query, '-d', $self->connstr($dbname) ]; my $result = IPC::Run::run $cmd, '>', \$stdout, '2>', \$stderr; chomp($stdout); $stdout =~ s/\r//g if $TestLib::windows_os; - if ($stdout eq "t") + + if ($stdout eq $expected) { return 1; } - # Wait a second before retrying. - sleep 1; + # Wait 0.1 second before retrying. + select undef, undef, undef, 0.1; + $attempts++; } diff --git a/src/test/recovery/t/007_sync_rep.pl b/src/test/recovery/t/007_sync_rep.pl index 8e3cc5e42e..0f999f0535 100644 --- a/src/test/recovery/t/007_sync_rep.pl +++ b/src/test/recovery/t/007_sync_rep.pl @@ -9,7 +9,7 @@ use Test::More tests => 11; my $check_sql = "SELECT application_name, sync_priority, sync_state FROM pg_stat_replication ORDER BY application_name;"; -# Check that sync_state of each standby is expected. +# Check that sync_state of each standby is expected (waiting till it is). # If $setting is given, synchronous_standby_names is set to it and # the configuration file is reloaded before the test. sub test_sync_state @@ -23,24 +23,7 @@ sub test_sync_state $self->reload; } - my $timeout_max = 30; - my $timeout = 0; - my $result; - - # A reload may take some time to take effect on busy machines, - # hence use a loop with a timeout to give some room for the test - # to pass. - while ($timeout < $timeout_max) - { - $result = $self->safe_psql('postgres', $check_sql); - - last if ($result eq $expected); - - $timeout++; - sleep 1; - } - - is($result, $expected, $msg); + ok( $self->poll_query_until('postgres', $check_sql, $expected), $msg); } # Initialize master node