95 lines
3.1 KiB
Go
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")
|
|
}
|
|
})
|
|
}
|
|
}
|