Skip to content

Add test for Conn.ExecuteSelectStreaming #649

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 1 addition & 23 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,16 @@ package client

import (
"encoding/json"
"flag"
"fmt"
"strings"
"testing"

"github.com/go-mysql-org/go-mysql/test_util/test_keys"
. "github.com/pingcap/check"
"github.com/pingcap/errors"

"github.com/go-mysql-org/go-mysql/mysql"
"github.com/go-mysql-org/go-mysql/test_util/test_keys"
)

var testHost = flag.String("host", "127.0.0.1", "MySQL server host")

// We cover the whole range of MySQL server versions using docker-compose to bind them to different ports for testing.
// MySQL is constantly updating auth plugin to make it secure:
// starting from MySQL 8.0.4, a new auth plugin is introduced, causing plain password auth to fail with error:
// ERROR 1251 (08004): Client does not support authentication protocol requested by server; consider upgrading MySQL client
// Hint: use docker-compose to start corresponding MySQL docker containers and add the their ports here
var testPort = flag.String("port", "3306", "MySQL server port") // choose one or more form 5561,5641,3306,5722,8003,8012,8013, e.g. '3306,5722,8003'
var testUser = flag.String("user", "root", "MySQL user")
var testPassword = flag.String("pass", "", "MySQL password")
var testDB = flag.String("db", "test", "MySQL test database")

func Test(t *testing.T) {
segs := strings.Split(*testPort, ",")
for _, seg := range segs {
Suite(&clientTestSuite{port: seg})
}
TestingT(t)
}

type clientTestSuite struct {
c *Conn
port string
Expand Down
30 changes: 30 additions & 0 deletions client/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package client

import (
"flag"
"strings"
"testing"

. "github.com/pingcap/check"
)

var testHost = flag.String("host", "127.0.0.1", "MySQL server host")

// We cover the whole range of MySQL server versions using docker-compose to bind them to different ports for testing.
// MySQL is constantly updating auth plugin to make it secure:
// starting from MySQL 8.0.4, a new auth plugin is introduced, causing plain password auth to fail with error:
// ERROR 1251 (08004): Client does not support authentication protocol requested by server; consider upgrading MySQL client
// Hint: use docker-compose to start corresponding MySQL docker containers and add the their ports here
var testPort = flag.String("port", "3306", "MySQL server port") // choose one or more form 5561,5641,3306,5722,8003,8012,8013, e.g. '3306,5722,8003'
var testUser = flag.String("user", "root", "MySQL user")
var testPassword = flag.String("pass", "", "MySQL password")
var testDB = flag.String("db", "test", "MySQL test database")

func Test(t *testing.T) {
segs := strings.Split(*testPort, ",")
for _, seg := range segs {
Suite(&clientTestSuite{port: seg})
Suite(&connTestSuite{port: seg})
}
TestingT(t)
}
126 changes: 126 additions & 0 deletions client/conn_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package client

import (
"fmt"

. "github.com/pingcap/check"

"github.com/go-mysql-org/go-mysql/mysql"
)

type connTestSuite struct {
c *Conn
port string
}

func (s *connTestSuite) SetUpSuite(c *C) {
var err error
addr := fmt.Sprintf("%s:%s", *testHost, s.port)
s.c, err = Connect(addr, *testUser, *testPassword, "")
if err != nil {
c.Fatal(err)
}

_, err = s.c.Execute("CREATE DATABASE IF NOT EXISTS " + *testDB)
c.Assert(err, IsNil)

_, err = s.c.Execute("USE " + *testDB)
c.Assert(err, IsNil)

s.testExecute_CreateTable(c)
}

func (s *connTestSuite) TearDownSuite(c *C) {
if s.c == nil {
return
}

s.testExecute_DropTable(c)

if s.c != nil {
s.c.Close()
}
}

var (
testExecuteSelectStreamingRows = [...]string{"foo", "helloworld", "bar", "", "spam"}
testExecuteSelectStreamingTablename = "execute_plain_table"
)

func (s *connTestSuite) testExecute_CreateTable(c *C) {
Copy link
Collaborator

@lance6716 lance6716 Dec 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if we should follow go's naming style like testExecuteCreateTable. This repo also has some variables using underscore so I think it doesn't matter 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copypasted this style from neighbour clientTestSuite :)

str := `CREATE TABLE IF NOT EXISTS ` + testExecuteSelectStreamingTablename + ` (
id INT UNSIGNED NOT NULL,
str VARCHAR(256),
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8`

result, err := s.c.Execute(str)
c.Assert(err, IsNil)
result.Close()

result, err = s.c.Execute(`TRUNCATE TABLE ` + testExecuteSelectStreamingTablename)
c.Assert(err, IsNil)
result.Close()

stmt, err := s.c.Prepare(`INSERT INTO ` + testExecuteSelectStreamingTablename + ` (id, str) VALUES (?, ?)`)
c.Assert(err, IsNil)
defer stmt.Close()

for id, str := range testExecuteSelectStreamingRows {
result, err := stmt.Execute(id, str)
c.Assert(err, IsNil)
result.Close()
}
}

func (s *connTestSuite) testExecute_DropTable(c *C) {
_, err := s.c.Execute(`drop table if exists ` + testExecuteSelectStreamingTablename)
c.Assert(err, IsNil)
}

func (s *connTestSuite) TestExecuteSelectStreaming(c *C) {
var (
expectedRowId int64
perResultCallbackCalledTimes int
result mysql.Result
)

const colsInResult = 2 // id, str

err := s.c.ExecuteSelectStreaming(`SELECT id, str FROM `+testExecuteSelectStreamingTablename+` ORDER BY id`,
&result,
func(row []mysql.FieldValue) error {
// Check number of columns
c.Assert(row, HasLen, colsInResult)
// Check type of columns
c.Assert(row[0].Type, Equals, mysql.FieldValueType(mysql.FieldValueTypeUnsigned))
c.Assert(row[1].Type, Equals, mysql.FieldValueType(mysql.FieldValueTypeString))

id := row[0].AsInt64()
str := row[1].AsString()

// Check order of rows
c.Assert(id, Equals, expectedRowId)
// Check string values (protection from incorrect reuse of memory)
c.Assert(string(str), Equals, testExecuteSelectStreamingRows[id])

expectedRowId++

return nil
}, func(result *mysql.Result) error {
// result.Resultset must be defined at this point
c.Assert(result.Resultset, NotNil)
// Check number of columns
c.Assert(result.Resultset.Fields, HasLen, colsInResult)

perResultCallbackCalledTimes++
return nil
})
c.Assert(err, IsNil)

// Check total rows count
c.Assert(expectedRowId, Equals, int64(len(testExecuteSelectStreamingRows)))

// Check perResultCallback call count
c.Assert(perResultCallbackCalledTimes, Equals, 1)
}