Files
weatherreporter/internal/app/output_test.go

130 lines
4.9 KiB
Go

package app
import (
"context"
"errors"
"os"
"path/filepath"
"testing"
"gitea.maximumdirect.net/eric/weatherreporter/internal/collect"
"gitea.maximumdirect.net/eric/weatherreporter/internal/config"
"gitea.maximumdirect.net/eric/weatherreporter/internal/report"
)
func TestResolveReportOutputPath(t *testing.T) {
workingDir := t.TempDir()
cfg := config.Defaults()
now := workflowTime("2026-05-29T08:30:00-05:00")
for _, test := range []struct {
report ReportKind
date string
name string
}{
{report: ReportDaily, date: "2026-05-30T12:00:00-05:00", name: "daily-2026-05-30.md"},
{report: ReportToday, date: "2026-05-29T12:00:00-05:00", name: "today.md"},
{report: ReportTomorrow, name: "tomorrow.md"},
{report: ReportHourly, name: "hourly.md"},
} {
t.Run(string(test.report), func(t *testing.T) {
req := GenerateRequest{Config: cfg, Report: test.report}
if test.date != "" {
req.Date = workflowTime(test.date)
}
resolved, err := ResolveGenerate(req, now)
if err != nil {
t.Fatalf("ResolveGenerate() error = %v", err)
}
path, err := resolveReportOutputPath(workingDir, "", resolved)
if err != nil {
t.Fatalf("resolveReportOutputPath() error = %v", err)
}
if path != filepath.Join(workingDir, test.name) {
t.Fatalf("path = %q, want %q", path, filepath.Join(workingDir, test.name))
}
})
}
resolved, err := ResolveGenerate(GenerateRequest{
Config: cfg, Report: ReportDaily, Date: workflowTime("2026-05-30T12:00:00-05:00"),
}, now)
if err != nil {
t.Fatalf("ResolveGenerate() error = %v", err)
}
absoluteDir := t.TempDir()
for _, test := range []struct {
override string
want string
}{
{override: filepath.Join("reports", "custom.md"), want: filepath.Join(workingDir, "reports", "custom.md")},
{override: filepath.Join(absoluteDir, "custom.md"), want: filepath.Join(absoluteDir, "custom.md")},
} {
path, err := resolveReportOutputPath(workingDir, test.override, resolved)
if err != nil {
t.Fatalf("resolveReportOutputPath(%q) error = %v", test.override, err)
}
if path != filepath.Clean(test.want) {
t.Fatalf("path = %q, want %q", path, filepath.Clean(test.want))
}
}
}
func TestGenerateDetailedRejectsInvalidOutputBeforeCollection(t *testing.T) {
cfg := workflowConfig(t)
collector := &workflowCollector{err: errors.New("collection must not run")}
_, err := GenerateDetailed(context.Background(), GenerateRequest{
Config: cfg, Report: ReportDaily, Date: workflowTime("2026-05-29T12:00:00-05:00"),
Now: workflowTime("2026-05-29T08:30:00-05:00"), WorkingDir: t.TempDir(), OutputPath: t.TempDir(),
Collector: collector,
})
if err == nil || collector.calls != 0 {
t.Fatalf("GenerateDetailed() error/calls = %v/%d, want invalid output before collection", err, collector.calls)
}
}
func TestGenerateDetailedPreservesExistingOutputWhenGenerationFails(t *testing.T) {
cfg := workflowConfig(t)
cfg.Notify.Distributor.Enabled = false
workingDir := t.TempDir()
outputPath := filepath.Join(workingDir, "daily-2026-05-29.md")
if err := os.WriteFile(outputPath, []byte("existing report"), 0o600); err != nil {
t.Fatalf("write existing output: %v", err)
}
bundle := workflowBundle(t)
result, err := GenerateDetailed(context.Background(), GenerateRequest{
Config: cfg, Report: ReportDaily, Date: workflowTime("2026-05-29T12:00:00-05:00"),
Now: workflowTime("2026-05-29T08:30:00-05:00"), WorkingDir: workingDir,
Collector: &workflowCollector{result: &collect.Result{Bundle: &bundle}},
Executor: &workflowExecutor{definition: report.DefaultRegistry().MustLookup(report.Daily), raw: []byte(`{}`)},
})
if err == nil || result == nil || result.OutputPath != "" {
t.Fatalf("result/error/output = %#v/%v/%q, want failed generation without output publication", result, err, result.OutputPath)
}
data, readErr := os.ReadFile(outputPath)
if readErr != nil || string(data) != "existing report" {
t.Fatalf("output after failure = %q, error %v, want preserved content", data, readErr)
}
}
func TestRunBatchDetailedUsesWorkingDirectoryForOutput(t *testing.T) {
cfg := assembledBatchConfig(t, false)
workingDir := t.TempDir()
bundle := assembledBatchBundle(t, "2026-05-31")
result, err := RunBatchDetailed(context.Background(), BatchRequest{
Config: cfg, Batch: BatchEvening, Now: workflowTime("2026-05-29T18:00:00-05:00"), WorkingDir: workingDir,
Collector: &workflowCollector{result: &collect.Result{Bundle: &bundle}},
Executor: newAssembledBatchExecutor(),
})
if err != nil || result == nil || result.Failed != 0 {
t.Fatalf("RunBatchDetailed() result/error = %#v/%v", result, err)
}
if len(result.Reports) != 2 {
t.Fatalf("reports = %#v, want Tomorrow and Daily", result.Reports)
}
if result.Reports[0].OutputPath != filepath.Join(workingDir, "tomorrow.md") ||
result.Reports[1].OutputPath != filepath.Join(workingDir, "daily-2026-05-31.md") {
t.Fatalf("output paths = %#v, want working-directory defaults", result.Reports)
}
}