Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

633 lines (531 sloc) 12.302 kb
package mysql
import (
"database/sql"
"fmt"
"net"
"os"
"sync"
"testing"
)
var (
dsn string
netAddr string
run bool
once sync.Once
)
// See https://github.com/Go-SQL-Driver/MySQL/wiki/Testing
func getEnv() bool {
once.Do(func() {
user := os.Getenv("MYSQL_TEST_USER")
if user == "" {
user = "root"
}
pass := os.Getenv("MYSQL_TEST_PASS")
prot := os.Getenv("MYSQL_TEST_PROT")
if prot == "" {
prot = "tcp"
}
addr := os.Getenv("MYSQL_TEST_ADDR")
if addr == "" {
addr = "localhost:3306"
}
dbname := os.Getenv("MYSQL_TEST_DBNAME")
if dbname == "" {
dbname = "gotest"
}
netAddr = fmt.Sprintf("%s(%s)", prot, addr)
dsn = fmt.Sprintf("%s:%s@%s/%s?charset=utf8", user, pass, netAddr, dbname)
c, err := net.Dial(prot, addr)
if err == nil {
run = true
c.Close()
}
})
return run
}
func mustExec(t *testing.T, db *sql.DB, query string, args ...interface{}) (res sql.Result) {
res, err := db.Exec(query, args...)
if err != nil {
t.Fatalf("Error on Exec %q: %v", query, err)
}
return
}
func mustQuery(t *testing.T, db *sql.DB, query string, args ...interface{}) (rows *sql.Rows) {
rows, err := db.Query(query, args...)
if err != nil {
t.Fatalf("Error on Query %q: %v", query, err)
}
return
}
func TestCRUD(t *testing.T) {
if !getEnv() {
t.Logf("MySQL-Server not running on %s. Skipping TestCRUD", netAddr)
return
}
db, err := sql.Open("mysql", dsn)
if err != nil {
t.Fatalf("Error connecting: %v", err)
}
defer db.Close()
mustExec(t, db, "DROP TABLE IF EXISTS test")
// Create Table
mustExec(t, db, "CREATE TABLE test (value BOOL)")
// Test for unexpected data
var out bool
rows := mustQuery(t, db, ("SELECT * FROM test"))
if rows.Next() {
t.Error("unexpected data in empty table")
}
// Create Data
res := mustExec(t, db, ("INSERT INTO test VALUES (1)"))
count, err := res.RowsAffected()
if err != nil {
t.Fatalf("res.RowsAffected() returned error: %v", err)
}
if count != 1 {
t.Fatalf("Expected 1 affected row, got %d", count)
}
id, err := res.LastInsertId()
if err != nil {
t.Fatalf("res.LastInsertId() returned error: %v", err)
}
if id != 0 {
t.Fatalf("Expected InsertID 0, got %d", id)
}
// Read
rows = mustQuery(t, db, ("SELECT value FROM test"))
if rows.Next() {
rows.Scan(&out)
if true != out {
t.Errorf("true != %t", out)
}
if rows.Next() {
t.Error("unexpected data")
}
} else {
t.Error("no data")
}
// Update
res = mustExec(t, db, "UPDATE test SET value = ? WHERE value = ?", false, true)
count, err = res.RowsAffected()
if err != nil {
t.Fatalf("res.RowsAffected() returned error: %v", err)
}
if count != 1 {
t.Fatalf("Expected 1 affected row, got %d", count)
}
// Check Update
rows = mustQuery(t, db, ("SELECT value FROM test"))
if rows.Next() {
rows.Scan(&out)
if false != out {
t.Errorf("false != %t", out)
}
if rows.Next() {
t.Error("unexpected data")
}
} else {
t.Error("no data")
}
// Delete
res = mustExec(t, db, "DELETE FROM test WHERE value = ?", false)
count, err = res.RowsAffected()
if err != nil {
t.Fatalf("res.RowsAffected() returned error: %v", err)
}
if count != 1 {
t.Fatalf("Expected 1 affected row, got %d", count)
}
// Check for unexpected rows
res = mustExec(t, db, "DELETE FROM test")
count, err = res.RowsAffected()
if err != nil {
t.Fatalf("res.RowsAffected() returned error: %v", err)
}
if count != 0 {
t.Fatalf("Expected 0 affected row, got %d", count)
}
}
func TestInt(t *testing.T) {
if !getEnv() {
t.Logf("MySQL-Server not running on %s. Skipping TestInt", netAddr)
return
}
db, err := sql.Open("mysql", dsn)
if err != nil {
t.Fatalf("Error connecting: %v", err)
}
defer db.Close()
mustExec(t, db, "DROP TABLE IF EXISTS test")
types := [5]string{"TINYINT", "SMALLINT", "MEDIUMINT", "INT", "BIGINT"}
in := int64(42)
var out int64
var rows *sql.Rows
// SIGNED
for _, v := range types {
mustExec(t, db, "CREATE TABLE test (value "+v+")")
mustExec(t, db, ("INSERT INTO test VALUES (?)"), in)
rows = mustQuery(t, db, ("SELECT value FROM test"))
if rows.Next() {
rows.Scan(&out)
if in != out {
t.Errorf("%s: %d != %d", v, in, out)
}
} else {
t.Errorf("%s: no data", v)
}
mustExec(t, db, "DROP TABLE IF EXISTS test")
}
// UNSIGNED ZEROFILL
for _, v := range types {
mustExec(t, db, "CREATE TABLE test (value "+v+" ZEROFILL)")
mustExec(t, db, ("INSERT INTO test VALUES (?)"), in)
rows = mustQuery(t, db, ("SELECT value FROM test"))
if rows.Next() {
rows.Scan(&out)
if in != out {
t.Errorf("%s ZEROFILL: %d != %d", v, in, out)
}
} else {
t.Errorf("%s ZEROFILL: no data", v)
}
mustExec(t, db, "DROP TABLE IF EXISTS test")
}
}
func TestFloat(t *testing.T) {
if !getEnv() {
t.Logf("MySQL-Server not running on %s. Skipping TestFloat", netAddr)
return
}
db, err := sql.Open("mysql", dsn)
if err != nil {
t.Fatalf("Error connecting: %v", err)
}
defer db.Close()
mustExec(t, db, "DROP TABLE IF EXISTS test")
types := [2]string{"FLOAT", "DOUBLE"}
in := float32(42.23)
var out float32
var rows *sql.Rows
for _, v := range types {
mustExec(t, db, "CREATE TABLE test (value "+v+")")
mustExec(t, db, ("INSERT INTO test VALUES (?)"), in)
rows = mustQuery(t, db, ("SELECT value FROM test"))
if rows.Next() {
rows.Scan(&out)
if in != out {
t.Errorf("%s: %g != %g", v, in, out)
}
} else {
t.Errorf("%s: no data", v)
}
mustExec(t, db, "DROP TABLE IF EXISTS test")
}
}
func TestString(t *testing.T) {
if !getEnv() {
t.Logf("MySQL-Server not running on %s. Skipping TestString", netAddr)
return
}
db, err := sql.Open("mysql", dsn)
if err != nil {
t.Fatalf("Error connecting: %v", err)
}
defer db.Close()
mustExec(t, db, "DROP TABLE IF EXISTS test")
types := [6]string{"CHAR(255)", "VARCHAR(255)", "TINYTEXT", "TEXT", "MEDIUMTEXT", "LONGTEXT"}
in := "κόσμε üöäßñóùéàâÿœ'îë Árvíztűrő いろはにほへとちりぬるを イロハニホヘト דג סקרן чащах น่าฟังเอย"
var out string
var rows *sql.Rows
for _, v := range types {
mustExec(t, db, "CREATE TABLE test (value "+v+") CHARACTER SET utf8 COLLATE utf8_unicode_ci")
mustExec(t, db, ("INSERT INTO test VALUES (?)"), in)
rows = mustQuery(t, db, ("SELECT value FROM test"))
if rows.Next() {
rows.Scan(&out)
if in != out {
t.Errorf("%s: %s != %s", v, in, out)
}
} else {
t.Errorf("%s: no data", v)
}
mustExec(t, db, "DROP TABLE IF EXISTS test")
}
}
func TestNULL(t *testing.T) {
if !getEnv() {
t.Logf("MySQL-Server not running on %s. Skipping TestNULL", netAddr)
return
}
db, err := sql.Open("mysql", dsn)
if err != nil {
t.Fatalf("Error connecting: %v", err)
}
defer db.Close()
nullStmt, err := db.Prepare("SELECT NULL")
if err != nil {
t.Fatal(err)
}
defer nullStmt.Close()
nonNullStmt, err := db.Prepare("SELECT 1")
if err != nil {
t.Fatal(err)
}
defer nonNullStmt.Close()
// NullBool
var nb sql.NullBool
// Invalid
err = nullStmt.QueryRow().Scan(&nb)
if err != nil {
t.Fatal(err)
}
if nb.Valid {
t.Error("Valid NullBool which should be invalid")
}
// Valid
err = nonNullStmt.QueryRow().Scan(&nb)
if err != nil {
t.Fatal(err)
}
if !nb.Valid {
t.Error("Invalid NullBool which should be valid")
} else if nb.Bool != true {
t.Errorf("Unexpected NullBool value: %t (should be true)", nb.Bool)
}
// NullFloat64
var nf sql.NullFloat64
// Invalid
err = nullStmt.QueryRow().Scan(&nf)
if err != nil {
t.Fatal(err)
}
if nf.Valid {
t.Error("Valid NullFloat64 which should be invalid")
}
// Valid
err = nonNullStmt.QueryRow().Scan(&nf)
if err != nil {
t.Fatal(err)
}
if !nf.Valid {
t.Error("Invalid NullFloat64 which should be valid")
} else if nf.Float64 != float64(1) {
t.Errorf("Unexpected NullFloat64 value: %f (should be 1.0)", nf.Float64)
}
// NullInt64
var ni sql.NullInt64
// Invalid
err = nullStmt.QueryRow().Scan(&ni)
if err != nil {
t.Fatal(err)
}
if ni.Valid {
t.Error("Valid NullInt64 which should be invalid")
}
// Valid
err = nonNullStmt.QueryRow().Scan(&ni)
if err != nil {
t.Fatal(err)
}
if !ni.Valid {
t.Error("Invalid NullInt64 which should be valid")
} else if ni.Int64 != int64(1) {
t.Errorf("Unexpected NullInt64 value: %d (should be 1)", ni.Int64)
}
// NullString
var ns sql.NullString
// Invalid
err = nullStmt.QueryRow().Scan(&ns)
if err != nil {
t.Fatal(err)
}
if ns.Valid {
t.Error("Valid NullString which should be invalid")
}
// Valid
err = nonNullStmt.QueryRow().Scan(&ns)
if err != nil {
t.Fatal(err)
}
if !ns.Valid {
t.Error("Invalid NullString which should be valid")
} else if ns.String != `1` {
t.Error("Unexpected NullString value:" + ns.String + " (should be `1`)")
}
}
// Special cases
func TestRowsClose(t *testing.T) {
if !getEnv() {
t.Logf("MySQL-Server not running on %s. Skipping TestRowsClose", netAddr)
return
}
db, err := sql.Open("mysql", dsn)
if err != nil {
t.Fatalf("Error connecting: %v", err)
}
defer db.Close()
rows, err := db.Query("SELECT 1")
if err != nil {
t.Fatal(err)
}
err = rows.Close()
if err != nil {
t.Fatal(err)
}
if rows.Next() {
t.Fatal("Unexpected row after rows.Close()")
}
err = rows.Err()
if err != nil {
t.Fatal(err)
}
}
// dangling statements
// http://code.google.com/p/go/issues/detail?id=3865
func TestCloseStmtBeforeRows(t *testing.T) {
if !getEnv() {
t.Logf("MySQL-Server not running on %s. Skipping TestCloseStmtBeforeRows", netAddr)
return
}
db, err := sql.Open("mysql", dsn)
if err != nil {
t.Fatalf("Error connecting: %v", err)
}
defer db.Close()
stmt, err := db.Prepare("SELECT 1")
if err != nil {
t.Fatal(err)
}
rows, err := stmt.Query()
if err != nil {
stmt.Close()
t.Fatal(err)
}
defer rows.Close()
err = stmt.Close()
if err != nil {
t.Fatal(err)
}
if !rows.Next() {
t.Fatal("Getting row failed")
} else {
err = rows.Err()
if err != nil {
t.Fatal(err)
}
var out bool
err = rows.Scan(&out)
if err != nil {
t.Fatalf("Error on rows.Scan(): %v", err)
}
if out != true {
t.Errorf("true != %t", out)
}
}
}
// It is valid to have multiple Rows for the same Stmt
// http://code.google.com/p/go/issues/detail?id=3734
func TestStmtMultiRows(t *testing.T) {
if !getEnv() {
t.Logf("MySQL-Server not running on %s. Skipping TestStmtMultiRows", netAddr)
return
}
db, err := sql.Open("mysql", dsn)
if err != nil {
t.Fatalf("Error connecting: %v", err)
}
defer db.Close()
stmt, err := db.Prepare("SELECT 1 UNION SELECT 0")
if err != nil {
t.Fatal(err)
}
rows1, err := stmt.Query()
if err != nil {
stmt.Close()
t.Fatal(err)
}
defer rows1.Close()
rows2, err := stmt.Query()
if err != nil {
stmt.Close()
t.Fatal(err)
}
defer rows2.Close()
var out bool
// 1
if !rows1.Next() {
t.Fatal("1st rows1.Next failed")
} else {
err = rows1.Err()
if err != nil {
t.Fatal(err)
}
err = rows1.Scan(&out)
if err != nil {
t.Fatalf("Error on rows.Scan(): %v", err)
}
if out != true {
t.Errorf("true != %t", out)
}
}
if !rows2.Next() {
t.Fatal("1st rows2.Next failed")
} else {
err = rows2.Err()
if err != nil {
t.Fatal(err)
}
err = rows2.Scan(&out)
if err != nil {
t.Fatalf("Error on rows.Scan(): %v", err)
}
if out != true {
t.Errorf("true != %t", out)
}
}
// 2
if !rows1.Next() {
t.Fatal("2nd rows1.Next failed")
} else {
err = rows1.Err()
if err != nil {
t.Fatal(err)
}
err = rows1.Scan(&out)
if err != nil {
t.Fatalf("Error on rows.Scan(): %v", err)
}
if out != false {
t.Errorf("false != %t", out)
}
if rows1.Next() {
t.Fatal("Unexpected row on rows1")
}
err = rows1.Close()
if err != nil {
t.Fatal(err)
}
}
if !rows2.Next() {
t.Fatal("2nd rows2.Next failed")
} else {
err = rows2.Err()
if err != nil {
t.Fatal(err)
}
err = rows2.Scan(&out)
if err != nil {
t.Fatalf("Error on rows.Scan(): %v", err)
}
if out != false {
t.Errorf("false != %t", out)
}
if rows2.Next() {
t.Fatal("Unexpected row on rows2")
}
err = rows2.Close()
if err != nil {
t.Fatal(err)
}
}
}
Jump to Line
Something went wrong with that request. Please try again.