agent/pkg/lifecycle/brain_test.go
Snider e90a84eaa0 feat: merge go-agent + go-agentic + php-devops into unified agent repo
Combines three repositories into a single workspace:
- go-agent → pkg/orchestrator (Clotho), pkg/jobrunner, pkg/loop, cmd/
- go-agentic → pkg/lifecycle (allowance, sessions, plans, dispatch)
- php-devops → repos.yaml, setup.sh, scripts/, .core/

Module path: forge.lthn.ai/core/agent

All packages build, all tests pass.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-06 15:23:00 +00:00

234 lines
7.1 KiB
Go

package lifecycle
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestClient_Remember_Good(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPost, r.Method)
assert.Equal(t, "/v1/brain/remember", r.URL.Path)
assert.Equal(t, "Bearer test-token", r.Header.Get("Authorization"))
assert.Equal(t, "application/json", r.Header.Get("Content-Type"))
var req RememberRequest
err := json.NewDecoder(r.Body).Decode(&req)
require.NoError(t, err)
assert.Equal(t, "Go uses structural typing", req.Content)
assert.Equal(t, "fact", req.Type)
assert.Equal(t, "go-agentic", req.Project)
assert.Equal(t, []string{"go", "typing"}, req.Tags)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
_ = json.NewEncoder(w).Encode(RememberResponse{
ID: "mem-abc-123",
Type: "fact",
Project: "go-agentic",
CreatedAt: "2026-03-03T12:00:00+00:00",
})
}))
defer server.Close()
client := NewClient(server.URL, "test-token")
result, err := client.Remember(context.Background(), RememberRequest{
Content: "Go uses structural typing",
Type: "fact",
Project: "go-agentic",
Tags: []string{"go", "typing"},
})
require.NoError(t, err)
assert.Equal(t, "mem-abc-123", result.ID)
assert.Equal(t, "fact", result.Type)
assert.Equal(t, "go-agentic", result.Project)
}
func TestClient_Remember_Bad_EmptyContent(t *testing.T) {
client := NewClient("https://api.example.com", "test-token")
result, err := client.Remember(context.Background(), RememberRequest{
Type: "fact",
})
assert.Error(t, err)
assert.Nil(t, result)
assert.Contains(t, err.Error(), "content is required")
}
func TestClient_Remember_Bad_EmptyType(t *testing.T) {
client := NewClient("https://api.example.com", "test-token")
result, err := client.Remember(context.Background(), RememberRequest{
Content: "something",
})
assert.Error(t, err)
assert.Nil(t, result)
assert.Contains(t, err.Error(), "type is required")
}
func TestClient_Remember_Bad_ServerError(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnprocessableEntity)
_ = json.NewEncoder(w).Encode(APIError{Message: "validation failed"})
}))
defer server.Close()
client := NewClient(server.URL, "test-token")
result, err := client.Remember(context.Background(), RememberRequest{
Content: "test",
Type: "fact",
})
assert.Error(t, err)
assert.Nil(t, result)
assert.Contains(t, err.Error(), "validation failed")
}
func TestClient_Recall_Good(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPost, r.Method)
assert.Equal(t, "/v1/brain/recall", r.URL.Path)
var req RecallRequest
err := json.NewDecoder(r.Body).Decode(&req)
require.NoError(t, err)
assert.Equal(t, "how does typing work in Go", req.Query)
assert.Equal(t, 5, req.TopK)
assert.Equal(t, "go-agentic", req.Project)
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(RecallResponse{
Memories: []Memory{
{
ID: "mem-abc-123",
Type: "fact",
Content: "Go uses structural typing",
Project: "go-agentic",
Confidence: 0.95,
},
},
Scores: map[string]float64{
"mem-abc-123": 0.87,
},
})
}))
defer server.Close()
client := NewClient(server.URL, "test-token")
result, err := client.Recall(context.Background(), RecallRequest{
Query: "how does typing work in Go",
TopK: 5,
Project: "go-agentic",
})
require.NoError(t, err)
assert.Len(t, result.Memories, 1)
assert.Equal(t, "mem-abc-123", result.Memories[0].ID)
assert.Equal(t, "Go uses structural typing", result.Memories[0].Content)
assert.InDelta(t, 0.87, result.Scores["mem-abc-123"], 0.001)
}
func TestClient_Recall_Good_EmptyResults(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(RecallResponse{
Memories: []Memory{},
Scores: map[string]float64{},
})
}))
defer server.Close()
client := NewClient(server.URL, "test-token")
result, err := client.Recall(context.Background(), RecallRequest{
Query: "something obscure",
})
require.NoError(t, err)
assert.Empty(t, result.Memories)
assert.Empty(t, result.Scores)
}
func TestClient_Recall_Bad_EmptyQuery(t *testing.T) {
client := NewClient("https://api.example.com", "test-token")
result, err := client.Recall(context.Background(), RecallRequest{})
assert.Error(t, err)
assert.Nil(t, result)
assert.Contains(t, err.Error(), "query is required")
}
func TestClient_Forget_Good(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodDelete, r.Method)
assert.Equal(t, "/v1/brain/forget/mem-abc-123", r.URL.Path)
assert.Equal(t, "Bearer test-token", r.Header.Get("Authorization"))
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]bool{"deleted": true})
}))
defer server.Close()
client := NewClient(server.URL, "test-token")
err := client.Forget(context.Background(), "mem-abc-123")
assert.NoError(t, err)
}
func TestClient_Forget_Bad_EmptyID(t *testing.T) {
client := NewClient("https://api.example.com", "test-token")
err := client.Forget(context.Background(), "")
assert.Error(t, err)
assert.Contains(t, err.Error(), "memory ID is required")
}
func TestClient_Forget_Bad_NotFound(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
_ = json.NewEncoder(w).Encode(APIError{Message: "memory not found"})
}))
defer server.Close()
client := NewClient(server.URL, "test-token")
err := client.Forget(context.Background(), "nonexistent")
assert.Error(t, err)
assert.Contains(t, err.Error(), "memory not found")
}
func TestClient_EnsureCollection_Good(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPost, r.Method)
assert.Equal(t, "/v1/brain/collections", r.URL.Path)
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
}))
defer server.Close()
client := NewClient(server.URL, "test-token")
err := client.EnsureCollection(context.Background())
assert.NoError(t, err)
}
func TestClient_EnsureCollection_Bad_ServerError(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
_ = json.NewEncoder(w).Encode(APIError{Message: "collection setup failed"})
}))
defer server.Close()
client := NewClient(server.URL, "test-token")
err := client.EnsureCollection(context.Background())
assert.Error(t, err)
assert.Contains(t, err.Error(), "collection setup failed")
}