Add tap test for pg_signal_autovacuum role

This commit provides testig coverage for ccd38024bc3c, checking that a
role granted pg_signal_autovacuum_worker is able to stop a vacuum
worker.

An injection point with a wait is placed at the beginning of autovacuum
worker startup to make sure that a worker is still alive when sending
and processing the signal sent.

Author: Anthony Leung, Michael Paquier, Kirill Reshke
Reviewed-by: Andrey Borodin, Nathan Bossart
Discussion: https://postgr.es/m/CALdSSPiQPuuQpOkF7x0g2QkA5eE-3xXt7hiJFvShV1bHKDvf8w@mail.gmail.com
This commit is contained in:
Michael Paquier 2024-07-16 10:05:46 +09:00
parent 47ecbfdfcc
commit d2b74882ca
3 changed files with 104 additions and 1 deletions

View File

@ -100,6 +100,7 @@
#include "utils/fmgroids.h"
#include "utils/fmgrprotos.h"
#include "utils/guc_hooks.h"
#include "utils/injection_point.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/ps_status.h"
@ -1902,6 +1903,12 @@ do_autovacuum(void)
/* Start a transaction so our commands have one to play into. */
StartTransactionCommand();
/*
* This injection point is put in a transaction block to work with a wait
* that uses a condition variable.
*/
INJECTION_POINT("autovacuum-worker-start");
/*
* Compute the multixact age for which freezing is urgent. This is
* normally autovacuum_multixact_freeze_max_age, but may be less if we are

View File

@ -13,7 +13,8 @@ tests += {
't/002_tablespace.pl',
't/003_check_guc.pl',
't/004_io_direct.pl',
't/005_timeouts.pl'
't/005_timeouts.pl',
't/006_signal_autovacuum.pl',
],
},
}

View File

@ -0,0 +1,95 @@
# Copyright (c) 2024, 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;
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;
$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 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();