agent/pkg/agentic/content_test.go
Virgil 28fbe8b988 feat(agentic): add SEO schema generation
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-01 15:34:37 +00:00

326 lines
13 KiB
Go

// SPDX-License-Identifier: EUPL-1.2
package agentic
import (
"context"
"net/http"
"net/http/httptest"
"testing"
core "dappco.re/go/core"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestContent_HandleContentGenerate_Good(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/v1/content/generate", r.URL.Path)
require.Equal(t, http.MethodPost, r.Method)
require.Equal(t, "Bearer secret-token", r.Header.Get("Authorization"))
bodyResult := core.ReadAll(r.Body)
require.True(t, bodyResult.OK)
var payload map[string]any
parseResult := core.JSONUnmarshalString(bodyResult.Value.(string), &payload)
require.True(t, parseResult.OK)
require.Equal(t, "Draft a release note", payload["prompt"])
require.Equal(t, "claude", payload["provider"])
config, ok := payload["config"].(map[string]any)
require.True(t, ok)
require.Equal(t, float64(4000), config["max_tokens"])
_, _ = w.Write([]byte(`{"data":{"id":"gen_1","provider":"claude","model":"claude-3.7-sonnet","content":"Release notes draft","input_tokens":12,"output_tokens":48,"duration_ms":321}}`))
}))
defer server.Close()
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
result := subsystem.handleContentGenerate(context.Background(), core.NewOptions(
core.Option{Key: "prompt", Value: "Draft a release note"},
core.Option{Key: "provider", Value: "claude"},
core.Option{Key: "config", Value: `{"max_tokens":4000}`},
))
require.True(t, result.OK)
output, ok := result.Value.(ContentGenerateOutput)
require.True(t, ok)
assert.Equal(t, "gen_1", output.Result.ID)
assert.Equal(t, "claude", output.Result.Provider)
assert.Equal(t, "claude-3.7-sonnet", output.Result.Model)
assert.Equal(t, "Release notes draft", output.Result.Content)
assert.Equal(t, 48, output.Result.OutputTokens)
}
func TestContent_HandleContentGenerate_Good_BriefTemplate(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/v1/content/generate", r.URL.Path)
require.Equal(t, http.MethodPost, r.Method)
bodyResult := core.ReadAll(r.Body)
require.True(t, bodyResult.OK)
var payload map[string]any
parseResult := core.JSONUnmarshalString(bodyResult.Value.(string), &payload)
require.True(t, parseResult.OK)
require.Equal(t, "brief_1", payload["brief_id"])
require.Equal(t, "help-article", payload["template"])
require.NotContains(t, payload, "prompt")
_, _ = w.Write([]byte(`{"data":{"result":{"id":"gen_2","provider":"claude","model":"claude-3.7-sonnet","content":"Template draft","status":"completed"}}}`))
}))
defer server.Close()
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
result := subsystem.handleContentGenerate(context.Background(), core.NewOptions(
core.Option{Key: "brief_id", Value: "brief_1"},
core.Option{Key: "template", Value: "help-article"},
core.Option{Key: "provider", Value: "claude"},
))
require.True(t, result.OK)
output, ok := result.Value.(ContentGenerateOutput)
require.True(t, ok)
assert.Equal(t, "gen_2", output.Result.ID)
assert.Equal(t, "Template draft", output.Result.Content)
}
func TestContent_HandleContentGenerate_Bad(t *testing.T) {
subsystem := testPrepWithPlatformServer(t, nil, "secret-token")
result := subsystem.handleContentGenerate(context.Background(), core.NewOptions())
assert.False(t, result.OK)
}
func TestContent_HandleContentGenerate_Ugly(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte(`{"data":`))
}))
defer server.Close()
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
result := subsystem.handleContentGenerate(context.Background(), core.NewOptions(
core.Option{Key: "prompt", Value: "Draft a release note"},
))
assert.False(t, result.OK)
}
func TestContent_HandleContentBriefCreate_Good(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/v1/content/briefs", r.URL.Path)
require.Equal(t, http.MethodPost, r.Method)
bodyResult := core.ReadAll(r.Body)
require.True(t, bodyResult.OK)
var payload map[string]any
parseResult := core.JSONUnmarshalString(bodyResult.Value.(string), &payload)
require.True(t, parseResult.OK)
require.Equal(t, "LinkHost brief", payload["title"])
require.Equal(t, "LinkHost", payload["product"])
_, _ = w.Write([]byte(`{"data":{"brief":{"id":"brief_1","slug":"host-link","title":"LinkHost brief","product":"LinkHost","category":"product","brief":"Core context"}}}`))
}))
defer server.Close()
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
result := subsystem.handleContentBriefCreate(context.Background(), core.NewOptions(
core.Option{Key: "title", Value: "LinkHost brief"},
core.Option{Key: "product", Value: "LinkHost"},
core.Option{Key: "category", Value: "product"},
core.Option{Key: "brief", Value: "Core context"},
))
require.True(t, result.OK)
output, ok := result.Value.(ContentBriefOutput)
require.True(t, ok)
assert.Equal(t, "brief_1", output.Brief.ID)
assert.Equal(t, "host-link", output.Brief.Slug)
assert.Equal(t, "LinkHost", output.Brief.Product)
}
func TestContent_HandleContentBriefList_Good(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/v1/content/briefs", r.URL.Path)
require.Equal(t, "product", r.URL.Query().Get("category"))
require.Equal(t, "5", r.URL.Query().Get("limit"))
_, _ = w.Write([]byte(`{"data":{"briefs":[{"id":"brief_1","slug":"host-link","title":"LinkHost brief","category":"product"}],"total":1}}`))
}))
defer server.Close()
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
result := subsystem.handleContentBriefList(context.Background(), core.NewOptions(
core.Option{Key: "category", Value: "product"},
core.Option{Key: "limit", Value: 5},
))
require.True(t, result.OK)
output, ok := result.Value.(ContentBriefListOutput)
require.True(t, ok)
assert.Equal(t, 1, output.Total)
require.Len(t, output.Briefs, 1)
assert.Equal(t, "host-link", output.Briefs[0].Slug)
}
func TestContent_HandleContentStatus_Good(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/v1/content/status/batch_123", r.URL.Path)
_, _ = w.Write([]byte(`{"data":{"status":"running","batch_id":"batch_123","queued":2}}`))
}))
defer server.Close()
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
result := subsystem.handleContentStatus(context.Background(), core.NewOptions(
core.Option{Key: "batch_id", Value: "batch_123"},
))
require.True(t, result.OK)
output, ok := result.Value.(ContentStatusOutput)
require.True(t, ok)
assert.Equal(t, "running", stringValue(output.Status["status"]))
assert.Equal(t, "batch_123", stringValue(output.Status["batch_id"]))
}
func TestContent_HandleContentUsageStats_Good(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/v1/content/usage/stats", r.URL.Path)
require.Equal(t, "claude", r.URL.Query().Get("provider"))
require.Equal(t, "week", r.URL.Query().Get("period"))
_, _ = w.Write([]byte(`{"data":{"calls":4,"tokens":1200}}`))
}))
defer server.Close()
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
result := subsystem.handleContentUsageStats(context.Background(), core.NewOptions(
core.Option{Key: "provider", Value: "claude"},
core.Option{Key: "period", Value: "week"},
))
require.True(t, result.OK)
output, ok := result.Value.(ContentUsageStatsOutput)
require.True(t, ok)
assert.Equal(t, 4, intValue(output.Usage["calls"]))
assert.Equal(t, 1200, intValue(output.Usage["tokens"]))
}
func TestContent_HandleContentFromPlan_Good(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/v1/content/from-plan", r.URL.Path)
require.Equal(t, http.MethodPost, r.Method)
bodyResult := core.ReadAll(r.Body)
require.True(t, bodyResult.OK)
var payload map[string]any
parseResult := core.JSONUnmarshalString(bodyResult.Value.(string), &payload)
require.True(t, parseResult.OK)
require.Equal(t, "release-notes", payload["plan_slug"])
require.Equal(t, "openai", payload["provider"])
_, _ = w.Write([]byte(`{"data":{"result":{"batch_id":"batch_123","provider":"openai","model":"gpt-5.4","content":"Plan-driven draft","status":"completed"}}}`))
}))
defer server.Close()
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
result := subsystem.handleContentFromPlan(context.Background(), core.NewOptions(
core.Option{Key: "plan_slug", Value: "release-notes"},
core.Option{Key: "provider", Value: "openai"},
))
require.True(t, result.OK)
output, ok := result.Value.(ContentFromPlanOutput)
require.True(t, ok)
assert.Equal(t, "batch_123", output.Result.BatchID)
assert.Equal(t, "completed", output.Result.Status)
assert.Equal(t, "Plan-driven draft", output.Result.Content)
}
func TestContent_HandleContentSchemaGenerate_Good_Article(t *testing.T) {
subsystem := testPrepWithPlatformServer(t, nil, "secret-token")
result := subsystem.handleContentSchemaGenerate(context.Background(), core.NewOptions(
core.Option{Key: "type", Value: "article"},
core.Option{Key: "title", Value: "Release notes"},
core.Option{Key: "description", Value: "What changed in this release"},
core.Option{Key: "url", Value: "https://example.test/releases/1"},
core.Option{Key: "author", Value: "Virgil"},
core.Option{Key: "language", Value: "en-GB"},
))
require.True(t, result.OK)
output, ok := result.Value.(ContentSchemaOutput)
require.True(t, ok)
assert.Equal(t, "BlogPosting", output.SchemaType)
assert.Equal(t, "Release notes", output.Schema["headline"])
assert.Equal(t, "What changed in this release", output.Schema["description"])
assert.Equal(t, "https://example.test/releases/1", output.Schema["url"])
assert.Equal(t, "en-GB", output.Schema["inLanguage"])
author, ok := output.Schema["author"].(map[string]any)
require.True(t, ok)
assert.Equal(t, "Virgil", author["name"])
assert.Contains(t, output.SchemaJSON, `"@type":"BlogPosting"`)
}
func TestContent_HandleContentSchemaGenerate_Good_FAQ(t *testing.T) {
subsystem := testPrepWithPlatformServer(t, nil, "secret-token")
result := subsystem.handleContentSchemaGenerate(context.Background(), core.NewOptions(
core.Option{Key: "kind", Value: "faq"},
core.Option{Key: "title", Value: "Release notes FAQ"},
core.Option{Key: "questions", Value: `[{"question":"What changed?","answer":"We added schema generation."}]`},
))
require.True(t, result.OK)
output, ok := result.Value.(ContentSchemaOutput)
require.True(t, ok)
assert.Equal(t, "FAQPage", output.SchemaType)
entries, ok := output.Schema["mainEntity"].([]map[string]any)
require.True(t, ok)
require.Len(t, entries, 1)
assert.Equal(t, "Question", entries[0]["@type"])
assert.Equal(t, "What changed?", entries[0]["name"])
answer, ok := entries[0]["acceptedAnswer"].(map[string]any)
require.True(t, ok)
assert.Equal(t, "Answer", answer["@type"])
assert.Equal(t, "We added schema generation.", answer["text"])
}
func TestContent_HandleContentSchemaGenerate_Good_HowTo(t *testing.T) {
subsystem := testPrepWithPlatformServer(t, nil, "secret-token")
result := subsystem.handleContentSchemaGenerate(context.Background(), core.NewOptions(
core.Option{Key: "kind", Value: "howto"},
core.Option{Key: "title", Value: "Set up the workspace"},
core.Option{Key: "steps", Value: `[{"name":"Prepare","text":"Clone the repo"},{"name":"Run","text":"Start the agent"}]`},
))
require.True(t, result.OK)
output, ok := result.Value.(ContentSchemaOutput)
require.True(t, ok)
assert.Equal(t, "HowTo", output.SchemaType)
steps, ok := output.Schema["step"].([]map[string]any)
require.True(t, ok)
require.Len(t, steps, 2)
assert.Equal(t, "HowToStep", steps[0]["@type"])
assert.Equal(t, "Prepare", steps[0]["name"])
assert.Equal(t, "Clone the repo", steps[0]["text"])
}
func TestContent_HandleContentSchemaGenerate_Bad(t *testing.T) {
subsystem := testPrepWithPlatformServer(t, nil, "secret-token")
result := subsystem.handleContentSchemaGenerate(context.Background(), core.NewOptions(
core.Option{Key: "type", Value: "article"},
))
assert.False(t, result.OK)
}
func TestContent_HandleContentSchemaGenerate_Ugly(t *testing.T) {
subsystem := testPrepWithPlatformServer(t, nil, "secret-token")
result := subsystem.handleContentSchemaGenerate(context.Background(), core.NewOptions(
core.Option{Key: "kind", Value: "faq"},
core.Option{Key: "title", Value: "FAQ"},
core.Option{Key: "questions", Value: `[{"question":"What changed?"`},
))
assert.False(t, result.OK)
}