Skip to content

Commit

Permalink
test: Implement TestContextCancelQueryWhileScan
Browse files Browse the repository at this point in the history
  • Loading branch information
vmg committed Apr 3, 2019
1 parent c0f6b44 commit 262d84d
Showing 1 changed file with 55 additions and 0 deletions.
55 changes: 55 additions & 0 deletions driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2938,3 +2938,58 @@ func TestValuerWithValueReceiverGivenNilValue(t *testing.T) {
// This test will panic on the INSERT if ConvertValue() does not check for typed nil before calling Value()
})
}

// TestRawBytesAreNotModified checks for a race condition that arises when a query context
// is canceled while a user is calling rows.Scan. This is a more stringent test than the one
// proposed in https://github.com/golang/go/issues/23519. Here we're explicitly using
// `sql.RawBytes` to check the contents of our internal buffers are not modified after an implicit
// call to `Rows.Close`, so Context cancellation should **not** invalidate the backing buffers.
func TestRawBytesAreNotModified(t *testing.T) {
const blob = "abcdefghijklmnop"
const contextRaceIterations = 10
const blobSize = 3000
const insertRows = 64

var sqlBlobs = [2]string{
strings.Repeat(blob, blobSize/len(blob)),
strings.Repeat(strings.ToUpper(blob), blobSize/len(blob)),
}

runTests(t, dsn, func(dbt *DBTest) {
dbt.mustExec("CREATE TABLE test (id int, value BLOB) CHARACTER SET utf8")
for i := 0; i < insertRows; i++ {
dbt.mustExec("INSERT INTO test VALUES (?, ?)", i+1, sqlBlobs[i&1])
}

for i := 0; i < contextRaceIterations; i++ {
func() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

rows, err := dbt.db.QueryContext(ctx, `SELECT id, value FROM test`)
if err != nil {
t.Fatal(err)
}

var b int
var raw sql.RawBytes
for rows.Next() {
if err := rows.Scan(&b, &raw); err != nil {
t.Fatal(err)
}

before := string(raw)
// Ensure cancelling the query does not corrupt the contents of `raw`
cancel()
time.Sleep(5 * time.Millisecond)
after := string(raw)

if before != after {
t.Fatal("the backing storage for sql.RawBytes has been modified")
}
}
rows.Close()
}()
}
})
}

0 comments on commit 262d84d

Please sign in to comment.