Build batch distributor upload requests
This commit is contained in:
@@ -2330,6 +2330,121 @@ func TestBatchResultJSONIncludesNotification(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildBatchNotificationRequestIncludesEveningReports(t *testing.T) {
|
||||
server := dailyBundleServer(t)
|
||||
cfg := dailyNotificationConfig(t, server)
|
||||
cfg.Notify.Distributor.ReportPathTemplates = []string{
|
||||
"archive/{valid_start_date}/{artifact_group}/{run_id}.md",
|
||||
"latest/{batch_output_name}",
|
||||
}
|
||||
cfg.Notify.Distributor.Batch.PipelineIDTemplate = "weatherreporter.{batch}.{batch_started_date}"
|
||||
cfg.Notify.Distributor.Batch.BundleIDTemplate = "weatherreporter.{location_id}.{batch}"
|
||||
cfg.Notify.Distributor.Batch.IdempotencyKeyTemplate = "{bundle_id}.{batch_run_id}"
|
||||
startedAt := mustParse("2026-05-29T18:00:00-05:00")
|
||||
planned, reports := plannedBatchNotificationReports(t, cfg, BatchEvening, startedAt, "2026-05-31", "2026-06-01")
|
||||
runID := batchRunID(startedAt, BatchEvening)
|
||||
|
||||
req, err := buildBatchNotificationRequest(cfg, BatchEvening, runID, startedAt, reports, planned)
|
||||
if err != nil {
|
||||
t.Fatalf("buildBatchNotificationRequest() error = %v", err)
|
||||
}
|
||||
|
||||
if req.Batch != BatchEvening || req.RunID != runID {
|
||||
t.Fatalf("batch identity = %s/%s, want %s/%s", req.Batch, req.RunID, BatchEvening, runID)
|
||||
}
|
||||
if req.PipelineID != "weatherreporter.evening.2026-05-29" {
|
||||
t.Fatalf("PipelineID = %q, want rendered batch pipeline", req.PipelineID)
|
||||
}
|
||||
if req.BundleID != "weatherreporter.home.evening" {
|
||||
t.Fatalf("BundleID = %q, want rendered batch bundle id", req.BundleID)
|
||||
}
|
||||
wantKey := "weatherreporter.home.evening." + runID
|
||||
if req.IdempotencyKey != wantKey {
|
||||
t.Fatalf("IdempotencyKey = %q, want %q", req.IdempotencyKey, wantKey)
|
||||
}
|
||||
if !req.CreatedAt.Equal(startedAt) {
|
||||
t.Fatalf("CreatedAt = %s, want %s", req.CreatedAt, startedAt)
|
||||
}
|
||||
if len(req.IncludedReports) != 3 {
|
||||
t.Fatalf("IncludedReports = %d, want 3", len(req.IncludedReports))
|
||||
}
|
||||
if len(req.Files) != 6 {
|
||||
t.Fatalf("Files = %d, want two mappings per report", len(req.Files))
|
||||
}
|
||||
|
||||
wantBundlePaths := map[string]struct{}{}
|
||||
for _, plannedReport := range planned {
|
||||
resolved := plannedReport.Resolved
|
||||
runID := resolved.Metadata().RunID
|
||||
outputName := plannedReport.OutputCopyName
|
||||
if outputName == "" {
|
||||
outputName = resolved.Definition.BatchOutputName
|
||||
}
|
||||
wantBundlePaths[fmt.Sprintf("archive/%s/%s/%s.md", resolved.ValidPeriod.Start.In(mustLoadTestLocation(t, cfg.WeatherAPI.Timezone)).Format(timeutil.DateLayout), resolved.Definition.ArtifactGroup, runID)] = struct{}{}
|
||||
wantBundlePaths["latest/"+outputName] = struct{}{}
|
||||
}
|
||||
gotBundlePaths := map[string]struct{}{}
|
||||
gotSourcePaths := map[string]struct{}{}
|
||||
for _, file := range req.Files {
|
||||
gotBundlePaths[file.BundlePath] = struct{}{}
|
||||
gotSourcePaths[file.SourcePath] = struct{}{}
|
||||
}
|
||||
for want := range wantBundlePaths {
|
||||
if _, ok := gotBundlePaths[want]; !ok {
|
||||
t.Fatalf("bundle paths = %#v, missing %q", gotBundlePaths, want)
|
||||
}
|
||||
}
|
||||
for _, item := range reports {
|
||||
if _, ok := gotSourcePaths[item.ReportPath]; !ok {
|
||||
t.Fatalf("source paths = %#v, missing managed report path %q", gotSourcePaths, item.ReportPath)
|
||||
}
|
||||
}
|
||||
|
||||
uploadReq := batchDistributorUploadRequest(req)
|
||||
if uploadReq.PipelineID != req.PipelineID || uploadReq.BundleID != req.BundleID || uploadReq.IdempotencyKey != req.IdempotencyKey || !uploadReq.CreatedAt.Equal(startedAt) {
|
||||
t.Fatalf("upload request = %#v, want batch notification identity", uploadReq)
|
||||
}
|
||||
if len(uploadReq.Files) != len(req.Files) {
|
||||
t.Fatalf("upload files = %d, want %d", len(uploadReq.Files), len(req.Files))
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildBatchNotificationRequestRejectsDuplicateBundlePaths(t *testing.T) {
|
||||
server := dailyBundleServer(t)
|
||||
cfg := dailyNotificationConfig(t, server)
|
||||
cfg.Notify.Distributor.ReportPathTemplates = []string{"index.md"}
|
||||
startedAt := mustParse("2026-05-29T18:00:00-05:00")
|
||||
planned, reports := plannedBatchNotificationReports(t, cfg, BatchEvening, startedAt, "2026-05-31")
|
||||
|
||||
_, err := buildBatchNotificationRequest(cfg, BatchEvening, batchRunID(startedAt, BatchEvening), startedAt, reports, planned)
|
||||
if err == nil {
|
||||
t.Fatal("buildBatchNotificationRequest() error = nil, want duplicate path error")
|
||||
}
|
||||
for _, want := range []string{"duplicate bundle path", "index.md", "report", "run", "source path"} {
|
||||
if !strings.Contains(err.Error(), want) {
|
||||
t.Fatalf("error = %q, want %q", err.Error(), want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildBatchNotificationRequestRejectsMissingReportPath(t *testing.T) {
|
||||
server := dailyBundleServer(t)
|
||||
cfg := dailyNotificationConfig(t, server)
|
||||
startedAt := mustParse("2026-05-29T18:00:00-05:00")
|
||||
planned, reports := plannedBatchNotificationReports(t, cfg, BatchEvening, startedAt, "2026-05-31")
|
||||
reports[0].ReportPath = ""
|
||||
|
||||
_, err := buildBatchNotificationRequest(cfg, BatchEvening, batchRunID(startedAt, BatchEvening), startedAt, reports, planned)
|
||||
if err == nil {
|
||||
t.Fatal("buildBatchNotificationRequest() error = nil, want missing path error")
|
||||
}
|
||||
for _, want := range []string{"missing managed report path", string(reports[0].ReportID), reports[0].RunID} {
|
||||
if !strings.Contains(err.Error(), want) {
|
||||
t.Fatalf("error = %q, want %q", err.Error(), want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunBatchContinuesAfterReportFailure(t *testing.T) {
|
||||
server := dailyBundleServer(t)
|
||||
cfg := dailyWorkspaceConfig(t, server)
|
||||
@@ -2712,6 +2827,27 @@ func dailyNotificationConfig(t *testing.T, server *httptest.Server) config.Confi
|
||||
return cfg
|
||||
}
|
||||
|
||||
func plannedBatchNotificationReports(t *testing.T, cfg config.Config, batch BatchKind, now time.Time, futureDailyDates ...string) ([]plannedBatchReport, []BatchReportResult) {
|
||||
t.Helper()
|
||||
collection := collectionWithFutureDailyForTest(t, cfg, futureDailyDates...)
|
||||
planned, err := planBatchRun(BatchRequest{Config: cfg, Batch: batch}, now, collection)
|
||||
if err != nil {
|
||||
t.Fatalf("planBatchRun() error = %v", err)
|
||||
}
|
||||
reportDir := filepath.Join(t.TempDir(), "managed-reports")
|
||||
results := make([]BatchReportResult, 0, len(planned))
|
||||
for _, item := range planned {
|
||||
metadata := item.Resolved.Metadata()
|
||||
results = append(results, BatchReportResult{
|
||||
ReportID: item.Resolved.Definition.ID,
|
||||
RunID: metadata.RunID,
|
||||
Status: "succeeded",
|
||||
ReportPath: filepath.Join(reportDir, string(item.Resolved.Definition.ID), metadata.RunID+".md"),
|
||||
})
|
||||
}
|
||||
return planned, results
|
||||
}
|
||||
|
||||
func collectionForTest(t *testing.T, cfg config.Config) collect.Result {
|
||||
t.Helper()
|
||||
bundle, err := FetchBundle(context.Background(), FetchBundleRequest{Config: cfg})
|
||||
|
||||
Reference in New Issue
Block a user