104 lines
4.3 KiB
Go
104 lines
4.3 KiB
Go
package dbmigration
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"git.pcux.cn/xuans/Smail/config"
|
|
)
|
|
|
|
// 用真实行扫描接口重放云端驱动类型;这些用例不能代替双 SQL 实机验收。
|
|
func TestPortableFixedCharacterDriverValues(t *testing.T) {
|
|
for _, item := range []struct {
|
|
name string
|
|
kind config.DatabaseType
|
|
columnType string
|
|
input, want any
|
|
}{
|
|
{"postgres_empty", config.DatabaseTypePostgreSQL, "BPCHAR", []byte(" "), []byte("")},
|
|
{"postgres_token", config.DatabaseTypePostgreSQL, "BPCHAR", []byte("abc "), []byte("abc")},
|
|
{"postgres_string", config.DatabaseTypePostgreSQL, "BPCHAR", "abc ", "abc"},
|
|
{"postgres_null", config.DatabaseTypePostgreSQL, "BPCHAR", nil, nil},
|
|
{"mysql_padding", config.DatabaseTypeMySQL, "CHAR", []byte("abc "), []byte("abc")},
|
|
{"postgres_leading_space", config.DatabaseTypePostgreSQL, "BPCHAR", []byte(" abc "), []byte(" abc")},
|
|
{"postgres_other_whitespace", config.DatabaseTypePostgreSQL, "BPCHAR", []byte("abc\t\n\u00a0 "), []byte("abc\t\n\u00a0")},
|
|
{"postgres_varchar", config.DatabaseTypePostgreSQL, "VARCHAR", "abc ", "abc "},
|
|
{"mysql_varchar", config.DatabaseTypeMySQL, "VARCHAR", []byte("abc "), []byte("abc ")},
|
|
{"postgres_text", config.DatabaseTypePostgreSQL, "TEXT", "abc ", "abc "},
|
|
{"postgres_binary", config.DatabaseTypePostgreSQL, "BYTEA", []byte{0, 255, 32, 32}, []byte{0, 255, 32, 32}},
|
|
{"mysql_binary", config.DatabaseTypeMySQL, "BLOB", []byte{0, 255, 32}, []byte{0, 255, 32}},
|
|
{"sqlite_char", config.DatabaseTypeSQLite, "CHAR", "abc ", "abc "},
|
|
{"sqlite_bpchar", config.DatabaseTypeSQLite, "BPCHAR", []byte("abc "), []byte("abc ")},
|
|
} {
|
|
t.Run(item.name, func(t *testing.T) {
|
|
database := portableCharacterFixture(t, item.columnType, item.input)
|
|
count := 0
|
|
err := visitPortableRows(context.Background(), database, item.kind, "sample", []string{"value"}, func(values []any) error {
|
|
count++
|
|
if !reflect.DeepEqual(values[0], item.want) {
|
|
t.Fatal("定长字符填充或非定长数据处理错误")
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil || count != 1 {
|
|
t.Fatal("驱动类型重放未完成")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPortableFixedCharacterDigest(t *testing.T) {
|
|
for _, item := range []struct {
|
|
name string
|
|
sourceType, targetType string
|
|
source, target any
|
|
equal bool
|
|
}{
|
|
{"empty_padding", "CHAR", "BPCHAR", []byte(""), []byte(" "), true},
|
|
{"token_padding", "CHAR", "BPCHAR", []byte("abc"), []byte("abc "), true},
|
|
{"changed_token", "CHAR", "BPCHAR", []byte("abc"), []byte("abd "), false},
|
|
{"leading_space", "CHAR", "BPCHAR", []byte("abc"), []byte(" abc "), false},
|
|
{"null_not_empty", "CHAR", "BPCHAR", nil, []byte(" "), false},
|
|
{"varchar_space", "VARCHAR", "VARCHAR", []byte("abc"), "abc ", false},
|
|
{"text_space", "TEXT", "TEXT", []byte("abc"), "abc ", false},
|
|
{"binary_space", "BLOB", "BYTEA", []byte{0, 255}, []byte{0, 255, 32}, false},
|
|
} {
|
|
t.Run(item.name, func(t *testing.T) {
|
|
source := portableCharacterFixture(t, item.sourceType, item.source)
|
|
target := portableCharacterFixture(t, item.targetType, item.target)
|
|
types := map[string]string{"value": item.targetType}
|
|
left, err := digestPortableTable(context.Background(), source, config.DatabaseTypeMySQL, "sample", []string{"value"}, types, config.DatabaseTypePostgreSQL)
|
|
if err != nil {
|
|
t.Fatal("源摘要计算失败")
|
|
}
|
|
right, err := digestPortableTable(context.Background(), target, config.DatabaseTypePostgreSQL, "sample", []string{"value"}, types, config.DatabaseTypePostgreSQL)
|
|
if err != nil {
|
|
t.Fatal("目标摘要计算失败")
|
|
}
|
|
if (left == right) != item.equal {
|
|
t.Fatal("摘要未区分填充与真实数据差异")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func portableCharacterFixture(t *testing.T, columnType string, value any) *sql.DB {
|
|
t.Helper()
|
|
database, err := sql.Open("sqlite", ":memory:")
|
|
if err != nil {
|
|
t.Fatal("创建重放数据库失败")
|
|
}
|
|
database.SetMaxOpenConns(1)
|
|
t.Cleanup(func() { _ = database.Close() })
|
|
// 类型来自本文件固定用例,不接受外部输入。
|
|
if _, err := database.Exec("CREATE TABLE sample (value " + columnType + ")"); err != nil {
|
|
t.Fatal("创建重放表失败")
|
|
}
|
|
if _, err := database.Exec("INSERT INTO sample(value) VALUES (?)", value); err != nil {
|
|
t.Fatal("写入重放值失败")
|
|
}
|
|
return database
|
|
}
|