返回 DeepSeek-Reasonix
tab_startup_history_test.go
根目录 / desktop / tab_startup_history_test.go
1 package main
2
3 import (
4 "os"
5 "testing"
6 "time"
7
8 "reasonix/internal/agent"
9 )
10
11 func TestTerminalStartupFailureRemainsInProjectHistoryAfterRestart(t *testing.T) {
12 isolateDesktopUserDirs(t)
13 projectRoot := t.TempDir()
14 topicID := "topic_failed_startup_history"
15 topicTitle := "Failed startup history"
16 if err := addProject(projectRoot, "Failed startup project"); err != nil {
17 t.Fatalf("add project: %v", err)
18 }
19 if err := setTopicTitle(projectRoot, topicID, topicTitle); err != nil {
20 t.Fatalf("set topic title: %v", err)
21 }
22 sessionDir := desktopSessionDir(projectRoot)
23 if err := os.MkdirAll(sessionDir, 0o755); err != nil {
24 t.Fatalf("mkdir session directory: %v", err)
25 }
26 sessionPath := writeTopicSession(t, sessionDir, "failed-startup.jsonl", topicID, topicTitle, projectRoot)
27
28 app := NewApp()
29 failed := &WorkspaceTab{
30 ID: "failed", Scope: "project", WorkspaceRoot: projectRoot,
31 TopicID: topicID, TopicTitle: topicTitle, SessionPath: sessionPath,
32 Ready: true, disabledMCP: map[string]ServerView{},
33 }
34 app.tabs[failed.ID] = failed
35 app.tabOrder = []string{failed.ID}
36 app.activeTabID = failed.ID
37 app.mu.Lock()
38 app.newSessionRuntimeLocked(failed, sessionRuntimeKey(sessionPath))
39 leaseHeld, save := app.markTabStartupFailureLocked(failed, agent.ErrSessionWriteAuthorityMissing, suppressStartupRestore)
40 app.mu.Unlock()
41 if leaseHeld || save == nil {
42 t.Fatalf("terminal failure result: leaseHeld=%v save=%#v", leaseHeld, save)
43 }
44 app.writeTabsSaveRequest(save)
45
46 persisted := loadTabsFile()
47 if len(persisted.Tabs) != 0 || persisted.ActiveTab != "" {
48 t.Fatalf("persisted tabs = %#v active=%q, want failed tab omitted", persisted.Tabs, persisted.ActiveTab)
49 }
50 if _, err := os.Stat(sessionPath); err != nil {
51 t.Fatalf("terminal startup failure removed session history: %v", err)
52 }
53
54 restarted := NewApp()
55 targetFound := false
56 for _, target := range restarted.sessionCatalogTargets() {
57 if sameDesktopPath(target.Path, sessionDir) && target.Scope == "project" && sameProjectRoot(target.WorkspaceRoot, projectRoot) {
58 targetFound = true
59 break
60 }
61 }
62 if !targetFound {
63 t.Fatalf("restart catalog targets = %#v, want project session directory %q", restarted.sessionCatalogTargets(), sessionDir)
64 }
65 restarted.startSessionCatalog()
66 t.Cleanup(func() { restarted.stopSessionCatalog(time.Second) })
67 waitForCatalogTreeCondition(t, restarted, "failed session history after restart", func(nodes []ProjectNode) bool {
68 for _, project := range nodes {
69 if project.Kind != "project" || !sameProjectRoot(project.Root, projectRoot) {
70 continue
71 }
72 for _, topic := range project.Children {
73 if topic.TopicID == topicID && sameDesktopPath(topic.SessionPath, sessionPath) {
74 return true
75 }
76 }
77 }
78 return false
79 })
80 }
81
81 lines GO