go-pq/issues_test.go

159 lines
3.5 KiB
Go

package pq
import (
"context"
"database/sql"
"errors"
"testing"
"time"
)
func TestIssue494(t *testing.T) {
db := openTestConn(t)
defer db.Close()
query := `CREATE TEMP TABLE t (i INT PRIMARY KEY)`
if _, err := db.Exec(query); err != nil {
t.Fatal(err)
}
txn, err := db.Begin()
if err != nil {
t.Fatal(err)
}
if _, err := txn.Prepare(CopyIn("t", "i")); err != nil {
t.Fatal(err)
}
if _, err := txn.Query("SELECT 1"); err == nil {
t.Fatal("expected error")
}
}
func TestIssue1046(t *testing.T) {
ctxTimeout := time.Second * 2
db := openTestConn(t)
defer db.Close()
ctx, cancel := context.WithTimeout(context.Background(), ctxTimeout)
defer cancel()
stmt, err := db.PrepareContext(ctx, `SELECT pg_sleep(10) AS id`)
if err != nil {
t.Fatal(err)
}
var d []uint8
err = stmt.QueryRowContext(ctx).Scan(&d)
dl, _ := ctx.Deadline()
since := time.Since(dl)
if since > ctxTimeout {
t.Logf("FAIL %s: query returned after context deadline: %v\n", t.Name(), since)
t.Fail()
}
if pgErr := (*Error)(nil); !(errors.As(err, &pgErr) && pgErr.Code == cancelErrorCode) {
t.Logf("ctx.Err(): [%T]%+v\n", ctx.Err(), ctx.Err())
t.Logf("got err: [%T] %+v expected errCode: %v", err, err, cancelErrorCode)
t.Fail()
}
}
func TestIssue1062(t *testing.T) {
db := openTestConn(t)
defer db.Close()
// Ensure that cancelling a QueryRowContext does not result in an ErrBadConn.
for i := 0; i < 100; i++ {
ctx, cancel := context.WithCancel(context.Background())
go cancel()
row := db.QueryRowContext(ctx, "select 1")
var v int
err := row.Scan(&v)
if pgErr := (*Error)(nil); err != nil &&
err != context.Canceled &&
!(errors.As(err, &pgErr) && pgErr.Code == cancelErrorCode) {
t.Fatalf("Scan resulted in unexpected error %v for canceled QueryRowContext at attempt %d", err, i+1)
}
}
}
func connIsValid(t *testing.T, db *sql.DB) {
t.Helper()
ctx := context.Background()
conn, err := db.Conn(ctx)
if err != nil {
t.Fatal(err)
}
defer conn.Close()
// the connection must be valid
err = conn.PingContext(ctx)
if err != nil {
t.Errorf("PingContext err=%#v", err)
}
// close must not return an error
err = conn.Close()
if err != nil {
t.Errorf("Close err=%#v", err)
}
}
func TestQueryCancelRace(t *testing.T) {
db := openTestConn(t)
defer db.Close()
// cancel a query while executing on Postgres: must return the cancelled error code
ctx, cancel := context.WithCancel(context.Background())
go func() {
time.Sleep(10 * time.Millisecond)
cancel()
}()
row := db.QueryRowContext(ctx, "select pg_sleep(0.5)")
var pgSleepVoid string
err := row.Scan(&pgSleepVoid)
if pgErr := (*Error)(nil); !(errors.As(err, &pgErr) && pgErr.Code == cancelErrorCode) {
t.Fatalf("expected cancelled error; err=%#v", err)
}
// get a connection: it must be a valid
connIsValid(t, db)
}
// Test cancelling a scan after it is started. This broke with 1.10.4.
func TestQueryCancelledReused(t *testing.T) {
db := openTestConn(t)
defer db.Close()
ctx, cancel := context.WithCancel(context.Background())
// run a query that returns a lot of data
rows, err := db.QueryContext(ctx, "select generate_series(1, 10000)")
if err != nil {
t.Fatal(err)
}
// scan the first value
if !rows.Next() {
t.Error("expected rows.Next() to return true")
}
var i int
err = rows.Scan(&i)
if err != nil {
t.Fatal(err)
}
if i != 1 {
t.Error(i)
}
// cancel the context and close rows, ignoring errors
cancel()
rows.Close()
// get a connection: it must be valid
connIsValid(t, db)
}