Move renderer tests to captured templates
This commit is contained in:
@@ -14,7 +14,6 @@ import (
|
||||
)
|
||||
|
||||
func TestGoRenderer_Render(t *testing.T) {
|
||||
renderer := NewGoRenderer()
|
||||
ctx := context.Background()
|
||||
|
||||
inputs := map[string]*domain.Artifact{
|
||||
@@ -33,7 +32,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
res, err := renderer.Render(ctx, def, inputs, vars)
|
||||
res, err := capturedTestRenderer(t, def).Render(ctx, def, inputs, vars)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -53,7 +52,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
res, err := renderer.Render(ctx, def, inputs, vars)
|
||||
res, err := capturedTestRenderer(t, def).Render(ctx, def, inputs, vars)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -71,7 +70,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
res, err := renderer.Render(ctx, def, inputs, vars)
|
||||
res, err := capturedTestRenderer(t, def).Render(ctx, def, inputs, vars)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -99,7 +98,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
res, err := renderer.Render(ctx, def, inputs, vars)
|
||||
res, err := capturedTestRenderer(t, def).Render(ctx, def, inputs, vars)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -129,7 +128,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
res, err := renderer.Render(ctx, def, inputs, vars)
|
||||
res, err := capturedTestRenderer(t, def).Render(ctx, def, inputs, vars)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -151,7 +150,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
res, err := renderer.Render(ctx, def, inputs, vars)
|
||||
res, err := capturedTestRenderer(t, def).Render(ctx, def, inputs, vars)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -169,7 +168,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
res, err := renderer.Render(ctx, def, inputs, map[string]string{
|
||||
res, err := capturedTestRenderer(t, def).Render(ctx, def, inputs, map[string]string{
|
||||
"tone": "concise",
|
||||
"session_id": "agent-session-123",
|
||||
})
|
||||
@@ -190,7 +189,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
res, err := renderer.Render(ctx, def, inputs, vars)
|
||||
res, err := capturedTestRenderer(t, def).Render(ctx, def, inputs, vars)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -208,7 +207,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
_, err := renderer.Render(ctx, def, inputs, vars)
|
||||
_, err := capturedTestRenderer(t, def).Render(ctx, def, inputs, vars)
|
||||
if !errors.Is(err, ErrRenderFailure) {
|
||||
t.Fatalf("expected ErrRenderFailure, got %v", err)
|
||||
}
|
||||
@@ -223,7 +222,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
_, err := renderer.Render(ctx, def, inputs, map[string]string{
|
||||
_, err := capturedTestRenderer(t, def).Render(ctx, def, inputs, map[string]string{
|
||||
"tone": "concise",
|
||||
"session_id": strings.Repeat("x", domain.SessionIDMaxLength+1),
|
||||
})
|
||||
@@ -241,7 +240,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
_, err := renderer.Render(ctx, def, inputs, map[string]string{
|
||||
_, err := capturedTestRenderer(t, def).Render(ctx, def, inputs, map[string]string{
|
||||
"tone": "concise",
|
||||
"session_id": "session" + string([]byte{0xff}),
|
||||
})
|
||||
@@ -258,7 +257,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
res, err := renderer.Render(ctx, def, inputs, vars)
|
||||
res, err := capturedTestRenderer(t, def).Render(ctx, def, inputs, vars)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -278,7 +277,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
res, err := renderer.Render(ctx, def, inputs, vars)
|
||||
res, err := capturedTestRenderer(t, def).Render(ctx, def, inputs, vars)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -298,7 +297,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
_, err := renderer.Render(ctx, def, inputs, vars)
|
||||
_, err := capturedTestRenderer(t, def).Render(ctx, def, inputs, vars)
|
||||
if !errors.Is(err, ErrRenderFailure) {
|
||||
t.Fatalf("expected ErrRenderFailure, got %v", err)
|
||||
}
|
||||
@@ -315,7 +314,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
_, err := renderer.Render(ctx, def, map[string]*domain.Artifact{}, vars)
|
||||
_, err := capturedTestRenderer(t, def).Render(ctx, def, map[string]*domain.Artifact{}, vars)
|
||||
if !errors.Is(err, ErrMissingRequiredInput) {
|
||||
t.Fatalf("expected ErrMissingRequiredInput, got %v", err)
|
||||
}
|
||||
@@ -329,9 +328,9 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
_, err := renderer.Render(ctx, def, inputs, vars)
|
||||
if !errors.Is(err, ErrInvalidTemplate) {
|
||||
t.Fatalf("expected ErrInvalidTemplate, got %v", err)
|
||||
_, err := CompileTemplate("message", def.Templates[0].Content)
|
||||
if err == nil {
|
||||
t.Fatal("expected template compilation to fail")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -343,7 +342,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
_, err := renderer.Render(ctx, def, inputs, vars)
|
||||
_, err := capturedTestRenderer(t, def).Render(ctx, def, inputs, vars)
|
||||
if !errors.Is(err, ErrRenderFailure) {
|
||||
t.Fatalf("expected ErrRenderFailure, got %v", err)
|
||||
}
|
||||
@@ -359,7 +358,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
{Role: "", Content: "Hello"},
|
||||
},
|
||||
}
|
||||
_, err := renderer.Render(ctx, def, inputs, vars)
|
||||
_, err := capturedTestRenderer(t, def).Render(ctx, def, inputs, vars)
|
||||
if !errors.Is(err, ErrInvalidMessageRole) {
|
||||
t.Fatalf("expected ErrInvalidMessageRole, got %v", err)
|
||||
}
|
||||
@@ -371,7 +370,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
{Role: " \u2003DeVeLoPeR\u2003 ", Content: "Hello"},
|
||||
},
|
||||
}
|
||||
res, err := renderer.Render(ctx, def, nil, vars)
|
||||
res, err := capturedTestRenderer(t, def).Render(ctx, def, nil, vars)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -385,7 +384,7 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
def := &domain.PromptDefinition{
|
||||
Templates: []domain.PromptMessageTemplate{{Role: unsupportedRole, Content: "Hello"}},
|
||||
}
|
||||
_, err := renderer.Render(ctx, def, nil, vars)
|
||||
_, err := capturedTestRenderer(t, def).Render(ctx, def, nil, vars)
|
||||
if !errors.Is(err, ErrInvalidMessageRole) {
|
||||
t.Fatalf("expected ErrInvalidMessageRole, got %v", err)
|
||||
}
|
||||
@@ -396,9 +395,9 @@ func TestGoRenderer_Render(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGoRendererCancellation(t *testing.T) {
|
||||
t.Run("before session parsing", func(t *testing.T) {
|
||||
t.Run("before rendering", func(t *testing.T) {
|
||||
definition := &domain.PromptDefinition{
|
||||
SessionID: "{{ malformed",
|
||||
SessionID: "{{.session}}",
|
||||
Templates: []domain.PromptMessageTemplate{
|
||||
{Role: "user", Content: "not rendered"},
|
||||
},
|
||||
@@ -406,18 +405,11 @@ func TestGoRendererCancellation(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
result, err := NewGoRenderer().Render(ctx, definition, nil, nil)
|
||||
renderer := capturedTestRenderer(t, definition)
|
||||
result, err := renderer.Render(ctx, definition, nil, nil)
|
||||
if result != nil || !errors.Is(err, context.Canceled) {
|
||||
t.Fatalf("result=%#v err=%v, want nil/context.Canceled", result, err)
|
||||
}
|
||||
if errors.Is(err, ErrInvalidTemplate) {
|
||||
t.Fatalf("pre-canceled render parsed the malformed session: %v", err)
|
||||
}
|
||||
|
||||
result, err = NewGoRenderer().Render(context.Background(), definition, nil, nil)
|
||||
if result != nil || !errors.Is(err, ErrInvalidTemplate) {
|
||||
t.Fatalf("active render result=%#v err=%v, want nil/ErrInvalidTemplate", result, err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("during artifact text conversion", func(t *testing.T) {
|
||||
@@ -447,14 +439,15 @@ func TestGoRendererCancellation(t *testing.T) {
|
||||
},
|
||||
}
|
||||
counter := &checkCountingContext{Context: context.Background()}
|
||||
if _, err := NewGoRenderer().Render(counter, definition, nil, nil); err != nil {
|
||||
renderer := capturedTestRenderer(t, definition)
|
||||
if _, err := renderer.Render(counter, definition, nil, nil); err != nil {
|
||||
t.Fatalf("count render checkpoints: %v", err)
|
||||
}
|
||||
|
||||
// The final three checks occur after template execution, after the
|
||||
// message is assembled, and immediately before publication.
|
||||
ctx := newCancelOnCheckContext(counter.checks - 2)
|
||||
result, err := NewGoRenderer().Render(ctx, definition, nil, nil)
|
||||
result, err := renderer.Render(ctx, definition, nil, nil)
|
||||
if result != nil || !errors.Is(err, context.Canceled) {
|
||||
t.Fatalf("result=%#v err=%v, want nil/context.Canceled", result, err)
|
||||
}
|
||||
@@ -472,7 +465,8 @@ func TestGoRendererArtifactTextLifecycle(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
first, err := NewGoRenderer().Render(context.Background(), definition, inputs, nil)
|
||||
renderer := capturedTestRenderer(t, definition)
|
||||
first, err := renderer.Render(context.Background(), definition, inputs, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("first render: %v", err)
|
||||
}
|
||||
@@ -488,7 +482,7 @@ func TestGoRendererArtifactTextLifecycle(t *testing.T) {
|
||||
if bytes.Equal([]byte(first.Messages[0].Content), append(append(append([]byte(nil), body...), '|'), body...)) {
|
||||
t.Fatal("completed render aliases the artifact body")
|
||||
}
|
||||
second, err := NewGoRenderer().Render(context.Background(), definition, inputs, nil)
|
||||
second, err := renderer.Render(context.Background(), definition, inputs, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("second render: %v", err)
|
||||
}
|
||||
@@ -498,7 +492,7 @@ func TestGoRendererArtifactTextLifecycle(t *testing.T) {
|
||||
}
|
||||
|
||||
nilInputs := map[string]*domain.Artifact{"document": nil}
|
||||
result, err := NewGoRenderer().Render(context.Background(), definition, nilInputs, nil)
|
||||
result, err := renderer.Render(context.Background(), definition, nilInputs, nil)
|
||||
if result != nil || !errors.Is(err, ErrUnknownInput) || !errors.Is(err, ErrRenderFailure) {
|
||||
t.Fatalf("nil input result=%#v err=%v, want ErrUnknownInput and ErrRenderFailure", result, err)
|
||||
}
|
||||
@@ -559,11 +553,56 @@ func TestCompiledRendererKeepsConcurrentRequestsIndependent(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompiledRendererRequiresCapturedTemplates(t *testing.T) {
|
||||
message, err := CompileTemplate("message", "hello")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
lookup TemplateLookup
|
||||
sessionID string
|
||||
}{
|
||||
{name: "missing lookup"},
|
||||
{name: "missing prompt", lookup: compiledRendererTestLookup{id: "other"}},
|
||||
{name: "missing message", lookup: compiledRendererTestLookup{id: "prompt"}},
|
||||
{name: "nil message", lookup: compiledRendererTestLookup{id: "prompt", templates: CompiledTemplates{Messages: []*template.Template{nil}}}},
|
||||
{name: "missing session", lookup: compiledRendererTestLookup{id: "prompt", templates: CompiledTemplates{Messages: []*template.Template{message}}}, sessionID: "session"},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
definition := &domain.PromptDefinition{ID: "prompt", SessionID: tc.sessionID, Templates: []domain.PromptMessageTemplate{{Role: "user", Content: "hello"}}}
|
||||
if _, err := NewCompiledRenderer(tc.lookup).Render(context.Background(), definition, nil, nil); !errors.Is(err, ErrRenderFailure) {
|
||||
t.Fatalf("render error = %v, want render failure", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type compiledRendererTestLookup struct {
|
||||
id string
|
||||
templates CompiledTemplates
|
||||
}
|
||||
|
||||
func capturedTestRenderer(t testing.TB, definition *domain.PromptDefinition) Renderer {
|
||||
t.Helper()
|
||||
var compiled CompiledTemplates
|
||||
var err error
|
||||
if definition.SessionID != "" {
|
||||
compiled.Session, err = CompileTemplate("session", definition.SessionID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
for _, message := range definition.Templates {
|
||||
parsed, err := CompileTemplate("message", message.Content)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
compiled.Messages = append(compiled.Messages, parsed)
|
||||
}
|
||||
return NewCompiledRenderer(compiledRendererTestLookup{id: definition.ID, templates: compiled})
|
||||
}
|
||||
|
||||
func (lookup compiledRendererTestLookup) GetCompiledTemplates(id string) (CompiledTemplates, bool) {
|
||||
if id != lookup.id {
|
||||
return CompiledTemplates{}, false
|
||||
@@ -571,8 +610,7 @@ func (lookup compiledRendererTestLookup) GetCompiledTemplates(id string) (Compil
|
||||
return lookup.templates, true
|
||||
}
|
||||
|
||||
// BenchmarkGoRendererArtifactReferences measures NewGoRenderer's per-call
|
||||
// template-parsing fallback rather than the captured compiled path.
|
||||
// BenchmarkGoRendererArtifactReferences measures rendering captured templates.
|
||||
func BenchmarkGoRendererArtifactReferences(b *testing.B) {
|
||||
body := bytes.Repeat([]byte("document content "), (artifactTextChunkSize*4)/len("document content "))
|
||||
inputs := map[string]*domain.Artifact{
|
||||
@@ -604,7 +642,7 @@ func BenchmarkGoRendererArtifactReferences(b *testing.B) {
|
||||
|
||||
for _, tc := range tests {
|
||||
b.Run(tc.name, func(b *testing.B) {
|
||||
renderer := NewGoRenderer()
|
||||
renderer := capturedTestRenderer(b, tc.definition)
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(body)))
|
||||
for range b.N {
|
||||
|
||||
@@ -314,7 +314,7 @@ func TestAnalyzeRequirementsClassifiesKnownConditions(t *testing.T) {
|
||||
"active": {Name: "active", Body: []byte("active")},
|
||||
"inactive": {Name: "inactive", Body: []byte("inactive")},
|
||||
}
|
||||
rendered, err := NewGoRenderer().Render(context.Background(), definition, artifacts, test.vars)
|
||||
rendered, err := capturedTestRenderer(t, definition).Render(context.Background(), definition, artifacts, test.vars)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -526,7 +526,7 @@ func TestAnalyzeRequirementsResolvesSimpleInputNames(t *testing.T) {
|
||||
t.Fatalf("name-source caller key classification is incorrect: %+v", result.Variables)
|
||||
}
|
||||
artifacts := map[string]*domain.Artifact{inputName: {Name: inputName, Body: []byte("resolved")}}
|
||||
rendered, err := NewGoRenderer().Render(context.Background(), definition, artifacts, test.vars)
|
||||
rendered, err := capturedTestRenderer(t, definition).Render(context.Background(), definition, artifacts, test.vars)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user