aboutsummaryrefslogtreecommitdiff
path: root/sqlite3_go18_test.go
diff options
context:
space:
mode:
authormattn <mattn.jp@gmail.com>2019-11-19 01:19:53 +0900
committerGitHub <noreply@github.com>2019-11-19 01:19:53 +0900
commit590d44c02bca83987d23f6eab75e6d0ddf95f644 (patch)
tree2d1979323f14971f927380c6a687a523aa033486 /sqlite3_go18_test.go
parentMerge pull request #760 from mattn/sqlite-amalgamation-3300100 (diff)
parentFix context cancellation racy handling (diff)
downloadgolite-590d44c02bca83987d23f6eab75e6d0ddf95f644.tar.gz
golite-590d44c02bca83987d23f6eab75e6d0ddf95f644.tar.xz
Merge pull request #744 from azavorotnii/ctx_cancel
Fix context cancellation racy handling
Diffstat (limited to 'sqlite3_go18_test.go')
-rw-r--r--sqlite3_go18_test.go88
1 files changed, 88 insertions, 0 deletions
diff --git a/sqlite3_go18_test.go b/sqlite3_go18_test.go
index f295bb6..cfc89b0 100644
--- a/sqlite3_go18_test.go
+++ b/sqlite3_go18_test.go
@@ -14,6 +14,7 @@ import (
"io/ioutil"
"math/rand"
"os"
+ "sync"
"testing"
"time"
)
@@ -135,6 +136,93 @@ func TestShortTimeout(t *testing.T) {
}
}
+func TestQueryRowContextCancel(t *testing.T) {
+ srcTempFilename := TempFilename(t)
+ defer os.Remove(srcTempFilename)
+
+ db, err := sql.Open("sqlite3", srcTempFilename)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer db.Close()
+ initDatabase(t, db, 100)
+
+ const query = `SELECT key_id FROM test_table ORDER BY key2 ASC`
+ var keyID string
+ unexpectedErrors := make(map[string]int)
+ for i := 0; i < 10000; i++ {
+ ctx, cancel := context.WithCancel(context.Background())
+ row := db.QueryRowContext(ctx, query)
+
+ cancel()
+ // it is fine to get "nil" as context cancellation can be handled with delay
+ if err := row.Scan(&keyID); err != nil && err != context.Canceled {
+ if err.Error() == "sql: Rows are closed" {
+ // see https://github.com/golang/go/issues/24431
+ // fixed in 1.11.1 to properly return context error
+ continue
+ }
+ unexpectedErrors[err.Error()]++
+ }
+ }
+ for errText, count := range unexpectedErrors {
+ t.Error(errText, count)
+ }
+}
+
+func TestQueryRowContextCancelParallel(t *testing.T) {
+ srcTempFilename := TempFilename(t)
+ defer os.Remove(srcTempFilename)
+
+ db, err := sql.Open("sqlite3", srcTempFilename)
+ if err != nil {
+ t.Fatal(err)
+ }
+ db.SetMaxOpenConns(10)
+ db.SetMaxIdleConns(5)
+
+ defer db.Close()
+ initDatabase(t, db, 100)
+
+ const query = `SELECT key_id FROM test_table ORDER BY key2 ASC`
+ wg := sync.WaitGroup{}
+ defer wg.Wait()
+
+ testCtx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ for i := 0; i < 50; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+
+ var keyID string
+ for {
+ select {
+ case <-testCtx.Done():
+ return
+ default:
+ }
+ ctx, cancel := context.WithCancel(context.Background())
+ row := db.QueryRowContext(ctx, query)
+
+ cancel()
+ _ = row.Scan(&keyID) // see TestQueryRowContextCancel
+ }
+ }()
+ }
+
+ var keyID string
+ for i := 0; i < 10000; i++ {
+ // note that testCtx is not cancelled during query execution
+ row := db.QueryRowContext(testCtx, query)
+
+ if err := row.Scan(&keyID); err != nil {
+ t.Fatal(i, err)
+ }
+ }
+}
+
func TestExecCancel(t *testing.T) {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {