返回 DeepSeek-Reasonix
service_lease_test.go
根目录 / internal / acp / service_lease_test.go
1 package acp
2
3 import (
4 "strings"
5 "testing"
6
7 "reasonix/internal/agent"
8 "reasonix/internal/permission"
9 "reasonix/internal/provider"
10 )
11
12 func leaseTestFactory(dir string) *e2eFactory {
13 return &e2eFactory{
14 prov: &scriptedProvider{name: "fake", responses: [][]provider.Chunk{
15 {{Type: provider.ChunkText, Text: "unused"}, {Type: provider.ChunkDone}},
16 }},
17 tool: fakeTool{name: "peek", ro: true, out: "unused"},
18 policy: permission.New("ask", nil, nil, nil),
19 sessionDir: dir,
20 }
21 }
22
23 // TestSessionLoadRefusedWhenLeaseHeld proves session/load returns a protocol
24 // error naming the holder when the transcript is owned by another runtime
25 // (a desktop window or CLI writing the same session), and does not register
26 // the session.
27 func TestSessionLoadRefusedWhenLeaseHeld(t *testing.T) {
28 dir := t.TempDir()
29 const id = "sess-held-lease"
30 path := transcriptPath(dir, id)
31 s := agent.NewSession("sys")
32 s.Add(provider.Message{Role: provider.RoleUser, Content: "editor session"})
33 if err := s.Save(path); err != nil {
34 t.Fatal(err)
35 }
36
37 holder, err := agent.TryAcquireSessionLease(path)
38 if err != nil {
39 t.Fatalf("test holder acquire: %v", err)
40 }
41 defer holder.Release()
42
43 client, stop := startServer(t, leaseTestFactory(dir))
44 defer stop()
45 client.call(t, "initialize", InitializeParams{ProtocolVersion: 1})
46
47 resp := client.call(t, "session/load", SessionLoadParams{SessionID: id, Cwd: t.TempDir()})
48 if resp.Error == nil {
49 t.Fatalf("session/load of a held session succeeded, want protocol error")
50 }
51 if !strings.Contains(resp.Error.Message, "in use by another Reasonix") {
52 t.Fatalf("session/load error = %q, want holder wording", resp.Error.Message)
53 }
54 if strings.Contains(resp.Error.Message, path) {
55 t.Fatalf("session/load error leaks the session path: %q", resp.Error.Message)
56 }
57
58 // The refused load must not have bound the session: a prompt is unknown.
59 promptResp := client.call(t, "session/prompt", SessionPromptParams{
60 SessionID: id,
61 Prompt: []ContentBlock{{Type: "text", Text: "should not run"}},
62 })
63 if promptResp.Error == nil {
64 t.Fatalf("session/prompt after refused load succeeded, want unknown session")
65 }
66 }
67
68 // TestSessionCloseReleasesLease proves the lease taken by session/new is
69 // released by session/close, so another runtime can bind the transcript.
70 func TestSessionCloseReleasesLease(t *testing.T) {
71 dir := t.TempDir()
72 client, stop := startServer(t, leaseTestFactory(dir))
73 defer stop()
74
75 sid := openSession(t, client)
76 path := transcriptPath(dir, sid)
77
78 // Held while the session is open.
79 if lease, err := agent.TryAcquireSessionLease(path); err == nil {
80 lease.Release()
81 t.Fatalf("transcript lease not held after session/new")
82 }
83
84 resp := client.call(t, "session/close", SessionCloseParams{SessionID: sid})
85 if resp.Error != nil {
86 t.Fatalf("session/close errored: %+v", resp.Error)
87 }
88 lease, err := agent.TryAcquireSessionLease(path)
89 if err != nil {
90 t.Fatalf("transcript lease not released by session/close: %v", err)
91 }
92 lease.Release()
93 }
94
94 lines GO