mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
database/sql: adds test for fix in issue 4433.
Tests that here should be automatic retries if a database driver's connection returns ErrBadConn on Begin. See "TestTxErrBadConn" in sql_test.go R=golang-dev CC=golang-dev https://golang.org/cl/6942050
This commit is contained in:
parent
10b3e310e2
commit
19e2f26b21
2 changed files with 60 additions and 5 deletions
|
|
@ -42,9 +42,10 @@ type fakeDriver struct {
|
||||||
type fakeDB struct {
|
type fakeDB struct {
|
||||||
name string
|
name string
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
free []*fakeConn
|
free []*fakeConn
|
||||||
tables map[string]*table
|
tables map[string]*table
|
||||||
|
badConn bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type table struct {
|
type table struct {
|
||||||
|
|
@ -83,6 +84,7 @@ type fakeConn struct {
|
||||||
stmtsMade int
|
stmtsMade int
|
||||||
stmtsClosed int
|
stmtsClosed int
|
||||||
numPrepare int
|
numPrepare int
|
||||||
|
bad bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeConn) incrStat(v *int) {
|
func (c *fakeConn) incrStat(v *int) {
|
||||||
|
|
@ -122,7 +124,9 @@ func init() {
|
||||||
|
|
||||||
// Supports dsn forms:
|
// Supports dsn forms:
|
||||||
// <dbname>
|
// <dbname>
|
||||||
// <dbname>;<opts> (no currently supported options)
|
// <dbname>;<opts> (only currently supported option is `badConn`,
|
||||||
|
// which causes driver.ErrBadConn to be returned on
|
||||||
|
// every other conn.Begin())
|
||||||
func (d *fakeDriver) Open(dsn string) (driver.Conn, error) {
|
func (d *fakeDriver) Open(dsn string) (driver.Conn, error) {
|
||||||
parts := strings.Split(dsn, ";")
|
parts := strings.Split(dsn, ";")
|
||||||
if len(parts) < 1 {
|
if len(parts) < 1 {
|
||||||
|
|
@ -135,7 +139,12 @@ func (d *fakeDriver) Open(dsn string) (driver.Conn, error) {
|
||||||
d.mu.Lock()
|
d.mu.Lock()
|
||||||
d.openCount++
|
d.openCount++
|
||||||
d.mu.Unlock()
|
d.mu.Unlock()
|
||||||
return &fakeConn{db: db}, nil
|
conn := &fakeConn{db: db}
|
||||||
|
|
||||||
|
if len(parts) >= 2 && parts[1] == "badConn" {
|
||||||
|
conn.bad = true
|
||||||
|
}
|
||||||
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *fakeDriver) getDB(name string) *fakeDB {
|
func (d *fakeDriver) getDB(name string) *fakeDB {
|
||||||
|
|
@ -199,7 +208,20 @@ func (db *fakeDB) columnType(table, column string) (typ string, ok bool) {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *fakeConn) isBad() bool {
|
||||||
|
// if not simulating bad conn, do nothing
|
||||||
|
if !c.bad {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// alternate between bad conn and not bad conn
|
||||||
|
c.db.badConn = !c.db.badConn
|
||||||
|
return c.db.badConn
|
||||||
|
}
|
||||||
|
|
||||||
func (c *fakeConn) Begin() (driver.Tx, error) {
|
func (c *fakeConn) Begin() (driver.Tx, error) {
|
||||||
|
if c.isBad() {
|
||||||
|
return nil, driver.ErrBadConn
|
||||||
|
}
|
||||||
if c.currTx != nil {
|
if c.currTx != nil {
|
||||||
return nil, errors.New("already in a transaction")
|
return nil, errors.New("already in a transaction")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -402,6 +402,39 @@ func TestTxQueryInvalid(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests fix for issue 4433, that retries in Begin happen when
|
||||||
|
// conn.Begin() returns ErrBadConn
|
||||||
|
func TestTxErrBadConn(t *testing.T) {
|
||||||
|
db, err := Open("test", fakeDBName+";badConn")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Open: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := db.Exec("WIPE"); err != nil {
|
||||||
|
t.Fatalf("exec wipe: %v", err)
|
||||||
|
}
|
||||||
|
defer closeDB(t, db)
|
||||||
|
exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
|
||||||
|
stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Stmt, err = %v, %v", stmt, err)
|
||||||
|
}
|
||||||
|
defer stmt.Close()
|
||||||
|
tx, err := db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Begin = %v", err)
|
||||||
|
}
|
||||||
|
txs := tx.Stmt(stmt)
|
||||||
|
defer txs.Close()
|
||||||
|
_, err = txs.Exec("Bobby", 7)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Exec = %v", err)
|
||||||
|
}
|
||||||
|
err = tx.Commit()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Commit = %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Tests fix for issue 2542, that we release a lock when querying on
|
// Tests fix for issue 2542, that we release a lock when querying on
|
||||||
// a closed connection.
|
// a closed connection.
|
||||||
func TestIssue2542Deadlock(t *testing.T) {
|
func TestIssue2542Deadlock(t *testing.T) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue