Files
quyun-v2/backend/tests/integration/database_test.go
2025-12-15 17:55:32 +08:00

368 lines
9.7 KiB
Go

//go:build legacytests
// +build legacytests
package integration
import (
"context"
"database/sql"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"quyun/v2/app/config"
"quyun/v2/app/database"
)
// TestUser 测试用户模型
type TestUser struct {
ID int `gorm:"primaryKey"`
Name string `gorm:"size:100;not null"`
Email string `gorm:"size:100;unique;not null"`
CreatedAt time.Time `gorm:"autoCreateTime"`
UpdatedAt time.Time `gorm:"autoUpdateTime"`
}
// TestDatabaseConnection 测试数据库连接
func TestDatabaseConnection(t *testing.T) {
Convey("数据库连接测试", t, func() {
var db *gorm.DB
var sqlDB *sql.DB
var testConfig *config.Config
var testDBName string
Convey("当准备测试数据库时", func() {
testDBName = "v2_test_integration"
testConfig = &config.Config{
Database: config.DatabaseConfig{
Host: "localhost",
Port: 5432,
Database: testDBName,
Username: "postgres",
Password: "password",
SslMode: "disable",
MaxIdleConns: 5,
MaxOpenConns: 20,
ConnMaxLifetime: 30 * time.Minute,
},
}
Convey("应该能够连接到数据库", func() {
dsn := testConfig.Database.GetDSN()
var err error
db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
So(err, ShouldBeNil)
So(db, ShouldNotBeNil)
sqlDB, err = db.DB()
So(err, ShouldBeNil)
So(sqlDB, ShouldNotBeNil)
// 设置连接池
sqlDB.SetMaxIdleConns(testConfig.Database.MaxIdleConns)
sqlDB.SetMaxOpenConns(testConfig.Database.MaxOpenConns)
sqlDB.SetConnMaxLifetime(testConfig.Database.ConnMaxLifetime)
// 测试连接
err = sqlDB.Ping()
So(err, ShouldBeNil)
})
Convey("应该能够创建测试表", func() {
err := db.Exec(`
CREATE TABLE IF NOT EXISTS integration_test_users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`).Error
So(err, ShouldBeNil)
})
})
Convey("当测试数据库操作时", func() {
Convey("应该能够创建记录", func() {
user := TestUser{
Name: "Integration Test User",
Email: "integration@example.com",
}
result := db.Create(&user)
So(result.Error, ShouldBeNil)
So(result.RowsAffected, ShouldEqual, 1)
So(user.ID, ShouldBeGreaterThan, 0)
})
Convey("应该能够查询记录", func() {
// 先插入测试数据
user := TestUser{
Name: "Query Test User",
Email: "query@example.com",
}
db.Create(&user)
// 查询记录
var result TestUser
err := db.First(&result, "email = ?", "query@example.com").Error
So(err, ShouldBeNil)
So(result.Name, ShouldEqual, "Query Test User")
So(result.Email, ShouldEqual, "query@example.com")
})
Convey("应该能够更新记录", func() {
// 先插入测试数据
user := TestUser{
Name: "Update Test User",
Email: "update@example.com",
}
db.Create(&user)
// 更新记录
result := db.Model(&user).Update("name", "Updated Integration User")
So(result.Error, ShouldBeNil)
So(result.RowsAffected, ShouldEqual, 1)
// 验证更新
var updatedUser TestUser
err := db.First(&updatedUser, user.ID).Error
So(err, ShouldBeNil)
So(updatedUser.Name, ShouldEqual, "Updated Integration User")
})
Convey("应该能够删除记录", func() {
// 先插入测试数据
user := TestUser{
Name: "Delete Test User",
Email: "delete@example.com",
}
db.Create(&user)
// 删除记录
result := db.Delete(&user)
So(result.Error, ShouldBeNil)
So(result.RowsAffected, ShouldEqual, 1)
// 验证删除
var deletedUser TestUser
err := db.First(&deletedUser, user.ID).Error
So(err, ShouldEqual, gorm.ErrRecordNotFound)
})
})
Convey("当测试事务时", func() {
Convey("应该能够执行事务操作", func() {
// 开始事务
tx := db.Begin()
So(tx, ShouldNotBeNil)
// 在事务中插入数据
user := TestUser{
Name: "Transaction Test User",
Email: "transaction@example.com",
}
result := tx.Create(&user)
So(result.Error, ShouldBeNil)
So(result.RowsAffected, ShouldEqual, 1)
// 查询事务中的数据
var count int64
tx.Model(&TestUser{}).Count(&count)
So(count, ShouldEqual, 1)
// 提交事务
err := tx.Commit().Error
So(err, ShouldBeNil)
// 验证数据已提交
db.Model(&TestUser{}).Count(&count)
So(count, ShouldBeGreaterThan, 0)
})
Convey("应该能够回滚事务", func() {
// 开始事务
tx := db.Begin()
// 在事务中插入数据
user := TestUser{
Name: "Rollback Test User",
Email: "rollback@example.com",
}
tx.Create(&user)
// 回滚事务
err := tx.Rollback().Error
So(err, ShouldBeNil)
// 验证数据已回滚
var count int64
db.Model(&TestUser{}).Where("email = ?", "rollback@example.com").Count(&count)
So(count, ShouldEqual, 0)
})
})
Convey("当测试批量操作时", func() {
Convey("应该能够批量插入记录", func() {
users := []TestUser{
{Name: "Batch User 1", Email: "batch1@example.com"},
{Name: "Batch User 2", Email: "batch2@example.com"},
{Name: "Batch User 3", Email: "batch3@example.com"},
}
result := db.Create(&users)
So(result.Error, ShouldBeNil)
So(result.RowsAffected, ShouldEqual, 3)
// 验证批量插入
var count int64
db.Model(&TestUser{}).Where("email LIKE ?", "batch%@example.com").Count(&count)
So(count, ShouldEqual, 3)
})
Convey("应该能够批量更新记录", func() {
// 先插入测试数据
users := []TestUser{
{Name: "Batch Update 1", Email: "batchupdate1@example.com"},
{Name: "Batch Update 2", Email: "batchupdate2@example.com"},
}
db.Create(&users)
// 批量更新
result := db.Model(&TestUser{}).
Where("email LIKE ?", "batchupdate%@example.com").
Update("name", "Batch Updated User")
So(result.Error, ShouldBeNil)
So(result.RowsAffected, ShouldEqual, 2)
// 验证更新
var updatedCount int64
db.Model(&TestUser{}).
Where("name = ?", "Batch Updated User").
Count(&updatedCount)
So(updatedCount, ShouldEqual, 2)
})
})
Convey("当测试查询条件时", func() {
Convey("应该能够使用各种查询条件", func() {
// 插入测试数据
testUsers := []TestUser{
{Name: "Alice", Email: "alice@example.com"},
{Name: "Bob", Email: "bob@example.com"},
{Name: "Charlie", Email: "charlie@example.com"},
{Name: "Alice Smith", Email: "alice.smith@example.com"},
}
db.Create(&testUsers)
Convey("应该能够使用 LIKE 查询", func() {
var users []TestUser
err := db.Where("name LIKE ?", "Alice%").Find(&users).Error
So(err, ShouldBeNil)
So(len(users), ShouldEqual, 2)
})
Convey("应该能够使用 IN 查询", func() {
var users []TestUser
err := db.Where("name IN ?", []string{"Alice", "Bob"}).Find(&users).Error
So(err, ShouldBeNil)
So(len(users), ShouldEqual, 2)
})
Convey("应该能够使用 BETWEEN 查询", func() {
var users []TestUser
err := db.Where("id BETWEEN ? AND ?", 1, 3).Find(&users).Error
So(err, ShouldBeNil)
So(len(users), ShouldBeGreaterThan, 0)
})
Convey("应该能够使用多条件查询", func() {
var users []TestUser
err := db.Where("name LIKE ? AND email LIKE ?", "%Alice%", "%example.com").Find(&users).Error
So(err, ShouldBeNil)
So(len(users), ShouldEqual, 2)
})
})
})
Reset(func() {
// 清理测试表
if db != nil {
db.Exec("DROP TABLE IF EXISTS integration_test_users")
}
// 关闭数据库连接
if sqlDB != nil {
sqlDB.Close()
}
})
})
}
// TestDatabaseConnectionPool 测试数据库连接池
func TestDatabaseConnectionPool(t *testing.T) {
Convey("数据库连接池测试", t, func() {
var db *gorm.DB
var sqlDB *sql.DB
Convey("当配置连接池时", func() {
testConfig := &config.Config{
Database: config.DatabaseConfig{
Host: "localhost",
Port: 5432,
Database: "v2_test_pool",
Username: "postgres",
Password: "password",
SslMode: "disable",
MaxIdleConns: 5,
MaxOpenConns: 10,
ConnMaxLifetime: 5 * time.Minute,
},
}
dsn := testConfig.Database.GetDSN()
var err error
db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
So(err, ShouldBeNil)
sqlDB, err = db.DB()
So(err, ShouldBeNil)
Convey("应该能够设置连接池参数", func() {
sqlDB.SetMaxIdleConns(testConfig.Database.MaxIdleConns)
sqlDB.SetMaxOpenConns(testConfig.Database.MaxOpenConns)
sqlDB.SetConnMaxLifetime(testConfig.Database.ConnMaxLifetime)
// 验证设置
stats := sqlDB.Stats()
So(stats.MaxOpenConns, ShouldEqual, testConfig.Database.MaxOpenConns)
So(stats.MaxIdleConns, ShouldEqual, testConfig.Database.MaxIdleConns)
})
Convey("应该能够监控连接池状态", func() {
// 获取初始状态
initialStats := sqlDB.Stats()
So(initialStats.OpenConnections, ShouldEqual, 0)
// 执行一些查询来创建连接
for i := 0; i < 3; i++ {
sqlDB.Ping()
}
// 获取使用后的状态
afterStats := sqlDB.Stats()
So(afterStats.OpenConnections, ShouldBeGreaterThan, 0)
So(afterStats.InUse, ShouldBeGreaterThan, 0)
})
})
Reset(func() {
// 关闭数据库连接
if sqlDB != nil {
sqlDB.Close()
}
})
})
}