Author SHA1 Message Date
panxiao81 f6d552f944 feat: 迁移 PostgreSQL registry 所有权存储与恢复测试
Verify / database-integration (pull_request) Failing after 14m6s
Verify / test (pull_request) Successful in 6m46s
Verify / lint (pull_request) Successful in 7m48s
2026-09-21 09:01:05 +00:00
4 changed files with 6 additions and 75 deletions
+2 -11
View File
@@ -45,8 +45,7 @@ jobs:
make lint-database-integration make lint-database-integration
database-integration: database-integration:
runs-on: [self-hosted, pod] runs-on: [self-hosted, vm]
timeout-minutes: 30
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
@@ -59,13 +58,5 @@ jobs:
go-version-file: go.mod go-version-file: go.mod
cache: true cache: true
# Runner 提供本 job 可用的 Docker;workflow 只验证,不重复启动 daemon。 - name: Test Database credentials with real backends
- name: Verify Docker availability
shell: bash
run: |
set -euo pipefail
docker version
docker info --format 'Server={{.ServerVersion}} StorageDriver={{.Driver}}'
- name: Test Database integration with real backends
run: make test-database-integration run: make test-database-integration
+1 -2
View File
@@ -53,8 +53,7 @@ controller 接入、Secret watch、finalizer、registry 观测装配与真实权
运行 `make test-database-integration` 验证真实 API server + 一次性 PostgreSQL;fixture 不接受外部 运行 `make test-database-integration` 验证真实 API server + 一次性 PostgreSQL;fixture 不接受外部
DSN,镜像固定摘要,使用随机本机回环端口并在退出时删除测试容器。覆盖缺失/错误凭据、RBAC、 DSN,镜像固定摘要,使用随机本机回环端口并在退出时删除测试容器。覆盖缺失/错误凭据、RBAC、
namespace 边界、有效值轮换、metadata 无关变化、中途轮换、重建/重试、并发读取、Forget/Close namespace 边界、有效值轮换、metadata 无关变化、中途轮换、重建/重试、并发读取、Forget/Close
与 TLS DNS/IP SAN、错误 CA/主机名和禁止明文降级。CI 使用 Pod runner 执行,由 runner 提供 与 TLS DNS/IP SAN、错误 CA/主机名和禁止明文降级。CI 使用 VM runner 执行,普通 lint 之外还检查
可用的 Docker,workflow 只做预检、不自行启动 daemon;不依赖 VM。普通 lint 之外还检查
integration 标签代码。领域单测、真实 API 行为与真实 PostgreSQL 行为分别验收,不以本切片 integration 标签代码。领域单测、真实 API 行为与真实 PostgreSQL 行为分别验收,不以本切片
替代整个 Instance controller 的集成验收。 替代整个 Instance controller 的集成验收。
+1 -6
View File
@@ -21,12 +21,7 @@ TLS 测试在临时目录生成一次性证书与私钥,不使用生产 CA。
当前覆盖固定 namespace 的 Secret 读取与 RBAC、缺失/无效凭据恢复、有效凭据变化后的重连、 当前覆盖固定 namespace 的 Secret 读取与 RBAC、缺失/无效凭据恢复、有效凭据变化后的重连、
无关字段更新不重连、中途轮换时丢弃观察、会话重建、并发读取、本地连接释放和 TLS 验证。 无关字段更新不重连、中途轮换时丢弃观察、会话重建、并发读取、本地连接释放和 TLS 验证。
快速测试、lint 和 Database 集成测试均使用 Pod runner。按维护者于 2026-09-21 更新的接口 默认 Pod runner 跑快速测试与 lint,VM runner 跑带 Docker 的 Database 集成测试。
约定,runner 提供默认可用的 Docker;workflow 通过 `docker version` 和 `docker info` 预检,
不自行启动 daemon、不强制 storage driver 或覆盖 Docker endpoint。该约定的 CI 验收依赖
runner 后端修复上线,不能从本地测试通过推断远端已经可用。
fixture 启动失败会保留退出错误与 stderr,并遮蔽测试密码,
以区分缺少命令、daemon 不可达、权限和镜像拉取失败。
registry 测试独立使用一次性 PostgreSQL,不启动 Kubernetes API server。覆盖重复和并发迁移、 registry 测试独立使用一次性 PostgreSQL,不启动 Kubernetes API server。覆盖重复和并发迁移、
所有权唯一约束、并发占用、Retain 墓碑与 Delete 幂等、连接重建、取消恢复、未知 schema 与 所有权唯一约束、并发占用、Retain 墓碑与 Delete 幂等、连接重建、取消恢复、未知 schema 与
@@ -20,7 +20,6 @@ package postgresql_test
import ( import (
"context" "context"
"errors"
"os/exec" "os/exec"
"regexp" "regexp"
"strconv" "strconv"
@@ -56,7 +55,7 @@ func postgresFixture(t *testing.T, ctx context.Context) (string, int) {
output, err := exec.CommandContext(ctx, "docker", "run", "--rm", "-d", "-p", "127.0.0.1::5432", output, err := exec.CommandContext(ctx, "docker", "run", "--rm", "-d", "-p", "127.0.0.1::5432",
"-e", "POSTGRES_PASSWORD="+fixturePassword, fixtureImage).Output() "-e", "POSTGRES_PASSWORD="+fixturePassword, fixtureImage).Output()
if err != nil { if err != nil {
t.Fatalf("cannot start isolated PostgreSQL fixture: %s", fixtureCommandError(err)) t.Fatal("cannot start isolated PostgreSQL fixture")
} }
id := strings.TrimSpace(string(output)) id := strings.TrimSpace(string(output))
if !regexp.MustCompile(`^[a-f0-9]{64}$`).MatchString(id) { if !regexp.MustCompile(`^[a-f0-9]{64}$`).MatchString(id) {
@@ -71,7 +70,7 @@ func postgresFixture(t *testing.T, ctx context.Context) (string, int) {
}) })
output, err = exec.CommandContext(ctx, "docker", "inspect", "--format", `{{(index (index .NetworkSettings.Ports "5432/tcp") 0).HostPort}}`, id).Output() output, err = exec.CommandContext(ctx, "docker", "inspect", "--format", `{{(index (index .NetworkSettings.Ports "5432/tcp") 0).HostPort}}`, id).Output()
if err != nil { if err != nil {
t.Fatalf("cannot inspect fixture port: %s", fixtureCommandError(err)) t.Fatal("cannot inspect fixture port")
} }
port, err := strconv.Atoi(strings.TrimSpace(string(output))) port, err := strconv.Atoi(strings.TrimSpace(string(output)))
if err != nil { if err != nil {
@@ -88,59 +87,6 @@ func postgresFixture(t *testing.T, ctx context.Context) (string, int) {
return id, port return id, port
} }
// Output 将 stderr 保存在 ExitError 中;保留诊断,但不打印命令参数和测试密码。
func fixtureCommandError(err error) string {
detail := err.Error()
if exitErr, ok := errors.AsType[*exec.ExitError](err); ok {
detail += ": " + strings.TrimSpace(string(exitErr.Stderr))
}
redactor := strings.NewReplacer(
fixturePassword, "[REDACTED]",
rotatedPassword, "[REDACTED]",
)
return redactor.Replace(detail)
}
func TestFixtureCommandErrorPreservesDiagnosticsAndRedactsPasswords(t *testing.T) {
tests := []struct {
name string
err error
want string
}{
{
name: "missing docker executable",
err: &exec.Error{Name: "docker", Err: exec.ErrNotFound},
want: "executable file not found",
},
{
name: "daemon failure from stderr",
err: &exec.ExitError{Stderr: []byte("Cannot connect to the Docker daemon")},
want: "Cannot connect to the Docker daemon",
},
{
name: "passwords in stderr",
err: &exec.ExitError{Stderr: []byte("failure: " + fixturePassword + " " + rotatedPassword)},
want: "failure: [REDACTED] [REDACTED]",
},
{
name: "password in error text",
err: errors.New("failure: " + fixturePassword),
want: "failure: [REDACTED]",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
detail := fixtureCommandError(tt.err)
if !strings.Contains(detail, tt.want) {
t.Fatalf("diagnostic lost expected information: %q", tt.want)
}
if strings.Contains(detail, fixturePassword) || strings.Contains(detail, rotatedPassword) {
t.Fatal("diagnostic exposed a fixture password")
}
})
}
}
func target(t *testing.T, port int, mode instance.TLSMode) instance.ObservationTarget { func target(t *testing.T, port int, mode instance.TLSMode) instance.ObservationTarget {
t.Helper() t.Helper()
id, err := instance.NewIdentity("fixture-uid", "fixture") id, err := instance.NewIdentity("fixture-uid", "fixture")