1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
# Copyright (c) 2024-2025, 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.
if (!$node->check_extension('injection_points'))
{
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();
|