Skip to content

Commit c61a87a

Browse files
authored
Merge pull request #1 from GrayCodeAI/dev
feat: complete MCP resources/prompts and add tests for 6 packages
2 parents 5e7f7fc + 44e04cb commit c61a87a

8 files changed

Lines changed: 1450 additions & 1 deletion

File tree

compact/compact_test.go

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
package compact
2+
3+
import (
4+
"context"
5+
"path/filepath"
6+
"testing"
7+
8+
"github.com/google/uuid"
9+
"github.com/GrayCodeAI/yaad/storage"
10+
)
11+
12+
func setupStore(t *testing.T) storage.Storage {
13+
t.Helper()
14+
dir := t.TempDir()
15+
store, err := storage.NewStore(filepath.Join(dir, "test.db"))
16+
if err != nil {
17+
t.Fatal(err)
18+
}
19+
t.Cleanup(func() { store.Close() })
20+
return store
21+
}
22+
23+
func TestNeedsCompaction_EmptyProject(t *testing.T) {
24+
store := setupStore(t)
25+
c := New(store, 100)
26+
ctx := context.Background()
27+
28+
needs, tokens := c.NeedsCompaction(ctx, "proj1")
29+
if needs {
30+
t.Error("empty project should not need compaction")
31+
}
32+
if tokens != 0 {
33+
t.Errorf("expected 0 tokens, got %d", tokens)
34+
}
35+
}
36+
37+
func TestNeedsCompaction_OverBudget(t *testing.T) {
38+
store := setupStore(t)
39+
ctx := context.Background()
40+
41+
// Create nodes with enough content to exceed a low token budget
42+
for i := 0; i < 5; i++ {
43+
content := make([]byte, 200)
44+
for j := range content {
45+
content[j] = 'a'
46+
}
47+
_ = store.CreateNode(ctx, &storage.Node{
48+
ID: uuid.New().String(),
49+
Type: "convention",
50+
Content: string(content),
51+
ContentHash: uuid.New().String(),
52+
Scope: "project",
53+
Project: "proj1",
54+
Confidence: 0.3,
55+
Version: 1,
56+
})
57+
}
58+
59+
// 5 nodes * 200 chars / 4 = 250 tokens. Budget = 100.
60+
c := New(store, 100)
61+
needs, tokens := c.NeedsCompaction(ctx, "proj1")
62+
if !needs {
63+
t.Errorf("expected compaction needed, tokens=%d", tokens)
64+
}
65+
if tokens < 200 {
66+
t.Errorf("expected tokens >= 200, got %d", tokens)
67+
}
68+
}
69+
70+
func TestCompact_NoNodesNoError(t *testing.T) {
71+
store := setupStore(t)
72+
c := New(store, 100)
73+
ctx := context.Background()
74+
75+
count, err := c.Compact(ctx, "empty-project")
76+
if err != nil {
77+
t.Fatalf("Compact on empty project: %v", err)
78+
}
79+
if count != 0 {
80+
t.Errorf("expected 0 compacted, got %d", count)
81+
}
82+
}
83+
84+
func TestCompact_SkipsHighConfidenceNodes(t *testing.T) {
85+
store := setupStore(t)
86+
ctx := context.Background()
87+
88+
// Create high-confidence nodes - should not be compacted
89+
for i := 0; i < 5; i++ {
90+
_ = store.CreateNode(ctx, &storage.Node{
91+
ID: uuid.New().String(),
92+
Type: "convention",
93+
Content: "high confidence content",
94+
ContentHash: uuid.New().String(),
95+
Scope: "project",
96+
Project: "proj1",
97+
Confidence: 0.9,
98+
AccessCount: 10,
99+
Version: 1,
100+
})
101+
}
102+
103+
c := New(store, 10)
104+
count, err := c.Compact(ctx, "proj1")
105+
if err != nil {
106+
t.Fatalf("Compact: %v", err)
107+
}
108+
if count != 0 {
109+
t.Errorf("high-confidence nodes should not be compacted, got %d", count)
110+
}
111+
}
112+
113+
func TestCompact_CompactsLowConfidenceNodes(t *testing.T) {
114+
store := setupStore(t)
115+
ctx := context.Background()
116+
117+
// Create 4 low-confidence convention nodes (> 3 threshold)
118+
var ids []string
119+
for i := 0; i < 4; i++ {
120+
id := uuid.New().String()
121+
ids = append(ids, id)
122+
_ = store.CreateNode(ctx, &storage.Node{
123+
ID: id,
124+
Type: "convention",
125+
Content: "low confidence content item",
126+
ContentHash: uuid.New().String(),
127+
Scope: "project",
128+
Project: "proj1",
129+
Confidence: 0.3,
130+
AccessCount: 1,
131+
Version: 1,
132+
})
133+
}
134+
135+
c := New(store, 10)
136+
count, err := c.Compact(ctx, "proj1")
137+
if err != nil {
138+
t.Fatalf("Compact: %v", err)
139+
}
140+
if count != 4 {
141+
t.Errorf("expected 4 compacted nodes, got %d", count)
142+
}
143+
144+
// Verify compacted nodes have confidence 0
145+
for _, id := range ids {
146+
n, _ := store.GetNode(ctx, id)
147+
if n != nil && n.Confidence != 0 {
148+
t.Errorf("node %s should have confidence 0 after compaction, got %f", id, n.Confidence)
149+
}
150+
}
151+
}
152+
153+
func TestCompact_SkipsAnchorTypes(t *testing.T) {
154+
store := setupStore(t)
155+
ctx := context.Background()
156+
157+
// Create low-confidence "file" nodes - should NOT be compacted (anchor type)
158+
for i := 0; i < 5; i++ {
159+
_ = store.CreateNode(ctx, &storage.Node{
160+
ID: uuid.New().String(),
161+
Type: "file",
162+
Content: "file anchor content",
163+
ContentHash: uuid.New().String(),
164+
Scope: "project",
165+
Project: "proj1",
166+
Confidence: 0.1,
167+
AccessCount: 0,
168+
Version: 1,
169+
})
170+
}
171+
172+
c := New(store, 10)
173+
count, err := c.Compact(ctx, "proj1")
174+
if err != nil {
175+
t.Fatalf("Compact: %v", err)
176+
}
177+
if count != 0 {
178+
t.Errorf("file/entity/session types should be skipped, got %d", count)
179+
}
180+
}
181+
182+
func TestCompact_CancelledContext(t *testing.T) {
183+
store := setupStore(t)
184+
c := New(store, 100)
185+
ctx, cancel := context.WithCancel(context.Background())
186+
cancel()
187+
188+
_, err := c.Compact(ctx, "proj1")
189+
if err == nil {
190+
t.Error("expected error from cancelled context")
191+
}
192+
}
193+
194+
func TestDefaultSummarizer(t *testing.T) {
195+
s := DefaultSummarizer{}
196+
ctx := context.Background()
197+
198+
contents := []string{"item one", "item two", "item three"}
199+
summary, err := s.Summarize(ctx, "convention", contents)
200+
if err != nil {
201+
t.Fatalf("Summarize: %v", err)
202+
}
203+
if summary == "" {
204+
t.Error("expected non-empty summary")
205+
}
206+
if len(summary) == 0 {
207+
t.Error("summary should contain content")
208+
}
209+
}
210+
211+
func TestNew_DefaultMaxTokens(t *testing.T) {
212+
store := setupStore(t)
213+
c := New(store, 0)
214+
if c.maxTokens != 50000 {
215+
t.Errorf("expected default maxTokens=50000, got %d", c.maxTokens)
216+
}
217+
}
218+
219+
func TestNew_NegativeMaxTokens(t *testing.T) {
220+
store := setupStore(t)
221+
c := New(store, -10)
222+
if c.maxTokens != 50000 {
223+
t.Errorf("expected default maxTokens=50000 for negative input, got %d", c.maxTokens)
224+
}
225+
}

0 commit comments

Comments
 (0)