From 14d5e53ea0d4ffbb7749c471c27d41dd93b3dae9 Mon Sep 17 00:00:00 2001 From: xuans Date: Wed, 30 Sep 2026 01:37:20 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E9=BD=90=E6=B4=BB=E5=8A=A8=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E5=88=A0=E9=99=A4=E4=BF=9D=E6=8A=A4=E7=9F=A9=E9=98=B5?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 覆盖五类证书任务和四种活动状态,验证拒绝删除后的域名与服务器关联保持不变,并补充终态删除及共享资源保护断言。 --- .../project_domain_repository_test.go | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/backend/internal/repository/project_domain_repository_test.go b/backend/internal/repository/project_domain_repository_test.go index 5c5d4f5..57fac4f 100644 --- a/backend/internal/repository/project_domain_repository_test.go +++ b/backend/internal/repository/project_domain_repository_test.go @@ -8,6 +8,7 @@ import ( "git.pcux.cn/xuans/Scert/backend/internal/config" "git.pcux.cn/xuans/Scert/backend/internal/database" + "git.pcux.cn/xuans/Scert/backend/internal/deployment" "git.pcux.cn/xuans/Scert/backend/internal/domain" ) @@ -60,6 +61,39 @@ func TestProjectDomainRepositorySQLite(t *testing.T) { if _, err := NewSQLDomainRepository(db.DB, cfg.Driver).GetByID(t.Context(), item.ID); err != nil { t.Fatal(err) } + serverRepo := NewSQLServerRepository(db.DB, cfg.Driver) + server := deployment.Server{ + ResourceScope: domain.ResourceScope{ProjectID: item.ProjectID}, + ID: "domain-delete-server", + Name: "domain delete test server", + Address: "192.0.2.10", + Port: 22, + Username: "deploy", + HostKeyFingerprint: "SHA256:test", + PasswordRef: "secret://ssh/domain-delete-server", + CertificatePath: "/etc/scert/{domain}/cert.pem", + PrivateKeyPath: "/etc/scert/{domain}/key.pem", + CertificateChainPath: "/etc/scert/{domain}/fullchain.pem", + WebServer: deployment.WebServerNginx, + } + if err := serverRepo.CreateServer(t.Context(), server); err != nil { + t.Fatal(err) + } + if err := serverRepo.ReplaceDomainServers(t.Context(), item.ID, []string{server.ID}); err != nil { + t.Fatal(err) + } + otherItem, err := domain.NewDomain("surviving.example.test", domain.CertificateSingle, nil) + if err != nil { + t.Fatal(err) + } + otherItem.ID = "surviving-domain" + otherItem.ProjectID = item.ProjectID + if err := writer.CreateProjectDomain(t.Context(), "domain-manager", otherItem); err != nil { + t.Fatal(err) + } + if err := serverRepo.ReplaceDomainServers(t.Context(), otherItem.ID, []string{server.ID}); err != nil { + t.Fatal(err) + } taskRepo := NewSQLTaskRepository(db.DB, cfg.Driver) if err := taskRepo.CreateTask(t.Context(), Task{HistoryScope: HistoryScope{ProjectID: item.ProjectID, ScopeType: ScopeProject}, ID: "domain-active-task", DomainID: item.ID, TaskType: "certificate_issue", Status: "running"}); err != nil { t.Fatal(err) @@ -70,6 +104,35 @@ func TestProjectDomainRepositorySQLite(t *testing.T) { if _, err := db.DB.ExecContext(context.Background(), Rebind(cfg.Driver, `UPDATE tasks SET status = 'success' WHERE id = ?`), "domain-active-task"); err != nil { t.Fatal(err) } + activeStatuses := []string{"queued", "running", "retry_wait", "cancelling"} + taskTypes := []string{"certificate_issue", "certificate_validate", "certificate_deploy", "certificate_import", "certificate_restore"} + for _, taskType := range taskTypes { + for _, status := range activeStatuses { + taskID := "domain-matrix-task-" + taskType + "-" + status + if err := taskRepo.CreateTask(t.Context(), Task{HistoryScope: HistoryScope{ProjectID: item.ProjectID, ScopeType: ScopeProject}, ID: taskID, DomainID: item.ID, TaskType: taskType, Status: status}); err != nil { + t.Fatal(err) + } + if err := writer.DeleteProjectDomain(t.Context(), "domain-manager", item.ID); !errors.Is(err, ErrProjectDomainBusy) { + t.Fatalf("delete should reject for task type %s and status %s: %v", taskType, status, err) + } + if _, err := NewSQLDomainRepository(db.DB).GetByID(t.Context(), item.ID); err != nil { + t.Fatalf("domain disappeared after rejected delete: %v", err) + } + associated, err := serverRepo.ListServersByDomainID(t.Context(), item.ID) + if err != nil || len(associated) != 1 || associated[0].ID != server.ID { + t.Fatalf("server binding changed after rejected delete: %+v, %v", associated, err) + } + if _, err := db.DB.ExecContext(t.Context(), Rebind(cfg.Driver, "UPDATE tasks SET status = 'partial_success' WHERE id = ?"), taskID); err != nil { + t.Fatal(err) + } + } + } + for _, status := range []string{"failed", "cancelled"} { + taskID := "domain-terminal-task-" + status + if err := taskRepo.CreateTask(t.Context(), Task{HistoryScope: HistoryScope{ProjectID: item.ProjectID, ScopeType: ScopeProject}, ID: taskID, DomainID: item.ID, TaskType: "certificate_issue", Status: status}); err != nil { + t.Fatal(err) + } + } trigger := `CREATE TRIGGER reject_project_domain_audit BEFORE INSERT ON audit_logs BEGIN SELECT RAISE(ABORT, 'audit-failure'); END` for _, status := range []string{"retry_wait", "cancelling"} { taskID := "domain-active-task-" + status @@ -133,4 +196,15 @@ func TestProjectDomainRepositorySQLite(t *testing.T) { if _, err := NewSQLDomainRepository(db.DB, cfg.Driver).GetByID(t.Context(), item.ID); !errors.Is(err, sql.ErrNoRows) { t.Fatalf("删除后域名应不存在:%v", err) } + + if _, err := NewSQLDomainRepository(db.DB).GetByID(t.Context(), otherItem.ID); err != nil { + t.Fatalf("surviving domain was removed with deleted domain: %v", err) + } + if _, err := serverRepo.GetServerByID(t.Context(), server.ID); err != nil { + t.Fatalf("server was removed with deleted domain: %v", err) + } + associated, err := serverRepo.ListServersByDomainID(t.Context(), otherItem.ID) + if err != nil || len(associated) != 1 || associated[0].ID != server.ID { + t.Fatalf("surviving domain binding was removed: %+v, %v", associated, err) + } }