github.com/ncruces/go-sqlite3@v0.15.1-0.20240520133447-53eef1510ff0/tests/bradfitz/sql_test.go (about)

     1  //go:build (linux || darwin || windows || freebsd || illumos) && !sqlite3_nosys
     2  
     3  package bradfitz
     4  
     5  // Adapted from: https://github.com/bradfitz/go-sql-test
     6  
     7  import (
     8  	"database/sql"
     9  	"fmt"
    10  	"math/rand"
    11  	"path/filepath"
    12  	"sync"
    13  	"testing"
    14  
    15  	_ "github.com/ncruces/go-sqlite3/driver"
    16  	_ "github.com/ncruces/go-sqlite3/embed"
    17  	_ "github.com/ncruces/go-sqlite3/tests/testcfg"
    18  )
    19  
    20  type Tester interface {
    21  	RunTest(*testing.T, func(params))
    22  }
    23  
    24  var (
    25  	sqlite Tester = sqliteDB{}
    26  )
    27  
    28  const TablePrefix = "gosqltest_"
    29  
    30  type sqliteDB struct{}
    31  
    32  type params struct {
    33  	dbType Tester
    34  	*testing.T
    35  	*sql.DB
    36  }
    37  
    38  func (t params) mustExec(sql string, args ...interface{}) sql.Result {
    39  	res, err := t.DB.Exec(sql, args...)
    40  	if err != nil {
    41  		t.Fatalf("Error running %q: %v", sql, err)
    42  	}
    43  	return res
    44  }
    45  
    46  func (sqliteDB) RunTest(t *testing.T, fn func(params)) {
    47  	db, err := sql.Open("sqlite3", "file:"+
    48  		filepath.Join(t.TempDir(), "foo.db")+
    49  		"?_pragma=busy_timeout(10000)&_pragma=synchronous(off)")
    50  	if err != nil {
    51  		t.Fatalf("foo.db open fail: %v", err)
    52  	}
    53  	fn(params{sqlite, t, db})
    54  	if err := db.Close(); err != nil {
    55  		t.Fatalf("foo.db close fail: %v", err)
    56  	}
    57  }
    58  
    59  func TestBlobs_SQLite(t *testing.T) { sqlite.RunTest(t, testBlobs) }
    60  
    61  func testBlobs(t params) {
    62  	var blob = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
    63  	t.mustExec("create table " + TablePrefix + "foo (id integer primary key, bar blob)")
    64  	t.mustExec("insert into "+TablePrefix+"foo (id, bar) values(?,?)", 0, blob)
    65  
    66  	want := fmt.Sprintf("%x", blob)
    67  
    68  	b := make([]byte, 16)
    69  	err := t.QueryRow("select bar from "+TablePrefix+"foo where id = ?", 0).Scan(&b)
    70  	got := fmt.Sprintf("%x", b)
    71  	if err != nil {
    72  		t.Errorf("[]byte scan: %v", err)
    73  	} else if got != want {
    74  		t.Errorf("for []byte, got %q; want %q", got, want)
    75  	}
    76  
    77  	err = t.QueryRow("select bar from "+TablePrefix+"foo where id = ?", 0).Scan(&got)
    78  	want = string(blob)
    79  	if err != nil {
    80  		t.Errorf("string scan: %v", err)
    81  	} else if got != want {
    82  		t.Errorf("for string, got %q; want %q", got, want)
    83  	}
    84  }
    85  
    86  func TestManyQueryRow_SQLite(t *testing.T) { sqlite.RunTest(t, testManyQueryRow) }
    87  
    88  func testManyQueryRow(t params) {
    89  	if testing.Short() {
    90  		t.Skip("skipping in short mode")
    91  	}
    92  	t.mustExec("create table " + TablePrefix + "foo (id integer primary key, name varchar(50))")
    93  	t.mustExec("insert into "+TablePrefix+"foo (id, name) values(?,?)", 1, "bob")
    94  	var name string
    95  	for i := 0; i < 10000; i++ {
    96  		err := t.QueryRow("select name from "+TablePrefix+"foo where id = ?", 1).Scan(&name)
    97  		if err != nil || name != "bob" {
    98  			t.Fatalf("on query %d: err=%v, name=%q", i, err, name)
    99  		}
   100  	}
   101  }
   102  
   103  func TestTxQuery_SQLite(t *testing.T) { sqlite.RunTest(t, testTxQuery) }
   104  
   105  func testTxQuery(t params) {
   106  	tx, err := t.Begin()
   107  	if err != nil {
   108  		t.Fatal(err)
   109  	}
   110  	defer tx.Rollback()
   111  
   112  	_, err = tx.Exec("create table " + TablePrefix + "foo (id integer primary key, name varchar(50))")
   113  	if err != nil {
   114  		t.Logf("cannot drop table "+TablePrefix+"foo: %s", err)
   115  	}
   116  
   117  	_, err = tx.Exec("insert into "+TablePrefix+"foo (id, name) values(?,?)", 1, "bob")
   118  	if err != nil {
   119  		t.Fatal(err)
   120  	}
   121  
   122  	r, err := tx.Query("select name from "+TablePrefix+"foo where id = ?", 1)
   123  	if err != nil {
   124  		t.Fatal(err)
   125  	}
   126  	defer r.Close()
   127  
   128  	if !r.Next() {
   129  		if r.Err() != nil {
   130  			t.Fatal(err)
   131  		}
   132  		t.Fatal("expected one row")
   133  	}
   134  
   135  	var name string
   136  	err = r.Scan(&name)
   137  	if err != nil {
   138  		t.Fatal(err)
   139  	}
   140  }
   141  
   142  func TestPreparedStmt_SQLite(t *testing.T) { sqlite.RunTest(t, testPreparedStmt) }
   143  
   144  func testPreparedStmt(t params) {
   145  	if testing.Short() {
   146  		t.Skip("skipping in short mode")
   147  	}
   148  
   149  	t.mustExec("CREATE TABLE " + TablePrefix + "t (count INT)")
   150  	sel, err := t.Prepare("SELECT count FROM " + TablePrefix + "t ORDER BY count DESC")
   151  	if err != nil {
   152  		t.Fatalf("prepare 1: %v", err)
   153  	}
   154  	ins, err := t.Prepare("INSERT INTO " + TablePrefix + "t (count) VALUES (?)")
   155  	if err != nil {
   156  		t.Fatalf("prepare 2: %v", err)
   157  	}
   158  
   159  	for n := 1; n <= 3; n++ {
   160  		if _, err := ins.Exec(n); err != nil {
   161  			t.Fatalf("insert(%d) = %v", n, err)
   162  		}
   163  	}
   164  
   165  	const nRuns = 10
   166  	var wg sync.WaitGroup
   167  	for i := 0; i < nRuns; i++ {
   168  		wg.Add(1)
   169  		go func() {
   170  			defer wg.Done()
   171  			for j := 0; j < 10; j++ {
   172  				count := 0
   173  				if err := sel.QueryRow().Scan(&count); err != nil && err != sql.ErrNoRows {
   174  					t.Errorf("Query: %v", err)
   175  					return
   176  				}
   177  				if _, err := ins.Exec(rand.Intn(100)); err != nil {
   178  					t.Errorf("Insert: %v", err)
   179  					return
   180  				}
   181  			}
   182  		}()
   183  	}
   184  	wg.Wait()
   185  }