@@ -13,6 +13,7 @@ import {
1313 assertRejects ,
1414 assertThrows ,
1515} from "jsr:@std/assert@1.0.10" ;
16+ import { MockError , stub } from "jsr:@std/testing/mock" ;
1617import { getMainConfiguration } from "./config.ts" ;
1718import type { PoolClient , QueryClient } from "../client.ts" ;
1819import type { ClientOptions } from "../connection/connection_params.ts" ;
@@ -694,9 +695,13 @@ Deno.test(
694695) ;
695696
696697// This test depends on the assumption that all clients will default to
697- // one reconneciton by default
698+ // one reconnection by default
699+ //
700+ // It also specifically tests the case where the database system sends a
701+ // graceful disconnect, not the case where the database connection is just
702+ // closed due to the database process crashing or being killed.
698703Deno . test (
699- "Default reconnection" ,
704+ "Default reconnection after graceful database connection close " ,
700705 withClient ( async ( client ) => {
701706 await assertRejects (
702707 ( ) =>
@@ -714,6 +719,64 @@ Deno.test(
714719 } ) ,
715720) ;
716721
722+ // This test depends on the assumption that all clients will default to
723+ // one reconnection by default
724+ Deno . test (
725+ "Default reconnection after connection drop" ,
726+ withClient ( async ( client ) => {
727+ // Test that connection is OK
728+ const { rows : result } = await client . queryObject < { res : number } > ( {
729+ text : `SELECT 1` ,
730+ fields : [ "res" ] ,
731+ } ) ;
732+ assertEquals ( result [ 0 ] . res , 1 ) ;
733+
734+ // Use mock simulate irrecoverably broken pipe
735+ const connWrite = stub (
736+ WritableStreamDefaultWriter . prototype ,
737+ "write" ,
738+ ( _buffer ) => {
739+ throw new Deno . errors . BrokenPipe ( ) ;
740+ } ,
741+ ) ;
742+ try {
743+ await assertRejects (
744+ ( ) => client . queryArray `SELECT 1` ,
745+ Deno . errors . BrokenPipe ,
746+ ) ;
747+ } finally {
748+ connWrite . restore ( ) ;
749+ }
750+
751+ // Use mock simulate broken pipe, that can be healed by reconnecting
752+ const connWrite2 = stub (
753+ WritableStreamDefaultWriter . prototype ,
754+ "write" ,
755+ ( _buffer ) => {
756+ connWrite2 . restore ( ) ;
757+ throw new Deno . errors . BrokenPipe ( ) ;
758+ } ,
759+ ) ;
760+ try {
761+ const { rows : result2 } = await client . queryObject < { res : number } > ( {
762+ text : `SELECT 1` ,
763+ fields : [ "res" ] ,
764+ } ) ;
765+ assertEquals ( result2 [ 0 ] . res , 1 ) ;
766+ } finally {
767+ // Restoring must fail here because it already happened
768+ //
769+ // If this fails, it means the Mock was never invoked and the test must be updated!
770+ assertThrows (
771+ ( ) => connWrite2 . restore ( ) ,
772+ MockError ,
773+ ) ;
774+ }
775+
776+ assertEquals ( client . connected , true ) ;
777+ } ) ,
778+ ) ;
779+
717780Deno . test (
718781 "Handling of debug notices" ,
719782 withClient ( async ( client ) => {
@@ -1498,6 +1561,40 @@ Deno.test(
14981561 } ) ,
14991562) ;
15001563
1564+ Deno . test (
1565+ "Transaction fails after connection drop" ,
1566+ withClient ( async ( client ) => {
1567+ const name = "transactionFailsOnConnectionDrop" ;
1568+ const transaction = client . createTransaction ( name ) ;
1569+
1570+ await transaction . begin ( ) ;
1571+
1572+ // Use mock simulate broken pipe
1573+ const connWrite = stub (
1574+ WritableStreamDefaultWriter . prototype ,
1575+ "write" ,
1576+ ( _buffer ) => {
1577+ throw new Deno . errors . BrokenPipe ( ) ;
1578+ } ,
1579+ ) ;
1580+ try {
1581+ await assertRejects (
1582+ ( ) => transaction . queryArray `SELECT 1` ,
1583+ TransactionError ,
1584+ ) ;
1585+ } finally {
1586+ connWrite . restore ( ) ;
1587+ }
1588+
1589+ // Test that connection is OK afterward
1590+ const { rows : result } = await client . queryObject < { res : number } > ( {
1591+ text : `SELECT 1` ,
1592+ fields : [ "res" ] ,
1593+ } ) ;
1594+ assertEquals ( result [ 0 ] . res , 1 ) ;
1595+ } ) ,
1596+ ) ;
1597+
15011598Deno . test (
15021599 "Transaction savepoints" ,
15031600 withClient ( async ( client ) => {
0 commit comments