test(http): 防止集成测试误用非测试数据库
原因:共享迁移辅助函数会直接对 AI_GATEWAY_TEST_DATABASE_URL 指向的数据库执行迁移,需要在任何写入前阻止误连非测试库。 影响:HTTP 集成测试仅允许名称明确包含 test 边界的数据库;不影响未配置数据库环境变量时的普通单元测试。 风险:自定义测试库名称若不符合规则会被拒绝,需要改用 test、test_*、*_test 或包含 _test_ 的名称。 验证:gofmt 无差异;env -u AI_GATEWAY_TEST_DATABASE_URL go test ./... -count=1 通过。
This commit is contained in:
@@ -2009,6 +2009,7 @@ func applyMigration(t *testing.T, ctx context.Context, databaseURL string) {
|
||||
t.Fatalf("connect migration db: %v", err)
|
||||
}
|
||||
defer pool.Close()
|
||||
requireDedicatedIntegrationTestDatabase(t, ctx, pool)
|
||||
if _, err := pool.Exec(ctx, `
|
||||
CREATE TABLE IF NOT EXISTS schema_migrations (
|
||||
version text PRIMARY KEY,
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package httpapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
func requireDedicatedIntegrationTestDatabase(t *testing.T, ctx context.Context, pool *pgxpool.Pool) {
|
||||
t.Helper()
|
||||
var databaseName string
|
||||
if err := pool.QueryRow(ctx, `SELECT current_database()`).Scan(&databaseName); err != nil {
|
||||
t.Fatalf("read integration test database name: %v", err)
|
||||
}
|
||||
if !isDedicatedIntegrationTestDatabase(databaseName) {
|
||||
t.Fatalf(
|
||||
"AI_GATEWAY_TEST_DATABASE_URL must reference a dedicated test database; refusing to use %q",
|
||||
databaseName,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func isDedicatedIntegrationTestDatabase(databaseName string) bool {
|
||||
normalized := strings.ToLower(strings.TrimSpace(databaseName))
|
||||
return normalized == "test" ||
|
||||
strings.HasPrefix(normalized, "test_") ||
|
||||
strings.HasSuffix(normalized, "_test") ||
|
||||
strings.Contains(normalized, "_test_")
|
||||
}
|
||||
|
||||
func TestDedicatedIntegrationTestDatabaseName(t *testing.T) {
|
||||
t.Parallel()
|
||||
for _, testCase := range []struct {
|
||||
name string
|
||||
database string
|
||||
allowed bool
|
||||
}{
|
||||
{name: "documented local test database", database: "easyai_ai_gateway_test_codex", allowed: true},
|
||||
{name: "test prefix", database: "test_gateway", allowed: true},
|
||||
{name: "test suffix", database: "gateway_test", allowed: true},
|
||||
{name: "production database", database: "easyai_ai_gateway", allowed: false},
|
||||
{name: "similar production name", database: "gateway_contest", allowed: false},
|
||||
} {
|
||||
testCase := testCase
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if got := isDedicatedIntegrationTestDatabase(testCase.database); got != testCase.allowed {
|
||||
t.Fatalf("isDedicatedIntegrationTestDatabase(%q) = %v, want %v", testCase.database, got, testCase.allowed)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user