From bdf22ec48f7edb32fb5b24addc32ab433fd1f35e Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Sat, 16 Mar 2024 04:10:32 +0000
Subject: [PATCH v3] Add TAP tests for backtrace functionality

---
 src/test/modules/test_misc/meson.build        |  3 +-
 src/test/modules/test_misc/t/006_backtrace.pl | 98 +++++++++++++++++++
 2 files changed, 100 insertions(+), 1 deletion(-)
 create mode 100644 src/test/modules/test_misc/t/006_backtrace.pl

diff --git a/src/test/modules/test_misc/meson.build b/src/test/modules/test_misc/meson.build
index df2913e893..0e0406de95 100644
--- a/src/test/modules/test_misc/meson.build
+++ b/src/test/modules/test_misc/meson.build
@@ -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_backtrace.pl'
     ],
   },
 }
diff --git a/src/test/modules/test_misc/t/006_backtrace.pl b/src/test/modules/test_misc/t/006_backtrace.pl
new file mode 100644
index 0000000000..414af436ae
--- /dev/null
+++ b/src/test/modules/test_misc/t/006_backtrace.pl
@@ -0,0 +1,98 @@
+# Copyright (c) 2024, PostgreSQL Global Development Group
+
+# Test PostgreSQL backtrace related code.
+use strict;
+use warnings FATAL => 'all';
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+my $node = PostgreSQL::Test::Cluster->new('node');
+$node->init;
+
+# Turn off query statement logging so that we get to see the functions in only
+# backtraces.
+$node->append_conf(
+	'postgresql.conf', qq{
+backtrace_functions = 'pg_terminate_backend, pg_create_restore_point'
+wal_level = replica
+log_statement = none
+log_min_error_statement = fatal
+});
+$node->start;
+
+# Check if backtrace generation is supported on this installation.
+my ($result, $stdout, $stderr);
+my $log_offset = -s $node->logfile;
+
+# Generate an error with negative timeout.
+($result, $stdout, $stderr) = $node->psql(
+	'postgres', q(
+	SELECT pg_terminate_backend(123, -1);
+));
+
+if ($stderr =~ m/"timeout" must not be negative/
+	&& $node->log_contains(
+		qr/backtrace generation is not supported by this installation/,
+		$log_offset))
+{
+	plan skip_all =>
+	  'backtrace generation is not supported by this installation';
+}
+
+# Start verifying for the results only after skip_all check.
+ok( $stderr =~ m/"timeout" must not be negative/,
+	'error from terminating backend is logged');
+
+my $backtrace_text = qr/BACKTRACE:  /;
+
+ok( $node->log_contains($backtrace_text, $log_offset),
+	"backtrace pg_terminate_backend start is found");
+
+ok($node->log_contains("pg_terminate_backend", $log_offset),
+	"backtrace pg_terminate_backend is found");
+
+$log_offset = -s $node->logfile;
+
+# Generate an error with a long restore point name.
+($result, $stdout, $stderr) = $node->psql(
+	'postgres', q(
+	SELECT pg_create_restore_point(repeat('A', 1024));
+));
+ok( $stderr =~ m/value too long for restore point \(maximum .* characters\)/,
+	'error from restore point function is logged');
+
+ok( $node->log_contains($backtrace_text, $log_offset),
+	"backtrace pg_create_restore_point start is found");
+
+ok($node->log_contains("pg_create_restore_point", $log_offset),
+	"backtrace pg_create_restore_point is found");
+
+# Test if backtrace gets generated on internal errors when
+# backtrace_on_internal_error is set. Note that we use a function (i.e.
+# pg_replication_slot_advance) that generates an error with ereport without
+# setting errcode explicitly, in which case elog.c assumes it as an internal
+# error (see edata->sqlerrcode = ERRCODE_INTERNAL_ERROR; in errstart() in
+# elog.c).
+$node->append_conf('postgresql.conf', "backtrace_on_internal_error = on");
+$node->reload;
+
+$node->safe_psql('postgres',
+	"SELECT pg_create_physical_replication_slot('myslot', true);");
+
+$log_offset = -s $node->logfile;
+
+($result, $stdout, $stderr) = $node->psql(
+	'postgres', q(
+	SELECT pg_replication_slot_advance('myslot', '0/0'::pg_lsn);
+));
+ok($stderr =~ m/invalid target WAL LSN/,
+	'error from replication slot advance is logged');
+
+ok( $node->log_contains($backtrace_text, $log_offset),
+	"backtrace pg_replication_slot_advance start is found");
+
+ok($node->log_contains("pg_replication_slot_advance", $log_offset),
+	"backtrace pg_replication_slot_advance is found");
+
+done_testing();
-- 
2.34.1

