github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/mattn/go-sqlite3/sqlite3_test/sqltest.go (about) 1 package sqlite3_test 2 3 import ( 4 "database/sql" 5 "fmt" 6 "math/rand" 7 "regexp" 8 "strconv" 9 "sync" 10 "testing" 11 "time" 12 ) 13 14 type Dialect int 15 16 const ( 17 SQLITE Dialect = iota 18 POSTGRESQL 19 MYSQL 20 ) 21 22 type DB struct { 23 *testing.T 24 *sql.DB 25 dialect Dialect 26 once sync.Once 27 } 28 29 var db *DB 30 31 // the following tables will be created and dropped during the test 32 var testTables = []string{"foo", "bar", "t", "bench"} 33 34 var tests = []testing.InternalTest{ 35 {"TestBlobs", TestBlobs}, 36 {"TestManyQueryRow", TestManyQueryRow}, 37 {"TestTxQuery", TestTxQuery}, 38 {"TestPreparedStmt", TestPreparedStmt}, 39 } 40 41 var benchmarks = []testing.InternalBenchmark{ 42 {"BenchmarkExec", BenchmarkExec}, 43 {"BenchmarkQuery", BenchmarkQuery}, 44 {"BenchmarkParams", BenchmarkParams}, 45 {"BenchmarkStmt", BenchmarkStmt}, 46 {"BenchmarkRows", BenchmarkRows}, 47 {"BenchmarkStmtRows", BenchmarkStmtRows}, 48 } 49 50 // RunTests runs the SQL test suite 51 func RunTests(t *testing.T, d *sql.DB, dialect Dialect) { 52 db = &DB{t, d, dialect, sync.Once{}} 53 testing.RunTests(func(string, string) (bool, error) { return true, nil }, tests) 54 55 if !testing.Short() { 56 for _, b := range benchmarks { 57 fmt.Printf("%-20s", b.Name) 58 r := testing.Benchmark(b.F) 59 fmt.Printf("%10d %10.0f req/s\n", r.N, float64(r.N)/r.T.Seconds()) 60 } 61 } 62 db.tearDown() 63 } 64 65 func (db *DB) mustExec(sql string, args ...interface{}) sql.Result { 66 res, err := db.Exec(sql, args...) 67 if err != nil { 68 db.Fatalf("Error running %q: %v", sql, err) 69 } 70 return res 71 } 72 73 func (db *DB) tearDown() { 74 for _, tbl := range testTables { 75 switch db.dialect { 76 case SQLITE: 77 db.mustExec("drop table if exists " + tbl) 78 case MYSQL, POSTGRESQL: 79 db.mustExec("drop table if exists " + tbl) 80 default: 81 db.Fatal("unkown dialect") 82 } 83 } 84 } 85 86 // q replaces ? parameters if needed 87 func (db *DB) q(sql string) string { 88 switch db.dialect { 89 case POSTGRESQL: // repace with $1, $2, .. 90 qrx := regexp.MustCompile(`\?`) 91 n := 0 92 return qrx.ReplaceAllStringFunc(sql, func(string) string { 93 n++ 94 return "$" + strconv.Itoa(n) 95 }) 96 } 97 return sql 98 } 99 100 func (db *DB) blobType(size int) string { 101 switch db.dialect { 102 case SQLITE: 103 return fmt.Sprintf("blob[%d]", size) 104 case POSTGRESQL: 105 return "bytea" 106 case MYSQL: 107 return fmt.Sprintf("VARBINARY(%d)", size) 108 } 109 panic("unkown dialect") 110 } 111 112 func (db *DB) serialPK() string { 113 switch db.dialect { 114 case SQLITE: 115 return "integer primary key autoincrement" 116 case POSTGRESQL: 117 return "serial primary key" 118 case MYSQL: 119 return "integer primary key auto_increment" 120 } 121 panic("unkown dialect") 122 } 123 124 func (db *DB) now() string { 125 switch db.dialect { 126 case SQLITE: 127 return "datetime('now')" 128 case POSTGRESQL: 129 return "now()" 130 case MYSQL: 131 return "now()" 132 } 133 panic("unkown dialect") 134 } 135 136 func makeBench() { 137 if _, err := db.Exec("create table bench (n varchar(32), i integer, d double, s varchar(32), t datetime)"); err != nil { 138 panic(err) 139 } 140 st, err := db.Prepare("insert into bench values (?, ?, ?, ?, ?)") 141 if err != nil { 142 panic(err) 143 } 144 defer st.Close() 145 for i := 0; i < 100; i++ { 146 if _, err = st.Exec(nil, i, float64(i), fmt.Sprintf("%d", i), time.Now()); err != nil { 147 panic(err) 148 } 149 } 150 } 151 152 func TestResult(t *testing.T) { 153 db.tearDown() 154 db.mustExec("create temporary table test (id " + db.serialPK() + ", name varchar(10))") 155 156 for i := 1; i < 3; i++ { 157 r := db.mustExec(db.q("insert into test (name) values (?)"), fmt.Sprintf("row %d", i)) 158 n, err := r.RowsAffected() 159 if err != nil { 160 t.Fatal(err) 161 } 162 if n != 1 { 163 t.Errorf("got %v, want %v", n, 1) 164 } 165 n, err = r.LastInsertId() 166 if err != nil { 167 t.Fatal(err) 168 } 169 if n != int64(i) { 170 t.Errorf("got %v, want %v", n, i) 171 } 172 } 173 if _, err := db.Exec("error!"); err == nil { 174 t.Fatalf("expected error") 175 } 176 } 177 178 func TestBlobs(t *testing.T) { 179 db.tearDown() 180 var blob = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 181 db.mustExec("create table foo (id integer primary key, bar " + db.blobType(16) + ")") 182 db.mustExec(db.q("insert into foo (id, bar) values(?,?)"), 0, blob) 183 184 want := fmt.Sprintf("%x", blob) 185 186 b := make([]byte, 16) 187 err := db.QueryRow(db.q("select bar from foo where id = ?"), 0).Scan(&b) 188 got := fmt.Sprintf("%x", b) 189 if err != nil { 190 t.Errorf("[]byte scan: %v", err) 191 } else if got != want { 192 t.Errorf("for []byte, got %q; want %q", got, want) 193 } 194 195 err = db.QueryRow(db.q("select bar from foo where id = ?"), 0).Scan(&got) 196 want = string(blob) 197 if err != nil { 198 t.Errorf("string scan: %v", err) 199 } else if got != want { 200 t.Errorf("for string, got %q; want %q", got, want) 201 } 202 } 203 204 func TestManyQueryRow(t *testing.T) { 205 if testing.Short() { 206 t.Log("skipping in short mode") 207 return 208 } 209 db.tearDown() 210 db.mustExec("create table foo (id integer primary key, name varchar(50))") 211 db.mustExec(db.q("insert into foo (id, name) values(?,?)"), 1, "bob") 212 var name string 213 for i := 0; i < 10000; i++ { 214 err := db.QueryRow(db.q("select name from foo where id = ?"), 1).Scan(&name) 215 if err != nil || name != "bob" { 216 t.Fatalf("on query %d: err=%v, name=%q", i, err, name) 217 } 218 } 219 } 220 221 func TestTxQuery(t *testing.T) { 222 db.tearDown() 223 tx, err := db.Begin() 224 if err != nil { 225 t.Fatal(err) 226 } 227 defer tx.Rollback() 228 229 _, err = tx.Exec("create table foo (id integer primary key, name varchar(50))") 230 if err != nil { 231 t.Fatal(err) 232 } 233 234 _, err = tx.Exec(db.q("insert into foo (id, name) values(?,?)"), 1, "bob") 235 if err != nil { 236 t.Fatal(err) 237 } 238 239 r, err := tx.Query(db.q("select name from foo where id = ?"), 1) 240 if err != nil { 241 t.Fatal(err) 242 } 243 defer r.Close() 244 245 if !r.Next() { 246 if r.Err() != nil { 247 t.Fatal(err) 248 } 249 t.Fatal("expected one rows") 250 } 251 252 var name string 253 err = r.Scan(&name) 254 if err != nil { 255 t.Fatal(err) 256 } 257 } 258 259 func TestPreparedStmt(t *testing.T) { 260 db.tearDown() 261 db.mustExec("CREATE TABLE t (count INT)") 262 sel, err := db.Prepare("SELECT count FROM t ORDER BY count DESC") 263 if err != nil { 264 t.Fatalf("prepare 1: %v", err) 265 } 266 ins, err := db.Prepare(db.q("INSERT INTO t (count) VALUES (?)")) 267 if err != nil { 268 t.Fatalf("prepare 2: %v", err) 269 } 270 271 for n := 1; n <= 3; n++ { 272 if _, err := ins.Exec(n); err != nil { 273 t.Fatalf("insert(%d) = %v", n, err) 274 } 275 } 276 277 const nRuns = 10 278 var wg sync.WaitGroup 279 for i := 0; i < nRuns; i++ { 280 wg.Add(1) 281 go func() { 282 defer wg.Done() 283 for j := 0; j < 10; j++ { 284 count := 0 285 if err := sel.QueryRow().Scan(&count); err != nil && err != sql.ErrNoRows { 286 t.Errorf("Query: %v", err) 287 return 288 } 289 if _, err := ins.Exec(rand.Intn(100)); err != nil { 290 t.Errorf("Insert: %v", err) 291 return 292 } 293 } 294 }() 295 } 296 wg.Wait() 297 } 298 299 // Benchmarks need to use panic() since b.Error errors are lost when 300 // running via testing.Benchmark() I would like to run these via go 301 // test -bench but calling Benchmark() from a benchmark test 302 // currently hangs go. 303 304 func BenchmarkExec(b *testing.B) { 305 for i := 0; i < b.N; i++ { 306 if _, err := db.Exec("select 1"); err != nil { 307 panic(err) 308 } 309 } 310 } 311 312 func BenchmarkQuery(b *testing.B) { 313 for i := 0; i < b.N; i++ { 314 var n sql.NullString 315 var i int 316 var f float64 317 var s string 318 // var t time.Time 319 if err := db.QueryRow("select null, 1, 1.1, 'foo'").Scan(&n, &i, &f, &s); err != nil { 320 panic(err) 321 } 322 } 323 } 324 325 func BenchmarkParams(b *testing.B) { 326 for i := 0; i < b.N; i++ { 327 var n sql.NullString 328 var i int 329 var f float64 330 var s string 331 // var t time.Time 332 if err := db.QueryRow("select ?, ?, ?, ?", nil, 1, 1.1, "foo").Scan(&n, &i, &f, &s); err != nil { 333 panic(err) 334 } 335 } 336 } 337 338 func BenchmarkStmt(b *testing.B) { 339 st, err := db.Prepare("select ?, ?, ?, ?") 340 if err != nil { 341 panic(err) 342 } 343 defer st.Close() 344 345 for n := 0; n < b.N; n++ { 346 var n sql.NullString 347 var i int 348 var f float64 349 var s string 350 // var t time.Time 351 if err := st.QueryRow(nil, 1, 1.1, "foo").Scan(&n, &i, &f, &s); err != nil { 352 panic(err) 353 } 354 } 355 } 356 357 func BenchmarkRows(b *testing.B) { 358 db.once.Do(makeBench) 359 360 for n := 0; n < b.N; n++ { 361 var n sql.NullString 362 var i int 363 var f float64 364 var s string 365 var t time.Time 366 r, err := db.Query("select * from bench") 367 if err != nil { 368 panic(err) 369 } 370 for r.Next() { 371 if err = r.Scan(&n, &i, &f, &s, &t); err != nil { 372 panic(err) 373 } 374 } 375 if err = r.Err(); err != nil { 376 panic(err) 377 } 378 } 379 } 380 381 func BenchmarkStmtRows(b *testing.B) { 382 db.once.Do(makeBench) 383 384 st, err := db.Prepare("select * from bench") 385 if err != nil { 386 panic(err) 387 } 388 defer st.Close() 389 390 for n := 0; n < b.N; n++ { 391 var n sql.NullString 392 var i int 393 var f float64 394 var s string 395 var t time.Time 396 r, err := st.Query() 397 if err != nil { 398 panic(err) 399 } 400 for r.Next() { 401 if err = r.Scan(&n, &i, &f, &s, &t); err != nil { 402 panic(err) 403 } 404 } 405 if err = r.Err(); err != nil { 406 panic(err) 407 } 408 } 409 }