Files
db/engine/engine_config_test.go
T
whatandClaude 304d553b3c docs: Add CLAUDE.md with codebase guidance
Create comprehensive documentation for future Claude Code instances working in this repository, including:
- Development commands for testing, building, and code quality
- Core architecture overview of the SQL query builder system
- Directory structure and component explanations
- Testing patterns and conventions
- Key dependencies and their purposes

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-27 15:47:28 +08:00

384 lines
10 KiB
Go

package engine_test
import (
"testing"
"time"
"git.fsdpf.net/go/db/engine"
)
// TestMySQLConfig 测试 MySQL 驱动的配置
func TestMySQLConfig(t *testing.T) {
tests := []struct {
name string
options []engine.Option
wantErr bool
errMsg string
}{
{
name: "Valid Config",
options: []engine.Option{
engine.WithHost("localhost"),
engine.WithDatabase("testdb"),
engine.WithUsername("root"),
engine.WithPassword("password"),
engine.WithMySQLCollation("utf8mb4_unicode_ci"),
},
wantErr: false,
},
{
name: "Missing Host",
options: []engine.Option{
engine.WithDatabase("testdb"),
engine.WithUsername("root"),
engine.WithPassword("password"),
},
wantErr: true,
errMsg: "Host, ReadHosts, or WriteHosts is required for mysql driver",
},
{
name: "Missing Database",
options: []engine.Option{
engine.WithHost("localhost"),
engine.WithUsername("root"),
engine.WithPassword("password"),
},
wantErr: true,
errMsg: "Database is required for mysql driver",
},
{
name: "engine.engine.With SQL Server engine.Option",
options: []engine.Option{
engine.WithHost("localhost"),
engine.WithDatabase("testdb"),
engine.WithUsername("root"),
engine.WithPassword("password"),
engine.WithSQLServerInstance("SQLEXPRESS"),
},
wantErr: true,
errMsg: "engine.WithSQLServerInstance is only valid for sqlserver driver",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
if !tt.wantErr {
t.Errorf("engine.NewDBConfig() panicked unexpectedly: %v", r)
} else if tt.errMsg != "" && r != tt.errMsg {
t.Errorf("engine.NewDBConfig() panic = %v, want %v", r, tt.errMsg)
}
} else if tt.wantErr {
t.Errorf("engine.NewDBConfig() did not panic, expected panic with: %v", tt.errMsg)
}
}()
config := engine.NewDBConfig("mysql", tt.options...)
if !tt.wantErr && (config.Driver != "mysql" || config.MySQL.Collation != "utf8mb4_unicode_ci") {
t.Errorf("MySQL config not set correctly: %+v", config)
}
})
}
}
// TestPostgreSQLConfig 测试 PostgreSQL 驱动的配置
func TestPostgreSQLConfig(t *testing.T) {
tests := []struct {
name string
options []engine.Option
wantErr bool
errMsg string
}{
{
name: "Valid Config",
options: []engine.Option{
engine.WithHost("localhost"),
engine.WithDatabase("testdb"),
engine.WithUsername("postgres"),
engine.WithPassword("password"),
engine.WithPgSslmode("disable"),
},
wantErr: false,
},
{
name: "Missing Username",
options: []engine.Option{
engine.WithHost("localhost"),
engine.WithDatabase("testdb"),
engine.WithPassword("password"),
},
wantErr: true,
errMsg: "Username is required for pgsql driver",
},
{
name: "engine.engine.With MySQL engine.Option",
options: []engine.Option{
engine.WithHost("localhost"),
engine.WithDatabase("testdb"),
engine.WithUsername("postgres"),
engine.WithPassword("password"),
engine.WithMySQLCollation("utf8mb4_unicode_ci"),
},
wantErr: true,
errMsg: "engine.WithMySQLCollation is only valid for mysql driver",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
if !tt.wantErr {
t.Errorf("engine.NewDBConfig() panicked unexpectedly: %v", r)
} else if tt.errMsg != "" && r != tt.errMsg {
t.Errorf("engine.NewDBConfig() panic = %v, want %v", r, tt.errMsg)
}
} else if tt.wantErr {
t.Errorf("engine.NewDBConfig() did not panic, expected panic with: %v", tt.errMsg)
}
}()
config := engine.NewDBConfig("pgsql", tt.options...)
if !tt.wantErr && (config.Driver != "pgsql" || config.PostgreSQL.Sslmode != "disable") {
t.Errorf("PostgreSQL config not set correctly: %+v", config)
}
})
}
}
// TestSQLiteConfig 测试 SQLite 驱动的配置
func TestSQLiteConfig(t *testing.T) {
tests := []struct {
name string
options []engine.Option
wantErr bool
errMsg string
}{
{
name: "Valid Config",
options: []engine.Option{
engine.WithSQLiteFile("test.db"),
engine.WithSQLiteJournal("WAL"),
},
wantErr: false,
},
{
name: "Missing File",
options: []engine.Option{},
wantErr: true,
errMsg: "File is required for sqlite3 driver",
},
{
name: "engine.engine.With PostgreSQL engine.Option",
options: []engine.Option{
engine.WithSQLiteFile("test.db"),
engine.WithPgSslmode("disable"),
},
wantErr: true,
errMsg: "engine.WithPgSslmode is only valid for pgsql driver",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
if !tt.wantErr {
t.Errorf("engine.NewDBConfig() panicked unexpectedly: %v", r)
} else if tt.errMsg != "" && r != tt.errMsg {
t.Errorf("engine.NewDBConfig() panic = %v, want %v", r, tt.errMsg)
}
} else if tt.wantErr {
t.Errorf("engine.NewDBConfig() did not panic, expected panic with: %v", tt.errMsg)
}
}()
config := engine.NewDBConfig("sqlite3", tt.options...)
if !tt.wantErr && (config.Driver != "sqlite3" || config.SQLite.File != "test.db") {
t.Errorf("SQLite config not set correctly: %+v", config)
}
})
}
}
// TestSQLServerConfig 测试 SQL Server 驱动的配置
func TestSQLServerConfig(t *testing.T) {
tests := []struct {
name string
options []engine.Option
wantErr bool
errMsg string
}{
{
name: "Valid Config",
options: []engine.Option{
engine.WithHost("sqlserver.example.com"),
engine.WithDatabase("master"),
engine.WithUsername("sa"),
engine.WithPassword("password"),
engine.WithSQLServerInstance("SQLEXPRESS"),
},
wantErr: false,
},
{
name: "Missing Password",
options: []engine.Option{
engine.WithHost("sqlserver.example.com"),
engine.WithDatabase("master"),
engine.WithUsername("sa"),
},
wantErr: true,
errMsg: "Password is required for sqlserver driver",
},
{
name: "engine.engine.With SQLite engine.Option",
options: []engine.Option{
engine.WithHost("sqlserver.example.com"),
engine.WithDatabase("master"),
engine.WithUsername("sa"),
engine.WithPassword("password"),
engine.WithSQLiteFile("test.db"),
},
wantErr: true,
errMsg: "engine.WithSQLiteFile is only valid for sqlite3 driver",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
if !tt.wantErr {
t.Errorf("engine.NewDBConfig() panicked unexpectedly: %v", r)
} else if tt.errMsg != "" && r != tt.errMsg {
t.Errorf("engine.NewDBConfig() panic = %v, want %v", r, tt.errMsg)
}
} else if tt.wantErr {
t.Errorf("engine.NewDBConfig() did not panic, expected panic with: %v", tt.errMsg)
}
}()
config := engine.NewDBConfig("sqlserver", tt.options...)
if !tt.wantErr && (config.Driver != "sqlserver" || config.SQLServer.Instance != "SQLEXPRESS") {
t.Errorf("SQL Server config not set correctly: %+v", config)
}
})
}
}
// TestInvalidDriver 测试不支持的驱动
func TestInvalidDriver(t *testing.T) {
defer func() {
if r := recover(); r != nil {
if r != "Unsupported driver: oracle" {
t.Errorf("engine.NewDBConfig() panic = %v, want 'Unsupported driver: oracle'", r)
}
} else {
t.Errorf("engine.NewDBConfig() did not panic for invalid driver")
}
}()
engine.NewDBConfig("oracle")
}
// TestDefaultValues 测试默认值
func TestDefaultValues(t *testing.T) {
config := engine.NewDBConfig("mysql",
engine.WithHost("localhost"),
engine.WithDatabase("testdb"),
engine.WithUsername("root"),
engine.WithPassword("password"),
)
if config.Charset != "utf8mb4" {
t.Errorf("Default Charset = %v, want utf8mb4", config.Charset)
}
if config.ConnMaxLifetime != 2*time.Hour {
t.Errorf("Default ConnMaxLifetime = %v, want 2h", config.ConnMaxLifetime)
}
if config.MaxOpenConns != 100 {
t.Errorf("Default MaxOpenConns = %v, want 100", config.MaxOpenConns)
}
}
func TestToDSN(t *testing.T) {
tests := []struct {
name string
config engine.DBConfig
wantDSN string
wantErr bool
errMsg string
}{
{
name: "MySQL DSN",
config: engine.NewDBConfig("mysql",
engine.WithHost("localhost"),
engine.WithPort("3306"),
engine.WithDatabase("testdb"),
engine.WithUsername("root"),
engine.WithPassword("password"),
engine.WithMySQLCollation("utf8mb4_unicode_ci"),
),
wantDSN: "root:password@tcp(localhost:3306)/testdb?charset=utf8mb4&collation=utf8mb4_unicode_ci",
wantErr: false,
},
{
name: "PostgreSQL DSN",
config: engine.NewDBConfig("pgsql",
engine.WithHost("localhost"),
engine.WithPort("5432"),
engine.WithDatabase("testdb"),
engine.WithUsername("postgres"),
engine.WithPassword("password"),
engine.WithPgSslmode("disable"),
),
wantDSN: "postgres://postgres:password@localhost:5432/testdb?host=localhost&port=5432&dbname=testdb&user=postgres&password=password&sslmode=disable",
wantErr: false,
},
{
name: "SQLite DSN",
config: engine.NewDBConfig("sqlite3",
engine.WithSQLiteFile("test.db"),
engine.WithSQLiteJournal("WAL"),
),
wantDSN: "test.db?_journal=WAL",
wantErr: false,
},
{
name: "SQL Server DSN",
config: engine.NewDBConfig("sqlserver",
engine.WithHost("sqlserver.example.com"),
engine.WithPort("1433"),
engine.WithDatabase("master"),
engine.WithUsername("sa"),
engine.WithPassword("password"),
engine.WithSQLServerInstance("SQLEXPRESS"),
),
wantDSN: "sqlserver://sa:password@sqlserver.example.com\\SQLEXPRESS:1433?server=sqlserver.example.com\\SQLEXPRESS&database=master",
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
if !tt.wantErr {
t.Errorf("ToDSN() panicked unexpectedly: %v", r)
} else if tt.errMsg != "" && r != tt.errMsg {
t.Errorf("ToDSN() panic = %v, want %v", r, tt.errMsg)
}
} else if tt.wantErr {
t.Errorf("ToDSN() did not panic, expected panic with: %v", tt.errMsg)
}
}()
dsn := tt.config.ToDSN()
if !tt.wantErr && dsn != tt.wantDSN {
t.Errorf("ToDSN() = %v, want %v", dsn, tt.wantDSN)
}
})
}
}