Fix to ensure unique document IDs when batch reports are generated

This commit is contained in:
2026-06-17 14:39:53 -05:00
parent a2f0a2fc36
commit 42f0e16b02
6 changed files with 213 additions and 19 deletions

View File

@@ -2409,6 +2409,97 @@ func TestRunBatchUsesOutputDirectory(t *testing.T) {
}
}
func TestRunBatchDynamicDailyReportsHaveDistinctIdentity(t *testing.T) {
server := dailyBundleServer(t)
cfg := dailyNotificationConfig(t, server)
collection := collectionWithFutureDailyForTest(t, cfg, "2026-05-31", "2026-06-01")
cfg.WeatherAPI.BaseURL = ""
collector := &recordingCollector{result: &collection}
notifier := &recordingNotifier{}
outputDir := filepath.Join(t.TempDir(), "reports")
result, err := RunBatchDetailed(context.Background(), BatchRequest{
Config: cfg,
Batch: BatchEvening,
Now: mustParse("2026-05-29T18:00:00-05:00"),
OutputDir: outputDir,
Collector: collector,
Renderer: &selectiveRenderer{runBody: "# Batch Report\n"},
Notifier: notifier,
})
if err != nil {
t.Fatalf("RunBatchDetailed() error = %v", err)
}
if result.Failed != 0 || len(result.Reports) != 3 {
t.Fatalf("summary = %#v, want three successful reports", result)
}
if len(notifier.requests) != 3 {
t.Fatalf("notification requests = %d, want one per report", len(notifier.requests))
}
dailyByDate := map[string]BatchReportResult{}
runIDs := map[string]struct{}{}
reportPaths := map[string]struct{}{}
metadataPaths := map[string]struct{}{}
dataPackagePaths := map[string]struct{}{}
for _, item := range result.Reports {
if _, ok := runIDs[item.RunID]; ok {
t.Fatalf("duplicate RunID in batch result: %q", item.RunID)
}
runIDs[item.RunID] = struct{}{}
if _, ok := reportPaths[item.ReportPath]; ok {
t.Fatalf("duplicate ReportPath in batch result: %q", item.ReportPath)
}
reportPaths[item.ReportPath] = struct{}{}
if _, ok := metadataPaths[item.MetadataPath]; ok {
t.Fatalf("duplicate MetadataPath in batch result: %q", item.MetadataPath)
}
metadataPaths[item.MetadataPath] = struct{}{}
if _, ok := dataPackagePaths[item.DataPackagePath]; ok {
t.Fatalf("duplicate DataPackagePath in batch result: %q", item.DataPackagePath)
}
dataPackagePaths[item.DataPackagePath] = struct{}{}
if item.ReportID == report.Daily {
if !strings.HasPrefix(item.RunID, "20260529T230000.000000000Z_daily_") {
t.Fatalf("Daily RunID = %q, want dated daily run id", item.RunID)
}
date := strings.TrimPrefix(filepath.Base(item.OutputPath), "daily-")
date = strings.TrimSuffix(date, ".md")
dailyByDate[date] = item
}
}
for _, date := range []string{"2026-05-31", "2026-06-01"} {
item, ok := dailyByDate[date]
if !ok {
t.Fatalf("daily outputs = %#v, want Daily output for %s", dailyByDate, date)
}
if item.RunID != "20260529T230000.000000000Z_daily_"+date {
t.Fatalf("Daily %s RunID = %q, want date disambiguator", date, item.RunID)
}
if item.OutputPath != filepath.Join(outputDir, "daily-"+date+".md") {
t.Fatalf("Daily %s OutputPath = %q, want date-qualified copy", date, item.OutputPath)
}
}
dailyKeys := map[string]struct{}{}
for _, req := range notifier.requests {
if req.ReportID != report.Daily {
continue
}
if req.IdempotencyKey != req.BundleID+"."+req.RunID {
t.Fatalf("Daily idempotency key = %q, want bundle id plus run id", req.IdempotencyKey)
}
if _, ok := dailyKeys[req.IdempotencyKey]; ok {
t.Fatalf("duplicate Daily idempotency key: %q", req.IdempotencyKey)
}
dailyKeys[req.IdempotencyKey] = struct{}{}
}
if len(dailyKeys) != 2 {
t.Fatalf("Daily notification keys = %#v, want two distinct keys", dailyKeys)
}
}
func TestRunBatchMorningUsesTodayOutputName(t *testing.T) {
server := dailyBundleServer(t)
cfg := dailyWorkspaceConfig(t, server)
@@ -2514,11 +2605,13 @@ func collectionForTest(t *testing.T, cfg config.Config) collect.Result {
return collect.Result{Bundle: bundle}
}
func collectionWithFutureDailyForTest(t *testing.T, cfg config.Config, date string) collect.Result {
func collectionWithFutureDailyForTest(t *testing.T, cfg config.Config, dates ...string) collect.Result {
t.Helper()
collection := collectionForTest(t, cfg)
location := mustLoadTestLocation(t, cfg.WeatherAPI.Timezone)
collection.Bundle.Hourly.Periods = append(collection.Bundle.Hourly.Periods, fullDayPeriods(t, date, location)...)
for _, date := range dates {
collection.Bundle.Hourly.Periods = append(collection.Bundle.Hourly.Periods, fullDayPeriods(t, date, location)...)
}
return collection
}