Этот коммит содержится в:
Christopher Speller
2018-01-29 14:17:40 -08:00
коммит произвёл GitHub
родитель 8d66523ba7
Коммит 961c04cae9
1508 изменённых файлов: 182081 добавлений и 24688 удалений

310
vendor/github.com/go-sql-driver/mysql/driver_test.go сгенерированный поставляемый
Просмотреть файл

@@ -27,6 +27,12 @@ import (
"time"
)
// Ensure that all the driver interfaces are implemented
var (
_ driver.Rows = &binaryRows{}
_ driver.Rows = &textRows{}
)
var (
user string
pass string
@@ -63,7 +69,7 @@ func init() {
addr = env("MYSQL_TEST_ADDR", "localhost:3306")
dbname = env("MYSQL_TEST_DBNAME", "gotest")
netAddr = fmt.Sprintf("%s(%s)", prot, addr)
dsn = fmt.Sprintf("%s:%s@%s/%s?timeout=30s&strict=true", user, pass, netAddr, dbname)
dsn = fmt.Sprintf("%s:%s@%s/%s?timeout=30s", user, pass, netAddr, dbname)
c, err := net.Dial(prot, addr)
if err == nil {
available = true
@@ -171,6 +177,17 @@ func (dbt *DBTest) mustQuery(query string, args ...interface{}) (rows *sql.Rows)
return rows
}
func maybeSkip(t *testing.T, err error, skipErrno uint16) {
mySQLErr, ok := err.(*MySQLError)
if !ok {
return
}
if mySQLErr.Number == skipErrno {
t.Skipf("skipping test for error: %v", err)
}
}
func TestEmptyQuery(t *testing.T) {
runTests(t, dsn, func(dbt *DBTest) {
// just a comment, no query
@@ -482,6 +499,85 @@ func TestString(t *testing.T) {
})
}
type testValuer struct {
value string
}
func (tv testValuer) Value() (driver.Value, error) {
return tv.value, nil
}
func TestValuer(t *testing.T) {
runTests(t, dsn, func(dbt *DBTest) {
in := testValuer{"a_value"}
var out string
var rows *sql.Rows
dbt.mustExec("CREATE TABLE test (value VARCHAR(255)) CHARACTER SET utf8")
dbt.mustExec("INSERT INTO test VALUES (?)", in)
rows = dbt.mustQuery("SELECT value FROM test")
if rows.Next() {
rows.Scan(&out)
if in.value != out {
dbt.Errorf("Valuer: %v != %s", in, out)
}
} else {
dbt.Errorf("Valuer: no data")
}
dbt.mustExec("DROP TABLE IF EXISTS test")
})
}
type testValuerWithValidation struct {
value string
}
func (tv testValuerWithValidation) Value() (driver.Value, error) {
if len(tv.value) == 0 {
return nil, fmt.Errorf("Invalid string valuer. Value must not be empty")
}
return tv.value, nil
}
func TestValuerWithValidation(t *testing.T) {
runTests(t, dsn, func(dbt *DBTest) {
in := testValuerWithValidation{"a_value"}
var out string
var rows *sql.Rows
dbt.mustExec("CREATE TABLE testValuer (value VARCHAR(255)) CHARACTER SET utf8")
dbt.mustExec("INSERT INTO testValuer VALUES (?)", in)
rows = dbt.mustQuery("SELECT value FROM testValuer")
defer rows.Close()
if rows.Next() {
rows.Scan(&out)
if in.value != out {
dbt.Errorf("Valuer: %v != %s", in, out)
}
} else {
dbt.Errorf("Valuer: no data")
}
if _, err := dbt.db.Exec("INSERT INTO testValuer VALUES (?)", testValuerWithValidation{""}); err == nil {
dbt.Errorf("Failed to check valuer error")
}
if _, err := dbt.db.Exec("INSERT INTO testValuer VALUES (?)", nil); err != nil {
dbt.Errorf("Failed to check nil")
}
if _, err := dbt.db.Exec("INSERT INTO testValuer VALUES (?)", map[string]bool{}); err == nil {
dbt.Errorf("Failed to check not valuer")
}
dbt.mustExec("DROP TABLE IF EXISTS testValuer")
})
}
type timeTests struct {
dbtype string
tlayout string
@@ -684,7 +780,7 @@ func TestDateTime(t *testing.T) {
for _, setup := range setups.tests {
allowBinTime := true
if setup.s == "" {
// fill time string whereever Go can reliable produce it
// fill time string wherever Go can reliable produce it
setup.s = setup.t.Format(setups.tlayout)
} else if setup.s[0] == '!' {
// skip tests using setup.t as source in queries
@@ -856,14 +952,14 @@ func TestNULL(t *testing.T) {
dbt.Fatal(err)
}
if b != nil {
dbt.Error("non-nil []byte wich should be nil")
dbt.Error("non-nil []byte which should be nil")
}
// Read non-nil
if err = nonNullStmt.QueryRow().Scan(&b); err != nil {
dbt.Fatal(err)
}
if b == nil {
dbt.Error("nil []byte wich should be non-nil")
dbt.Error("nil []byte which should be non-nil")
}
// Insert nil
b = nil
@@ -953,7 +1049,7 @@ func TestUint64(t *testing.T) {
}
func TestLongData(t *testing.T) {
runTests(t, dsn, func(dbt *DBTest) {
runTests(t, dsn+"&maxAllowedPacket=0", func(dbt *DBTest) {
var maxAllowedPacketSize int
err := dbt.db.QueryRow("select @@max_allowed_packet").Scan(&maxAllowedPacketSize)
if err != nil {
@@ -1054,22 +1150,36 @@ func TestLoadData(t *testing.T) {
dbt.Fatalf("rows count mismatch. Got %d, want 4", i)
}
}
file, err := ioutil.TempFile("", "gotest")
defer os.Remove(file.Name())
if err != nil {
dbt.Fatal(err)
}
file.WriteString("1\ta string\n2\ta string containing a \\t\n3\ta string containing a \\n\n4\ta string containing both \\t\\n\n")
file.Close()
dbt.db.Exec("DROP TABLE IF EXISTS test")
dbt.mustExec("CREATE TABLE test (id INT NOT NULL PRIMARY KEY, value TEXT NOT NULL) CHARACTER SET utf8")
// Local File
file, err := ioutil.TempFile("", "gotest")
defer os.Remove(file.Name())
if err != nil {
dbt.Fatal(err)
}
RegisterLocalFile(file.Name())
// Try first with empty file
dbt.mustExec(fmt.Sprintf("LOAD DATA LOCAL INFILE %q INTO TABLE test", file.Name()))
var count int
err = dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&count)
if err != nil {
dbt.Fatal(err.Error())
}
if count != 0 {
dbt.Fatalf("unexpected row count: got %d, want 0", count)
}
// Then fille File with data and try to load it
file.WriteString("1\ta string\n2\ta string containing a \\t\n3\ta string containing a \\n\n4\ta string containing both \\t\\n\n")
file.Close()
dbt.mustExec(fmt.Sprintf("LOAD DATA LOCAL INFILE %q INTO TABLE test", file.Name()))
verifyLoadDataResult()
// negative test
// Try with non-existing file
_, err = dbt.db.Exec("LOAD DATA LOCAL INFILE 'doesnotexist' INTO TABLE test")
if err == nil {
dbt.Fatal("load non-existent file didn't fail")
@@ -1145,84 +1255,6 @@ func TestFoundRows(t *testing.T) {
})
}
func TestStrict(t *testing.T) {
// ALLOW_INVALID_DATES to get rid of stricter modes - we want to test for warnings, not errors
relaxedDsn := dsn + "&sql_mode='ALLOW_INVALID_DATES,NO_AUTO_CREATE_USER'"
// make sure the MySQL version is recent enough with a separate connection
// before running the test
conn, err := MySQLDriver{}.Open(relaxedDsn)
if conn != nil {
conn.Close()
}
if me, ok := err.(*MySQLError); ok && me.Number == 1231 {
// Error 1231: Variable 'sql_mode' can't be set to the value of 'ALLOW_INVALID_DATES'
// => skip test, MySQL server version is too old
return
}
runTests(t, relaxedDsn, func(dbt *DBTest) {
dbt.mustExec("CREATE TABLE test (a TINYINT NOT NULL, b CHAR(4))")
var queries = [...]struct {
in string
codes []string
}{
{"DROP TABLE IF EXISTS no_such_table", []string{"1051"}},
{"INSERT INTO test VALUES(10,'mysql'),(NULL,'test'),(300,'Open Source')", []string{"1265", "1048", "1264", "1265"}},
}
var err error
var checkWarnings = func(err error, mode string, idx int) {
if err == nil {
dbt.Errorf("expected STRICT error on query [%s] %s", mode, queries[idx].in)
}
if warnings, ok := err.(MySQLWarnings); ok {
var codes = make([]string, len(warnings))
for i := range warnings {
codes[i] = warnings[i].Code
}
if len(codes) != len(queries[idx].codes) {
dbt.Errorf("unexpected STRICT error count on query [%s] %s: Wanted %v, Got %v", mode, queries[idx].in, queries[idx].codes, codes)
}
for i := range warnings {
if codes[i] != queries[idx].codes[i] {
dbt.Errorf("unexpected STRICT error codes on query [%s] %s: Wanted %v, Got %v", mode, queries[idx].in, queries[idx].codes, codes)
return
}
}
} else {
dbt.Errorf("unexpected error on query [%s] %s: %s", mode, queries[idx].in, err.Error())
}
}
// text protocol
for i := range queries {
_, err = dbt.db.Exec(queries[i].in)
checkWarnings(err, "text", i)
}
var stmt *sql.Stmt
// binary protocol
for i := range queries {
stmt, err = dbt.db.Prepare(queries[i].in)
if err != nil {
dbt.Errorf("error on preparing query %s: %s", queries[i].in, err.Error())
}
_, err = stmt.Exec()
checkWarnings(err, "binary", i)
err = stmt.Close()
if err != nil {
dbt.Errorf("error on closing stmt for query %s: %s", queries[i].in, err.Error())
}
}
})
}
func TestTLS(t *testing.T) {
tlsTest := func(dbt *DBTest) {
if err := dbt.db.Ping(); err != nil {
@@ -1422,7 +1454,6 @@ func TestTimezoneConversion(t *testing.T) {
// Regression test for timezone handling
tzTest := func(dbt *DBTest) {
// Create table
dbt.mustExec("CREATE TABLE test (ts TIMESTAMP)")
@@ -1638,8 +1669,9 @@ func TestStmtMultiRows(t *testing.T) {
// Regression test for
// * more than 32 NULL parameters (issue 209)
// * more parameters than fit into the buffer (issue 201)
// * parameters * 64 > max_allowed_packet (issue 734)
func TestPreparedManyCols(t *testing.T) {
const numParams = defaultBufSize
numParams := 65535
runTests(t, dsn, func(dbt *DBTest) {
query := "SELECT ?" + strings.Repeat(",?", numParams-1)
stmt, err := dbt.db.Prepare(query)
@@ -1647,15 +1679,25 @@ func TestPreparedManyCols(t *testing.T) {
dbt.Fatal(err)
}
defer stmt.Close()
// create more parameters than fit into the buffer
// which will take nil-values
params := make([]interface{}, numParams)
rows, err := stmt.Query(params...)
if err != nil {
stmt.Close()
dbt.Fatal(err)
}
defer rows.Close()
rows.Close()
// Create 0byte string which we can't send via STMT_LONG_DATA.
for i := 0; i < numParams; i++ {
params[i] = ""
}
rows, err = stmt.Query(params...)
if err != nil {
dbt.Fatal(err)
}
rows.Close()
})
}
@@ -1739,7 +1781,7 @@ func TestCustomDial(t *testing.T) {
return net.Dial(prot, addr)
})
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@mydial(%s)/%s?timeout=30s&strict=true", user, pass, addr, dbname))
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@mydial(%s)/%s?timeout=30s", user, pass, addr, dbname))
if err != nil {
t.Fatalf("error connecting: %s", err.Error())
}
@@ -1836,7 +1878,7 @@ func TestUnixSocketAuthFail(t *testing.T) {
}
}
t.Logf("socket: %s", socket)
badDSN := fmt.Sprintf("%s:%s@unix(%s)/%s?timeout=30s&strict=true", user, badPass, socket, dbname)
badDSN := fmt.Sprintf("%s:%s@unix(%s)/%s?timeout=30s", user, badPass, socket, dbname)
db, err := sql.Open("mysql", badDSN)
if err != nil {
t.Fatalf("error connecting: %s", err.Error())
@@ -1902,3 +1944,77 @@ func TestInterruptBySignal(t *testing.T) {
}
})
}
func TestColumnsReusesSlice(t *testing.T) {
rows := mysqlRows{
rs: resultSet{
columns: []mysqlField{
{
tableName: "test",
name: "A",
},
{
tableName: "test",
name: "B",
},
},
},
}
allocs := testing.AllocsPerRun(1, func() {
cols := rows.Columns()
if len(cols) != 2 {
t.Fatalf("expected 2 columns, got %d", len(cols))
}
})
if allocs != 0 {
t.Fatalf("expected 0 allocations, got %d", int(allocs))
}
if rows.rs.columnNames == nil {
t.Fatalf("expected columnNames to be set, got nil")
}
}
func TestRejectReadOnly(t *testing.T) {
runTests(t, dsn, func(dbt *DBTest) {
// Create Table
dbt.mustExec("CREATE TABLE test (value BOOL)")
// Set the session to read-only. We didn't set the `rejectReadOnly`
// option, so any writes after this should fail.
_, err := dbt.db.Exec("SET SESSION TRANSACTION READ ONLY")
// Error 1193: Unknown system variable 'TRANSACTION' => skip test,
// MySQL server version is too old
maybeSkip(t, err, 1193)
if _, err := dbt.db.Exec("DROP TABLE test"); err == nil {
t.Fatalf("writing to DB in read-only session without " +
"rejectReadOnly did not error")
}
// Set the session back to read-write so runTests() can properly clean
// up the table `test`.
dbt.mustExec("SET SESSION TRANSACTION READ WRITE")
})
// Enable the `rejectReadOnly` option.
runTests(t, dsn+"&rejectReadOnly=true", func(dbt *DBTest) {
// Create Table
dbt.mustExec("CREATE TABLE test (value BOOL)")
// Set the session to read only. Any writes after this should error on
// a driver.ErrBadConn, and cause `database/sql` to initiate a new
// connection.
dbt.mustExec("SET SESSION TRANSACTION READ ONLY")
// This would error, but `database/sql` should automatically retry on a
// new connection which is not read-only, and eventually succeed.
dbt.mustExec("DROP TABLE test")
})
}
func TestPing(t *testing.T) {
runTests(t, dsn, func(dbt *DBTest) {
if err := dbt.db.Ping(); err != nil {
dbt.fail("Ping", "Ping", err)
}
})
}