storj/private/dbutil/cockroachutil/driver_test.go
Egon Elbre 85c45cd56f private/dbutil/pgtest: support multiple databases for testing
Currently Cockroach isn't performant for concurrent database setup and
tear-down. Instead of a single instance allow setting multiple potential
connection strings and let the tests pick one connection string
randomly.

This improves test duration by ~10 minutes.

While we are at significantly changing how pgtest works, introduce
helper PickPostgres and PickCockroach for selecting the database to
reduce code duplications in multiple places.

Change-Id: I8ad171d5c4c8a4fc081ec2ae9bdd0cc948a80619
2020-04-28 21:55:49 +03:00

110 lines
2.9 KiB
Go

// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
package cockroachutil
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/zeebo/errs"
"storj.io/common/testcontext"
"storj.io/storj/private/dbutil/pgtest"
"storj.io/storj/private/tagsql"
)
func TestLibPqCompatibility(t *testing.T) {
connstr := pgtest.PickCockroach(t)
ctx := testcontext.New(t)
defer ctx.Cleanup()
testDB, err := OpenUnique(ctx, connstr, "TestLibPqCompatibility")
require.NoError(t, err)
defer ctx.Check(testDB.Close)
// use a single dedicated conn for testing
conn, err := testDB.Conn(ctx)
require.NoError(t, err)
defer ctx.Check(conn.Close)
// should be in idle status, no transaction, initially
require.Equal(t, txnStatusIdle, getTxnStatus(ctx, t, conn))
require.False(t, checkIsInTx(ctx, t, conn))
// start a transaction
tx, err := conn.BeginTx(ctx, nil)
require.NoError(t, err)
func() {
defer func() { err = tx.Rollback() }()
// should be idle in transaction now
require.Equal(t, txnStatusIdleInTransaction, getTxnStatus(ctx, t, conn))
require.True(t, checkIsInTx(ctx, t, conn))
// issue successful query
rows, err := tx.QueryContext(ctx, `SELECT 1`)
require.NoError(t, err)
require.True(t, rows.Next())
var n int
err = rows.Scan(&n)
require.NoError(t, err)
require.False(t, rows.Next())
err = rows.Err()
require.NoError(t, err)
err = rows.Close()
require.NoError(t, err)
// should still be idle in transaction
require.Equal(t, txnStatusIdleInTransaction, getTxnStatus(ctx, t, conn))
require.True(t, checkIsInTx(ctx, t, conn))
// issue bad query
_, err = tx.QueryContext(ctx, `SELECT BALONEY SANDWICHES`)
require.Error(t, err)
// should be in a failed transaction now
require.Equal(t, txnStatusInFailedTransaction, getTxnStatus(ctx, t, conn))
require.True(t, checkIsInTx(ctx, t, conn))
}()
// check rollback error
require.NoError(t, err)
// should be back out of any transaction
require.Equal(t, txnStatusIdle, getTxnStatus(ctx, t, conn))
require.False(t, checkIsInTx(ctx, t, conn))
}
func withCockroachConn(ctx context.Context, sqlConn tagsql.Conn, fn func(conn *cockroachConn) error) error {
return sqlConn.Raw(ctx, func(rawConn interface{}) error {
crConn, ok := rawConn.(*cockroachConn)
if !ok {
return errs.New("conn object is %T, not *cockroachConn", crConn)
}
return fn(crConn)
})
}
func getTxnStatus(ctx context.Context, t *testing.T, sqlConn tagsql.Conn) (txnStatus transactionStatus) {
err := withCockroachConn(ctx, sqlConn, func(crConn *cockroachConn) error {
txnStatus = crConn.txnStatus()
return nil
})
require.NoError(t, err)
return txnStatus
}
func checkIsInTx(ctx context.Context, t *testing.T, sqlConn tagsql.Conn) (isInTx bool) {
err := withCockroachConn(ctx, sqlConn, func(crConn *cockroachConn) error {
isInTx = crConn.isInTransaction()
return nil
})
require.NoError(t, err)
return isInTx
}