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
|
# Copyright (c) 2024-2025, PostgreSQL Global Development Group
# Test signaling autovacuum worker with pg_signal_autovacuum_worker.
#
# Only roles with privileges of pg_signal_autovacuum_worker are allowed to
# signal autovacuum workers. This test uses an injection point located
# at the beginning of the autovacuum worker startup.
use strict;
use warnings FATAL => 'all';
use PostgreSQL::Test::Cluster;
use Test::More;
if ($ENV{enable_injection_points} ne 'yes')
{
plan skip_all => 'Injection points not supported by this build';
}
# Initialize postgres
my $psql_err = '';
my $psql_out = '';
my $node = PostgreSQL::Test::Cluster->new('node');
$node->init;
# This ensures a quick worker spawn.
$node->append_conf('postgresql.conf', 'autovacuum_naptime = 1');
$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;');
$node->safe_psql(
'postgres', qq(
CREATE ROLE regress_regular_role;
CREATE ROLE regress_worker_role;
GRANT pg_signal_autovacuum_worker TO regress_worker_role;
));
# From this point, autovacuum worker will wait at startup.
$node->safe_psql('postgres',
"SELECT injection_points_attach('autovacuum-worker-start', 'wait');");
# Accelerate worker creation in case we reach this point before the naptime
# ends.
$node->reload();
# Wait until an autovacuum worker starts.
$node->wait_for_event('autovacuum worker', 'autovacuum-worker-start');
# And grab one of them.
my $av_pid = $node->safe_psql(
'postgres', qq(
SELECT pid FROM pg_stat_activity WHERE backend_type = 'autovacuum worker' AND wait_event = 'autovacuum-worker-start' LIMIT 1;
));
# Regular role cannot terminate autovacuum worker.
my $terminate_with_no_pg_signal_av = $node->psql(
'postgres', qq(
SET ROLE regress_regular_role;
SELECT pg_terminate_backend('$av_pid');
),
stdout => \$psql_out,
stderr => \$psql_err);
like(
$psql_err,
qr/ERROR: permission denied to terminate process\nDETAIL: Only roles with privileges of the "pg_signal_autovacuum_worker" role may terminate autovacuum workers./,
"autovacuum worker not signaled with regular role");
my $offset = -s $node->logfile;
# Role with pg_signal_autovacuum_worker can terminate autovacuum worker.
my $terminate_with_pg_signal_av = $node->psql(
'postgres', qq(
SET ROLE regress_worker_role;
SELECT pg_terminate_backend('$av_pid');
),
stdout => \$psql_out,
stderr => \$psql_err);
# Wait for the autovacuum worker to exit before scanning the logs.
$node->poll_query_until('postgres',
"SELECT count(*) = 0 FROM pg_stat_activity "
. "WHERE pid = '$av_pid' AND backend_type = 'autovacuum worker';");
# Check that the primary server logs a FATAL indicating that autovacuum
# is terminated.
ok( $node->log_contains(
qr/FATAL: .*terminating autovacuum process due to administrator command/,
$offset),
"autovacuum worker signaled with pg_signal_autovacuum_worker granted");
# Release injection point.
$node->safe_psql('postgres',
"SELECT injection_points_detach('autovacuum-worker-start');");
done_testing();
|