Forge
csharpdeeb25a2
1using CascadeIDE.Features.Chat;
2using CascadeIDE.Models.AgentChat;
3using Xunit;
4
5namespace CascadeIDE.Tests;
6
7public sealed class ChatSessionStoreTests
8{
9 [Fact]
10 public async Task ResolveOrCreateCurrentSessionId_ReusesPointer()
11 {
12 var root = CreateTempWorkspaceRoot();
13 var store = new ChatSessionStore(root);
14 var first = await store.ResolveOrCreateCurrentSessionIdAsync();
15 var second = await store.ResolveOrCreateCurrentSessionIdAsync();
16 Assert.Equal(first, second);
17 }
18
19 [Fact]
20 public async Task ResolveOrCreateCurrentSessionId_PicksLatestMetaWhenPointerMissing()
21 {
22 var root = CreateTempWorkspaceRoot();
23 var store = new ChatSessionStore(root);
24 var olderId = Guid.Parse("11111111111111111111111111111111");
25 var newerId = Guid.Parse("22222222222222222222222222222222");
26 var now = DateTimeOffset.UtcNow;
27 await store.SaveMetadataAsync(new ChatSessionMetadata(olderId, now.AddHours(-2), now.AddHours(-1)), CancellationToken.None);
28 await store.SaveMetadataAsync(new ChatSessionMetadata(newerId, now.AddHours(-1), now), CancellationToken.None);
29
30 var resolved = await store.ResolveOrCreateCurrentSessionIdAsync();
31 Assert.Equal(newerId, resolved);
32 }
33
34 [Fact]
35 public async Task ReadEventsAsync_RoundTripsAppendOnlyLog()
36 {
37 var root = CreateTempWorkspaceRoot();
38 var store = new ChatSessionStore(root);
39 var sessionId = await store.ResolveOrCreateCurrentSessionIdAsync();
40 var ev = new ChatHistoryEvent(
41 Guid.NewGuid(),
42 sessionId,
43 DateTimeOffset.UtcNow,
44 ChatHistoryEventKind.MessageAdded,
45 ChatHistoryJson.Serialize(new ChatHistoryMessagePayload(
46 Guid.NewGuid().ToString("N"),
47 "user",
48 "hello",
49 Guid.NewGuid().ToString("N"))));
50 await store.AppendEventAsync(ev, CancellationToken.None);
51
52 var rows = await store.ReadEventsAsync(sessionId, CancellationToken.None);
53 Assert.Single(rows);
54 Assert.Equal(ev.EventId, rows[0].EventId);
55 }
56
57 [Fact]
58 public async Task ResolveOrCreateCurrentSessionId_PicksLatestEventsWhenNoMeta()
59 {
60 var root = CreateTempWorkspaceRoot();
61 var store = new ChatSessionStore(root);
62 var olderId = Guid.Parse("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
63 var newerId = Guid.Parse("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
64 var sessionsDir = Path.Combine(root, ".cascade-ide", "chat-sessions");
65 Directory.CreateDirectory(sessionsDir);
66 var olderPath = Path.Combine(sessionsDir, $"session-{olderId:N}.events.ndjson");
67 var newerPath = Path.Combine(sessionsDir, $"session-{newerId:N}.events.ndjson");
68 await File.WriteAllTextAsync(olderPath, "");
69 await Task.Delay(20);
70 await File.WriteAllTextAsync(newerPath, "");
71
72 var resolved = await store.ResolveOrCreateCurrentSessionIdAsync();
73 Assert.Equal(newerId, resolved);
74 }
75
76 [Fact]
77 public void SetWorkspaceRoot_SwitchesSessionDirectory()
78 {
79 var a = CreateTempWorkspaceRoot();
80 var b = CreateTempWorkspaceRoot();
81 var store = new ChatSessionStore(a);
82 Assert.Contains(a, store.RootPath, StringComparison.OrdinalIgnoreCase);
83 store.SetWorkspaceRoot(b);
84 Assert.Contains(b, store.RootPath, StringComparison.OrdinalIgnoreCase);
85 Assert.DoesNotContain(a, store.RootPath, StringComparison.OrdinalIgnoreCase);
86 }
87
88 private static string CreateTempWorkspaceRoot()
89 {
90 var path = Path.Combine(Path.GetTempPath(), "cascade-chat-store-" + Guid.NewGuid().ToString("N"));
91 Directory.CreateDirectory(path);
92 return path;
93 }
94}
95
View only · write via MCP/CIDE