mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
database/sql: fix TestPendingConnsAfterErr
TestPendingConnsAfterErr showed a failure on slower systems. Wait and check for the database to close all connections before pronouncing failure. A more careful method was attempted but the connection pool behavior is too dependent on the scheduler behavior to be predictable. Fixes #15684 Change-Id: Iafdbc90ba51170c76a079db04c3d5452047433a4 Reviewed-on: https://go-review.googlesource.com/33418 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
199d410df5
commit
e12f6ee0ab
1 changed files with 31 additions and 9 deletions
|
|
@ -1438,7 +1438,11 @@ func TestPendingConnsAfterErr(t *testing.T) {
|
||||||
tryOpen = maxOpen*2 + 2
|
tryOpen = maxOpen*2 + 2
|
||||||
)
|
)
|
||||||
|
|
||||||
db := newTestDB(t, "people")
|
// No queries will be run.
|
||||||
|
db, err := Open("test", fakeDBName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Open: %v", err)
|
||||||
|
}
|
||||||
defer closeDB(t, db)
|
defer closeDB(t, db)
|
||||||
defer func() {
|
defer func() {
|
||||||
for k, v := range db.lastPut {
|
for k, v := range db.lastPut {
|
||||||
|
|
@ -1450,29 +1454,29 @@ func TestPendingConnsAfterErr(t *testing.T) {
|
||||||
db.SetMaxIdleConns(0)
|
db.SetMaxIdleConns(0)
|
||||||
|
|
||||||
errOffline := errors.New("db offline")
|
errOffline := errors.New("db offline")
|
||||||
|
|
||||||
defer func() { setHookOpenErr(nil) }()
|
defer func() { setHookOpenErr(nil) }()
|
||||||
|
|
||||||
errs := make(chan error, tryOpen)
|
errs := make(chan error, tryOpen)
|
||||||
|
|
||||||
unblock := make(chan struct{})
|
var opening sync.WaitGroup
|
||||||
|
opening.Add(tryOpen)
|
||||||
|
|
||||||
setHookOpenErr(func() error {
|
setHookOpenErr(func() error {
|
||||||
<-unblock // block until all connections are in flight
|
// Wait for all connections to enqueue.
|
||||||
|
opening.Wait()
|
||||||
return errOffline
|
return errOffline
|
||||||
})
|
})
|
||||||
|
|
||||||
var opening sync.WaitGroup
|
|
||||||
opening.Add(tryOpen)
|
|
||||||
for i := 0; i < tryOpen; i++ {
|
for i := 0; i < tryOpen; i++ {
|
||||||
go func() {
|
go func() {
|
||||||
opening.Done() // signal one connection is in flight
|
opening.Done() // signal one connection is in flight
|
||||||
_, err := db.Exec("INSERT|people|name=Julia,age=19")
|
_, err := db.Exec("will never run")
|
||||||
errs <- err
|
errs <- err
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
opening.Wait() // wait for all workers to begin running
|
opening.Wait() // wait for all workers to begin running
|
||||||
time.Sleep(10 * time.Millisecond) // make extra sure all workers are blocked
|
|
||||||
close(unblock) // let all workers proceed
|
|
||||||
|
|
||||||
const timeout = 5 * time.Second
|
const timeout = 5 * time.Second
|
||||||
to := time.NewTimer(timeout)
|
to := time.NewTimer(timeout)
|
||||||
|
|
@ -1489,6 +1493,24 @@ func TestPendingConnsAfterErr(t *testing.T) {
|
||||||
t.Fatalf("orphaned connection request(s), still waiting after %v", timeout)
|
t.Fatalf("orphaned connection request(s), still waiting after %v", timeout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait a reasonable time for the database to close all connections.
|
||||||
|
tick := time.NewTicker(3 * time.Millisecond)
|
||||||
|
defer tick.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-tick.C:
|
||||||
|
db.mu.Lock()
|
||||||
|
if db.numOpen == 0 {
|
||||||
|
db.mu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
db.mu.Unlock()
|
||||||
|
case <-to.C:
|
||||||
|
// Closing the database will check for numOpen and fail the test.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSingleOpenConn(t *testing.T) {
|
func TestSingleOpenConn(t *testing.T) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue