From 1d1d27e9b696a01d3468acf51d13aca92b629e59 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Tue, 12 Dec 2023 11:40:50 +0100 Subject: [PATCH v6 2/4] Add test module test_injection_points This is a test facility aimed at providing basic coverage for the code routines of injection points. This will be extended with more tests. --- src/test/modules/Makefile | 7 ++ src/test/modules/meson.build | 1 + .../modules/test_injection_points/.gitignore | 4 + .../modules/test_injection_points/Makefile | 22 ++++ .../expected/test_injection_points.out | 117 ++++++++++++++++++ .../modules/test_injection_points/meson.build | 37 ++++++ .../sql/test_injection_points.sql | 33 +++++ .../test_injection_points--1.0.sql | 36 ++++++ .../test_injection_points.c | 91 ++++++++++++++ .../test_injection_points.control | 4 + 10 files changed, 352 insertions(+) create mode 100644 src/test/modules/test_injection_points/.gitignore create mode 100644 src/test/modules/test_injection_points/Makefile create mode 100644 src/test/modules/test_injection_points/expected/test_injection_points.out create mode 100644 src/test/modules/test_injection_points/meson.build create mode 100644 src/test/modules/test_injection_points/sql/test_injection_points.sql create mode 100644 src/test/modules/test_injection_points/test_injection_points--1.0.sql create mode 100644 src/test/modules/test_injection_points/test_injection_points.c create mode 100644 src/test/modules/test_injection_points/test_injection_points.control diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile index 5d33fa6a9a..9a55a6924e 100644 --- a/src/test/modules/Makefile +++ b/src/test/modules/Makefile @@ -37,6 +37,13 @@ SUBDIRS = \ worker_spi \ xid_wraparound + +ifeq ($(enable_injection_points),yes) +SUBDIRS += test_injection_points +else +ALWAYS_SUBDIRS += test_injection_points +endif + ifeq ($(with_ssl),openssl) SUBDIRS += ssl_passphrase_callback else diff --git a/src/test/modules/meson.build b/src/test/modules/meson.build index b76f588559..dc0048a6e4 100644 --- a/src/test/modules/meson.build +++ b/src/test/modules/meson.build @@ -17,6 +17,7 @@ subdir('test_ddl_deparse') subdir('test_dsa') subdir('test_extensions') subdir('test_ginpostinglist') +subdir('test_injection_points') subdir('test_integerset') subdir('test_lfind') subdir('test_misc') diff --git a/src/test/modules/test_injection_points/.gitignore b/src/test/modules/test_injection_points/.gitignore new file mode 100644 index 0000000000..5dcb3ff972 --- /dev/null +++ b/src/test/modules/test_injection_points/.gitignore @@ -0,0 +1,4 @@ +# Generated subdirectories +/log/ +/results/ +/tmp_check/ diff --git a/src/test/modules/test_injection_points/Makefile b/src/test/modules/test_injection_points/Makefile new file mode 100644 index 0000000000..65bcdde782 --- /dev/null +++ b/src/test/modules/test_injection_points/Makefile @@ -0,0 +1,22 @@ +# src/test/modules/test_injection_points/Makefile + +MODULE_big = test_injection_points +OBJS = \ + $(WIN32RES) \ + test_injection_points.o +PGFILEDESC = "test_injection_points - test injection points" + +EXTENSION = test_injection_points +DATA = test_injection_points--1.0.sql +REGRESS = test_injection_points + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = src/test/modules/test_injection_points +top_builddir = ../../../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/src/test/modules/test_injection_points/expected/test_injection_points.out b/src/test/modules/test_injection_points/expected/test_injection_points.out new file mode 100644 index 0000000000..a8ddae0aad --- /dev/null +++ b/src/test/modules/test_injection_points/expected/test_injection_points.out @@ -0,0 +1,117 @@ +CREATE EXTENSION test_injection_points; +SELECT test_injection_points_attach('TestInjectionBooh', 'booh'); +ERROR: incorrect mode "booh" for injection point creation +SELECT test_injection_points_attach('TestInjectionError', 'error'); + test_injection_points_attach +------------------------------ + +(1 row) + +SELECT test_injection_points_attach('TestInjectionLog', 'notice'); + test_injection_points_attach +------------------------------ + +(1 row) + +SELECT test_injection_points_attach('TestInjectionLog2', 'notice'); + test_injection_points_attach +------------------------------ + +(1 row) + +SELECT test_injection_points_run('TestInjectionBooh'); -- nothing + test_injection_points_run +--------------------------- + +(1 row) + +SELECT test_injection_points_run('TestInjectionLog2'); -- notice +NOTICE: notice triggered for injection point TestInjectionLog2 + test_injection_points_run +--------------------------- + +(1 row) + +SELECT test_injection_points_run('TestInjectionLog'); -- notice +NOTICE: notice triggered for injection point TestInjectionLog + test_injection_points_run +--------------------------- + +(1 row) + +SELECT test_injection_points_run('TestInjectionError'); -- error +ERROR: error triggered for injection point TestInjectionError +-- Re-load and run again. +\c +SELECT test_injection_points_run('TestInjectionLog2'); -- notice +NOTICE: notice triggered for injection point TestInjectionLog2 + test_injection_points_run +--------------------------- + +(1 row) + +SELECT test_injection_points_run('TestInjectionLog'); -- notice +NOTICE: notice triggered for injection point TestInjectionLog + test_injection_points_run +--------------------------- + +(1 row) + +SELECT test_injection_points_run('TestInjectionError'); -- error +ERROR: error triggered for injection point TestInjectionError +-- Remove one entry and check the other one. +SELECT test_injection_points_detach('TestInjectionError'); -- ok + test_injection_points_detach +------------------------------ + +(1 row) + +SELECT test_injection_points_run('TestInjectionLog'); -- notice +NOTICE: notice triggered for injection point TestInjectionLog + test_injection_points_run +--------------------------- + +(1 row) + +SELECT test_injection_points_run('TestInjectionError'); -- nothing + test_injection_points_run +--------------------------- + +(1 row) + +-- All entries removed, nothing happens +SELECT test_injection_points_detach('TestInjectionLog'); -- ok + test_injection_points_detach +------------------------------ + +(1 row) + +SELECT test_injection_points_run('TestInjectionLog'); -- nothing + test_injection_points_run +--------------------------- + +(1 row) + +SELECT test_injection_points_run('TestInjectionError'); -- nothing + test_injection_points_run +--------------------------- + +(1 row) + +SELECT test_injection_points_run('TestInjectionLog2'); -- notice +NOTICE: notice triggered for injection point TestInjectionLog2 + test_injection_points_run +--------------------------- + +(1 row) + +SELECT test_injection_points_detach('TestInjectionLog'); -- fails +ERROR: injection point "TestInjectionLog" not found +SELECT test_injection_points_run('TestInjectionLog2'); -- notice +NOTICE: notice triggered for injection point TestInjectionLog2 + test_injection_points_run +--------------------------- + +(1 row) + +DROP EXTENSION test_injection_points; diff --git a/src/test/modules/test_injection_points/meson.build b/src/test/modules/test_injection_points/meson.build new file mode 100644 index 0000000000..7509a102ef --- /dev/null +++ b/src/test/modules/test_injection_points/meson.build @@ -0,0 +1,37 @@ +# Copyright (c) 2022-2023, PostgreSQL Global Development Group + +if not get_option('injection_points') + subdir_done() +endif + +test_injection_points_sources = files( + 'test_injection_points.c', +) + +if host_system == 'windows' + test_injection_points_sources += rc_lib_gen.process(win32ver_rc, extra_args: [ + '--NAME', 'test_injection_points', + '--FILEDESC', 'test_injection_points - test injection points',]) +endif + +test_injection_points = shared_module('test_injection_points', + test_injection_points_sources, + kwargs: pg_test_mod_args, +) +test_install_libs += test_injection_points + +test_install_data += files( + 'test_injection_points.control', + 'test_injection_points--1.0.sql', +) + +tests += { + 'name': 'test_injection_points', + 'sd': meson.current_source_dir(), + 'bd': meson.current_build_dir(), + 'regress': { + 'sql': [ + 'test_injection_points', + ], + }, +} diff --git a/src/test/modules/test_injection_points/sql/test_injection_points.sql b/src/test/modules/test_injection_points/sql/test_injection_points.sql new file mode 100644 index 0000000000..8f23f4c044 --- /dev/null +++ b/src/test/modules/test_injection_points/sql/test_injection_points.sql @@ -0,0 +1,33 @@ +CREATE EXTENSION test_injection_points; + +SELECT test_injection_points_attach('TestInjectionBooh', 'booh'); +SELECT test_injection_points_attach('TestInjectionError', 'error'); +SELECT test_injection_points_attach('TestInjectionLog', 'notice'); +SELECT test_injection_points_attach('TestInjectionLog2', 'notice'); + +SELECT test_injection_points_run('TestInjectionBooh'); -- nothing +SELECT test_injection_points_run('TestInjectionLog2'); -- notice +SELECT test_injection_points_run('TestInjectionLog'); -- notice +SELECT test_injection_points_run('TestInjectionError'); -- error + +-- Re-load and run again. +\c +SELECT test_injection_points_run('TestInjectionLog2'); -- notice +SELECT test_injection_points_run('TestInjectionLog'); -- notice +SELECT test_injection_points_run('TestInjectionError'); -- error + +-- Remove one entry and check the other one. +SELECT test_injection_points_detach('TestInjectionError'); -- ok +SELECT test_injection_points_run('TestInjectionLog'); -- notice +SELECT test_injection_points_run('TestInjectionError'); -- nothing +-- All entries removed, nothing happens +SELECT test_injection_points_detach('TestInjectionLog'); -- ok +SELECT test_injection_points_run('TestInjectionLog'); -- nothing +SELECT test_injection_points_run('TestInjectionError'); -- nothing +SELECT test_injection_points_run('TestInjectionLog2'); -- notice + +SELECT test_injection_points_detach('TestInjectionLog'); -- fails + +SELECT test_injection_points_run('TestInjectionLog2'); -- notice + +DROP EXTENSION test_injection_points; diff --git a/src/test/modules/test_injection_points/test_injection_points--1.0.sql b/src/test/modules/test_injection_points/test_injection_points--1.0.sql new file mode 100644 index 0000000000..1c0a689ae2 --- /dev/null +++ b/src/test/modules/test_injection_points/test_injection_points--1.0.sql @@ -0,0 +1,36 @@ +/* src/test/modules/test_injection_points/test_injection_points--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION test_injection_points" to load this file. \quit + +-- +-- test_injection_points_attach() +-- +-- Attaches an injection point using callbacks from one of the predefined +-- modes. +-- +CREATE FUNCTION test_injection_points_attach(IN point_name TEXT, + IN mode text) +RETURNS void +AS 'MODULE_PATHNAME', 'test_injection_points_attach' +LANGUAGE C STRICT PARALLEL UNSAFE; + +-- +-- test_injection_points_run() +-- +-- Executes an injection point. +-- +CREATE FUNCTION test_injection_points_run(IN point_name TEXT) +RETURNS void +AS 'MODULE_PATHNAME', 'test_injection_points_run' +LANGUAGE C STRICT PARALLEL UNSAFE; + +-- +-- test_injection_points_detach() +-- +-- Detaches an injection point. +-- +CREATE FUNCTION test_injection_points_detach(IN point_name TEXT) +RETURNS void +AS 'MODULE_PATHNAME', 'test_injection_points_detach' +LANGUAGE C STRICT PARALLEL UNSAFE; diff --git a/src/test/modules/test_injection_points/test_injection_points.c b/src/test/modules/test_injection_points/test_injection_points.c new file mode 100644 index 0000000000..efb2c74c47 --- /dev/null +++ b/src/test/modules/test_injection_points/test_injection_points.c @@ -0,0 +1,91 @@ +/*-------------------------------------------------------------------------- + * + * test_injection_points.c + * Code for testing injection points. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/test/modules/test_injection_points/test_injection_points.c + * + * Injection points are able to trigger user-defined callbacks in pre-defined + * code paths. + * + * ------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "fmgr.h" +#include "utils/builtins.h" +#include "utils/injection_point.h" + +PG_MODULE_MAGIC; + +extern PGDLLEXPORT void test_injection_error(const char *name); +extern PGDLLEXPORT void test_injection_notice(const char *name); + +/* Set of callbacks available at point creation */ +void +test_injection_error(const char *name) +{ + elog(ERROR, "error triggered for injection point %s", name); +} + +void +test_injection_notice(const char *name) +{ + elog(NOTICE, "notice triggered for injection point %s", name); +} + +/* + * SQL function for creating an injection point. + */ +PG_FUNCTION_INFO_V1(test_injection_points_attach); +Datum +test_injection_points_attach(PG_FUNCTION_ARGS) +{ + char *name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + char *mode = text_to_cstring(PG_GETARG_TEXT_PP(1)); + char *function; + + if (strcmp(mode, "error") == 0) + function = "test_injection_error"; + else if (strcmp(mode, "notice") == 0) + function = "test_injection_notice"; + else + elog(ERROR, "incorrect mode \"%s\" for injection point creation", mode); + + InjectionPointAttach(name, "test_injection_points", function); + + PG_RETURN_VOID(); +} + +/* + * SQL function for triggering an injection point. + */ +PG_FUNCTION_INFO_V1(test_injection_points_run); +Datum +test_injection_points_run(PG_FUNCTION_ARGS) +{ + char *name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + + INJECTION_POINT(name); + + PG_RETURN_VOID(); +} + +/* + * SQL function for dropping an injection point. + */ +PG_FUNCTION_INFO_V1(test_injection_points_detach); +Datum +test_injection_points_detach(PG_FUNCTION_ARGS) +{ + char *name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + + InjectionPointDetach(name); + + PG_RETURN_VOID(); +} diff --git a/src/test/modules/test_injection_points/test_injection_points.control b/src/test/modules/test_injection_points/test_injection_points.control new file mode 100644 index 0000000000..a13657cfc6 --- /dev/null +++ b/src/test/modules/test_injection_points/test_injection_points.control @@ -0,0 +1,4 @@ +comment = 'Test code for injection points' +default_version = '1.0' +module_pathname = '$libdir/test_injection_points' +relocatable = true -- 2.43.0