зеркало из https://github.com/github/vitess-gh.git
impove connpool unit test
1. remove old unit test rely on local mysql instance 2. add unit test using fake mysql db implementation
This commit is contained in:
Родитель
e919986a41
Коммит
6660741a1f
|
@ -1,115 +1,177 @@
|
|||
// Copyright 2015, Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package tabletserver
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
mproto "github.com/youtube/vitess/go/mysql/proto"
|
||||
"github.com/youtube/vitess/go/sqldb"
|
||||
"github.com/youtube/vitess/go/stats"
|
||||
"github.com/youtube/vitess/go/vt/tabletserver/fakesqldb"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
var (
|
||||
appParams = &sqldb.ConnParams{
|
||||
Uname: "vt_app",
|
||||
DbName: "sougou",
|
||||
UnixSocket: os.Getenv("VTDATAROOT") + "/vt_0000062347/mysql.sock",
|
||||
Charset: "utf8",
|
||||
func TestConnPoolTryGetWhilePoolIsClosed(t *testing.T) {
|
||||
fakesqldb.Register()
|
||||
connPool := NewConnPool("ConnPool", 100, 10*time.Second, false)
|
||||
_, err := connPool.TryGet()
|
||||
if err != ErrConnPoolClosed {
|
||||
t.Fatalf("pool is closed, should get ErrConnPoolClosed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnPoolTryGetWhenFailedToConnectToDB(t *testing.T) {
|
||||
db := fakesqldb.Register()
|
||||
db.EnableConnFail()
|
||||
appParams := &sqldb.ConnParams{}
|
||||
dbaParams := &sqldb.ConnParams{}
|
||||
connPool := NewConnPool("ConnPool", 100, 10*time.Second, false)
|
||||
connPool.Open(appParams, dbaParams)
|
||||
defer connPool.Close()
|
||||
_, err := connPool.TryGet()
|
||||
if err == nil {
|
||||
t.Fatalf("should get a connection error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnPoolTryGet(t *testing.T) {
|
||||
fakesqldb.Register()
|
||||
appParams := &sqldb.ConnParams{}
|
||||
dbaParams := &sqldb.ConnParams{}
|
||||
connPool := NewConnPool("ConnPool", 100, 10*time.Second, false)
|
||||
connPool.Open(appParams, dbaParams)
|
||||
defer connPool.Close()
|
||||
dbConn, err := connPool.TryGet()
|
||||
if err != nil {
|
||||
t.Fatalf("should get an error, but got: %v", err)
|
||||
}
|
||||
if dbConn == nil {
|
||||
t.Fatalf("db conn should not be nil")
|
||||
}
|
||||
dbConn.Recycle()
|
||||
}
|
||||
|
||||
func TestConnPoolGet(t *testing.T) {
|
||||
fakesqldb.Register()
|
||||
appParams := &sqldb.ConnParams{}
|
||||
dbaParams := &sqldb.ConnParams{}
|
||||
connPool := NewConnPool("ConnPool", 100, 10*time.Second, false)
|
||||
connPool.Open(appParams, dbaParams)
|
||||
defer connPool.Close()
|
||||
dbConn, err := connPool.Get(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("should get an error, but got: %v", err)
|
||||
}
|
||||
if dbConn == nil {
|
||||
t.Fatalf("db conn should not be nil")
|
||||
}
|
||||
dbConn.Recycle()
|
||||
}
|
||||
|
||||
func TestConnPoolPutWhilePoolIsClosed(t *testing.T) {
|
||||
fakesqldb.Register()
|
||||
connPool := NewConnPool("ConnPool", 100, 10*time.Second, false)
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
t.Fatalf("pool is closed, should get an error")
|
||||
}
|
||||
}()
|
||||
connPool.Put(nil)
|
||||
}
|
||||
|
||||
func TestConnPoolSetCapacity(t *testing.T) {
|
||||
fakesqldb.Register()
|
||||
appParams := &sqldb.ConnParams{}
|
||||
dbaParams := &sqldb.ConnParams{}
|
||||
connPool := NewConnPool("ConnPool", 100, 10*time.Second, false)
|
||||
connPool.Open(appParams, dbaParams)
|
||||
defer connPool.Close()
|
||||
err := connPool.SetCapacity(-10)
|
||||
if err == nil {
|
||||
t.Fatalf("set capacity should return error for negative capacity")
|
||||
}
|
||||
err = connPool.SetCapacity(10)
|
||||
if err != nil {
|
||||
t.Fatalf("set capacity should succeed")
|
||||
}
|
||||
if connPool.Capacity() != 10 {
|
||||
t.Fatalf("capacity should be 10")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnPoolStatJSON(t *testing.T) {
|
||||
fakesqldb.Register()
|
||||
connPool := NewConnPool("ConnPool", 100, 10*time.Second, false)
|
||||
if connPool.StatsJSON() != "{}" {
|
||||
t.Fatalf("pool is closed, stats json should be empty: {}")
|
||||
}
|
||||
appParams := &sqldb.ConnParams{}
|
||||
dbaParams := &sqldb.ConnParams{}
|
||||
connPool.Open(appParams, dbaParams)
|
||||
defer connPool.Close()
|
||||
statsJSON := connPool.StatsJSON()
|
||||
if statsJSON == "" || statsJSON == "{}" {
|
||||
t.Fatalf("stats json should not be empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnPoolStateWhilePoolIsClosed(t *testing.T) {
|
||||
fakesqldb.Register()
|
||||
connPool := NewConnPool("ConnPool", 100, 10*time.Second, false)
|
||||
if connPool.Capacity() != 0 {
|
||||
t.Fatalf("pool capacity should be 0 because it is still closed")
|
||||
}
|
||||
if connPool.Available() != 0 {
|
||||
t.Fatalf("pool available connections should be 0 because it is still closed")
|
||||
}
|
||||
if connPool.MaxCap() != 0 {
|
||||
t.Fatalf("pool max capacity should be 0 because it is still closed")
|
||||
}
|
||||
if connPool.WaitCount() != 0 {
|
||||
t.Fatalf("pool wait count should be 0 because it is still closed")
|
||||
}
|
||||
if connPool.WaitTime() != 0 {
|
||||
t.Fatalf("pool wait time should be 0 because it is still closed")
|
||||
}
|
||||
if connPool.IdleTimeout() != 0 {
|
||||
t.Fatalf("pool idle timeout should be 0 because it is still closed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnPoolStateWhilePoolIsOpen(t *testing.T) {
|
||||
fakesqldb.Register()
|
||||
appParams := &sqldb.ConnParams{}
|
||||
dbaParams := &sqldb.ConnParams{}
|
||||
idleTimeout := 10 * time.Second
|
||||
connPool := NewConnPool("ConnPool", 100, idleTimeout, false)
|
||||
connPool.Open(appParams, dbaParams)
|
||||
defer connPool.Close()
|
||||
if connPool.Capacity() != 100 {
|
||||
t.Fatalf("pool capacity should be 100")
|
||||
}
|
||||
if connPool.MaxCap() != 100 {
|
||||
t.Fatalf("pool max capacity should be 100")
|
||||
}
|
||||
if connPool.WaitTime() != 0 {
|
||||
t.Fatalf("pool wait time should be 0")
|
||||
}
|
||||
if connPool.WaitCount() != 0 {
|
||||
t.Fatalf("pool wait count should be 0")
|
||||
}
|
||||
if connPool.IdleTimeout() != idleTimeout {
|
||||
t.Fatalf("pool idle timeout should be 0")
|
||||
}
|
||||
if connPool.Available() != 100 {
|
||||
t.Fatalf("pool available connections should be 100")
|
||||
}
|
||||
dbConn, _ := connPool.Get(context.Background())
|
||||
if connPool.Available() != 99 {
|
||||
t.Fatalf("pool available connections should be 99")
|
||||
}
|
||||
dbConn.Recycle()
|
||||
if connPool.Available() != 100 {
|
||||
t.Fatalf("pool available connections should be 100")
|
||||
}
|
||||
dbaParams = &sqldb.ConnParams{
|
||||
Uname: "vt_dba",
|
||||
DbName: "sougou",
|
||||
UnixSocket: os.Getenv("VTDATAROOT") + "/vt_0000062347/mysql.sock",
|
||||
Charset: "utf8",
|
||||
}
|
||||
)
|
||||
|
||||
// TestConnectivity is a manual test that requires code changes.
|
||||
// You first need to bring up a mysql instance to match the connection params.
|
||||
// Setup: mysqlctl -tablet_uid=62347 -mysql_port=15001 init.
|
||||
// Connect: mysql -S vt_0000062347/mysql.sock -u vt_dba
|
||||
// Initialize: create database sougou; use sougou; create table a(id int, primary key(id));
|
||||
// Run the test normally once. Then you add a 20s sleep in dbconn.execOnce
|
||||
// and run it again. You also have to check the code coverage to see that all critical
|
||||
// paths were covered.
|
||||
// Shutdown: mysqlctl -tablet_uid=62347 -mysql_port=15001 teardown
|
||||
// TODO(sougou): Figure out a way to automate this.
|
||||
func TestConnectivity(t *testing.T) {
|
||||
t.Skip("manual test")
|
||||
ctx := context.Background()
|
||||
killStats = stats.NewCounters("TestKills")
|
||||
internalErrors = stats.NewCounters("TestInternalErrors")
|
||||
mysqlStats = stats.NewTimings("TestMySQLStats")
|
||||
pool := NewConnPool("p1", 1, 30*time.Second, false)
|
||||
pool.Open(appParams, dbaParams)
|
||||
|
||||
conn, err := pool.Get(ctx)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
conn.Kill()
|
||||
|
||||
newctx, cancel := withTimeout(ctx, 2*time.Second)
|
||||
_, err = conn.Exec(newctx, "select * from a", 1000, true)
|
||||
cancel()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
conn.Close()
|
||||
|
||||
newctx, cancel = withTimeout(ctx, 2*time.Second)
|
||||
_, err = conn.Exec(newctx, "select * from a", 1000, true)
|
||||
cancel()
|
||||
// You'll get a timedout error in slow mode. Otherwise, this should succeed.
|
||||
timedout := "error: setDeadline: timed out"
|
||||
if err != nil && err.Error() != timedout {
|
||||
t.Errorf("got: %v, want nil or %s", err, timedout)
|
||||
}
|
||||
conn.Recycle()
|
||||
|
||||
conn, err = pool.Get(ctx)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
ch := make(chan bool)
|
||||
go func() {
|
||||
newctx, cancel = withTimeout(ctx, 2*time.Millisecond)
|
||||
_, err = conn.Exec(newctx, "select sleep(1) from dual", 1000, true)
|
||||
cancel()
|
||||
lostConn := "error: the query was killed either because it timed out or was canceled: Lost connection to MySQL server during query (errno 2013) during query: select sleep(1) from dual"
|
||||
if err == nil || err.Error() != lostConn {
|
||||
t.Errorf("got: %v, want %s", err, lostConn)
|
||||
}
|
||||
ch <- true
|
||||
}()
|
||||
time.Sleep(40 * time.Millisecond)
|
||||
conn.Kill()
|
||||
<-ch
|
||||
conn.Recycle()
|
||||
|
||||
conn, err = pool.Get(ctx)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
ch = make(chan bool)
|
||||
go func() {
|
||||
newctx, cancel = withTimeout(ctx, 2*time.Millisecond)
|
||||
err = conn.Stream(newctx, "select sleep(1) from dual", func(*mproto.QueryResult) error {
|
||||
return nil
|
||||
}, 4096)
|
||||
cancel()
|
||||
lostConn := "Lost connection to MySQL server during query (errno 2013) during query: select sleep(1) from dual"
|
||||
if err == nil || err.Error() != lostConn {
|
||||
t.Errorf("got: %v, want %s", err, lostConn)
|
||||
}
|
||||
ch <- true
|
||||
}()
|
||||
time.Sleep(40 * time.Millisecond)
|
||||
conn.Kill()
|
||||
<-ch
|
||||
conn.Recycle()
|
||||
|
||||
pool.Close()
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче