aboutsummaryrefslogtreecommitdiff
path: root/src/database/sql/sql_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/database/sql/sql_test.go')
-rw-r--r--src/database/sql/sql_test.go57
1 files changed, 37 insertions, 20 deletions
diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go
index e14c66de22..8441aff4bc 100644
--- a/src/database/sql/sql_test.go
+++ b/src/database/sql/sql_test.go
@@ -153,8 +153,13 @@ func closeDB(t testing.TB, db *DB) {
if err != nil {
t.Fatalf("error closing DB: %v", err)
}
- if count := db.numOpenConns(); count != 0 {
- t.Fatalf("%d connections still open after closing DB", count)
+
+ var numOpen int
+ if !waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
+ numOpen = db.numOpenConns()
+ return numOpen == 0
+ }) {
+ t.Fatalf("%d connections still open after closing DB", numOpen)
}
}
@@ -276,6 +281,7 @@ func TestQuery(t *testing.T) {
}
}
+// TestQueryContext tests canceling the context while scanning the rows.
func TestQueryContext(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
@@ -297,7 +303,7 @@ func TestQueryContext(t *testing.T) {
for rows.Next() {
if index == 2 {
cancel()
- time.Sleep(10 * time.Millisecond)
+ waitForRowsClose(t, rows, 5*time.Second)
}
var r row
err = rows.Scan(&r.age, &r.name)
@@ -331,6 +337,7 @@ func TestQueryContext(t *testing.T) {
// And verify that the final rows.Next() call, which hit EOF,
// also closed the rows connection.
+ waitForRowsClose(t, rows, 5*time.Second)
waitForFree(t, db, 5*time.Second, 1)
if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
t.Errorf("executed %d Prepare statements; want 1", prepares)
@@ -360,12 +367,26 @@ func waitForFree(t *testing.T, db *DB, maxWait time.Duration, want int) {
}
}
+func waitForRowsClose(t *testing.T, rows *Rows, maxWait time.Duration) {
+ if !waitCondition(maxWait, 5*time.Millisecond, func() bool {
+ rows.closemu.RLock()
+ defer rows.closemu.RUnlock()
+ return rows.closed
+ }) {
+ t.Fatal("failed to close rows")
+ }
+}
+
+// TestQueryContextWait ensures that rows and all internal statements are closed when
+// a query context is closed during execution.
func TestQueryContextWait(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
prepares0 := numPrepares(t, db)
- ctx, cancel := context.WithTimeout(context.Background(), 15*time.Millisecond)
+ // TODO(kardianos): convert this from using a timeout to using an explicit
+ // cancel when the query signals that is is "executing" the query.
+ ctx, cancel := context.WithTimeout(context.Background(), 300*time.Millisecond)
defer cancel()
// This will trigger the *fakeConn.Prepare method which will take time
@@ -379,10 +400,15 @@ func TestQueryContextWait(t *testing.T) {
// Verify closed rows connection after error condition.
waitForFree(t, db, 5*time.Second, 1)
if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
- t.Errorf("executed %d Prepare statements; want 1", prepares)
+ // TODO(kardianos): if the context timeouts before the db.QueryContext
+ // executes this check may fail. After adjusting how the context
+ // is canceled above revert this back to a Fatal error.
+ t.Logf("executed %d Prepare statements; want 1", prepares)
}
}
+// TestTxContextWait tests the transaction behavior when the tx context is canceled
+// during execution of the query.
func TestTxContextWait(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
@@ -392,6 +418,10 @@ func TestTxContextWait(t *testing.T) {
tx, err := db.BeginTx(ctx, nil)
if err != nil {
+ // Guard against the context being canceled before BeginTx completes.
+ if err == context.DeadlineExceeded {
+ t.Skip("tx context canceled prior to first use")
+ }
t.Fatal(err)
}
@@ -404,12 +434,6 @@ func TestTxContextWait(t *testing.T) {
}
waitForFree(t, db, 5*time.Second, 0)
-
- // Ensure the dropped connection allows more connections to be made.
- // Checked on DB Close.
- waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
- return db.numOpenConns() == 0
- })
}
func TestMultiResultSetQuery(t *testing.T) {
@@ -2740,7 +2764,6 @@ func TestIssue18429(t *testing.T) {
}()
}
wg.Wait()
- time.Sleep(milliWait * 3 * time.Millisecond)
}
// TestIssue18719 closes the context right before use. The sql.driverConn
@@ -2783,14 +2806,8 @@ func TestIssue18719(t *testing.T) {
// Do not explicitly rollback. The rollback will happen from the
// canceled context.
- // Wait for connections to return to pool.
- var numOpen int
- if !waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
- numOpen = db.numOpenConns()
- return numOpen == 0
- }) {
- t.Fatalf("open conns after hitting EOF = %d; want 0", numOpen)
- }
+ cancel()
+ waitForRowsClose(t, rows, 5*time.Second)
}
func TestConcurrency(t *testing.T) {