Scert/backend/internal/adminconsole/recovery_test.go
xuans 978f023a7f 保存本机只读核查入口并开始全量失败修复
本机协议及菜单已实现,Linux专项通过;全量存在环境缺失和SQLite截止时间失败,尚未通过生产验收。
2026-10-03 18:23:48 +08:00

95 lines
3.1 KiB
Go

package adminconsole
import (
"context"
"errors"
"strings"
"testing"
"time"
"git.pcux.cn/xuans/Scert/backend/internal/deployment"
)
type recoveryTestClient struct {
cursors []string
inspected []string
err error
}
func (c *recoveryTestClient) ListRecoveries(cursor string) (deployment.PendingRecoveryPage, error) {
c.cursors = append(c.cursors, cursor)
if cursor == "" {
return deployment.PendingRecoveryPage{Items: []deployment.PendingRecovery{{ID: "tx-1", ServerID: "server-1"}}, NextCursor: "tx-1"}, nil
}
return deployment.PendingRecoveryPage{Items: []deployment.PendingRecovery{{ID: "tx-2", ServerID: "server-2"}}}, nil
}
func (c *recoveryTestClient) InspectRecovery(id string) (deployment.RecoveryInspection, error) {
c.inspected = append(c.inspected, id)
return deployment.RecoveryInspection{TransactionID: id, ServerID: "server-2", ObservedAt: time.Now(),
Files: []deployment.RecoveryFileObservation{{Path: "/ssl/\x1b[2J\n\u202efile", Kind: "target", Comparison: "unrecorded"}}}, c.err
}
type recoveryTestScreen struct {
testTerminalInput
lines []string
showError bool
}
func (s *recoveryTestScreen) Show(line string) error {
if s.showError {
return errors.New("display-unavailable")
}
s.lines = append(s.lines, line)
return nil
}
func TestRecoveryConsolePaginationAndSafeDisplay(t *testing.T) {
client := &recoveryTestClient{}
screen := &recoveryTestScreen{testTerminalInput: testTerminalInput{values: []string{"n", "1"}}}
if err := recoveryFlow(t.Context(), client, screen); err != nil {
t.Fatal(err)
}
if len(client.cursors) != 2 || client.cursors[1] != "tx-1" || len(client.inspected) != 1 || client.inspected[0] != "tx-2" {
t.Fatal("pagination or selection incorrect")
}
output := strings.Join(screen.lines, "|")
if strings.ContainsAny(output, "\x1b\n\u202e") || !strings.Contains(output, "\\u001b") ||
!strings.Contains(output, "缺失,禁止据此认定历史成功") || !strings.Contains(output, "未提交或回滚事务") {
t.Fatal("unsafe display or missing evidence warning")
}
}
func TestRecoveryConsoleCancellationAndFailures(t *testing.T) {
for _, scenario := range []string{"quit", "invalid", "cancelled", "display-error", "inspection-error"} {
t.Run(scenario, func(t *testing.T) {
ctx, cancel := context.WithCancel(t.Context())
defer cancel()
client := &recoveryTestClient{}
screen := &recoveryTestScreen{testTerminalInput: testTerminalInput{values: []string{"1"}}}
switch scenario {
case "quit":
screen.values[0] = "q"
case "invalid":
screen.values[0] = "0"
case "cancelled":
screen.readHook = func(int) { cancel() }
case "display-error":
screen.showError = true
case "inspection-error":
client.err = errors.New("unavailable")
}
err := recoveryFlow(ctx, client, screen)
if (err == nil) != (scenario == "quit") {
t.Fatalf("unexpected result: %v", err)
}
if scenario != "inspection-error" && len(client.inspected) != 0 {
t.Fatal("cancelled operation inspected")
}
if strings.Contains(strings.Join(screen.lines, "|"), "只读采样已完成") {
t.Fatal("failure reported success")
}
})
}
}