Forráskód Böngészése

Add MySQL-Driver tests

Julien Schmidt 13 éve
szülő
commit
5a964bf3bf
1 módosított fájl, 539 hozzáadás és 0 törlés
  1. 539 0
      driver_test.go

+ 539 - 0
driver_test.go

@@ -0,0 +1,539 @@
+package mysql
+
+import (
+	"database/sql"
+	"fmt"
+	"net"
+	"os"
+	"sync"
+	"testing"
+)
+
+var (
+	dsn     string
+	netAddr string
+	run     bool
+	once    sync.Once
+)
+
+func getEnv() bool {
+	once.Do(func() {
+		user := os.Getenv("MYSQL_TEST_USER")
+		if user == "" {
+			user = "root"
+		}
+		pass := os.Getenv("MYSQL_TEST_PASS")
+		if pass == "" {
+			pass = "root"
+		}
+		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 != %d", out)
+		}
+
+		if rows.Next() {
+			t.Error("unexpected data")
+		}
+	} else {
+		t.Error("no data")
+	}
+
+	// Update
+	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 != %d", out)
+		}
+
+		if rows.Next() {
+			t.Error("unexpected data")
+		}
+	} else {
+		t.Error("no data")
+	}
+
+	// Delete
+	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)
+	}
+}
+
+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 := float64(42.23)
+	var out float64
+	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: %d != %d", 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: %d != %d", 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()
+
+	stmt, err := db.Prepare("SELECT NULL")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer stmt.Close()
+
+	var ns sql.NullString
+	err = stmt.QueryRow().Scan(&ns)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if ns.Valid {
+		t.Error("Valid NullString which should be invalid")
+	}
+}
+
+// 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 != %d", 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 != %d", 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 != %d", 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 != %d", 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 != %d", out)
+		}
+
+		if rows2.Next() {
+			t.Fatal("Unexpected row on rows2")
+		}
+		err = rows2.Close()
+		if err != nil {
+			t.Fatal(err)
+		}
+	}
+
+}