mirror of
https://github.com/getsops/sops.git
synced 2026-02-05 12:45:21 +01:00
It's been around 9 months since our last vendor update. This is also needed for some new features being worked on for sops workspace. Additionally, this PR regenerates the kms mocks.
320 lines
7.6 KiB
Go
320 lines
7.6 KiB
Go
package pq
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestMultipleSimpleQuery(t *testing.T) {
|
|
db := openTestConn(t)
|
|
defer db.Close()
|
|
|
|
rows, err := db.Query("select 1; set time zone default; select 2; select 3")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var i int
|
|
for rows.Next() {
|
|
if err := rows.Scan(&i); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if i != 1 {
|
|
t.Fatalf("expected 1, got %d", i)
|
|
}
|
|
}
|
|
if !rows.NextResultSet() {
|
|
t.Fatal("expected more result sets", rows.Err())
|
|
}
|
|
for rows.Next() {
|
|
if err := rows.Scan(&i); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if i != 2 {
|
|
t.Fatalf("expected 2, got %d", i)
|
|
}
|
|
}
|
|
|
|
// Make sure that if we ignore a result we can still query.
|
|
|
|
rows, err = db.Query("select 4; select 5")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
for rows.Next() {
|
|
if err := rows.Scan(&i); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if i != 4 {
|
|
t.Fatalf("expected 4, got %d", i)
|
|
}
|
|
}
|
|
if !rows.NextResultSet() {
|
|
t.Fatal("expected more result sets", rows.Err())
|
|
}
|
|
for rows.Next() {
|
|
if err := rows.Scan(&i); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if i != 5 {
|
|
t.Fatalf("expected 5, got %d", i)
|
|
}
|
|
}
|
|
if rows.NextResultSet() {
|
|
t.Fatal("unexpected result set")
|
|
}
|
|
}
|
|
|
|
const contextRaceIterations = 100
|
|
|
|
func TestContextCancelExec(t *testing.T) {
|
|
db := openTestConn(t)
|
|
defer db.Close()
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
// Delay execution for just a bit until db.ExecContext has begun.
|
|
defer time.AfterFunc(time.Millisecond*10, cancel).Stop()
|
|
|
|
// Not canceled until after the exec has started.
|
|
if _, err := db.ExecContext(ctx, "select pg_sleep(1)"); err == nil {
|
|
t.Fatal("expected error")
|
|
} else if err.Error() != "pq: canceling statement due to user request" {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
// Context is already canceled, so error should come before execution.
|
|
if _, err := db.ExecContext(ctx, "select pg_sleep(1)"); err == nil {
|
|
t.Fatal("expected error")
|
|
} else if err.Error() != "context canceled" {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
for i := 0; i < contextRaceIterations; i++ {
|
|
func() {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
if _, err := db.ExecContext(ctx, "select 1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}()
|
|
|
|
if _, err := db.Exec("select 1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestContextCancelQuery(t *testing.T) {
|
|
db := openTestConn(t)
|
|
defer db.Close()
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
// Delay execution for just a bit until db.QueryContext has begun.
|
|
defer time.AfterFunc(time.Millisecond*10, cancel).Stop()
|
|
|
|
// Not canceled until after the exec has started.
|
|
if _, err := db.QueryContext(ctx, "select pg_sleep(1)"); err == nil {
|
|
t.Fatal("expected error")
|
|
} else if err.Error() != "pq: canceling statement due to user request" {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
// Context is already canceled, so error should come before execution.
|
|
if _, err := db.QueryContext(ctx, "select pg_sleep(1)"); err == nil {
|
|
t.Fatal("expected error")
|
|
} else if err.Error() != "context canceled" {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
for i := 0; i < contextRaceIterations; i++ {
|
|
func() {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
rows, err := db.QueryContext(ctx, "select 1")
|
|
cancel()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
} else if err := rows.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}()
|
|
|
|
if rows, err := db.Query("select 1"); err != nil {
|
|
t.Fatal(err)
|
|
} else if err := rows.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestIssue617 tests that a failed query in QueryContext doesn't lead to a
|
|
// goroutine leak.
|
|
func TestIssue617(t *testing.T) {
|
|
db := openTestConn(t)
|
|
defer db.Close()
|
|
|
|
const N = 10
|
|
|
|
numGoroutineStart := runtime.NumGoroutine()
|
|
for i := 0; i < N; i++ {
|
|
func() {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
_, err := db.QueryContext(ctx, `SELECT * FROM DOESNOTEXIST`)
|
|
pqErr, _ := err.(*Error)
|
|
// Expecting "pq: relation \"doesnotexist\" does not exist" error.
|
|
if err == nil || pqErr == nil || pqErr.Code != "42P01" {
|
|
t.Fatalf("expected undefined table error, got %v", err)
|
|
}
|
|
}()
|
|
}
|
|
numGoroutineFinish := runtime.NumGoroutine()
|
|
|
|
// We use N/2 and not N because the GC and other actors may increase or
|
|
// decrease the number of goroutines.
|
|
if numGoroutineFinish-numGoroutineStart >= N/2 {
|
|
t.Errorf("goroutine leak detected, was %d, now %d", numGoroutineStart, numGoroutineFinish)
|
|
}
|
|
}
|
|
|
|
func TestContextCancelBegin(t *testing.T) {
|
|
db := openTestConn(t)
|
|
defer db.Close()
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
tx, err := db.BeginTx(ctx, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Delay execution for just a bit until tx.Exec has begun.
|
|
defer time.AfterFunc(time.Millisecond*10, cancel).Stop()
|
|
|
|
// Not canceled until after the exec has started.
|
|
if _, err := tx.Exec("select pg_sleep(1)"); err == nil {
|
|
t.Fatal("expected error")
|
|
} else if err.Error() != "pq: canceling statement due to user request" {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
// Transaction is canceled, so expect an error.
|
|
if _, err := tx.Query("select pg_sleep(1)"); err == nil {
|
|
t.Fatal("expected error")
|
|
} else if err != sql.ErrTxDone {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
// Context is canceled, so cannot begin a transaction.
|
|
if _, err := db.BeginTx(ctx, nil); err == nil {
|
|
t.Fatal("expected error")
|
|
} else if err.Error() != "context canceled" {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
for i := 0; i < contextRaceIterations; i++ {
|
|
func() {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
tx, err := db.BeginTx(ctx, nil)
|
|
cancel()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
} else if err := tx.Rollback(); err != nil &&
|
|
err.Error() != "pq: canceling statement due to user request" &&
|
|
err != sql.ErrTxDone {
|
|
t.Fatal(err)
|
|
}
|
|
}()
|
|
|
|
if tx, err := db.Begin(); err != nil {
|
|
t.Fatal(err)
|
|
} else if err := tx.Rollback(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTxOptions(t *testing.T) {
|
|
db := openTestConn(t)
|
|
defer db.Close()
|
|
ctx := context.Background()
|
|
|
|
tests := []struct {
|
|
level sql.IsolationLevel
|
|
isolation string
|
|
}{
|
|
{
|
|
level: sql.LevelDefault,
|
|
isolation: "",
|
|
},
|
|
{
|
|
level: sql.LevelReadUncommitted,
|
|
isolation: "read uncommitted",
|
|
},
|
|
{
|
|
level: sql.LevelReadCommitted,
|
|
isolation: "read committed",
|
|
},
|
|
{
|
|
level: sql.LevelRepeatableRead,
|
|
isolation: "repeatable read",
|
|
},
|
|
{
|
|
level: sql.LevelSerializable,
|
|
isolation: "serializable",
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
for _, ro := range []bool{true, false} {
|
|
tx, err := db.BeginTx(ctx, &sql.TxOptions{
|
|
Isolation: test.level,
|
|
ReadOnly: ro,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var isolation string
|
|
err = tx.QueryRow("select current_setting('transaction_isolation')").Scan(&isolation)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if test.isolation != "" && isolation != test.isolation {
|
|
t.Errorf("wrong isolation level: %s != %s", isolation, test.isolation)
|
|
}
|
|
|
|
var isRO string
|
|
err = tx.QueryRow("select current_setting('transaction_read_only')").Scan(&isRO)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ro != (isRO == "on") {
|
|
t.Errorf("read/[write,only] not set: %t != %s for level %s",
|
|
ro, isRO, test.isolation)
|
|
}
|
|
|
|
tx.Rollback()
|
|
}
|
|
}
|
|
|
|
_, err := db.BeginTx(ctx, &sql.TxOptions{
|
|
Isolation: sql.LevelLinearizable,
|
|
})
|
|
if err == nil {
|
|
t.Fatal("expected LevelLinearizable to fail")
|
|
}
|
|
if !strings.Contains(err.Error(), "isolation level not supported") {
|
|
t.Errorf("Expected error to mention isolation level, got %q", err)
|
|
}
|
|
}
|