package pg_test
import (
"time"
"github.com/go-pg/pg"
. "gopkg.in/check.v1"
)
var _ = Suite(&PoolTest{})
type PoolTest struct {
db *pg.DB
}
func (t *PoolTest) SetUpTest(c *C) {
opt := pgOptions()
opt.IdleTimeout = time.Second
t.db = pg.Connect(opt)
}
func (t *PoolTest) TearDownTest(c *C) {
_ = t.db.Close()
}
func (t *PoolTest) TestPoolReusesConnection(c *C) {
for i := 0; i < 100; i++ {
_, err := t.db.Exec("SELECT 'test_pool_reuses_connection'")
c.Assert(err, IsNil)
}
c.Assert(t.db.Pool().Len(), Equals, 1)
c.Assert(t.db.Pool().IdleLen(), Equals, 1)
}
func (t *PoolTest) TestPoolMaxSize(c *C) {
N := 1000
perform(N, func(int) {
_, err := t.db.Exec("SELECT 'test_pool_max_size'")
c.Assert(err, IsNil)
})
c.Assert(t.db.Pool().Len(), Equals, 10)
c.Assert(t.db.Pool().IdleLen(), Equals, 10)
}
func (t *PoolTest) TestCloseClosesAllConnections(c *C) {
ln := t.db.Listen("test_channel")
wait := make(chan struct{}, 2)
go func() {
wait <- struct{}{}
_, _, err := ln.Receive()
c.Assert(err, ErrorMatches, `^(.*use of closed (file or )?network connection|EOF)$`)
wait <- struct{}{}
}()
select {
case <-wait:
// ok
case <-time.After(3 * time.Second):
c.Fatal("timeout")
}
c.Assert(t.db.Close(), IsNil)
select {
case <-wait:
// ok
case <-time.After(3 * time.Second):
c.Fatal("timeout")
}
c.Assert(t.db.Pool().Len(), Equals, 0)
c.Assert(t.db.Pool().IdleLen(), Equals, 0)
}
func (t *PoolTest) TestClosedDB(c *C) {
c.Assert(t.db.Close(), IsNil)
c.Assert(t.db.Pool().Len(), Equals, 0)
c.Assert(t.db.Pool().IdleLen(), Equals, 0)
err := t.db.Close()
c.Assert(err, Not(IsNil))
c.Assert(err.Error(), Equals, "pg: database is closed")
_, err = t.db.Exec("SELECT 'test_closed_db'")
c.Assert(err, Not(IsNil))
c.Assert(err.Error(), Equals, "pg: database is closed")
}
func (t *PoolTest) TestClosedListener(c *C) {
ln := t.db.Listen("test_channel")
c.Assert(t.db.Pool().Len(), Equals, 1)
c.Assert(t.db.Pool().IdleLen(), Equals, 0)
c.Assert(ln.Close(), IsNil)
c.Assert(t.db.Pool().Len(), Equals, 0)
c.Assert(t.db.Pool().IdleLen(), Equals, 0)
err := ln.Close()
c.Assert(err, Not(IsNil))
c.Assert(err.Error(), Equals, "pg: listener is closed")
_, _, err = ln.ReceiveTimeout(time.Second)
c.Assert(err, Not(IsNil))
c.Assert(err.Error(), Equals, "pg: listener is closed")
}
func (t *PoolTest) TestClosedTx(c *C) {
tx, err := t.db.Begin()
c.Assert(err, IsNil)
c.Assert(t.db.Pool().Len(), Equals, 1)
c.Assert(t.db.Pool().IdleLen(), Equals, 0)
c.Assert(tx.Rollback(), IsNil)
c.Assert(t.db.Pool().Len(), Equals, 1)
c.Assert(t.db.Pool().IdleLen(), Equals, 1)
err = tx.Rollback()
c.Assert(err, Not(IsNil))
c.Assert(err.Error(), Equals, "pg: transaction has already been committed or rolled back")
_, err = tx.Exec("SELECT 'test_closed_tx'")
c.Assert(err, Not(IsNil))
c.Assert(err.Error(), Equals, "pg: transaction has already been committed or rolled back")
}
func (t *PoolTest) TestClosedStmt(c *C) {
stmt, err := t.db.Prepare("SELECT $1::int")
c.Assert(err, IsNil)
c.Assert(t.db.Pool().Len(), Equals, 1)
c.Assert(t.db.Pool().IdleLen(), Equals, 0)
c.Assert(stmt.Close(), IsNil)
c.Assert(t.db.Pool().Len(), Equals, 1)
c.Assert(t.db.Pool().IdleLen(), Equals, 1)
err = stmt.Close()
c.Assert(err, Not(IsNil))
c.Assert(err.Error(), Equals, "pg: statement is closed")
_, err = stmt.Exec(1)
c.Assert(err.Error(), Equals, "pg: statement is closed")
}