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  }