Add Daily prompt input preflight
This commit is contained in:
@@ -2,6 +2,7 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/adapters/scriptorium"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/config"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/report"
|
||||
)
|
||||
@@ -130,6 +132,110 @@ func TestGenerateDailyBriefingDefaultPath(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareDailyReportWritesDataPackageAndPreflight(t *testing.T) {
|
||||
server := dailyBundleServer(t)
|
||||
cfg := config.Defaults()
|
||||
cfg.WeatherAPI.BaseURL = server.URL + "/"
|
||||
cfg.WeatherAPI.Timezone = "America/Chicago"
|
||||
cfg.Workspace.Root = t.TempDir()
|
||||
resolved, err := ResolveGenerate(GenerateRequest{
|
||||
Config: cfg,
|
||||
Report: ReportDaily,
|
||||
Date: mustParse("2026-05-29T12:00:00-05:00"),
|
||||
}, mustParse("2026-05-29T05:00:00-05:00"))
|
||||
if err != nil {
|
||||
t.Fatalf("ResolveGenerate() error = %v", err)
|
||||
}
|
||||
renderer := &recordingRenderer{
|
||||
result: &scriptorium.RenderResult{
|
||||
Command: []string{"scriptorium", "render"},
|
||||
Stdout: `{"prepared":true}`,
|
||||
ExitCode: 0,
|
||||
},
|
||||
}
|
||||
dataPackagePath := filepath.Join(t.TempDir(), "daily.data_package.json")
|
||||
|
||||
result, err := PrepareDailyReport(context.Background(), DailyPreparationRequest{
|
||||
Config: cfg,
|
||||
Resolved: resolved,
|
||||
DataPackagePath: dataPackagePath,
|
||||
Renderer: renderer,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("PrepareDailyReport() error = %v", err)
|
||||
}
|
||||
|
||||
if renderer.calls != 1 {
|
||||
t.Fatalf("renderer calls = %d, want 1", renderer.calls)
|
||||
}
|
||||
if renderer.request.PromptID != "weather.daily_report" {
|
||||
t.Fatalf("PromptID = %q, want weather.daily_report", renderer.request.PromptID)
|
||||
}
|
||||
if renderer.request.DataPackagePath != dataPackagePath {
|
||||
t.Fatalf("DataPackagePath = %q, want %q", renderer.request.DataPackagePath, dataPackagePath)
|
||||
}
|
||||
for _, path := range []string{result.BriefingPath, result.DataPackagePath, result.PreflightPath} {
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
t.Fatalf("expected artifact %q: %v", path, err)
|
||||
}
|
||||
}
|
||||
data, err := os.ReadFile(dataPackagePath)
|
||||
if err != nil {
|
||||
t.Fatalf("read data package: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(data), `"recentChanges"`) || !strings.Contains(string(data), `data_package.v1`) {
|
||||
t.Fatalf("data package missing expected content:\n%s", string(data))
|
||||
}
|
||||
preflight, err := os.ReadFile(result.PreflightPath)
|
||||
if err != nil {
|
||||
t.Fatalf("read preflight: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(preflight), `prepared`) {
|
||||
t.Fatalf("preflight output missing render stdout:\n%s", string(preflight))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareDailyReportPersistsFailedPreflight(t *testing.T) {
|
||||
server := dailyBundleServer(t)
|
||||
cfg := config.Defaults()
|
||||
cfg.WeatherAPI.BaseURL = server.URL + "/"
|
||||
cfg.WeatherAPI.Timezone = "America/Chicago"
|
||||
cfg.Workspace.Root = t.TempDir()
|
||||
resolved, err := ResolveGenerate(GenerateRequest{
|
||||
Config: cfg,
|
||||
Report: ReportDaily,
|
||||
Date: mustParse("2026-05-29T12:00:00-05:00"),
|
||||
}, mustParse("2026-05-29T05:00:00-05:00"))
|
||||
if err != nil {
|
||||
t.Fatalf("ResolveGenerate() error = %v", err)
|
||||
}
|
||||
renderer := &recordingRenderer{
|
||||
result: &scriptorium.RenderResult{
|
||||
Command: []string{"scriptorium", "render"},
|
||||
Stderr: "render failed",
|
||||
ExitCode: 1,
|
||||
},
|
||||
err: errors.New("scriptorium render exited with code 1: render failed"),
|
||||
}
|
||||
|
||||
_, err = PrepareDailyReport(context.Background(), DailyPreparationRequest{
|
||||
Config: cfg,
|
||||
Resolved: resolved,
|
||||
Renderer: renderer,
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("PrepareDailyReport() error = nil, want render error")
|
||||
}
|
||||
preflightPath := defaultPreflightPath(cfg, resolved)
|
||||
preflight, readErr := os.ReadFile(preflightPath)
|
||||
if readErr != nil {
|
||||
t.Fatalf("read failed preflight: %v", readErr)
|
||||
}
|
||||
if !strings.Contains(string(preflight), `"exitCode": 1`) {
|
||||
t.Fatalf("failed preflight was not persisted:\n%s", string(preflight))
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveGenerateMapsCommandToReportDefinition(t *testing.T) {
|
||||
cfg := config.Defaults()
|
||||
cfg.WeatherAPI.Timezone = "America/Chicago"
|
||||
@@ -227,3 +333,16 @@ func mustParse(value string) time.Time {
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
type recordingRenderer struct {
|
||||
calls int
|
||||
request scriptorium.RenderRequest
|
||||
result *scriptorium.RenderResult
|
||||
err error
|
||||
}
|
||||
|
||||
func (r *recordingRenderer) Render(_ context.Context, req scriptorium.RenderRequest) (*scriptorium.RenderResult, error) {
|
||||
r.calls++
|
||||
r.request = req
|
||||
return r.result, r.err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user