MCPcopy
hub / github.com/jackc/pgx / TestPipelineCloseDoesNotPanicOnMultipleFatalErrors

Function TestPipelineCloseDoesNotPanicOnMultipleFatalErrors

pgconn/pgconn_test.go:4605–4698  ·  view source on GitHub ↗

https://github.com/jackc/pgx/issues/2470 When the server sends multiple FATAL errors in a single batch (as PgBouncer can do when terminating idle-in-transaction connections), Pipeline.Close() must not panic with "close of closed channel" on cleanupDone. The first FATAL triggers OnPgError which close

(t *testing.T)

Source from the content-addressed store, hash-verified

4603// This test sends all server responses in a single TCP write to guarantee both FATAL errors
4604// are in the chunkReader buffer simultaneously.
4605func TestPipelineCloseDoesNotPanicOnMultipleFatalErrors(t *testing.T) {
4606 t.Parallel()
4607
4608 ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
4609 defer cancel()
4610
4611 ln, err := net.Listen("tcp", "127.0.0.1:")
4612 require.NoError(t, err)
4613 defer ln.Close()
4614
4615 serverErrChan := make(chan error, 1)
4616 go func() {
4617 defer close(serverErrChan)
4618
4619 conn, err := ln.Accept()
4620 if err != nil {
4621 serverErrChan <- err
4622 return
4623 }
4624 defer conn.Close()
4625
4626 err = conn.SetDeadline(time.Now().Add(59 * time.Second))
4627 if err != nil {
4628 serverErrChan <- err
4629 return
4630 }
4631
4632 backend := pgproto3.NewBackend(conn, conn)
4633
4634 // Handle startup
4635 _, err = backend.ReceiveStartupMessage()
4636 if err != nil {
4637 serverErrChan <- err
4638 return
4639 }
4640 backend.Send(&pgproto3.AuthenticationOk{})
4641 backend.Send(&pgproto3.BackendKeyData{ProcessID: 0, SecretKey: []byte{0, 0, 0, 0}})
4642 backend.Send(&pgproto3.ReadyForQuery{TxStatus: 'I'})
4643 err = backend.Flush()
4644 if err != nil {
4645 serverErrChan <- err
4646 return
4647 }
4648
4649 // Read all client pipeline messages (Parse, Describe, Parse, Describe, Sync)
4650 for i := 0; i < 5; i++ {
4651 _, err = backend.Receive()
4652 if err != nil {
4653 serverErrChan <- err
4654 return
4655 }
4656 }
4657
4658 // Send ALL responses in a single write so they all end up in the chunkReader buffer.
4659 // This simulates PgBouncer sending a FATAL and then the real PostgreSQL also sending
4660 // a FATAL, both arriving in the same TCP segment.
4661 backend.Send(&pgproto3.ParseComplete{})
4662 backend.Send(&pgproto3.ParameterDescription{})

Callers

nothing calls this directly

Calls 13

ReceiveStartupMessageMethod · 0.95
SendMethod · 0.95
FlushMethod · 0.95
ReceiveMethod · 0.95
NewBackendFunction · 0.92
ConnectFunction · 0.92
StartPipelineMethod · 0.80
SendPrepareMethod · 0.80
SyncMethod · 0.80
CloseMethod · 0.65
SetDeadlineMethod · 0.45
StringMethod · 0.45

Tested by

no test coverage detected