Cover hourly CLI generation workflow
This commit is contained in:
@@ -685,6 +685,59 @@ func TestRunGenerateDailyWritesMarkdownReport(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunGenerateHourlyWritesGeneratedTextReport(t *testing.T) {
|
||||
server := dailyServer(t)
|
||||
tempDir := t.TempDir()
|
||||
scriptoriumPath := writeStructuredOutputScriptorium(t, tempDir)
|
||||
workspaceRoot := filepath.Join(tempDir, "workspace")
|
||||
configPath := writeTestConfig(t, server, scriptoriumPath, workspaceRoot)
|
||||
outPath := filepath.Join(tempDir, "hourly.md")
|
||||
var stdout bytes.Buffer
|
||||
var stderr bytes.Buffer
|
||||
runner := Runner{Clock: timeutil.FixedClock{Time: time.Date(2026, 5, 29, 11, 0, 0, 0, time.UTC)}}
|
||||
|
||||
err := runner.Run(context.Background(), []string{
|
||||
"generate", "hourly",
|
||||
"--config", configPath,
|
||||
"--out", outPath,
|
||||
}, &stdout, &stderr)
|
||||
if err != nil {
|
||||
t.Fatalf("Run() error = %v", err)
|
||||
}
|
||||
report, err := os.ReadFile(outPath)
|
||||
if err != nil {
|
||||
t.Fatalf("read report: %v", err)
|
||||
}
|
||||
for _, want := range []string{
|
||||
"# Hourly Report",
|
||||
"Storm chances increase through late morning.",
|
||||
"The main window is 10 AM to noon.",
|
||||
"Brief downpours may slow travel.",
|
||||
} {
|
||||
if !strings.Contains(string(report), want) {
|
||||
t.Fatalf("report output missing %q:\n%s", want, string(report))
|
||||
}
|
||||
}
|
||||
dataPackagePath := oneArtifact(t, workspaceRoot, "data-packages", "hourly", "2026-05-29", "*.data_package.yaml")
|
||||
dataPackage, err := os.ReadFile(dataPackagePath)
|
||||
if err != nil {
|
||||
t.Fatalf("read managed data package: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(dataPackage), "id: hourly") ||
|
||||
!strings.Contains(string(dataPackage), "prompt_id: weather.hourly_generated_text") ||
|
||||
!strings.Contains(string(dataPackage), "hourly_forecast:") {
|
||||
t.Fatalf("data package output missing hourly content:\n%s", string(dataPackage))
|
||||
}
|
||||
rawGeneratedTextPath := oneArtifact(t, workspaceRoot, "snapshots", "hourly", "2026-05-29", "*.generated_text.raw.json")
|
||||
validatedGeneratedTextPath := oneArtifact(t, workspaceRoot, "snapshots", "hourly", "2026-05-29", "*.generated_text.json")
|
||||
renderContextPath := oneArtifact(t, workspaceRoot, "snapshots", "hourly", "2026-05-29", "*.render_context.json")
|
||||
managedReportPath := oneArtifact(t, workspaceRoot, "reports", "hourly", "*.md")
|
||||
assertFileContains(t, rawGeneratedTextPath, `"summary": " Storm chances increase through late morning. "`)
|
||||
assertFileContains(t, validatedGeneratedTextPath, `"summary":"Storm chances increase through late morning."`)
|
||||
assertFileContains(t, renderContextPath, `"ReportTitle": "Hourly Report"`)
|
||||
assertFileContains(t, managedReportPath, "# Hourly Report")
|
||||
}
|
||||
|
||||
func TestRunInspectGeneratedArtifacts(t *testing.T) {
|
||||
server := dailyServer(t)
|
||||
tempDir := t.TempDir()
|
||||
@@ -867,6 +920,8 @@ func TestResolveGenerateHourlyRejectsDateAndStormBounds(t *testing.T) {
|
||||
{"hourly", "--date", "2026-05-29"},
|
||||
{"hourly", "--start", "2026-05-29T18:00"},
|
||||
{"hourly", "--end", "2026-05-29T20:00"},
|
||||
{"hourly", "--hours", "6"},
|
||||
{"hourly", "--duration", "6h"},
|
||||
} {
|
||||
_, err := runner.resolveGenerate(args)
|
||||
if err == nil {
|
||||
@@ -1092,6 +1147,17 @@ func oneArtifact(t *testing.T, root string, parts ...string) string {
|
||||
return matches[0]
|
||||
}
|
||||
|
||||
func assertFileContains(t *testing.T, path string, want string) {
|
||||
t.Helper()
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatalf("read %s: %v", path, err)
|
||||
}
|
||||
if !strings.Contains(string(data), want) {
|
||||
t.Fatalf("%s missing %q:\n%s", path, want, string(data))
|
||||
}
|
||||
}
|
||||
|
||||
func writeFakeScriptorium(t *testing.T, dir string) string {
|
||||
t.Helper()
|
||||
path := filepath.Join(dir, "scriptorium")
|
||||
@@ -1122,6 +1188,52 @@ exit 1
|
||||
return path
|
||||
}
|
||||
|
||||
func writeStructuredOutputScriptorium(t *testing.T, dir string) string {
|
||||
t.Helper()
|
||||
path := filepath.Join(dir, "scriptorium")
|
||||
body := `#!/bin/sh
|
||||
if [ "$1" = "render" ]; then
|
||||
printf '{"ok":true,"argv":"%s"}' "$*"
|
||||
exit 0
|
||||
fi
|
||||
if [ "$1" = "run" ]; then
|
||||
out=""
|
||||
prompt=""
|
||||
while [ "$#" -gt 0 ]; do
|
||||
if [ "$1" = "--out" ]; then
|
||||
shift
|
||||
out="$1"
|
||||
elif [ "$1" = "--prompt" ]; then
|
||||
shift
|
||||
prompt="$1"
|
||||
fi
|
||||
shift
|
||||
done
|
||||
if [ "$prompt" = "weather.hourly_generated_text" ]; then
|
||||
cat > "$out" <<'JSON'
|
||||
{
|
||||
"summary": " Storm chances increase through late morning. ",
|
||||
"timing": "The main window is 10 AM to noon.",
|
||||
"impacts": "Brief downpours may slow travel.",
|
||||
"confidence": "Medium"
|
||||
}
|
||||
JSON
|
||||
printf 'wrote generated text\n' >&2
|
||||
exit 0
|
||||
fi
|
||||
printf '# Daily Report\n\nGenerated by fake scriptorium.\n' > "$out"
|
||||
printf 'wrote report\n' >&2
|
||||
exit 0
|
||||
fi
|
||||
printf 'unexpected command\n' >&2
|
||||
exit 1
|
||||
`
|
||||
if err := os.WriteFile(path, []byte(body), 0o700); err != nil {
|
||||
t.Fatalf("write fake scriptorium: %v", err)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func writeFailingScriptorium(t *testing.T, dir string) string {
|
||||
t.Helper()
|
||||
path := filepath.Join(dir, "scriptorium")
|
||||
|
||||
Reference in New Issue
Block a user