test: isolate postgres integration fixture
This commit is contained in:
parent
2341296271
commit
02097596fa
@ -8,10 +8,15 @@ Grafana 与 Kubernetes。配置已通过静态展开,但当前仓库的 `cmd/p
|
||||
|
||||
```powershell
|
||||
docker compose -f deploy/docker-compose.yml config --quiet
|
||||
docker compose -f deploy/docker-compose.test.yml config --quiet
|
||||
kubectl kustomize deploy/kubernetes/base | Out-Null
|
||||
go run ./deploy/tools/configcheck deploy/config/local.yaml
|
||||
```
|
||||
|
||||
`docker-compose.test.yml` 为 Redis 与 PostgreSQL 18 提供互相独立的本地集成测试
|
||||
服务。两者只绑定回环地址;Redis 禁止持久化,PostgreSQL 使用
|
||||
`/var/lib/postgresql` tmpfs。`test-redis.ps1` 通过专属 Compose 项目只启动 Redis;
|
||||
PostgreSQL Adapter 和对应执行脚本完成前,不把数据库契约记为通过。
|
||||
|
||||
运行时完成后,还必须通过 `production-readiness.md` 中的一致性、安全、恢复、
|
||||
竞态与容量门禁,才能构建镜像并发布。
|
||||
|
||||
|
||||
@ -2,6 +2,8 @@ package deploy
|
||||
|
||||
import (
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"go.yaml.in/yaml/v4"
|
||||
@ -13,11 +15,48 @@ type composeDocument struct {
|
||||
}
|
||||
|
||||
type composeService struct {
|
||||
Image string `yaml:"image"`
|
||||
Command []string `yaml:"command"`
|
||||
Ports []string `yaml:"ports"`
|
||||
Volumes []string `yaml:"volumes"`
|
||||
Tmpfs []string `yaml:"tmpfs"`
|
||||
DependsOn any `yaml:"depends_on"`
|
||||
}
|
||||
|
||||
func TestPostgresIntegrationFixtureIsIsolatedAndEphemeral(t *testing.T) {
|
||||
document := loadComposeFile(t, "docker-compose.test.yml")
|
||||
postgres, ok := document.Services["postgres"]
|
||||
if !ok {
|
||||
t.Fatal("docker-compose.test.yml has no postgres service")
|
||||
}
|
||||
if postgres.Image != "postgres:18-alpine" {
|
||||
t.Fatalf("postgres image = %q, want postgres:18-alpine", postgres.Image)
|
||||
}
|
||||
if !slices.Equal(postgres.Ports, []string{"127.0.0.1:15432:5432"}) {
|
||||
t.Fatalf("postgres ports = %v, want loopback test port", postgres.Ports)
|
||||
}
|
||||
if !slices.Contains(postgres.Tmpfs, "/var/lib/postgresql") || len(postgres.Volumes) != 0 {
|
||||
t.Fatalf("postgres tmpfs = %v, volumes = %v; want ephemeral PG18 data root", postgres.Tmpfs, postgres.Volumes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRedisFixtureScriptUsesDedicatedComposeProject(t *testing.T) {
|
||||
payload, err := os.ReadFile("../scripts/test-redis.ps1")
|
||||
if err != nil {
|
||||
t.Fatalf("read test-redis.ps1: %v", err)
|
||||
}
|
||||
script := string(payload)
|
||||
for _, required := range []string{
|
||||
`-p $composeProject`,
|
||||
`up -d --wait --wait-timeout 60 redis`,
|
||||
`down --volumes --remove-orphans`,
|
||||
} {
|
||||
if !strings.Contains(script, required) {
|
||||
t.Errorf("test-redis.ps1 missing %q", required)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalRedisIsExplicitlyEphemeral(t *testing.T) {
|
||||
document := loadComposeDocument(t)
|
||||
redis, ok := document.Services["redis"]
|
||||
@ -55,13 +94,18 @@ func TestLocalGatewaysDoNotDependOnControlPlaneStorage(t *testing.T) {
|
||||
|
||||
func loadComposeDocument(t *testing.T) composeDocument {
|
||||
t.Helper()
|
||||
payload, err := os.ReadFile("docker-compose.yml")
|
||||
return loadComposeFile(t, "docker-compose.yml")
|
||||
}
|
||||
|
||||
func loadComposeFile(t *testing.T, name string) composeDocument {
|
||||
t.Helper()
|
||||
payload, err := os.ReadFile(name)
|
||||
if err != nil {
|
||||
t.Fatalf("read docker-compose.yml: %v", err)
|
||||
t.Fatalf("read %s: %v", name, err)
|
||||
}
|
||||
var document composeDocument
|
||||
if err := yaml.Unmarshal(payload, &document); err != nil {
|
||||
t.Fatalf("parse docker-compose.yml: %v", err)
|
||||
t.Fatalf("parse %s: %v", name, err)
|
||||
}
|
||||
return document
|
||||
}
|
||||
|
||||
@ -1,6 +1,23 @@
|
||||
name: proxy-pool-test
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:18-alpine
|
||||
environment:
|
||||
POSTGRES_DB: proxy_pool_test
|
||||
POSTGRES_USER: proxy_pool_test
|
||||
POSTGRES_PASSWORD: proxy-pool-test
|
||||
ports:
|
||||
- "127.0.0.1:15432:5432"
|
||||
tmpfs:
|
||||
- /var/lib/postgresql
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U proxy_pool_test -d proxy_pool_test"]
|
||||
interval: 1s
|
||||
timeout: 1s
|
||||
retries: 30
|
||||
start_period: 1s
|
||||
|
||||
redis:
|
||||
image: redis:8.2-alpine
|
||||
command: ["redis-server", "--appendonly", "no", "--save", ""]
|
||||
|
||||
@ -95,8 +95,9 @@ fixture 的执行命令是:
|
||||
|
||||
PostgreSQL 管理面使用 `adminstate/contracttest` 作为 Memory/PostgreSQL 公用
|
||||
行为契约。当前 MemoryStore 已覆盖配置提交、Upstream 幂等、100 并发 Routing
|
||||
CAS、审计和租约 Outbox;Schema 静态测试证明只声明六张管理表。只有 pgx
|
||||
Adapter 在真实 PostgreSQL 18 上运行同一契约后,才标记生产持久化完成。
|
||||
CAS、审计分页、Routing no-op、原子批量 ACK 和租约 Outbox;Schema 静态测试
|
||||
证明只声明六张管理表。PostgreSQL 18 的回环端口、tmpfs 隔离 fixture 已完成
|
||||
静态验证;只有 pgx Adapter 在该实例上运行同一契约后,才标记生产持久化完成。
|
||||
|
||||
Admin 应用层测试覆盖 typed-nil 依赖、Actor/SourceIP 映射、Routing CAS 错误、
|
||||
权威管理快照与低基数运行态聚合、未知字段拒绝、主配置/Secret 文件 I/O 分类、
|
||||
|
||||
10
findings.md
10
findings.md
@ -173,3 +173,13 @@ Routing 自上而下匹配,首条命中停止;支持 Gateway 与 Extract 两
|
||||
可执行的 `deploy/tools/configcheck`,并明确生产 Controller 入口仍是计划能力。
|
||||
- 文档中的具体 `go run`/`go build` 目标现在必须存在;包含 `...` 的通配包命令
|
||||
由 Go 工具链自身解析并在完整验证中执行。
|
||||
|
||||
## PostgreSQL 18 Fixture 审计(2026-07-29)
|
||||
|
||||
- 集成 Compose 已新增仅绑定 `127.0.0.1:15432` 的 `postgres:18-alpine` 服务,
|
||||
数据目录挂载为 `/var/lib/postgresql` tmpfs,不声明测试持久卷。
|
||||
- Redis 测试脚本现使用专属 Compose 项目并只启动 Redis,防止未来加入的
|
||||
PostgreSQL fixture 被无关测试启动或清理。
|
||||
- 生产 `docker-compose.yml` 仍把 PostgreSQL 18 命名卷挂在旧路径
|
||||
`/var/lib/postgresql/data`;直接修改可能影响已有本地数据,必须配套迁移步骤后
|
||||
单独处理,当前不能把生产持久化拓扑视为已验证。
|
||||
|
||||
@ -2,6 +2,9 @@
|
||||
|
||||
## 2026-07-29
|
||||
|
||||
- 新增 PostgreSQL 18 隔离测试服务的静态契约:回环端口、正确 PG18 tmpfs 数据
|
||||
根目录、零持久卷;Redis 测试改用独立 Compose 项目和显式服务启动,避免两个
|
||||
fixture 相互影响。未拉取或启动容器,pgx Adapter/真实契约仍待依赖确认。
|
||||
- 扩展 `adminstate/contracttest` 公用契约:审计完整字段和 AfterID 分页、Routing
|
||||
no-op 审计且不写 Outbox、批量 ACK 零部分提交,以及六个 Store 方法的 Context
|
||||
取消;MemoryStore 全部通过,后续 PostgreSQL Adapter 必须运行同一套契约。
|
||||
|
||||
@ -2,10 +2,11 @@ $ErrorActionPreference = "Stop"
|
||||
|
||||
$repositoryRoot = Split-Path -Parent $PSScriptRoot
|
||||
$composeFile = Join-Path $repositoryRoot "deploy/docker-compose.test.yml"
|
||||
$composeProject = "proxy-pool-redis-test"
|
||||
$previousRedisURL = [Environment]::GetEnvironmentVariable("PROXY_POOL_TEST_REDIS_URL", "Process")
|
||||
|
||||
try {
|
||||
docker compose -f $composeFile up -d --wait
|
||||
docker compose -p $composeProject -f $composeFile up -d --wait --wait-timeout 60 redis
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "starting Redis test fixture failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
@ -29,5 +30,5 @@ finally {
|
||||
else {
|
||||
$env:PROXY_POOL_TEST_REDIS_URL = $previousRedisURL
|
||||
}
|
||||
docker compose -f $composeFile down --remove-orphans
|
||||
docker compose -p $composeProject -f $composeFile down --volumes --remove-orphans
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user