Files

186 lines
4.4 KiB
Go
Raw Permalink Normal View History

2024-11-29 15:51:51 +00:00
//go:build linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock || sqlite3_dotlk
2023-02-22 14:19:56 +00:00
package bradfitz
// Adapted from: https://github.com/bradfitz/go-sql-test
2023-02-18 12:20:42 +00:00
import (
"database/sql"
"fmt"
"math/rand"
"path/filepath"
2023-02-22 14:19:56 +00:00
"sync"
2023-02-18 12:20:42 +00:00
"testing"
_ "github.com/ncruces/go-sqlite3/driver"
_ "github.com/ncruces/go-sqlite3/embed"
2024-06-02 10:33:20 +01:00
_ "github.com/ncruces/go-sqlite3/internal/testcfg"
2023-02-18 12:20:42 +00:00
)
type Tester interface {
RunTest(*testing.T, func(params))
}
var (
sqlite Tester = sqliteDB{}
)
const TablePrefix = "gosqltest_"
type sqliteDB struct{}
type params struct {
dbType Tester
*testing.T
*sql.DB
}
2025-08-13 03:31:12 +01:00
func (t params) mustExec(sql string, args ...any) sql.Result {
2023-02-18 12:20:42 +00:00
res, err := t.DB.Exec(sql, args...)
if err != nil {
t.Fatalf("Error running %q: %v", sql, err)
}
return res
}
func (sqliteDB) RunTest(t *testing.T, fn func(params)) {
2023-02-23 02:22:57 +00:00
db, err := sql.Open("sqlite3", "file:"+
2024-08-05 21:25:47 +01:00
filepath.ToSlash(filepath.Join(t.TempDir(), "foo.db"))+
2023-06-24 02:18:56 +01:00
"?_pragma=busy_timeout(10000)&_pragma=synchronous(off)")
2023-02-18 12:20:42 +00:00
if err != nil {
t.Fatalf("foo.db open fail: %v", err)
}
fn(params{sqlite, t, db})
if err := db.Close(); err != nil {
t.Fatalf("foo.db close fail: %v", err)
}
}
func TestBlobs_SQLite(t *testing.T) { sqlite.RunTest(t, testBlobs) }
func testBlobs(t params) {
var blob = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
2023-02-22 14:19:56 +00:00
t.mustExec("create table " + TablePrefix + "foo (id integer primary key, bar blob)")
t.mustExec("insert into "+TablePrefix+"foo (id, bar) values(?,?)", 0, blob)
2023-02-18 12:20:42 +00:00
want := fmt.Sprintf("%x", blob)
b := make([]byte, 16)
2023-02-22 14:19:56 +00:00
err := t.QueryRow("select bar from "+TablePrefix+"foo where id = ?", 0).Scan(&b)
2023-02-18 12:20:42 +00:00
got := fmt.Sprintf("%x", b)
if err != nil {
t.Errorf("[]byte scan: %v", err)
} else if got != want {
t.Errorf("for []byte, got %q; want %q", got, want)
}
2023-02-22 14:19:56 +00:00
err = t.QueryRow("select bar from "+TablePrefix+"foo where id = ?", 0).Scan(&got)
2023-02-18 12:20:42 +00:00
want = string(blob)
if err != nil {
t.Errorf("string scan: %v", err)
} else if got != want {
t.Errorf("for string, got %q; want %q", got, want)
}
}
func TestManyQueryRow_SQLite(t *testing.T) { sqlite.RunTest(t, testManyQueryRow) }
func testManyQueryRow(t params) {
if testing.Short() {
2023-02-22 14:19:56 +00:00
t.Skip("skipping in short mode")
2023-02-18 12:20:42 +00:00
}
t.mustExec("create table " + TablePrefix + "foo (id integer primary key, name varchar(50))")
2023-02-22 14:19:56 +00:00
t.mustExec("insert into "+TablePrefix+"foo (id, name) values(?,?)", 1, "bob")
2023-02-18 12:20:42 +00:00
var name string
2025-01-24 10:46:05 +00:00
for i := range 10000 {
2023-02-22 14:19:56 +00:00
err := t.QueryRow("select name from "+TablePrefix+"foo where id = ?", 1).Scan(&name)
2023-02-18 12:20:42 +00:00
if err != nil || name != "bob" {
t.Fatalf("on query %d: err=%v, name=%q", i, err, name)
}
}
}
func TestTxQuery_SQLite(t *testing.T) { sqlite.RunTest(t, testTxQuery) }
func testTxQuery(t params) {
tx, err := t.Begin()
if err != nil {
t.Fatal(err)
}
defer tx.Rollback()
2023-02-23 02:22:57 +00:00
_, err = tx.Exec("create table " + TablePrefix + "foo (id integer primary key, name varchar(50))")
2023-02-18 12:20:42 +00:00
if err != nil {
t.Logf("cannot drop table "+TablePrefix+"foo: %s", err)
}
2023-02-22 14:19:56 +00:00
_, err = tx.Exec("insert into "+TablePrefix+"foo (id, name) values(?,?)", 1, "bob")
2023-02-18 12:20:42 +00:00
if err != nil {
t.Fatal(err)
}
2023-02-22 14:19:56 +00:00
r, err := tx.Query("select name from "+TablePrefix+"foo where id = ?", 1)
2023-02-18 12:20:42 +00:00
if err != nil {
t.Fatal(err)
}
defer r.Close()
if !r.Next() {
if r.Err() != nil {
t.Fatal(err)
}
2023-03-21 00:13:12 +00:00
t.Fatal("expected one row")
2023-02-18 12:20:42 +00:00
}
var name string
err = r.Scan(&name)
if err != nil {
t.Fatal(err)
}
}
func TestPreparedStmt_SQLite(t *testing.T) { sqlite.RunTest(t, testPreparedStmt) }
func testPreparedStmt(t params) {
2023-02-19 16:16:13 +00:00
if testing.Short() {
2023-02-22 14:19:56 +00:00
t.Skip("skipping in short mode")
2023-02-19 16:16:13 +00:00
}
2023-02-18 12:20:42 +00:00
t.mustExec("CREATE TABLE " + TablePrefix + "t (count INT)")
sel, err := t.Prepare("SELECT count FROM " + TablePrefix + "t ORDER BY count DESC")
if err != nil {
t.Fatalf("prepare 1: %v", err)
}
2023-02-22 14:19:56 +00:00
ins, err := t.Prepare("INSERT INTO " + TablePrefix + "t (count) VALUES (?)")
2023-02-18 12:20:42 +00:00
if err != nil {
t.Fatalf("prepare 2: %v", err)
}
for n := 1; n <= 3; n++ {
if _, err := ins.Exec(n); err != nil {
t.Fatalf("insert(%d) = %v", n, err)
}
}
const nRuns = 10
2023-02-22 14:19:56 +00:00
var wg sync.WaitGroup
2025-01-24 10:46:05 +00:00
for range nRuns {
2023-02-22 14:19:56 +00:00
wg.Add(1)
2023-02-18 12:20:42 +00:00
go func() {
2023-02-22 14:19:56 +00:00
defer wg.Done()
2025-01-24 10:46:05 +00:00
for range 10 {
2023-02-18 12:20:42 +00:00
count := 0
if err := sel.QueryRow().Scan(&count); err != nil && err != sql.ErrNoRows {
t.Errorf("Query: %v", err)
return
}
if _, err := ins.Exec(rand.Intn(100)); err != nil {
t.Errorf("Insert: %v", err)
return
}
}
}()
}
2023-02-22 14:19:56 +00:00
wg.Wait()
2023-02-18 12:20:42 +00:00
}