Skip to content
This repository has been archived by the owner on Dec 16, 2022. It is now read-only.

Commit

Permalink
Merge pull request vitessio#5670 from princeparmar/prepared-statement
Browse files Browse the repository at this point in the history
prepared statement testcases
  • Loading branch information
sougou authored Jan 19, 2020
2 parents c4e06a1 + 5c05f6e commit 7fe2822
Show file tree
Hide file tree
Showing 8 changed files with 466 additions and 30 deletions.
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ require (
github.com/hashicorp/memberlist v0.1.4 // indirect
github.com/hashicorp/serf v0.0.0-20161207011743-d3a67ab21bc8 // indirect
github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428
github.com/jinzhu/gorm v1.9.12
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 // indirect
github.com/klauspost/crc32 v1.2.0 // indirect
github.com/klauspost/pgzip v1.2.0
Expand Down
8 changes: 4 additions & 4 deletions go/test/endtoend/cluster/cluster_process.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,12 +221,12 @@ func (cluster *LocalProcessCluster) StartKeyspace(keyspace Keyspace, shardNames
// Start Mysqlctl process
log.Info(fmt.Sprintf("Starting mysqlctl for table uid %d, mysql port %d", tablet.TabletUID, tablet.MySQLPort))
tablet.MysqlctlProcess = *MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, cluster.TmpDirectory)
if proc, err := tablet.MysqlctlProcess.StartProcess(); err != nil {
proc, err := tablet.MysqlctlProcess.StartProcess()
if err != nil {
log.Error(err.Error())
return err
} else {
mysqlctlProcessList = append(mysqlctlProcessList, proc)
}
mysqlctlProcessList = append(mysqlctlProcessList, proc)

// start vttablet process
tablet.VttabletProcess = VttabletProcessInstance(tablet.HTTPPort,
Expand Down Expand Up @@ -573,7 +573,7 @@ func (cluster *LocalProcessCluster) GetVttabletInstance(tabletType string, UID i
}
}

// GetVttabletInstance creates a new vttablet object
// GetVtprocessInstanceFromVttablet creates a new vttablet object
func (cluster *LocalProcessCluster) GetVtprocessInstanceFromVttablet(tablet *Vttablet, shardName string, ksName string) *VttabletProcess {
return VttabletProcessInstance(tablet.HTTPPort,
tablet.GrpcPort,
Expand Down
11 changes: 5 additions & 6 deletions go/test/endtoend/cluster/cluster_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,21 @@ func GetMasterPosition(t *testing.T, vttablet Vttablet, hostname string) (string
return pos, gtID
}

// Verify total number of rows in a tablet
// VerifyRowsInTablet Verify total number of rows in a tablet
func VerifyRowsInTablet(t *testing.T, vttablet *Vttablet, ksName string, expectedRows int) {
timeout := time.Now().Add(10 * time.Second)
for time.Now().Before(timeout) {
qr, err := vttablet.VttabletProcess.QueryTablet("select * from vt_insert_test", ksName, true)
assert.Nil(t, err)
if len(qr.Rows) != expectedRows {
time.Sleep(300 * time.Millisecond)
} else {
if len(qr.Rows) == expectedRows {
return
}
time.Sleep(300 * time.Millisecond)
}
assert.Fail(t, "expected rows not found.")
}

// Verify Local Metadata of a tablet
// VerifyLocalMetadata Verify Local Metadata of a tablet
func VerifyLocalMetadata(t *testing.T, tablet *Vttablet, ksName string, shardName string, cell string) {
qr, err := tablet.VttabletProcess.QueryTablet("select * from _vt.local_metadata", ksName, false)
assert.Nil(t, err)
Expand All @@ -74,7 +73,7 @@ func VerifyLocalMetadata(t *testing.T, tablet *Vttablet, ksName string, shardNam
}
}

//Lists back preset in shard
// ListBackups Lists back preset in shard
func (cluster LocalProcessCluster) ListBackups(shardKsName string) ([]string, error) {
output, err := cluster.VtctlclientProcess.ExecuteCommandWithOutput("ListBackups", shardKsName)
if err != nil {
Expand Down
17 changes: 9 additions & 8 deletions go/test/endtoend/cluster/mysqlctl_process.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ func (mysqlctl *MysqlctlProcess) InitDb() (err error) {

// Start executes mysqlctl command to start mysql instance
func (mysqlctl *MysqlctlProcess) Start() (err error) {
if tmpProcess, err := mysqlctl.StartProcess(); err != nil {
tmpProcess, err := mysqlctl.StartProcess()
if err != nil {
return err
} else {
return tmpProcess.Wait()
}
return tmpProcess.Wait()
}

// StartProcess starts the mysqlctl and returns the process reference
Expand All @@ -78,19 +78,20 @@ func (mysqlctl *MysqlctlProcess) StartProcess() (*exec.Cmd, error) {
if mysqlctl.InitMysql {
tmpProcess.Args = append(tmpProcess.Args, "init",
"-init_db_sql_file", mysqlctl.InitDBFile)
} else {
tmpProcess.Args = append(tmpProcess.Args, "start")
}
tmpProcess.Args = append(tmpProcess.Args, "start")

return tmpProcess, tmpProcess.Start()
}

// Stop executes mysqlctl command to stop mysql instance
func (mysqlctl *MysqlctlProcess) Stop() (err error) {
if tmpProcess, err := mysqlctl.StopProcess(); err != nil {
tmpProcess, err := mysqlctl.StopProcess()
if err != nil {
return err
} else {
return tmpProcess.Wait()
}
return tmpProcess.Wait()

}

// StopProcess executes mysqlctl command to stop mysql instance and returns process reference
Expand Down
2 changes: 0 additions & 2 deletions go/test/endtoend/mysqlserver/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ import (

"vitess.io/vitess/go/mysql"
"vitess.io/vitess/go/test/endtoend/cluster"

_ "github.com/jinzhu/gorm/dialects/mysql"
)

var (
Expand Down
270 changes: 270 additions & 0 deletions go/test/endtoend/preparestmt/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
/*
Copyright 2019 The Vitess Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package preparestmt

import (
"database/sql"
"flag"
"fmt"
"os"
"strings"
"testing"

"vitess.io/vitess/go/test/endtoend/cluster"

"github.com/go-sql-driver/mysql"
"github.com/stretchr/testify/require"
)

// tableData is a temporary structure to hold selected data.
type tableData struct {
Msg string
Data string
TextCol string
}

// DBInfo information about the database.
type DBInfo struct {
Username string
Password string
Host string
Port uint
KeyspaceName string
Params []string
}

func init() {
dbInfo.KeyspaceName = keyspaceName
dbInfo.Username = "testuser1"
dbInfo.Password = "testpassword1"
dbInfo.Params = []string{
"charset=utf8",
"parseTime=True",
"loc=Local",
}
}

var (
clusterInstance *cluster.LocalProcessCluster
dbInfo DBInfo
hostname = "localhost"
keyspaceName = "test_keyspace"
testingID = 1
tableName = "vt_prepare_stmt_test"
cell = "zone1"
mysqlAuthServerStatic = "mysql_auth_server_static.json"
jsonExample = `{
"quiz": {
"sport": {
"q1": {
"question": "Which one is correct team name in NBA?",
"options": [
"New York Bulls",
"Los Angeles Kings",
"Golden State Warriors",
"Huston Rocket"
],
"answer": "Huston Rocket"
}
},
"maths": {
"q1": {
"question": "5 + 7 = ?",
"options": [
"10",
"11",
"12",
"13"
],
"answer": "12"
},
"q2": {
"question": "12 - 8 = ?",
"options": [
"1",
"2",
"3",
"4"
],
"answer": "4"
}
}
}
}`
sqlSchema = `create table ` + tableName + ` (
id bigint auto_increment,
msg varchar(64),
keyspace_id bigint(20) unsigned NOT NULL,
tinyint_unsigned TINYINT,
bool_signed BOOL,
smallint_unsigned SMALLINT,
mediumint_unsigned MEDIUMINT,
int_unsigned INT,
float_unsigned FLOAT(10,2),
double_unsigned DOUBLE(16,2),
decimal_unsigned DECIMAL,
t_date DATE,
t_datetime DATETIME,
t_time TIME,
t_timestamp TIMESTAMP,
c8 bit(8) DEFAULT NULL,
c16 bit(16) DEFAULT NULL,
c24 bit(24) DEFAULT NULL,
c32 bit(32) DEFAULT NULL,
c40 bit(40) DEFAULT NULL,
c48 bit(48) DEFAULT NULL,
c56 bit(56) DEFAULT NULL,
c63 bit(63) DEFAULT NULL,
c64 bit(64) DEFAULT NULL,
json_col JSON,
text_col TEXT,
data longblob,
primary key (id)
) Engine=InnoDB`
)

func TestMain(m *testing.M) {
flag.Parse()

exitcode, err := func() (int, error) {
clusterInstance = cluster.NewCluster(cell, hostname)

defer clusterInstance.Teardown()

// Start topo server
if err := clusterInstance.StartTopo(); err != nil {
return 1, err
}

// create auth server config
SQLConfig := `{
"testuser1": {
"Password": "testpassword1",
"UserData": "vtgate client 1"
}
}`
if err := createConfig(mysqlAuthServerStatic, SQLConfig); err != nil {
return 1, err
}

// add extra arguments
clusterInstance.VtGateExtraArgs = []string{
"-mysql_auth_server_impl", "static",
"-mysql_server_query_timeout", "1s",
"-mysql_auth_server_static_file", clusterInstance.TmpDirectory + "/" + mysqlAuthServerStatic,
"-mysql_server_version", "8.0.16-7",
}

// Start keyspace
keyspace := &cluster.Keyspace{
Name: keyspaceName,
SchemaSQL: sqlSchema,
}
if err := clusterInstance.StartUnshardedKeyspace(*keyspace, 1, false); err != nil {
return 1, err
}

// Start vtgate
if err := clusterInstance.StartVtgate(); err != nil {
return 1, err
}

dbInfo.Host = clusterInstance.Hostname
dbInfo.Port = uint(clusterInstance.VtgateMySQLPort)

return m.Run(), nil
}()
if err != nil {
fmt.Printf("%v\n", err)
os.Exit(1)
} else {
os.Exit(exitcode)
}

}

// ConnectionString generates the connection string using dbinfo.
func (db DBInfo) ConnectionString(params ...string) string {
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?%s", db.Username, db.Password, db.Host,
db.Port, db.KeyspaceName, strings.Join(append(db.Params, params...), "&"))
}

// createConfig creates a config file in TmpDir in vtdataroot and writes the given data.
func createConfig(name, data string) error {
// creating new file
f, err := os.Create(clusterInstance.TmpDirectory + "/" + name)
if err != nil {
return err
}

if data == "" {
return nil
}

// write the given data
_, err = fmt.Fprint(f, data)
return err
}

// Connect will connect the vtgate through mysql protocol.
func Connect(t *testing.T, params ...string) *sql.DB {
dbo, err := sql.Open("mysql", dbInfo.ConnectionString(params...))
require.Nil(t, err)
return dbo
}

// execWithError executes the prepared query, and validates the error_code.
func execWithError(t *testing.T, dbo *sql.DB, errorCodes []uint16, stmt string, params ...interface{}) {
_, err := dbo.Exec(stmt, params...)
require.NotNilf(t, err, "error expected, got nil")
require.Contains(t, errorCodes, err.(*mysql.MySQLError).Number)
}

// exec executes the query using the params.
func exec(t *testing.T, dbo *sql.DB, stmt string, params ...interface{}) {
require.Nil(t, execErr(dbo, stmt, params...))
}

// execErr executes the query and returns an error if one occurs.
func execErr(dbo *sql.DB, stmt string, params ...interface{}) *mysql.MySQLError {
if _, err := dbo.Exec(stmt, params...); err != nil {
return err.(*mysql.MySQLError)
}
return nil
}

// selectWhere select the row corresponding to the where condition.
func selectWhere(t *testing.T, dbo *sql.DB, where string, params ...interface{}) []tableData {
var out []tableData
// prepare query
qry := "SELECT msg, data, text_col FROM " + tableName
if where != "" {
qry += " WHERE (" + where + ")"
}

// execute query
r, err := dbo.Query(qry, params...)
require.Nil(t, err)

// prepare result
for r.Next() {
var t tableData
r.Scan(&t.Msg, &t.Data, &t.TextCol)
out = append(out, t)
}
return out
}
Loading

0 comments on commit 7fe2822

Please sign in to comment.