| 1 | using AgentNotes.Core; |
| 2 | using System.Text; |
| 3 | using System.Text.Json; |
| 4 | |
| 5 | namespace AgentNotesMcp.Tests; |
| 6 | |
| 7 | public sealed class KnowledgeRootsRouteContextTests |
| 8 | { |
| 9 | [Fact] |
| 10 | public void RouteContext_IncludesKnowledgeRootsOverlay_WhenRegistryMatchesGroupQuery() |
| 11 | { |
| 12 | using var primary = LocalSettingsLoaderTests.TempKnowledgeRoot.Create(); |
| 13 | using var group = MultiRootKnowledgeTests.CreateGroupKbRootPublic(); |
| 14 | using var runtime = MultiRootKnowledgeTests.InstallWithReadOnlyPublic(primary.Path, group.Path); |
| 15 | SeedKnowledgeRootsRouting(primary.Path); |
| 16 | |
| 17 | var storage = new NotesStorage(); |
| 18 | var workspace = Path.Combine(Path.GetTempPath(), "AgentNotesMcpTests", Guid.NewGuid().ToString("N")); |
| 19 | Directory.CreateDirectory(workspace); |
| 20 | |
| 21 | var json = storage.RouteContext(workspace, "group smoke test", null, maxSections: 6, maxChars: 12000); |
| 22 | using var doc = JsonDocument.Parse(json); |
| 23 | var root = doc.RootElement; |
| 24 | |
| 25 | Assert.True(root.GetProperty("knowledge_roots_overlay_applied").GetBoolean()); |
| 26 | Assert.True(root.GetProperty("knowledge_roots_registry_hits").GetInt32() >= 1); |
| 27 | |
| 28 | var assembled = root.GetProperty("assembled_context").GetString() ?? ""; |
| 29 | Assert.Contains("knowledge-roots-routing-v1", assembled); |
| 30 | Assert.Contains("knowledge_root_id=group", assembled, StringComparison.Ordinal); |
| 31 | Assert.Contains("group-kb smoke", assembled, StringComparison.OrdinalIgnoreCase); |
| 32 | } |
| 33 | |
| 34 | [Fact] |
| 35 | public void RouteContext_IncludesPrefixRegistry_WhenQueryMatchesCatalogSegment() |
| 36 | { |
| 37 | using var primary = LocalSettingsLoaderTests.TempKnowledgeRoot.Create(); |
| 38 | using var group = CreateGroupKbWithOpenStackPrefix(); |
| 39 | using var runtime = MultiRootKnowledgeTests.InstallWithReadOnlyPublic(primary.Path, group.Path); |
| 40 | SeedKnowledgeRootsRoutingWithPrefix(primary.Path); |
| 41 | |
| 42 | var storage = new NotesStorage(); |
| 43 | var workspace = Path.Combine(Path.GetTempPath(), "AgentNotesMcpTests", Guid.NewGuid().ToString("N")); |
| 44 | Directory.CreateDirectory(workspace); |
| 45 | |
| 46 | var json = storage.RouteContext(workspace, "aiguiders-open mission cards", null, maxSections: 8, maxChars: 12000); |
| 47 | using var doc = JsonDocument.Parse(json); |
| 48 | var root = doc.RootElement; |
| 49 | |
| 50 | Assert.True(root.GetProperty("knowledge_roots_overlay_applied").GetBoolean()); |
| 51 | Assert.True(root.GetProperty("knowledge_roots_registry_hits").GetInt32() >= 1); |
| 52 | |
| 53 | var assembled = root.GetProperty("assembled_context").GetString() ?? ""; |
| 54 | Assert.Contains("Prefix:", assembled, StringComparison.Ordinal); |
| 55 | Assert.Contains("aiguiders-open", assembled, StringComparison.OrdinalIgnoreCase); |
| 56 | Assert.Contains("open-stack hub", assembled, StringComparison.OrdinalIgnoreCase); |
| 57 | } |
| 58 | |
| 59 | [Fact] |
| 60 | public void RouteContext_NoOverlay_WhenUnrelatedQueryAndNoRegistryMatch() |
| 61 | { |
| 62 | using var primary = LocalSettingsLoaderTests.TempKnowledgeRoot.Create(); |
| 63 | using var group = MultiRootKnowledgeTests.CreateGroupKbRootPublic(); |
| 64 | using var runtime = MultiRootKnowledgeTests.InstallWithReadOnlyPublic(primary.Path, group.Path); |
| 65 | SeedKnowledgeRootsRouting(primary.Path); |
| 66 | |
| 67 | var storage = new NotesStorage(); |
| 68 | var workspace = Path.Combine(Path.GetTempPath(), "AgentNotesMcpTests", Guid.NewGuid().ToString("N")); |
| 69 | Directory.CreateDirectory(workspace); |
| 70 | |
| 71 | Assert.Equal("OK", storage.UpsertSection(workspace, "current-task", "Ship release flow for unrelated feature")); |
| 72 | |
| 73 | var json = storage.RouteContext(workspace, "release flow", null, maxSections: 3, maxChars: 5000); |
| 74 | using var doc = JsonDocument.Parse(json); |
| 75 | var root = doc.RootElement; |
| 76 | |
| 77 | Assert.False(root.GetProperty("knowledge_roots_overlay_applied").GetBoolean()); |
| 78 | var assembled = root.GetProperty("assembled_context").GetString() ?? ""; |
| 79 | Assert.DoesNotContain("knowledge_root_id=group", assembled); |
| 80 | } |
| 81 | |
| 82 | private static MultiRootKnowledgeTests.GroupKbRoot CreateGroupKbWithOpenStackPrefix() |
| 83 | { |
| 84 | var path = Path.Combine(Path.GetTempPath(), "AgentNotesMcpTests", "group-kb", Guid.NewGuid().ToString("N")); |
| 85 | var openDir = Path.Combine(path, "knowledge", "work", "projects", "aiguiders-open"); |
| 86 | Directory.CreateDirectory(Path.Combine(path, "knowledge", "group")); |
| 87 | Directory.CreateDirectory(openDir); |
| 88 | File.WriteAllText( |
| 89 | Path.Combine(path, "knowledge", "group", "smoke-test-v1.md"), |
| 90 | "# Group KB smoke\n\ngroup-kb smoke test content.\n", |
| 91 | Encoding.UTF8); |
| 92 | File.WriteAllText( |
| 93 | Path.Combine(openDir, "README.md"), |
| 94 | "# Open stack hub\n\nopen-stack hub for tests.\n", |
| 95 | Encoding.UTF8); |
| 96 | File.WriteAllText(Path.Combine(path, "agent-notes.md"), "# Group hot (stub)\n", Encoding.UTF8); |
| 97 | return new MultiRootKnowledgeTests.GroupKbRoot(path); |
| 98 | } |
| 99 | |
| 100 | private static void SeedKnowledgeRootsRouting(string primaryPath) => |
| 101 | WriteKnowledgeRootsIndex(primaryPath, "group/smoke-test-v1.md => group\n"); |
| 102 | |
| 103 | private static void SeedKnowledgeRootsRoutingWithPrefix(string primaryPath) => |
| 104 | WriteKnowledgeRootsIndex( |
| 105 | primaryPath, |
| 106 | """ |
| 107 | group/smoke-test-v1.md => group |
| 108 | work/projects/aiguiders-open/ => group |
| 109 | """); |
| 110 | |
| 111 | private static void WriteKnowledgeRootsIndex(string primaryPath, string body) |
| 112 | { |
| 113 | Directory.CreateDirectory(Path.Combine(primaryPath, "knowledge", "work", "local")); |
| 114 | File.WriteAllText( |
| 115 | Path.Combine(primaryPath, "knowledge", "work", "local", "knowledge-roots-index-v1.md"), |
| 116 | body, |
| 117 | Encoding.UTF8); |
| 118 | |
| 119 | File.WriteAllText( |
| 120 | Path.Combine(primaryPath, "agent-notes.md"), |
| 121 | """ |
| 122 | <!-- section:knowledge-roots-routing-v1 --> |
| 123 | chmod ugo: group=read-only via knowledge_root_id=group; user=primary writes. |
| 124 | Registry: work/local/knowledge-roots-index-v1.md |
| 125 | <!-- /section:knowledge-roots-routing-v1 --> |
| 126 | <!-- section:current-task --> |
| 127 | unrelated default task |
| 128 | <!-- /section:current-task --> |
| 129 | """, |
| 130 | Encoding.UTF8); |
| 131 | } |
| 132 | } |
| 133 | |