Scert/backend/internal/app/certificate_task_cancellation_test.go

55 lines
2.1 KiB
Go

package app
import (
"context"
"errors"
"strings"
"testing"
"time"
"git.pcux.cn/xuans/Scert/backend/internal/deployment"
)
func TestCertificateCancellationPreservesDeploymentOutcome(t *testing.T) {
for _, scenario := range []struct {
name string
report deployment.Report
expected string
}{
{"partial", deployment.Report{Status: "partial", Total: 2, Success: 1, Failed: 1}, "partial_success"},
{"recovery_unconfirmed", deployment.Report{Status: "failed", RecoveryStatus: "unconfirmed", Total: 1, Failed: 1}, "failed"},
{"recovery_failed", deployment.Report{Status: "failed", RecoveryStatus: "failed", Total: 1, Failed: 1}, "failed"},
{"restored", deployment.Report{Status: "failed", RecoveryStatus: "success", Total: 1, Failed: 1}, "cancelled"},
} {
t.Run(scenario.name, func(t *testing.T) {
w, a := newCertificateTaskFixture(t)
ctx, cancel := context.WithCancel(t.Context())
defer cancel()
scenario.report.Results = []deployment.Result{{ServerID: "cancel-target", Status: "failed", Message: "secret-output"}}
if scenario.report.Success > 0 {
scenario.report.Results = append(scenario.report.Results, deployment.Result{ServerID: "completed-target", Status: "success"})
}
calls := 0
_, err := w.run(ctx, "task-domain", "renewal_run", "certificate_issue", 3, time.Nanosecond,
func(context.Context, string) (CertificateWorkflowResult, error) {
calls++
cancel()
return CertificateWorkflowResult{Deployment: scenario.report}, context.Canceled
})
if !errors.Is(err, context.Canceled) || calls != 1 {
t.Fatalf("取消后仍重试或丢失原始取消原因:%d %v", calls, err)
}
task := assertCertificateTask(t, a, scenario.expected, scenario.expected)
results, err := a.Tasks.ListTaskDeploymentResults(t.Context(), task.ID)
if err != nil || len(results) != len(scenario.report.Results) {
t.Fatalf("取消后必须保留实际部署结果:%+v %v", results, err)
}
for _, result := range results {
if strings.Contains(result.Message, "secret-output") {
t.Fatal("取消后的部署结果泄露原始远端输出")
}
}
})
}
}