Files
poimen-workflows/internal/memory/activities_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

352 lines
8.1 KiB
Go

package memory
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"go.temporal.io/sdk/testsuite"
)
func TestActivityCreateKnowledge(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(IngestResponse{ID: "chunk-123"})
}))
defer server.Close()
suite := &testsuite.WorkflowTestSuite{}
env := suite.NewTestActivityEnvironment()
svc := NewService(server.URL, "test-token", "poimen")
activities := NewActivities(svc)
env.RegisterActivity(activities.CreateKnowledgeActivity)
record := &KnowledgeRecord{
Level: "L1",
Content: "test",
}
result, err := env.ExecuteActivity(activities.CreateKnowledgeActivity, record)
if err != nil {
t.Fatalf("activity failed: %v", err)
}
var id string
if err := result.Get(&id); err != nil {
t.Fatalf("get result failed: %v", err)
}
if id != "chunk-123" {
t.Errorf("expected chunk-123, got %s", id)
}
}
func TestActivitySearchKnowledge(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(QueryResponse{
Results: []QueryResult{
{
ID: "chunk-123",
Text: "matching knowledge",
},
},
})
}))
defer server.Close()
suite := &testsuite.WorkflowTestSuite{}
env := suite.NewTestActivityEnvironment()
svc := NewService(server.URL, "test-token", "poimen")
activities := NewActivities(svc)
env.RegisterActivity(activities.SearchKnowledgeActivity)
result, err := env.ExecuteActivity(activities.SearchKnowledgeActivity, "test query", nil)
if err != nil {
t.Fatalf("activity failed: %v", err)
}
var records []KnowledgeRecord
if err := result.Get(&records); err != nil {
t.Fatalf("get result failed: %v", err)
}
if len(records) != 1 {
t.Errorf("expected 1 record, got %d", len(records))
}
}
func TestActivityGetContext(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(ContextResponse{
Tier: 1,
Lessons: []ContextLesson{
{
Tier: 1,
Text: "lesson text",
},
},
})
}))
defer server.Close()
suite := &testsuite.WorkflowTestSuite{}
env := suite.NewTestActivityEnvironment()
svc := NewService(server.URL, "test-token", "poimen")
activities := NewActivities(svc)
env.RegisterActivity(activities.GetContextActivity)
result, err := env.ExecuteActivity(activities.GetContextActivity, "kubectl", "debug", 8192)
if err != nil {
t.Fatalf("activity failed: %v", err)
}
var ctx *ServiceContext
if err := result.Get(&ctx); err != nil {
t.Fatalf("get result failed: %v", err)
}
if ctx.Tier != 1 {
t.Errorf("expected tier 1, got %d", ctx.Tier)
}
if len(ctx.Lessons) != 1 {
t.Errorf("expected 1 lesson, got %d", len(ctx.Lessons))
}
}
func TestActivityDiagnoseIssue(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(ContextResponse{
Tier: 1,
Lessons: []ContextLesson{
{
Tier: 1,
Text: "diagnosis: check logs",
},
},
Skills: []ContextSkill{
{
Name: "debug-skill",
Why: "matched",
},
},
})
}))
defer server.Close()
suite := &testsuite.WorkflowTestSuite{}
env := suite.NewTestActivityEnvironment()
svc := NewService(server.URL, "test-token", "poimen")
activities := NewActivities(svc)
env.RegisterActivity(activities.DiagnoseIssueActivity)
result, err := env.ExecuteActivity(activities.DiagnoseIssueActivity, "kubectl", "pod-crash")
if err != nil {
t.Fatalf("activity failed: %v", err)
}
var recommendations []string
if err := result.Get(&recommendations); err != nil {
t.Fatalf("get result failed: %v", err)
}
if len(recommendations) == 0 {
t.Error("expected recommendations")
}
}
func TestActivityAnalyzeError(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(QueryResponse{
Results: []QueryResult{
{
ID: "chunk-123",
Level: "L1",
Text: "solution: restart pod",
},
},
})
}))
defer server.Close()
suite := &testsuite.WorkflowTestSuite{}
env := suite.NewTestActivityEnvironment()
svc := NewService(server.URL, "test-token", "poimen")
activities := NewActivities(svc)
env.RegisterActivity(activities.AnalyzeErrorActivity)
result, err := env.ExecuteActivity(activities.AnalyzeErrorActivity, "CrashLoopBackOff")
if err != nil {
t.Fatalf("activity failed: %v", err)
}
var records []KnowledgeRecord
if err := result.Get(&records); err != nil {
t.Fatalf("get result failed: %v", err)
}
if len(records) != 1 {
t.Errorf("expected 1 record, got %d", len(records))
}
}
func TestActivityHealthCheck(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
defer server.Close()
suite := &testsuite.WorkflowTestSuite{}
env := suite.NewTestActivityEnvironment()
svc := NewService(server.URL, "test-token", "poimen")
activities := NewActivities(svc)
env.RegisterActivity(activities.HealthCheckActivity)
result, err := env.ExecuteActivity(activities.HealthCheckActivity)
if err != nil {
t.Fatalf("activity failed: %v", err)
}
var healthy bool
if err := result.Get(&healthy); err != nil {
t.Fatalf("get result failed: %v", err)
}
if !healthy {
t.Error("expected healthy")
}
}
func TestActivityLearnFromExecution(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(IngestResponse{ID: "chunk-456"})
}))
defer server.Close()
suite := &testsuite.WorkflowTestSuite{}
env := suite.NewTestActivityEnvironment()
svc := NewService(server.URL, "test-token", "poimen")
activities := NewActivities(svc)
env.RegisterActivity(activities.LearnFromExecutionActivity)
result, err := env.ExecuteActivity(activities.LearnFromExecutionActivity, "task-123", "success", []string{"tag1"})
if err != nil {
t.Fatalf("activity failed: %v", err)
}
var id string
if err := result.Get(&id); err != nil {
t.Fatalf("get result failed: %v", err)
}
if id != "chunk-456" {
t.Errorf("expected chunk-456, got %s", id)
}
}
func TestActivityDocumentDecision(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(IngestResponse{ID: "chunk-789"})
}))
defer server.Close()
suite := &testsuite.WorkflowTestSuite{}
env := suite.NewTestActivityEnvironment()
svc := NewService(server.URL, "test-token", "poimen")
activities := NewActivities(svc)
env.RegisterActivity(activities.DocumentDecisionActivity)
result, err := env.ExecuteActivity(
activities.DocumentDecisionActivity,
"scaling",
"scale to 5 replicas",
"high CPU usage",
)
if err != nil {
t.Fatalf("activity failed: %v", err)
}
var id string
if err := result.Get(&id); err != nil {
t.Fatalf("get result failed: %v", err)
}
if id != "chunk-789" {
t.Errorf("expected chunk-789, got %s", id)
}
}
func TestActivityOptions(t *testing.T) {
opts := DefaultActivityOptions()
if opts.RetryAttempts != 3 {
t.Errorf("expected 3 retry attempts, got %d", opts.RetryAttempts)
}
if opts.StartTimeout == 0 {
t.Error("expected non-zero start timeout")
}
}
func TestActivityError(t *testing.T) {
err := &MemoryActivityError{
ActivityName: "test-activity",
Attempt: 2,
Err: context.Canceled,
}
msg := err.Error()
if msg == "" {
t.Error("expected error message")
}
if !contains(msg, "test-activity") {
t.Error("expected activity name in error")
}
if !contains(msg, "attempt 2") {
t.Error("expected attempt number in error")
}
}
func contains(s, substr string) bool {
for i := 0; i < len(s)-len(substr)+1; i++ {
if s[i:i+len(substr)] == substr {
return true
}
}
return false
}