Files
lijiaoqiao/supply-api/internal/repository/package_integration_test.go
Your Name 2bc4a00ecd test(supply-api): add repository integration suite and runner
Add repository integration probes, repository policy tests, the compose-based integration runner, and the matching usage documentation. Align the runner environment with both repository and middleware integration test expectations, and verify with fresh repository tests, integration-tag test runs, bash -n, and docker-compose config before commit.
2026-04-11 11:25:19 +08:00

243 lines
6.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//go:build integration
// +build integration
package repository
import (
"context"
"os"
"testing"
"github.com/jackc/pgx/v5/pgxpool"
)
// getPackageTestDB 获取测试数据库连接
func getPackageTestDB(t *testing.T) *pgxpool.Pool {
t.Helper()
host := os.Getenv("SUPPLY_API_DB_HOST")
if host == "" {
host = "/var/run/postgresql"
}
port := os.Getenv("SUPPLY_API_DB_PORT")
if port == "" {
port = "5432"
}
user := os.Getenv("SUPPLY_API_DB_USER")
if user == "" {
user = "long"
}
password := os.Getenv("SUPPLY_API_DB_PASSWORD")
dbName := os.Getenv("SUPPLY_API_DB_NAME")
if dbName == "" {
dbName = "supply_test"
}
// 构建 DSN - 如果 host 是路径Unix socket使用 host= 参数
var dsn string
if host[0] == '/' {
dsn = "postgres://" + user + ":" + password + "@/" + dbName + "?host=" + host + "&sslmode=disable"
} else {
dsn = "postgres://" + user + ":" + password + "@" + host + ":" + port + "/" + dbName + "?sslmode=disable"
}
pool, err := pgxpool.New(context.Background(), dsn)
if err != nil {
t.Skipf("跳过集成测试:无法连接数据库: %v", err)
return nil
}
if err := pool.Ping(context.Background()); err != nil {
pool.Close()
t.Skipf("跳过集成测试:无法 ping 数据库: %v", err)
return nil
}
t.Cleanup(func() {
pool.Close()
})
return pool
}
// TestPackageRepository_Create_Integration 集成测试:创建套餐
func TestPackageRepository_Create_Integration(t *testing.T) {
if testing.Short() {
t.Skip("跳过集成测试short mode")
}
pool := getPackageTestDB(t)
if pool == nil {
return
}
// 验证 supply_packages 表存在
var tableName string
err := pool.QueryRow(context.Background(), "SELECT table_name FROM information_schema.tables WHERE table_name = 'supply_packages'").Scan(&tableName)
if err != nil {
t.Skipf("跳过supply_packages 表不存在: %v", err)
}
t.Log("集成测试supply_packages 表存在")
}
// TestPackageRepository_GetByID_Integration 集成测试:获取套餐
func TestPackageRepository_GetByID_Integration(t *testing.T) {
if testing.Short() {
t.Skip("跳过集成测试short mode")
}
pool := getPackageTestDB(t)
if pool == nil {
return
}
var count int
err := pool.QueryRow(context.Background(), "SELECT COUNT(*) FROM supply_packages").Scan(&count)
if err != nil {
t.Logf("集成测试supply_packages 查询结果: %v", err)
} else {
t.Logf("集成测试supply_packages 共有 %d 条记录", count)
}
}
// TestPackageRepository_Update_Integration 集成测试:更新套餐(乐观锁)
func TestPackageRepository_Update_Integration(t *testing.T) {
if testing.Short() {
t.Skip("跳过集成测试short mode")
}
pool := getPackageTestDB(t)
if pool == nil {
return
}
// 验证 version 字段存在(乐观锁)
var columnExists bool
err := pool.QueryRow(context.Background(), `
SELECT EXISTS(
SELECT 1 FROM information_schema.columns
WHERE table_name = 'supply_packages' AND column_name = 'version'
)
`).Scan(&columnExists)
if err != nil || !columnExists {
t.Skip("跳过supply_packages 表缺少 version 字段")
}
t.Log("集成测试supply_packages 包含 version 字段(乐观锁)")
}
// TestPackageRepository_List_Integration 集成测试:列出套餐
func TestPackageRepository_List_Integration(t *testing.T) {
if testing.Short() {
t.Skip("跳过集成测试short mode")
}
pool := getPackageTestDB(t)
if pool == nil {
return
}
// 列出供应商标套餐
rows, err := pool.Query(context.Background(), `
SELECT id, supplier_id, available_quota
FROM supply_packages
LIMIT 10
`)
if err != nil {
t.Logf("集成测试:列出套餐: %v", err)
return
}
defer rows.Close()
count := 0
for rows.Next() {
var id, supplierID int64
var availableQuota int
rows.Scan(&id, &supplierID, &availableQuota)
count++
t.Logf("集成测试:套餐 ID=%d, SupplierID=%d, AvailableQuota=%d", id, supplierID, availableQuota)
}
t.Logf("集成测试:列出 %d 个套餐", count)
}
// TestPackageRepository_UpdateQuota_Integration 集成测试:扣减配额
func TestPackageRepository_UpdateQuota_Integration(t *testing.T) {
if testing.Short() {
t.Skip("跳过集成测试short mode")
}
pool := getPackageTestDB(t)
if pool == nil {
return
}
// 验证 available_quota 字段存在
var columnExists bool
err := pool.QueryRow(context.Background(), `
SELECT EXISTS(
SELECT 1 FROM information_schema.columns
WHERE table_name = 'supply_packages' AND column_name = 'available_quota'
)
`).Scan(&columnExists)
if err != nil || !columnExists {
t.Skip("跳过supply_packages 表缺少 available_quota 字段")
}
t.Log("集成测试supply_packages 包含 available_quota 字段")
}
// TestPackageRepository_GetForUpdate_Integration 集成测试:悲观锁获取
func TestPackageRepository_GetForUpdate_Integration(t *testing.T) {
if testing.Short() {
t.Skip("跳过集成测试short mode")
}
pool := getPackageTestDB(t)
if pool == nil {
return
}
// 测试 FOR UPDATE 锁
tx, err := pool.Begin(context.Background())
if err != nil {
t.Fatalf("开始事务失败: %v", err)
}
defer tx.Rollback(context.Background())
rows, err := tx.Query(context.Background(), "SELECT id FROM supply_packages LIMIT 1 FOR UPDATE")
if err != nil {
t.Logf("集成测试FOR UPDATE 查询: %v", err)
} else {
rows.Close()
t.Log("集成测试FOR UPDATE 锁获取成功")
}
tx.Rollback(context.Background())
}
// TestPackageRepository_OptimisticLock_Integration 集成测试:乐观锁冲突
func TestPackageRepository_OptimisticLock_Integration(t *testing.T) {
if testing.Short() {
t.Skip("跳过集成测试short mode")
}
pool := getPackageTestDB(t)
if pool == nil {
return
}
// 验证 version 字段存在
var versionCol int
err := pool.QueryRow(context.Background(), `
SELECT COUNT(*) FROM information_schema.columns
WHERE table_name = 'supply_packages' AND column_name = 'version'
`).Scan(&versionCol)
if err != nil || versionCol == 0 {
t.Skip("跳过supply_packages 表缺少 version 字段")
}
t.Log("集成测试:乐观锁字段验证通过")
}