From 2de6e4b3548ba979fe413a5796132fd0e5761f49 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <amborodin@acm.org>
Date: Sat, 22 Aug 2026 20:38:51 +0300
Subject: [PATCH v1] Let isolationtester report connection loss as a step
 result

---
 src/test/isolation/isolationtester.c          | 45 ++++++++--
 .../expected/wait_cleanup_1.out               | 86 +++++++++++++++++++
 2 files changed, 124 insertions(+), 7 deletions(-)
 create mode 100644 src/test/modules/injection_points/expected/wait_cleanup_1.out

diff --git a/src/test/isolation/isolationtester.c b/src/test/isolation/isolationtester.c
index e64dc020b18..31e7341a67a 100644
--- a/src/test/isolation/isolationtester.c
+++ b/src/test/isolation/isolationtester.c
@@ -828,6 +828,7 @@ try_complete_step(TestSpec *testspec, PermutationStep *pstep, int flags)
 	PGresult   *res;
 	PGnotify   *notify;
 	bool		canceled = false;
+	char	   *connection_error = NULL;
 
 	/*
 	 * If the step is annotated with (*), then on the first call, force it to
@@ -910,9 +911,19 @@ try_complete_step(TestSpec *testspec, PermutationStep *pstep, int flags)
 					 */
 					if (!PQconsumeInput(conn))
 					{
-						fprintf(stderr, "PQconsumeInput failed: %s\n",
-								PQerrorMessage(conn));
-						exit(1);
+						if (PQstatus(conn) != CONNECTION_BAD)
+						{
+							fprintf(stderr, "PQconsumeInput failed: %s\n",
+									PQerrorMessage(conn));
+							exit(1);
+						}
+
+						/*
+						 * Save the error before PQgetResult() adds another complaint
+						 * about attempting to read from the dead socket.
+						 */
+						connection_error = pg_strdup(PQerrorMessage(conn));
+						break;
 					}
 					if (!PQisBusy(conn))
 						break;
@@ -979,9 +990,19 @@ try_complete_step(TestSpec *testspec, PermutationStep *pstep, int flags)
 		}
 		else if (!PQconsumeInput(conn)) /* select(): data available */
 		{
-			fprintf(stderr, "PQconsumeInput failed: %s\n",
-					PQerrorMessage(conn));
-			exit(1);
+			if (PQstatus(conn) != CONNECTION_BAD)
+			{
+				fprintf(stderr, "PQconsumeInput failed: %s\n",
+						PQerrorMessage(conn));
+				exit(1);
+			}
+
+			/*
+			 * Save the error before PQgetResult() adds another complaint about
+			 * attempting to read from the dead socket.
+			 */
+			connection_error = pg_strdup(PQerrorMessage(conn));
+			break;
 		}
 	}
 
@@ -1028,7 +1049,7 @@ try_complete_step(TestSpec *testspec, PermutationStep *pstep, int flags)
 
 					if (sev && msg)
 						printf("%s:  %s\n", sev, msg);
-					else
+					else if (!connection_error)
 						printf("%s\n", PQresultErrorMessage(res));
 				}
 				break;
@@ -1037,6 +1058,16 @@ try_complete_step(TestSpec *testspec, PermutationStep *pstep, int flags)
 					   PQresStatus(PQresultStatus(res)));
 		}
 		PQclear(res);
+
+		/* The connection is dead, so don't ask libpq for another result. */
+		if (connection_error)
+			break;
+	}
+
+	if (connection_error)
+	{
+		printf("%s\n", connection_error);
+		pg_free(connection_error);
 	}
 
 	/* Report any available NOTIFY messages, too */
diff --git a/src/test/modules/injection_points/expected/wait_cleanup_1.out b/src/test/modules/injection_points/expected/wait_cleanup_1.out
new file mode 100644
index 00000000000..516a428b364
--- /dev/null
+++ b/src/test/modules/injection_points/expected/wait_cleanup_1.out
@@ -0,0 +1,86 @@
+Parsed test spec with 3 sessions
+
+starting permutation: wait1 cancel3 noop3 wait2 wakeup3 noop2 detach3
+injection_points_attach
+-----------------------
+                       
+(1 row)
+
+step wait1: SELECT injection_points_run('injection-points-wait'); <waiting ...>
+step cancel3: 
+	SELECT pg_cancel_backend(pid) FROM pg_stat_activity
+	  WHERE wait_event = 'injection-points-wait';
+ <waiting ...>
+step wait1: <... completed>
+ERROR:  canceling statement due to user request
+step cancel3: <... completed>
+pg_cancel_backend
+-----------------
+t                
+(1 row)
+
+step noop3: 
+step wait2: SELECT injection_points_run('injection-points-wait'); <waiting ...>
+step wakeup3: SELECT injection_points_wakeup('injection-points-wait');
+injection_points_wakeup
+-----------------------
+                       
+(1 row)
+
+step wait2: <... completed>
+injection_points_run
+--------------------
+                    
+(1 row)
+
+step noop2: 
+step detach3: SELECT injection_points_detach('injection-points-wait');
+injection_points_detach
+-----------------------
+                       
+(1 row)
+
+
+starting permutation: wait1 terminate3 noop3 wait2 wakeup3 noop2 detach3
+injection_points_attach
+-----------------------
+                       
+(1 row)
+
+step wait1: SELECT injection_points_run('injection-points-wait'); <waiting ...>
+step terminate3: 
+	SELECT pg_terminate_backend(pid) FROM pg_stat_activity
+	  WHERE wait_event = 'injection-points-wait';
+ <waiting ...>
+step wait1: <... completed>
+server closed the connection unexpectedly
+	This probably means the server terminated abnormally
+	before or while processing the request.
+
+step terminate3: <... completed>
+pg_terminate_backend
+--------------------
+t                   
+(1 row)
+
+step noop3: 
+step wait2: SELECT injection_points_run('injection-points-wait'); <waiting ...>
+step wakeup3: SELECT injection_points_wakeup('injection-points-wait');
+injection_points_wakeup
+-----------------------
+                       
+(1 row)
+
+step wait2: <... completed>
+injection_points_run
+--------------------
+                    
+(1 row)
+
+step noop2: 
+step detach3: SELECT injection_points_detach('injection-points-wait');
+injection_points_detach
+-----------------------
+                       
+(1 row)
+
-- 
That's all, folks. May the source be with you.

