On Tue, Feb 13, 2024 at 2:11 AM Bharath Rupireddy
<bharath.rupireddyforpostg...@gmail.com> wrote:
>
> Hi,
>
> Postgres has a good amount of code for dealing with backtraces - two
> GUCs backtrace_functions and backtrace_on_internal_error,
> errbacktrace; all of which use core function set_backtrace from
> elog.c. I've not seen this code being tested at all, see code coverage
> report - 
> https://coverage.postgresql.org/src/backend/utils/error/elog.c.gcov.html.
>
> I think adding a simple test module (containing no .c files) with only
> TAP tests will help cover this code. I ended up having it as a
> separate module under src/test/modules/test_backtrace as I was not
> able to find an existing TAP file in src/test to add these tests.  I'm
> able to verify the backtrace related code with the attached patch
> consistently. The TAP tests rely on the fact that the server emits
> text "BACKTRACE: " to server logs before logging the backtrace, and
> the backtrace contains the function name in which the error occurs.
> I've turned off query statement logging (set log_statement = none,
> log_min_error_statement = fatal) so that the tests get to see the
> functions only in the backtrace. Although the CF bot is happy with the
> attached patch 
> https://github.com/BRupireddy2/postgres/tree/add_test_module_for_bcktrace_functionality_v1,
> there might be some more flakiness to it.
>
> Thoughts?

Ran pgperltidy on the new TAP test file added. Please see the attached v2 patch.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com
From 2cfe9c87dea980efa2f319e9c2e873e83e561b9e Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Tue, 20 Feb 2024 05:48:41 +0000
Subject: [PATCH v2] Add test module for backtrace functionality

---
 src/test/modules/Makefile                     |  1 +
 src/test/modules/meson.build                  |  1 +
 src/test/modules/test_backtrace/.gitignore    |  4 +
 src/test/modules/test_backtrace/Makefile      | 14 +++
 src/test/modules/test_backtrace/README        |  4 +
 src/test/modules/test_backtrace/meson.build   | 12 +++
 .../modules/test_backtrace/t/001_backtrace.pl | 98 +++++++++++++++++++
 7 files changed, 134 insertions(+)
 create mode 100644 src/test/modules/test_backtrace/.gitignore
 create mode 100644 src/test/modules/test_backtrace/Makefile
 create mode 100644 src/test/modules/test_backtrace/README
 create mode 100644 src/test/modules/test_backtrace/meson.build
 create mode 100644 src/test/modules/test_backtrace/t/001_backtrace.pl

diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile
index 89aa41b5e3..3967311048 100644
--- a/src/test/modules/Makefile
+++ b/src/test/modules/Makefile
@@ -13,6 +13,7 @@ SUBDIRS = \
 		  libpq_pipeline \
 		  plsample \
 		  spgist_name_ops \
+		  test_backtrace \
 		  test_bloomfilter \
 		  test_copy_callbacks \
 		  test_custom_rmgrs \
diff --git a/src/test/modules/meson.build b/src/test/modules/meson.build
index 8fbe742d38..3b21b389af 100644
--- a/src/test/modules/meson.build
+++ b/src/test/modules/meson.build
@@ -12,6 +12,7 @@ subdir('libpq_pipeline')
 subdir('plsample')
 subdir('spgist_name_ops')
 subdir('ssl_passphrase_callback')
+subdir('test_backtrace')
 subdir('test_bloomfilter')
 subdir('test_copy_callbacks')
 subdir('test_custom_rmgrs')
diff --git a/src/test/modules/test_backtrace/.gitignore b/src/test/modules/test_backtrace/.gitignore
new file mode 100644
index 0000000000..5dcb3ff972
--- /dev/null
+++ b/src/test/modules/test_backtrace/.gitignore
@@ -0,0 +1,4 @@
+# Generated subdirectories
+/log/
+/results/
+/tmp_check/
diff --git a/src/test/modules/test_backtrace/Makefile b/src/test/modules/test_backtrace/Makefile
new file mode 100644
index 0000000000..b908864e89
--- /dev/null
+++ b/src/test/modules/test_backtrace/Makefile
@@ -0,0 +1,14 @@
+# src/test/modules/test_backtrace/Makefile
+
+TAP_TESTS = 1
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = src/test/modules/test_backtrace
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/src/test/modules/test_backtrace/README b/src/test/modules/test_backtrace/README
new file mode 100644
index 0000000000..ae1366bd58
--- /dev/null
+++ b/src/test/modules/test_backtrace/README
@@ -0,0 +1,4 @@
+This directory doesn't actually contain any extension module.
+
+Instead it is a home for backtrace tests that we want to run using TAP
+infrastructure.
diff --git a/src/test/modules/test_backtrace/meson.build b/src/test/modules/test_backtrace/meson.build
new file mode 100644
index 0000000000..4adffcc914
--- /dev/null
+++ b/src/test/modules/test_backtrace/meson.build
@@ -0,0 +1,12 @@
+# Copyright (c) 2024, PostgreSQL Global Development Group
+
+tests += {
+  'name': 'test_backtrace',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_backtrace.pl',
+    ],
+  },
+}
diff --git a/src/test/modules/test_backtrace/t/001_backtrace.pl b/src/test/modules/test_backtrace/t/001_backtrace.pl
new file mode 100644
index 0000000000..414af436ae
--- /dev/null
+++ b/src/test/modules/test_backtrace/t/001_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

Reply via email to