github.com/jackc/pgx/v5@v5.5.5/pgproto3/frontend_test.go (about)

     1  package pgproto3_test
     2  
     3  import (
     4  	"io"
     5  	"testing"
     6  
     7  	"github.com/jackc/pgx/v5/pgproto3"
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  )
    11  
    12  type interruptReader struct {
    13  	chunks [][]byte
    14  }
    15  
    16  func (ir *interruptReader) Read(p []byte) (n int, err error) {
    17  	if len(ir.chunks) == 0 {
    18  		return 0, io.EOF
    19  	}
    20  
    21  	n = copy(p, ir.chunks[0])
    22  	if n != len(ir.chunks[0]) {
    23  		panic("this test reader doesn't support partial reads of chunks")
    24  	}
    25  
    26  	ir.chunks = ir.chunks[1:]
    27  
    28  	return n, nil
    29  }
    30  
    31  func (ir *interruptReader) push(p []byte) {
    32  	ir.chunks = append(ir.chunks, p)
    33  }
    34  
    35  func TestFrontendReceiveInterrupted(t *testing.T) {
    36  	t.Parallel()
    37  
    38  	server := &interruptReader{}
    39  	server.push([]byte{'Z', 0, 0, 0, 5})
    40  
    41  	frontend := pgproto3.NewFrontend(server, nil)
    42  
    43  	msg, err := frontend.Receive()
    44  	if err == nil {
    45  		t.Fatal("expected err")
    46  	}
    47  	if msg != nil {
    48  		t.Fatalf("did not expect msg, but %v", msg)
    49  	}
    50  
    51  	server.push([]byte{'I'})
    52  
    53  	msg, err = frontend.Receive()
    54  	if err != nil {
    55  		t.Fatal(err)
    56  	}
    57  	if msg, ok := msg.(*pgproto3.ReadyForQuery); !ok || msg.TxStatus != 'I' {
    58  		t.Fatalf("unexpected msg: %v", msg)
    59  	}
    60  }
    61  
    62  func TestFrontendReceiveUnexpectedEOF(t *testing.T) {
    63  	t.Parallel()
    64  
    65  	server := &interruptReader{}
    66  	server.push([]byte{'Z', 0, 0, 0, 5})
    67  
    68  	frontend := pgproto3.NewFrontend(server, nil)
    69  
    70  	msg, err := frontend.Receive()
    71  	if err == nil {
    72  		t.Fatal("expected err")
    73  	}
    74  	if msg != nil {
    75  		t.Fatalf("did not expect msg, but %v", msg)
    76  	}
    77  
    78  	msg, err = frontend.Receive()
    79  	assert.Nil(t, msg)
    80  	assert.Equal(t, io.ErrUnexpectedEOF, err)
    81  }
    82  
    83  func TestErrorResponse(t *testing.T) {
    84  	t.Parallel()
    85  
    86  	want := &pgproto3.ErrorResponse{
    87  		Severity:            "ERROR",
    88  		SeverityUnlocalized: "ERROR",
    89  		Message:             `column "foo" does not exist`,
    90  		File:                "parse_relation.c",
    91  		Code:                "42703",
    92  		Position:            8,
    93  		Line:                3513,
    94  		Routine:             "errorMissingColumn",
    95  	}
    96  
    97  	raw := []byte{
    98  		'E', 0, 0, 0, 'f',
    99  		'S', 'E', 'R', 'R', 'O', 'R', 0,
   100  		'V', 'E', 'R', 'R', 'O', 'R', 0,
   101  		'C', '4', '2', '7', '0', '3', 0,
   102  		'M', 'c', 'o', 'l', 'u', 'm', 'n', 32, '"', 'f', 'o', 'o', '"', 32, 'd', 'o', 'e', 's', 32, 'n', 'o', 't', 32, 'e', 'x', 'i', 's', 't', 0,
   103  		'P', '8', 0,
   104  		'F', 'p', 'a', 'r', 's', 'e', '_', 'r', 'e', 'l', 'a', 't', 'i', 'o', 'n', '.', 'c', 0,
   105  		'L', '3', '5', '1', '3', 0,
   106  		'R', 'e', 'r', 'r', 'o', 'r', 'M', 'i', 's', 's', 'i', 'n', 'g', 'C', 'o', 'l', 'u', 'm', 'n', 0, 0,
   107  	}
   108  
   109  	server := &interruptReader{}
   110  	server.push(raw)
   111  
   112  	frontend := pgproto3.NewFrontend(server, nil)
   113  
   114  	got, err := frontend.Receive()
   115  	require.NoError(t, err)
   116  	assert.Equal(t, want, got)
   117  }