Skip to content

Commit 49cd2b9

Browse files
committed
Add test module injection_points
This provides basic coverage for injection points within a single process, while providing some callbacks that can be used for other tests. There are plans to extend this module later with more advanced capabilities for tests. Author: Michael Paquier, with comment fixes from Ashutosh Bapat. Reviewed-by: Ashutosh Bapat, Nathan Bossart, Álvaro Herrera, Dilip Kumar, Amul Sul, Nazir Bilal Yavuz Discussion: https://postgr.es/m/ZTiV8tn_MIb_H2rE@paquier.xyz
1 parent d86d20f commit 49cd2b9

10 files changed

+355
-0
lines changed

src/test/modules/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ SUBDIRS = \
3838
worker_spi \
3939
xid_wraparound
4040

41+
42+
ifeq ($(enable_injection_points),yes)
43+
SUBDIRS += injection_points
44+
else
45+
ALWAYS_SUBDIRS += injection_points
46+
endif
47+
4148
ifeq ($(with_ssl),openssl)
4249
SUBDIRS += ssl_passphrase_callback
4350
else
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Generated subdirectories
2+
/log/
3+
/results/
4+
/tmp_check/
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# src/test/modules/injection_points/Makefile
2+
3+
MODULES = injection_points
4+
5+
EXTENSION = injection_points
6+
DATA = injection_points--1.0.sql
7+
PGFILEDESC = "injection_points - facility for injection points"
8+
9+
REGRESS = injection_points
10+
11+
ifdef USE_PGXS
12+
PG_CONFIG = pg_config
13+
PGXS := $(shell $(PG_CONFIG) --pgxs)
14+
include $(PGXS)
15+
else
16+
subdir = src/test/modules/injection_points
17+
top_builddir = ../../../..
18+
include $(top_builddir)/src/Makefile.global
19+
include $(top_srcdir)/contrib/contrib-global.mk
20+
endif
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
CREATE EXTENSION injection_points;
2+
SELECT injection_points_attach('TestInjectionBooh', 'booh');
3+
ERROR: incorrect action "booh" for injection point creation
4+
SELECT injection_points_attach('TestInjectionError', 'error');
5+
injection_points_attach
6+
-------------------------
7+
8+
(1 row)
9+
10+
SELECT injection_points_attach('TestInjectionLog', 'notice');
11+
injection_points_attach
12+
-------------------------
13+
14+
(1 row)
15+
16+
SELECT injection_points_attach('TestInjectionLog2', 'notice');
17+
injection_points_attach
18+
-------------------------
19+
20+
(1 row)
21+
22+
SELECT injection_points_run('TestInjectionBooh'); -- nothing
23+
injection_points_run
24+
----------------------
25+
26+
(1 row)
27+
28+
SELECT injection_points_run('TestInjectionLog2'); -- notice
29+
NOTICE: notice triggered for injection point TestInjectionLog2
30+
injection_points_run
31+
----------------------
32+
33+
(1 row)
34+
35+
SELECT injection_points_run('TestInjectionLog'); -- notice
36+
NOTICE: notice triggered for injection point TestInjectionLog
37+
injection_points_run
38+
----------------------
39+
40+
(1 row)
41+
42+
SELECT injection_points_run('TestInjectionError'); -- error
43+
ERROR: error triggered for injection point TestInjectionError
44+
-- Re-load cache and run again.
45+
\c
46+
SELECT injection_points_run('TestInjectionLog2'); -- notice
47+
NOTICE: notice triggered for injection point TestInjectionLog2
48+
injection_points_run
49+
----------------------
50+
51+
(1 row)
52+
53+
SELECT injection_points_run('TestInjectionLog'); -- notice
54+
NOTICE: notice triggered for injection point TestInjectionLog
55+
injection_points_run
56+
----------------------
57+
58+
(1 row)
59+
60+
SELECT injection_points_run('TestInjectionError'); -- error
61+
ERROR: error triggered for injection point TestInjectionError
62+
-- Remove one entry and check the remaining entries.
63+
SELECT injection_points_detach('TestInjectionError'); -- ok
64+
injection_points_detach
65+
-------------------------
66+
67+
(1 row)
68+
69+
SELECT injection_points_run('TestInjectionLog'); -- notice
70+
NOTICE: notice triggered for injection point TestInjectionLog
71+
injection_points_run
72+
----------------------
73+
74+
(1 row)
75+
76+
SELECT injection_points_run('TestInjectionError'); -- nothing
77+
injection_points_run
78+
----------------------
79+
80+
(1 row)
81+
82+
-- More entries removed, letting TestInjectionLog2 to check the same
83+
-- callback used in more than one point.
84+
SELECT injection_points_detach('TestInjectionLog'); -- ok
85+
injection_points_detach
86+
-------------------------
87+
88+
(1 row)
89+
90+
SELECT injection_points_run('TestInjectionLog'); -- nothing
91+
injection_points_run
92+
----------------------
93+
94+
(1 row)
95+
96+
SELECT injection_points_run('TestInjectionError'); -- nothing
97+
injection_points_run
98+
----------------------
99+
100+
(1 row)
101+
102+
SELECT injection_points_run('TestInjectionLog2'); -- notice
103+
NOTICE: notice triggered for injection point TestInjectionLog2
104+
injection_points_run
105+
----------------------
106+
107+
(1 row)
108+
109+
SELECT injection_points_detach('TestInjectionLog'); -- fails
110+
ERROR: injection point "TestInjectionLog" not found
111+
SELECT injection_points_run('TestInjectionLog2'); -- notice
112+
NOTICE: notice triggered for injection point TestInjectionLog2
113+
injection_points_run
114+
----------------------
115+
116+
(1 row)
117+
118+
DROP EXTENSION injection_points;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/* src/test/modules/injection_points/injection_points--1.0.sql */
2+
3+
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
4+
\echo Use "CREATE EXTENSION injection_points" to load this file. \quit
5+
6+
--
7+
-- injection_points_attach()
8+
--
9+
-- Attaches the action to the given injection point.
10+
--
11+
CREATE FUNCTION injection_points_attach(IN point_name TEXT,
12+
IN action text)
13+
RETURNS void
14+
AS 'MODULE_PATHNAME', 'injection_points_attach'
15+
LANGUAGE C STRICT PARALLEL UNSAFE;
16+
17+
--
18+
-- injection_points_run()
19+
--
20+
-- Executes the action attached to the injection point.
21+
--
22+
CREATE FUNCTION injection_points_run(IN point_name TEXT)
23+
RETURNS void
24+
AS 'MODULE_PATHNAME', 'injection_points_run'
25+
LANGUAGE C STRICT PARALLEL UNSAFE;
26+
27+
--
28+
-- injection_points_detach()
29+
--
30+
-- Detaches the current action, if any, from the given injection point.
31+
--
32+
CREATE FUNCTION injection_points_detach(IN point_name TEXT)
33+
RETURNS void
34+
AS 'MODULE_PATHNAME', 'injection_points_detach'
35+
LANGUAGE C STRICT PARALLEL UNSAFE;
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*--------------------------------------------------------------------------
2+
*
3+
* injection_points.c
4+
* Code for testing injection points.
5+
*
6+
* Injection points are able to trigger user-defined callbacks in pre-defined
7+
* code paths.
8+
*
9+
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
10+
* Portions Copyright (c) 1994, Regents of the University of California
11+
*
12+
* IDENTIFICATION
13+
* src/test/modules/injection_points/injection_points.c
14+
*
15+
* -------------------------------------------------------------------------
16+
*/
17+
18+
#include "postgres.h"
19+
20+
#include "fmgr.h"
21+
#include "storage/lwlock.h"
22+
#include "storage/shmem.h"
23+
#include "utils/builtins.h"
24+
#include "utils/injection_point.h"
25+
#include "utils/wait_event.h"
26+
27+
PG_MODULE_MAGIC;
28+
29+
extern PGDLLEXPORT void injection_error(const char *name);
30+
extern PGDLLEXPORT void injection_notice(const char *name);
31+
32+
33+
/* Set of callbacks available to be attached to an injection point. */
34+
void
35+
injection_error(const char *name)
36+
{
37+
elog(ERROR, "error triggered for injection point %s", name);
38+
}
39+
40+
void
41+
injection_notice(const char *name)
42+
{
43+
elog(NOTICE, "notice triggered for injection point %s", name);
44+
}
45+
46+
/*
47+
* SQL function for creating an injection point.
48+
*/
49+
PG_FUNCTION_INFO_V1(injection_points_attach);
50+
Datum
51+
injection_points_attach(PG_FUNCTION_ARGS)
52+
{
53+
char *name = text_to_cstring(PG_GETARG_TEXT_PP(0));
54+
char *action = text_to_cstring(PG_GETARG_TEXT_PP(1));
55+
char *function;
56+
57+
if (strcmp(action, "error") == 0)
58+
function = "injection_error";
59+
else if (strcmp(action, "notice") == 0)
60+
function = "injection_notice";
61+
else
62+
elog(ERROR, "incorrect action \"%s\" for injection point creation", action);
63+
64+
InjectionPointAttach(name, "injection_points", function);
65+
66+
PG_RETURN_VOID();
67+
}
68+
69+
/*
70+
* SQL function for triggering an injection point.
71+
*/
72+
PG_FUNCTION_INFO_V1(injection_points_run);
73+
Datum
74+
injection_points_run(PG_FUNCTION_ARGS)
75+
{
76+
char *name = text_to_cstring(PG_GETARG_TEXT_PP(0));
77+
78+
INJECTION_POINT(name);
79+
80+
PG_RETURN_VOID();
81+
}
82+
83+
/*
84+
* SQL function for dropping an injection point.
85+
*/
86+
PG_FUNCTION_INFO_V1(injection_points_detach);
87+
Datum
88+
injection_points_detach(PG_FUNCTION_ARGS)
89+
{
90+
char *name = text_to_cstring(PG_GETARG_TEXT_PP(0));
91+
92+
InjectionPointDetach(name);
93+
94+
PG_RETURN_VOID();
95+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
comment = 'Test code for injection points'
2+
default_version = '1.0'
3+
module_pathname = '$libdir/injection_points'
4+
relocatable = true
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Copyright (c) 2022-2024, PostgreSQL Global Development Group
2+
3+
if not get_option('injection_points')
4+
subdir_done()
5+
endif
6+
7+
injection_points_sources = files(
8+
'injection_points.c',
9+
)
10+
11+
if host_system == 'windows'
12+
injection_points_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
13+
'--NAME', 'injection_points',
14+
'--FILEDESC', 'injection_points - facility for injection points',])
15+
endif
16+
17+
injection_points = shared_module('injection_points',
18+
injection_points_sources,
19+
kwargs: pg_test_mod_args,
20+
)
21+
test_install_libs += injection_points
22+
23+
test_install_data += files(
24+
'injection_points.control',
25+
'injection_points--1.0.sql',
26+
)
27+
28+
tests += {
29+
'name': 'injection_points',
30+
'sd': meson.current_source_dir(),
31+
'bd': meson.current_build_dir(),
32+
'regress': {
33+
'sql': [
34+
'injection_points',
35+
],
36+
},
37+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
CREATE EXTENSION injection_points;
2+
3+
SELECT injection_points_attach('TestInjectionBooh', 'booh');
4+
SELECT injection_points_attach('TestInjectionError', 'error');
5+
SELECT injection_points_attach('TestInjectionLog', 'notice');
6+
SELECT injection_points_attach('TestInjectionLog2', 'notice');
7+
8+
SELECT injection_points_run('TestInjectionBooh'); -- nothing
9+
SELECT injection_points_run('TestInjectionLog2'); -- notice
10+
SELECT injection_points_run('TestInjectionLog'); -- notice
11+
SELECT injection_points_run('TestInjectionError'); -- error
12+
13+
-- Re-load cache and run again.
14+
\c
15+
SELECT injection_points_run('TestInjectionLog2'); -- notice
16+
SELECT injection_points_run('TestInjectionLog'); -- notice
17+
SELECT injection_points_run('TestInjectionError'); -- error
18+
19+
-- Remove one entry and check the remaining entries.
20+
SELECT injection_points_detach('TestInjectionError'); -- ok
21+
SELECT injection_points_run('TestInjectionLog'); -- notice
22+
SELECT injection_points_run('TestInjectionError'); -- nothing
23+
-- More entries removed, letting TestInjectionLog2 to check the same
24+
-- callback used in more than one point.
25+
SELECT injection_points_detach('TestInjectionLog'); -- ok
26+
SELECT injection_points_run('TestInjectionLog'); -- nothing
27+
SELECT injection_points_run('TestInjectionError'); -- nothing
28+
SELECT injection_points_run('TestInjectionLog2'); -- notice
29+
30+
SELECT injection_points_detach('TestInjectionLog'); -- fails
31+
32+
SELECT injection_points_run('TestInjectionLog2'); -- notice
33+
34+
DROP EXTENSION injection_points;

src/test/modules/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ subdir('commit_ts')
55
subdir('delay_execution')
66
subdir('dummy_index_am')
77
subdir('dummy_seclabel')
8+
subdir('injection_points')
89
subdir('ldap_password_func')
910
subdir('libpq_pipeline')
1011
subdir('plsample')

0 commit comments

Comments
 (0)