Files
poimen-workflows/internal/memory/service_test.go
T
Test 5ef14ad5ec feat(memory): add Temporal activities integration for memory service
- Implement 12 Temporal activities for memory operations
- Activities: create, update, search, context, diagnose, analyze, document
- Add activity registration and worker setup
- Full retry/timeout configuration with observability
- Include workflow patterns and examples
- All tests passing (23/23)

Documentation:
- MEMORY_INTEGRATION.md: High-level integration guide
- MEMORY_ACTIVITIES.md: Complete activities reference
- REGISTERED_ACTIVITIES.md: Registry and calling conventions
2026-08-29 21:49:24 -07:00

255 lines
5.7 KiB
Go

package memory
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
)
func TestServiceCreateKnowledge(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/memory/ingest" {
t.Errorf("unexpected path: %s", r.URL.Path)
}
var req IngestRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
t.Fatalf("decode request: %v", err)
}
if req.Project != "poimen" {
t.Errorf("expected project poimen, got %s", req.Project)
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(IngestResponse{
ID: "chunk-123",
QueueStatus: "pending",
})
}))
defer server.Close()
svc := NewService(server.URL, "test-token", "poimen")
id, err := svc.CreateKnowledge(context.Background(), &KnowledgeRecord{
Content: "test knowledge",
Level: "L1",
})
if err != nil {
t.Fatalf("create knowledge failed: %v", err)
}
if id != "chunk-123" {
t.Errorf("expected ID chunk-123, got %s", id)
}
}
func TestServiceRetrieveKnowledge(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/memory/query" {
t.Errorf("unexpected path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(QueryResponse{
Query: "test",
Results: []QueryResult{
{
ID: "chunk-123",
Level: "L1",
Score: 0.95,
SemanticScore: 0.96,
LexicalScore: 0.94,
Text: "knowledge content",
Breadcrumb: "path > to > doc",
Source: "test",
},
},
TotalHits: 1,
SearchTimeMS: 50,
})
}))
defer server.Close()
svc := NewService(server.URL, "test-token", "poimen")
records, err := svc.RetrieveKnowledge(context.Background(), "test", nil)
if err != nil {
t.Fatalf("retrieve knowledge failed: %v", err)
}
if len(records) != 1 {
t.Errorf("expected 1 record, got %d", len(records))
}
if records[0].Content != "knowledge content" {
t.Errorf("unexpected content")
}
meta := records[0].Metadata
if score, ok := meta["score"].(float32); ok {
if score != 0.95 {
t.Errorf("expected score 0.95, got %f", score)
}
}
}
func TestServiceRetrieveContext(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/memory/context" {
t.Errorf("unexpected path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(ContextResponse{
Tier: 1,
Lessons: []ContextLesson{
{
Tier: 1,
Level: "L1",
Score: 1.0,
Text: "first lesson",
MatchedKind: "signature",
},
{
Tier: 2,
Level: "L2",
Score: 0.87,
Text: "second lesson",
},
},
Skills: []ContextSkill{
{
Name: "debug-skill",
Why: "tier 1 matched",
},
},
Budget: ContextBudget{
Requested: 8192,
Used: 2048,
Dropped: 0,
},
})
}))
defer server.Close()
svc := NewService(server.URL, "test-token", "poimen")
ctx, err := svc.RetrieveContext(context.Background(), "kubectl", "debug-pod", 8192)
if err != nil {
t.Fatalf("retrieve context failed: %v", err)
}
if ctx.Tier != 1 {
t.Errorf("expected tier 1, got %d", ctx.Tier)
}
if len(ctx.Lessons) != 2 {
t.Errorf("expected 2 lessons, got %d", len(ctx.Lessons))
}
if len(ctx.Skills) != 1 {
t.Errorf("expected 1 skill, got %d", len(ctx.Skills))
}
if ctx.BudgetUsed != 2048 {
t.Errorf("expected budget used 2048, got %d", ctx.BudgetUsed)
}
}
func TestServiceGetVault(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/memory/vault" {
t.Errorf("unexpected path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(VaultResponse{
Project: "poimen",
TotalRecords: 100,
Files: []VaultFile{
{
Path: "docs/guide.md",
Title: "Guide",
Level: "L1",
RecordCount: 25,
},
{
Path: "reference/api.md",
Title: "API",
Level: "R",
RecordCount: 75,
},
},
})
}))
defer server.Close()
svc := NewService(server.URL, "test-token", "poimen")
files, err := svc.GetVault(context.Background())
if err != nil {
t.Fatalf("get vault failed: %v", err)
}
if len(files) != 2 {
t.Errorf("expected 2 files, got %d", len(files))
}
if files[0].Title != "Guide" {
t.Errorf("expected title Guide, got %s", files[0].Title)
}
}
func TestServiceIsHealthy(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
defer server.Close()
svc := NewService(server.URL, "test-token", "poimen")
if !svc.IsHealthy(context.Background()) {
t.Error("expected service to be healthy")
}
}
func TestServiceUpdateKnowledge(t *testing.T) {
callCount := 0
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
callCount++
if r.URL.Path != "/memory/ingest" {
t.Errorf("unexpected path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(IngestResponse{
ID: "chunk-123",
QueueStatus: "pending",
})
}))
defer server.Close()
svc := NewService(server.URL, "test-token", "poimen")
record := &KnowledgeRecord{
ID: "chunk-123",
Content: "updated knowledge",
Level: "L1",
}
id, err := svc.UpdateKnowledge(context.Background(), record)
if err != nil {
t.Fatalf("update knowledge failed: %v", err)
}
if id != "chunk-123" {
t.Errorf("expected ID chunk-123, got %s", id)
}
if callCount != 1 {
t.Errorf("expected 1 call, got %d", callCount)
}
}