1
0
mirror of https://github.com/postgres/postgres.git synced 2025-04-25 21:42:33 +03:00
postgres/src/test/modules/test_misc/t/005_timeouts.pl
Michael Paquier 2cdcae9da6 Avoid installcheck failure in TAP tests using injection_points
These tests depend on the test module injection_points to be installed,
but it may not be available as the contents of src/test/modules/ are not
installed by default.

This commit adds a workaround based on a scan of pg_available_extensions
to check if the extension is available, skipping the test if it is not.
This allows installcheck to work transparently.

There are more tests impacted by this problem on HEAD, but for now this
addresses only the tests that exist on HEAD and v17 as the release is
close by.

Reported-by: Maxim Orlov
Discussion: https://postgr.es/m/CACG=ezZkoT-pFz6a9XnyToiuR-Wg8fGELqHLoyBodr+2h-77qA@mail.gmail.com
Backpatch-through: 17
2024-09-04 08:56:23 +09:00

146 lines
4.0 KiB
Perl

# Copyright (c) 2024, PostgreSQL Global Development Group
use strict;
use warnings FATAL => 'all';
use locale;
use PostgreSQL::Test::Cluster;
use PostgreSQL::Test::Utils;
use Time::HiRes qw(usleep);
use Test::More;
# Test timeouts that will cause FATAL errors. This test relies on injection
# points to await a timeout occurrence. Relying on sleep proved to be unstable
# on buildfarm. It's difficult to rely on the NOTICE injection point because
# the backend under FATAL error can behave differently.
if ($ENV{enable_injection_points} ne 'yes')
{
plan skip_all => 'Injection points not supported by this build';
}
# Node initialization
my $node = PostgreSQL::Test::Cluster->new('master');
$node->init();
$node->start;
# Check if the extension injection_points is available, as it may be
# possible that this script is run with installcheck, where the module
# would not be installed by default.
my $result = $node->safe_psql('postgres',
"SELECT count(*) > 0 FROM pg_available_extensions WHERE name = 'injection_points';"
);
if ($result eq 'f')
{
plan skip_all => 'Extension injection_points not installed';
}
$node->safe_psql('postgres', 'CREATE EXTENSION injection_points;');
#
# 1. Test of the transaction timeout
#
$node->safe_psql('postgres',
"SELECT injection_points_attach('transaction-timeout', 'wait');");
my $psql_session = $node->background_psql('postgres');
# The following query will generate a stream of SELECT 1 queries. This is done
# so to exercise transaction timeout in the presence of short queries.
# Note: the interval value is parsed with locale-aware strtod()
$psql_session->query_until(
qr/starting_bg_psql/,
sprintf(
q(\echo starting_bg_psql
SET transaction_timeout to '10ms';
BEGIN;
SELECT 1 \watch %g
\q
), 0.001));
# Wait until the backend enters the timeout injection point. Will get an error
# here if anything goes wrong.
$node->wait_for_event('client backend', 'transaction-timeout');
my $log_offset = -s $node->logfile;
# Remove the injection point.
$node->safe_psql('postgres',
"SELECT injection_points_wakeup('transaction-timeout');");
# Check that the timeout was logged.
$node->wait_for_log('terminating connection due to transaction timeout',
$log_offset);
# If we send \q with $psql_session->quit the command can be sent to the session
# already closed. So \q is in initial script, here we only finish IPC::Run.
$psql_session->{run}->finish;
#
# 2. Test of the idle in transaction timeout
#
$node->safe_psql('postgres',
"SELECT injection_points_attach('idle-in-transaction-session-timeout', 'wait');"
);
# We begin a transaction and the hand on the line
$psql_session = $node->background_psql('postgres');
$psql_session->query_until(
qr/starting_bg_psql/, q(
\echo starting_bg_psql
SET idle_in_transaction_session_timeout to '10ms';
BEGIN;
));
# Wait until the backend enters the timeout injection point.
$node->wait_for_event('client backend',
'idle-in-transaction-session-timeout');
$log_offset = -s $node->logfile;
# Remove the injection point.
$node->safe_psql('postgres',
"SELECT injection_points_wakeup('idle-in-transaction-session-timeout');");
# Check that the timeout was logged.
$node->wait_for_log(
'terminating connection due to idle-in-transaction timeout', $log_offset);
ok($psql_session->quit);
#
# 3. Test of the idle session timeout
#
$node->safe_psql('postgres',
"SELECT injection_points_attach('idle-session-timeout', 'wait');");
# We just initialize the GUC and wait. No transaction is required.
$psql_session = $node->background_psql('postgres');
$psql_session->query_until(
qr/starting_bg_psql/, q(
\echo starting_bg_psql
SET idle_session_timeout to '10ms';
));
# Wait until the backend enters the timeout injection point.
$node->wait_for_event('client backend', 'idle-session-timeout');
$log_offset = -s $node->logfile;
# Remove the injection point.
$node->safe_psql('postgres',
"SELECT injection_points_wakeup('idle-session-timeout');");
# Check that the timeout was logged.
$node->wait_for_log('terminating connection due to idle-session timeout',
$log_offset);
ok($psql_session->quit);
done_testing();