From b2315034628f0ae6572f9a4887a54f14974105c2 Mon Sep 17 00:00:00 2001
From: Rahila Syed <rahilasyed.90@gmail.com>
Date: Fri, 28 Nov 2025 14:46:38 +0530
Subject: [PATCH 2/2] Test module to test memory context reporting with
 injection points

---
 src/test/modules/Makefile                     |   1 +
 .../test_memcontext_reporting/Makefile        |  29 ++++
 .../t/001_memcontext_inj.pl                   | 150 ++++++++++++++++++
 .../test_memcontext_reporting.c               |  12 ++
 .../test_memcontext_reporting.control         |   4 +
 5 files changed, 196 insertions(+)
 create mode 100644 src/test/modules/test_memcontext_reporting/Makefile
 create mode 100644 src/test/modules/test_memcontext_reporting/t/001_memcontext_inj.pl
 create mode 100644 src/test/modules/test_memcontext_reporting/test_memcontext_reporting.c
 create mode 100644 src/test/modules/test_memcontext_reporting/test_memcontext_reporting.control

diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile
index 4c6d56d97d8..1156d731014 100644
--- a/src/test/modules/Makefile
+++ b/src/test/modules/Makefile
@@ -34,6 +34,7 @@ SUBDIRS = \
 		  test_json_parser \
 		  test_lfind \
 		  test_lwlock_tranches \
+		  test_memcontext_reporting \
 		  test_misc \
 		  test_oat_hooks \
 		  test_parser \
diff --git a/src/test/modules/test_memcontext_reporting/Makefile b/src/test/modules/test_memcontext_reporting/Makefile
new file mode 100644
index 00000000000..0a2dfc44f1c
--- /dev/null
+++ b/src/test/modules/test_memcontext_reporting/Makefile
@@ -0,0 +1,29 @@
+# src/test/modules/test_memcontext_reporting/Makefile
+
+EXTRA_INSTALL = src/test/modules/injection_points
+
+export enable_injection_points
+MODULE_big = test_memcontext_reporting
+OBJS = \
+   $(WIN32RES) \
+   test_memcontext_reporting.o
+PGFILEDESC = "test_memcontext_reporting - test code for memory context reporting"
+
+REGRESS = test_memcontext_reporting
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = src/test/modules/test_memcontext_reporting
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
+
+check:
+	$(prove_check)
+
+installcheck:
+	$(prove_installcheck)
diff --git a/src/test/modules/test_memcontext_reporting/t/001_memcontext_inj.pl b/src/test/modules/test_memcontext_reporting/t/001_memcontext_inj.pl
new file mode 100644
index 00000000000..b491d6ebc0a
--- /dev/null
+++ b/src/test/modules/test_memcontext_reporting/t/001_memcontext_inj.pl
@@ -0,0 +1,150 @@
+# Copyright (c) 2025, PostgreSQL Global Development Group
+
+# Test suite for testing memory context statistics reporting
+
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+if ($ENV{enable_injection_points} ne 'yes')
+{
+	plan skip_all => 'Injection points not supported by this build';
+}
+my $psql_err;
+my $psql_out;
+# Create and start a cluster with one node
+my $node = PostgreSQL::Test::Cluster->new('main');
+$node->init;
+$node->append_conf(
+	'postgresql.conf',
+	qq[
+max_connections = 100
+log_statement = none
+restart_after_crash = false
+]);
+$node->start;
+$node->safe_psql('postgres', 'CREATE EXTENSION injection_points;');
+
+# Attaching to a client process's injection point that throws an error
+$node->safe_psql('postgres',
+	"select injection_points_attach('memcontext-client-injection', 'error');"
+);
+
+my $pid = $node->safe_psql('postgres',
+	"SELECT pid from pg_stat_activity where backend_type='checkpointer'");
+
+#Client should have thrown error
+$node->psql(
+	'postgres',
+	qq(select pg_get_process_memory_contexts($pid, true);),
+	stderr => \$psql_err);
+like($psql_err,
+	qr/error triggered for injection point memcontext-client-injection/);
+
+#Query the same process after detaching the injection point, using some other client and it should succeed.
+$node->safe_psql('postgres',
+	"select injection_points_detach('memcontext-client-injection');");
+my $topcontext_name = $node->safe_psql('postgres',
+	"select name from pg_get_process_memory_contexts($pid, true) where path = '{1}';"
+);
+ok($topcontext_name = 'TopMemoryContext');
+
+# Attaching to a target process injection point that throws an error
+$node->safe_psql('postgres',
+	"select injection_points_attach('memcontext-server-injection', 'error');"
+);
+
+#Server should have thrown error
+$node->psql(
+	'postgres',
+	qq(select pg_get_process_memory_contexts($pid, true);),
+	stderr => \$psql_err);
+
+#Query the same process after detaching the injection point, using some other client and it should succeed.
+$node->safe_psql('postgres',
+	"select injection_points_detach('memcontext-server-injection');");
+$topcontext_name = $node->safe_psql('postgres',
+	"select name from pg_get_process_memory_contexts($pid, true) where path = '{1}';"
+);
+ok($topcontext_name = 'TopMemoryContext');
+
+# Test that two concurrent requests to the same process results in a warning for
+# one of those
+
+$node->safe_psql('postgres',
+	"SELECT injection_points_attach('memcontext-client-injection', 'wait');");
+$node->safe_psql('postgres',
+	"SELECT injection_points_attach('memcontext-server-wait', 'wait');");
+my $psql_session1 = $node->background_psql('postgres');
+$psql_session1->query_until(
+	qr//,
+	qq(
+    SELECT pg_get_process_memory_contexts($pid, true);
+));
+$node->wait_for_event('client backend', 'memcontext-client-injection');
+$node->psql(
+	'postgres',
+	qq(select pg_get_process_memory_contexts($pid, true);),
+	stderr => \$psql_err);
+ok($psql_err =~
+	  /WARNING:  server process $pid is processing previous request/);
+#Wake the client up.
+$node->safe_psql('postgres',
+	"SELECT injection_points_wakeup('memcontext-client-injection');");
+
+$node->safe_psql('postgres',
+	"select injection_points_detach('memcontext-client-injection');");
+$node->safe_psql('postgres',
+	"select injection_points_detach('memcontext-server-wait');");
+
+# Test the client process exiting with timeout does not break the server process
+
+$node->safe_psql('postgres',
+	"SELECT injection_points_attach('memcontext-server-wait', 'wait');");
+# Following client query times out, returning NULL as output
+$node->psql(
+	'postgres',
+	qq(select name from pg_get_process_memory_contexts($pid, true) where path = '{1}';),
+	stdout => \$psql_out);
+ok($psql_out = 'NULL');
+#Wakeup the server process up and detach the injection point.
+$node->safe_psql('postgres',
+	"SELECT injection_points_wakeup('memcontext-server-wait');");
+$node->safe_psql('postgres',
+	"select injection_points_detach('memcontext-server-wait');");
+#Query the same server process again and it should succeed.
+$topcontext_name = $node->safe_psql('postgres',
+	"select name from pg_get_process_memory_contexts($pid, true) where path = '{1}';"
+);
+ok($topcontext_name = 'TopMemoryContext');
+
+# Test if the monitoring works fine, when the client backend crashes.
+$node->safe_psql('postgres',
+	"select injection_points_attach('memcontext-client-injection', 'test_memcontext_reporting', 'crash', NULL);"
+);
+
+#Client will crash
+$node->psql(
+	'postgres',
+	qq(select name from pg_get_process_memory_contexts($pid, true) where path = '{1}';),
+	stderr => \$psql_err);
+like($psql_err,
+	qr/WARNING:  terminating connection because of crash of another server process|server closed the connection unexpectedly|connection to server was lost|could not send data to server/
+);
+
+# Wait till server restarts
+$node->restart;
+$node->poll_query_until('postgres', "SELECT 1;", '1');
+
+#Querying memory stats should succeed after server start
+$pid = $node->safe_psql('postgres',
+	"SELECT pid from pg_stat_activity where backend_type='checkpointer'");
+$topcontext_name = $node->safe_psql('postgres',
+	"select name from pg_get_process_memory_contexts($pid, true) where path = '{1}';"
+);
+ok($topcontext_name = 'TopMemoryContext');
+
+done_testing();
diff --git a/src/test/modules/test_memcontext_reporting/test_memcontext_reporting.c b/src/test/modules/test_memcontext_reporting/test_memcontext_reporting.c
new file mode 100644
index 00000000000..d641f3616dc
--- /dev/null
+++ b/src/test/modules/test_memcontext_reporting/test_memcontext_reporting.c
@@ -0,0 +1,12 @@
+#include "postgres.h"
+#include "funcapi.h"
+
+PG_MODULE_MAGIC;
+
+extern PGDLLEXPORT void crash(const char *name, const void *private_data, void *arg);
+
+void
+crash(const char *name, const void *private_data, void *arg)
+{
+	abort();
+}
diff --git a/src/test/modules/test_memcontext_reporting/test_memcontext_reporting.control b/src/test/modules/test_memcontext_reporting/test_memcontext_reporting.control
new file mode 100644
index 00000000000..48b501682d5
--- /dev/null
+++ b/src/test/modules/test_memcontext_reporting/test_memcontext_reporting.control
@@ -0,0 +1,4 @@
+comment = 'Test code for memcontext reporting'
+default_version = '1.0'
+module_pathname = '$libdir/test_memcontext_reporting'
+relocatable = true
-- 
2.34.1

