github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/tidb_test.go (about) 1 // Copyright 2015 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package tidb 15 16 import ( 17 "flag" 18 "fmt" 19 "net/url" 20 "os" 21 "runtime" 22 "sync" 23 "testing" 24 "time" 25 26 "github.com/insionng/yougam/libraries/juju/errors" 27 "github.com/insionng/yougam/libraries/ngaut/log" 28 . "github.com/insionng/yougam/libraries/pingcap/check" 29 "github.com/insionng/yougam/libraries/pingcap/tidb/ast" 30 "github.com/insionng/yougam/libraries/pingcap/tidb/kv" 31 "github.com/insionng/yougam/libraries/pingcap/tidb/util/testleak" 32 "github.com/insionng/yougam/libraries/pingcap/tidb/util/types" 33 ) 34 35 var store = flag.String("store", "memory", "registered store name, [memory, goleveldb, boltdb]") 36 37 func TestT(t *testing.T) { 38 TestingT(t) 39 } 40 41 var _ = Suite(&testMainSuite{}) 42 43 type testMainSuite struct { 44 dbName string 45 createDBSQL string 46 dropDBSQL string 47 useDBSQL string 48 createTableSQL string 49 selectSQL string 50 } 51 52 type brokenStore struct{} 53 54 func (s *brokenStore) Open(schema string) (kv.Storage, error) { 55 return nil, errors.New("try again later") 56 } 57 58 func (s *testMainSuite) SetUpSuite(c *C) { 59 testleak.BeforeTest() 60 s.dbName = "test_main_db" 61 s.createDBSQL = fmt.Sprintf("create database if not exists %s;", s.dbName) 62 s.dropDBSQL = fmt.Sprintf("drop database %s;", s.dbName) 63 s.useDBSQL = fmt.Sprintf("use %s;", s.dbName) 64 s.createTableSQL = ` 65 CREATE TABLE tbl_test(id INT NOT NULL DEFAULT 1, name varchar(255), PRIMARY KEY(id)); 66 CREATE TABLE tbl_test1(id INT NOT NULL DEFAULT 2, name varchar(255), PRIMARY KEY(id), INDEX name(name)); 67 CREATE TABLE tbl_test2(id INT NOT NULL DEFAULT 3, name varchar(255), PRIMARY KEY(id));` 68 s.selectSQL = `SELECT * from tbl_test;` 69 runtime.GOMAXPROCS(runtime.NumCPU()) 70 71 log.SetLevelByString("error") 72 } 73 74 func (s *testMainSuite) TearDownSuite(c *C) { 75 defer testleak.AfterTest(c)() 76 removeStore(c, s.dbName) 77 } 78 79 func checkResult(c *C, se Session, affectedRows uint64, insertID uint64) { 80 gotRows := se.AffectedRows() 81 c.Assert(gotRows, Equals, affectedRows) 82 83 gotID := se.LastInsertID() 84 c.Assert(gotID, Equals, insertID) 85 } 86 87 func (s *testMainSuite) TestConcurrent(c *C) { 88 dbName := "test_concurrent_db" 89 defer removeStore(c, dbName) 90 store := newStore(c, dbName) 91 se := newSession(c, store, dbName) 92 defer store.Close() 93 // create db 94 createDBSQL := fmt.Sprintf("create database if not exists %s;", dbName) 95 dropDBSQL := fmt.Sprintf("drop database %s;", dbName) 96 useDBSQL := fmt.Sprintf("use %s;", dbName) 97 createTableSQL := ` CREATE TABLE test(id INT NOT NULL DEFAULT 1, name varchar(255), PRIMARY KEY(id)); ` 98 99 mustExecSQL(c, se, dropDBSQL) 100 mustExecSQL(c, se, createDBSQL) 101 mustExecSQL(c, se, useDBSQL) 102 mustExecSQL(c, se, createTableSQL) 103 wg := &sync.WaitGroup{} 104 f := func(start, count int) { 105 sess := newSession(c, store, dbName) 106 for i := 0; i < count; i++ { 107 // insert data 108 mustExecSQL(c, sess, fmt.Sprintf(`INSERT INTO test VALUES (%d, "hello");`, start+i)) 109 } 110 wg.Done() 111 } 112 step := 10 113 for i := 0; i < step; i++ { 114 wg.Add(1) 115 go f(i*step, step) 116 } 117 wg.Wait() 118 mustExecSQL(c, se, dropDBSQL) 119 } 120 121 func (s *testMainSuite) TestTableInfoMeta(c *C) { 122 store := newStore(c, s.dbName) 123 se := newSession(c, store, s.dbName) 124 defer store.Close() 125 126 // create db 127 mustExecSQL(c, se, s.createDBSQL) 128 129 // use db 130 mustExecSQL(c, se, s.useDBSQL) 131 132 // create table 133 mustExecSQL(c, se, s.createTableSQL) 134 135 // insert data 136 mustExecSQL(c, se, `INSERT INTO tbl_test VALUES (1, "hello");`) 137 checkResult(c, se, 1, 0) 138 139 mustExecSQL(c, se, `INSERT INTO tbl_test VALUES (2, "hello");`) 140 checkResult(c, se, 1, 0) 141 142 mustExecSQL(c, se, `UPDATE tbl_test SET name = "abc" where id = 2;`) 143 checkResult(c, se, 1, 0) 144 145 mustExecSQL(c, se, `DELETE from tbl_test where id = 2;`) 146 checkResult(c, se, 1, 0) 147 148 // select data 149 mustExecMatch(c, se, s.selectSQL, [][]interface{}{{1, []byte("hello")}}) 150 151 // drop db 152 mustExecSQL(c, se, s.dropDBSQL) 153 } 154 155 func (s *testMainSuite) TestInfoSchema(c *C) { 156 store := newStore(c, s.dbName) 157 se := newSession(c, store, s.dbName) 158 rs := mustExecSQL(c, se, "SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.CHARACTER_SETS WHERE CHARACTER_SET_NAME = 'utf8mb4'") 159 row, err := rs.Next() 160 c.Assert(err, IsNil) 161 match(c, row.Data, "utf8mb4") 162 163 err = store.Close() 164 c.Assert(err, IsNil) 165 } 166 167 func (s *testMainSuite) TestCaseInsensitive(c *C) { 168 store := newStore(c, s.dbName) 169 se := newSession(c, store, s.dbName) 170 defer store.Close() 171 mustExecSQL(c, se, "create table T (a text, B int)") 172 mustExecSQL(c, se, "insert t (A, b) values ('aaa', 1)") 173 rs := mustExecSQL(c, se, "select * from t") 174 fields, err := rs.Fields() 175 c.Assert(err, IsNil) 176 c.Assert(fields[0].ColumnAsName.O, Equals, "a") 177 c.Assert(fields[1].ColumnAsName.O, Equals, "B") 178 rs = mustExecSQL(c, se, "select A, b from t") 179 fields, err = rs.Fields() 180 c.Assert(err, IsNil) 181 c.Assert(fields[0].ColumnAsName.O, Equals, "A") 182 c.Assert(fields[1].ColumnAsName.O, Equals, "b") 183 mustExecSQL(c, se, "update T set b = B + 1") 184 mustExecSQL(c, se, "update T set B = b + 1") 185 rs = mustExecSQL(c, se, "select b from T") 186 rows, err := GetRows(rs) 187 c.Assert(err, IsNil) 188 match(c, rows[0], 3) 189 190 mustExecSQL(c, se, s.dropDBSQL) 191 err = store.Close() 192 c.Assert(err, IsNil) 193 } 194 195 // Testcase for delete panic 196 func (s *testMainSuite) TestDeletePanic(c *C) { 197 store := newStore(c, s.dbName) 198 se := newSession(c, store, s.dbName) 199 defer store.Close() 200 mustExecSQL(c, se, "create table t (c int)") 201 mustExecSQL(c, se, "insert into t values (1), (2), (3)") 202 mustExecSQL(c, se, "delete from `t` where `c` = ?", 1) 203 rs := mustExecSQL(c, se, "delete from `t` where `c` = ?", 2) 204 c.Assert(rs, IsNil) 205 } 206 207 // Testcase for arg type. 208 func (s *testMainSuite) TestCheckArgs(c *C) { 209 store := newStore(c, s.dbName) 210 se := newSession(c, store, s.dbName) 211 defer store.Close() 212 mustExecSQL(c, se, "create table if not exists t (c datetime)") 213 mustExecSQL(c, se, "insert t values (?)", time.Now()) 214 mustExecSQL(c, se, "drop table t") 215 checkArgs(nil, true, false, int8(1), int16(1), int32(1), int64(1), 1, 216 uint8(1), uint16(1), uint32(1), uint64(1), uint(1), float32(1), float64(1), 217 "abc", []byte("abc"), time.Now(), time.Hour, time.Local) 218 } 219 220 func (s *testMainSuite) TestIsQuery(c *C) { 221 tbl := []struct { 222 sql string 223 ok bool 224 }{ 225 {"/*comment*/ select 1;", true}, 226 {"/*comment*/ /*comment*/ select 1;", true}, 227 {"select /*comment*/ 1 /*comment*/;", true}, 228 {"(select /*comment*/ 1 /*comment*/);", true}, 229 } 230 for _, t := range tbl { 231 c.Assert(IsQuery(t.sql), Equals, t.ok, Commentf(t.sql)) 232 } 233 } 234 235 func (s *testMainSuite) TestTrimSQL(c *C) { 236 tbl := []struct { 237 sql string 238 target string 239 }{ 240 {"/*comment*/ select 1; ", "select 1;"}, 241 {"/*comment*/ /*comment*/ select 1;", "select 1;"}, 242 {"select /*comment*/ 1 /*comment*/;", "select /*comment*/ 1 /*comment*/;"}, 243 {"/*comment select 1; ", "/*comment select 1;"}, 244 } 245 for _, t := range tbl { 246 c.Assert(trimSQL(t.sql), Equals, t.target, Commentf(t.sql)) 247 } 248 } 249 250 func (s *testMainSuite) TestRetryOpenStore(c *C) { 251 begin := time.Now() 252 RegisterStore("dummy", &brokenStore{}) 253 _, err := newStoreWithRetry("dummy://dummy-store", 3) 254 c.Assert(err, NotNil) 255 elapse := time.Since(begin) 256 c.Assert(uint64(elapse), GreaterEqual, uint64(3*time.Second)) 257 } 258 259 func (s *testMainSuite) TestParseDSN(c *C) { 260 tbl := []struct { 261 dsn string 262 ok bool 263 storeDSN string 264 dbName string 265 }{ 266 {"s://path/db", true, "s://path", "db"}, 267 {"s://path/db/", true, "s://path", "db"}, 268 {"s:///path/db", true, "s:///path", "db"}, 269 {"s:///path/db/", true, "s:///path", "db"}, 270 {"s://zk1,zk2/tbl/db", true, "s://zk1,zk2/tbl", "db"}, 271 {"s://zk1:80,zk2:81/tbl/db", true, "s://zk1:80,zk2:81/tbl", "db"}, 272 {"s://path/db?p=v", true, "s://path?p=v", "db"}, 273 {"s:///path/db?p1=v1&p2=v2", true, "s:///path?p1=v1&p2=v2", "db"}, 274 {"s://z,k,zk/tbl/db?p=v", true, "s://z,k,zk/tbl?p=v", "db"}, 275 {"", false, "", ""}, 276 {"/", false, "", ""}, 277 {"s://", false, "", ""}, 278 {"s:///", false, "", ""}, 279 {"s:///db", false, "", ""}, 280 } 281 282 for _, t := range tbl { 283 params, err := parseDriverDSN(t.dsn) 284 if t.ok { 285 c.Assert(err, IsNil, Commentf("dsn=%v", t.dsn)) 286 c.Assert(params.storePath, Equals, t.storeDSN, Commentf("dsn=%v", t.dsn)) 287 c.Assert(params.dbName, Equals, t.dbName, Commentf("dsn=%v", t.dsn)) 288 _, err = url.Parse(params.storePath) 289 c.Assert(err, IsNil, Commentf("dsn=%v", t.dsn)) 290 } else { 291 c.Assert(err, NotNil, Commentf("dsn=%v", t.dsn)) 292 } 293 } 294 } 295 296 func (s *testMainSuite) TestTPS(c *C) { 297 store := newStore(c, s.dbName) 298 se := newSession(c, store, s.dbName) 299 defer store.Close() 300 301 mustExecSQL(c, se, "set @@autocommit=0;") 302 for i := 1; i < 6; i++ { 303 for j := 0; j < 5; j++ { 304 for k := 0; k < i; k++ { 305 mustExecSQL(c, se, "begin;") 306 mustExecSQL(c, se, "select 1;") 307 mustExecSQL(c, se, "commit;") 308 } 309 time.Sleep(220 * time.Millisecond) 310 } 311 // It is hard to get the accurate tps because there is another timeline in tpsMetrics. 312 // We could only get the upper/lower boundary for tps 313 c.Assert(GetTPS(), GreaterEqual, int64(4*(i-1))) 314 } 315 } 316 func sessionExec(c *C, se Session, sql string) ([]ast.RecordSet, error) { 317 se.Execute("BEGIN;") 318 r, err := se.Execute(sql) 319 c.Assert(err, IsNil) 320 se.Execute("COMMIT;") 321 return r, err 322 } 323 324 func newStore(c *C, dbPath string) kv.Storage { 325 store, err := NewStore(*store + "://" + dbPath) 326 c.Assert(err, IsNil) 327 return store 328 } 329 330 func newSession(c *C, store kv.Storage, dbName string) Session { 331 se, err := CreateSession(store) 332 c.Assert(err, IsNil) 333 se.Auth("root@%", nil, []byte("012345678901234567890")) 334 mustExecSQL(c, se, "create database if not exists "+dbName) 335 mustExecSQL(c, se, "use "+dbName) 336 return se 337 } 338 339 func removeStore(c *C, dbPath string) { 340 os.RemoveAll(dbPath) 341 } 342 343 func exec(c *C, se Session, sql string, args ...interface{}) (ast.RecordSet, error) { 344 if len(args) == 0 { 345 rs, err := se.Execute(sql) 346 if err == nil && len(rs) > 0 { 347 return rs[0], nil 348 } 349 return nil, err 350 } 351 stmtID, _, _, err := se.PrepareStmt(sql) 352 if err != nil { 353 return nil, err 354 } 355 rs, err := se.ExecutePreparedStmt(stmtID, args...) 356 if err != nil { 357 return nil, err 358 } 359 return rs, nil 360 } 361 362 func mustExecSQL(c *C, se Session, sql string, args ...interface{}) ast.RecordSet { 363 rs, err := exec(c, se, sql, args...) 364 c.Assert(err, IsNil) 365 return rs 366 } 367 368 func match(c *C, row []types.Datum, expected ...interface{}) { 369 c.Assert(len(row), Equals, len(expected)) 370 for i := range row { 371 got := fmt.Sprintf("%v", row[i].GetValue()) 372 need := fmt.Sprintf("%v", expected[i]) 373 c.Assert(got, Equals, need) 374 } 375 } 376 377 func matches(c *C, rows [][]types.Datum, expected [][]interface{}) { 378 c.Assert(len(rows), Equals, len(expected)) 379 for i := 0; i < len(rows); i++ { 380 match(c, rows[i], expected[i]...) 381 } 382 } 383 384 func mustExecMatch(c *C, se Session, sql string, expected [][]interface{}) { 385 r := mustExecSQL(c, se, sql) 386 rows, err := GetRows(r) 387 c.Assert(err, IsNil) 388 matches(c, rows, expected) 389 } 390 391 func mustExecFailed(c *C, se Session, sql string, args ...interface{}) { 392 r, err := exec(c, se, sql, args...) 393 if err == nil && r != nil { 394 // sometimes we may meet error after executing first row. 395 _, err = r.Next() 396 } 397 c.Assert(err, NotNil) 398 }