package state import ( "context" "encoding/json" "os" "path/filepath" "strings" "testing" "time" "gitea.maximumdirect.net/eric/weatherreporter/internal/briefing" "gitea.maximumdirect.net/eric/weatherreporter/internal/config" "gitea.maximumdirect.net/eric/weatherreporter/internal/module" "gitea.maximumdirect.net/eric/weatherreporter/internal/promptinput" "gitea.maximumdirect.net/eric/weatherreporter/internal/report" "gitea.maximumdirect.net/eric/weatherreporter/internal/timeutil" ) func TestPathsUseRunIDAndWorkspace(t *testing.T) { store := newTestStore(t) resolved := resolveDailyAt(t, "2026-05-29T05:00:00-05:00") paths, err := store.Paths(resolved) if err != nil { t.Fatalf("Paths() error = %v", err) } for _, want := range []string{ filepath.Join("snapshots", "daily", "2026-05-29", "20260529T100000.000000000Z_daily_today.modules.json"), filepath.Join("snapshots", "daily", "2026-05-29", "20260529T100000.000000000Z_daily_today.metadata.json"), filepath.Join("data-packages", "daily", "2026-05-29", "20260529T100000.000000000Z_daily_today.data_package.yaml"), filepath.Join("preflight", "daily", "2026-05-29", "20260529T100000.000000000Z_daily_today.render.json"), filepath.Join("notifications", "daily", "2026-05-29", "20260529T100000.000000000Z_daily_today.distributor.json"), filepath.Join("reports", "daily", "20260529T100000.000000000Z_daily_today.md"), } { if !strings.Contains(pathsString(paths), want) { t.Fatalf("paths = %#v, want component %q", paths, want) } } } func TestGeneratedTextArtifactPathsUseSnapshotTree(t *testing.T) { store := newTestStore(t) tests := []struct { name string resolved report.Resolved group string validDate string runID string }{ { name: "hourly", resolved: resolveHourlyAt(t, "2026-05-29T05:00:00-05:00"), group: "hourly", validDate: "2026-05-29", runID: "20260529T100000.000000000Z_hourly", }, { name: "tomorrow", resolved: resolveTomorrowAt(t, "2026-05-29T18:00:00-05:00"), group: "tomorrow", validDate: "2026-05-30", runID: "20260529T230000.000000000Z_tomorrow", }, { name: "today", resolved: resolveTodayAt(t, "2026-05-29T05:00:00-05:00"), group: "today", validDate: "2026-05-29", runID: "20260529T100000.000000000Z_today", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { paths, err := store.Paths(tt.resolved) if err != nil { t.Fatalf("Paths() error = %v", err) } wants := map[string]string{ "DataPackage": filepath.Join("data-packages", tt.group, tt.validDate, tt.runID+".data_package.yaml"), "RenderedReport": filepath.Join("reports", tt.group, tt.runID+".md"), "GeneratedTextRaw": filepath.Join("snapshots", tt.group, tt.validDate, tt.runID+".generated_text.raw.json"), "GeneratedTextResult": filepath.Join("snapshots", tt.group, tt.validDate, tt.runID+".generated_text.run.json"), "GeneratedText": filepath.Join("snapshots", tt.group, tt.validDate, tt.runID+".generated_text.json"), "RenderContext": filepath.Join("snapshots", tt.group, tt.validDate, tt.runID+".render_context.json"), } got := map[string]string{ "DataPackage": paths.DataPackage, "RenderedReport": paths.RenderedReport, "GeneratedTextRaw": paths.GeneratedTextRaw, "GeneratedTextResult": paths.GeneratedTextResult, "GeneratedText": paths.GeneratedText, "RenderContext": paths.RenderContext, } for name, want := range wants { if !strings.Contains(got[name], want) { t.Fatalf("%s path = %q, want component %q", name, got[name], want) } } }) } } func TestSaveArtifactsAndMetadataRoundTrip(t *testing.T) { store := newTestStore(t) resolved := resolveDailyAt(t, "2026-05-29T05:00:00-05:00") briefingMetadata := stateBriefingMetadata(resolved) snapshot, err := module.NewSnapshot([]module.Output{{ID: module.Metadata, StanzaName: "metadata", Value: map[string]string{"run_id": resolved.Metadata().RunID}}}) if err != nil { t.Fatalf("NewSnapshot() error = %v", err) } dataPackage, err := promptinput.Build(promptinput.BuildRequest{ Metadata: promptinput.Metadata{ RunID: resolved.Metadata().RunID, ReportID: resolved.Definition.ID, Variant: briefingMetadata.Variant, PromptID: resolved.Definition.PromptID, GeneratedAt: resolved.GeneratedAt, Timezone: resolved.Timezone, ValidPeriod: resolved.ValidPeriod, }, Modules: snapshot, }) if err != nil { t.Fatalf("Build() error = %v", err) } dataPackagePath, err := store.SaveDataPackage(context.Background(), resolved, dataPackage) if err != nil { t.Fatalf("SaveDataPackage() error = %v", err) } moduleSnapshotPath, err := store.SaveModuleSnapshot(context.Background(), resolved, snapshot) if err != nil { t.Fatalf("SaveModuleSnapshot() error = %v", err) } preflightPath, err := store.SavePreflight(context.Background(), resolved, PreflightArtifact{Stdout: `{"ok":true}`}) if err != nil { t.Fatalf("SavePreflight() error = %v", err) } notificationPath, err := store.SaveDistributorNotification(context.Background(), resolved, DistributorNotificationArtifact{ RunID: resolved.Metadata().RunID, ReportID: resolved.Definition.ID, AttemptedAt: resolved.GeneratedAt, Endpoint: "https://distributor.example.test", PipelineID: "weatherreporter.daily", BundleID: "weatherreporter.home.daily.run", IdempotencyKey: "weatherreporter.home.daily.run", SourcePath: "/tmp/report.md", BundlePaths: []string{"2026-05-29/daily/report.md"}, BundleCreated: resolved.GeneratedAt, Status: "succeeded", RunStatus: &DistributorRunStatus{RunID: "distributor-run", Status: "succeeded"}, }) if err != nil { t.Fatalf("SaveDistributorNotification() error = %v", err) } renderedReportPath, err := store.PrepareRenderedReport(context.Background(), resolved) if err != nil { t.Fatalf("PrepareRenderedReport() error = %v", err) } if err := os.WriteFile(renderedReportPath, []byte("# Daily Report\n"), 0o600); err != nil { t.Fatalf("write rendered report: %v", err) } var preflight PreflightArtifact preflightData, err := os.ReadFile(preflightPath) if err != nil { t.Fatalf("read preflight: %v", err) } if err := json.Unmarshal(preflightData, &preflight); err != nil { t.Fatalf("decode preflight: %v", err) } if preflight.Stdout != `{"ok":true}` { t.Fatalf("preflight stdout = %q, want render stdout", preflight.Stdout) } var notification DistributorNotificationArtifact notificationData, err := os.ReadFile(notificationPath) if err != nil { t.Fatalf("read notification: %v", err) } if err := json.Unmarshal(notificationData, ¬ification); err != nil { t.Fatalf("decode notification: %v", err) } if notification.SchemaVersion != DistributorNotificationSchemaVersion || notification.PipelineID != "weatherreporter.daily" || len(notification.BundlePaths) != 1 || notification.RunStatus == nil || notification.RunStatus.Status != "succeeded" { t.Fatalf("notification = %#v, want persisted distributor status", notification) } paths, err := store.Paths(resolved) if err != nil { t.Fatalf("Paths() error = %v", err) } metadata := BuildMetadataFromBriefingMetadata(resolved, briefingMetadata, ArtifactPaths{ ModuleSnapshot: moduleSnapshotPath, Metadata: paths.Metadata, DataPackage: dataPackagePath, Preflight: preflightPath, RenderedReport: renderedReportPath, }) metadataPath, err := store.SaveMetadata(context.Background(), metadata) if err != nil { t.Fatalf("SaveMetadata() error = %v", err) } for _, path := range []string{moduleSnapshotPath, dataPackagePath, preflightPath, notificationPath, renderedReportPath, metadataPath} { if _, err := os.Stat(path); err != nil { t.Fatalf("expected artifact %q: %v", path, err) } } loadedSnapshot, err := store.LoadModuleSnapshot(context.Background(), moduleSnapshotPath) if err != nil { t.Fatalf("LoadModuleSnapshot() error = %v", err) } if loadedSnapshot.SchemaVersion != module.SnapshotSchemaVersion || len(loadedSnapshot.Outputs) != 1 { t.Fatalf("loaded module snapshot = %#v, want one metadata output", loadedSnapshot) } loadedDataPackage, err := store.LoadDataPackage(context.Background(), dataPackagePath) if err != nil { t.Fatalf("LoadDataPackage() error = %v", err) } if loadedDataPackage.SchemaVersion != promptinput.SchemaVersion || loadedDataPackage.Briefing.Order[0] != "metadata" { t.Fatalf("loaded data package = %#v, want YAML package with metadata stanza", loadedDataPackage) } var decoded Metadata data, err := os.ReadFile(metadataPath) if err != nil { t.Fatalf("read metadata: %v", err) } if err := json.Unmarshal(data, &decoded); err != nil { t.Fatalf("decode metadata: %v", err) } if decoded.RunID != resolved.Metadata().RunID { t.Fatalf("RunID = %q, want %q", decoded.RunID, resolved.Metadata().RunID) } if decoded.ModuleSnapshotPath != moduleSnapshotPath || decoded.DataPackagePath != dataPackagePath || decoded.PreflightPath != preflightPath { t.Fatalf("metadata paths = %#v, want saved artifact paths", decoded) } if decoded.RenderedReportPath != renderedReportPath { t.Fatalf("RenderedReportPath = %q, want %q", decoded.RenderedReportPath, renderedReportPath) } if decoded.Location == nil || decoded.Location.Name != "Brentwood" || decoded.Location.Timezone != "America/Chicago" { t.Fatalf("metadata location = %#v, want briefing location", decoded.Location) } if strings.Contains(string(data), "MetadataPath") || strings.Contains(string(data), "metadataPath") { t.Fatalf("metadata JSON includes runtime-only MetadataPath:\n%s", string(data)) } for _, unexpected := range []string{"generatedTextSchemaId", "generatedTextRawPath", "generatedTextResultPath", "generatedTextPath", "renderContextPath"} { if strings.Contains(string(data), unexpected) { t.Fatalf("metadata JSON includes generated-text field %q for Markdown report:\n%s", unexpected, string(data)) } } } func TestSaveGeneratedTextArtifactsAndMetadataRoundTrip(t *testing.T) { store := newTestStore(t) resolved := resolveHourlyAt(t, "2026-05-29T05:00:00-05:00") briefingMetadata := stateBriefingMetadata(resolved) rawPath, err := store.SaveGeneratedTextRaw(context.Background(), resolved, []byte(`{"summary":"raw"}`)) if err != nil { t.Fatalf("SaveGeneratedTextRaw() error = %v", err) } resultPath, err := store.SaveGeneratedTextResult(context.Background(), resolved, map[string]any{ "command": []string{"scriptorium", "run"}, "status": "succeeded", }) if err != nil { t.Fatalf("SaveGeneratedTextResult() error = %v", err) } generatedPath, err := store.SaveGeneratedText(context.Background(), resolved, []byte(`{"summary":"Storm chances increase.","forecast_discussion":"A front will keep the region unsettled."}`)) if err != nil { t.Fatalf("SaveGeneratedText() error = %v", err) } contextPath, err := store.SaveRenderContext(context.Background(), resolved, struct { ReportTitle string `json:"reportTitle"` Location string `json:"location"` }{ ReportTitle: "Hourly Report", Location: "Brentwood", }) if err != nil { t.Fatalf("SaveRenderContext() error = %v", err) } for _, path := range []string{rawPath, resultPath, generatedPath, contextPath} { if _, err := os.Stat(path); err != nil { t.Fatalf("expected generated-text artifact %q: %v", path, err) } } rawData, err := store.LoadGeneratedText(context.Background(), rawPath) if err != nil { t.Fatalf("LoadGeneratedText() raw error = %v", err) } if string(rawData) != `{"summary":"raw"}` { t.Fatalf("raw data = %q, want saved bytes", rawData) } generatedData, err := store.LoadGeneratedText(context.Background(), generatedPath) if err != nil { t.Fatalf("LoadGeneratedText() generated error = %v", err) } if !strings.Contains(string(generatedData), `"forecast_discussion":"A front will keep the region unsettled."`) { t.Fatalf("generated text = %q, want saved normalized JSON", generatedData) } var runResult struct { Command []string `json:"command"` Status string `json:"status"` } if err := store.LoadGeneratedTextResult(context.Background(), resultPath, &runResult); err != nil { t.Fatalf("LoadGeneratedTextResult() error = %v", err) } if runResult.Status != "succeeded" || strings.Join(runResult.Command, " ") != "scriptorium run" { t.Fatalf("run result = %#v, want saved result", runResult) } var renderContext struct { ReportTitle string `json:"reportTitle"` Location string `json:"location"` } if err := store.LoadRenderContext(context.Background(), contextPath, &renderContext); err != nil { t.Fatalf("LoadRenderContext() error = %v", err) } if renderContext.ReportTitle != "Hourly Report" || renderContext.Location != "Brentwood" { t.Fatalf("render context = %#v, want saved context", renderContext) } paths, err := store.Paths(resolved) if err != nil { t.Fatalf("Paths() error = %v", err) } metadata := BuildMetadataFromBriefingMetadata(resolved, briefingMetadata, ArtifactPaths{ ModuleSnapshot: paths.ModuleSnapshot, Metadata: paths.Metadata, DataPackage: paths.DataPackage, Preflight: paths.Preflight, RenderedReport: paths.RenderedReport, GeneratedTextRaw: rawPath, GeneratedTextResult: resultPath, GeneratedText: generatedPath, RenderContext: contextPath, }) metadataPath, err := store.SaveMetadata(context.Background(), metadata) if err != nil { t.Fatalf("SaveMetadata() error = %v", err) } var decoded Metadata metadataData, err := os.ReadFile(metadataPath) if err != nil { t.Fatalf("read metadata: %v", err) } if err := json.Unmarshal(metadataData, &decoded); err != nil { t.Fatalf("decode metadata: %v", err) } if decoded.GeneratedTextSchemaID != "hourly" { t.Fatalf("GeneratedTextSchemaID = %q, want hourly", decoded.GeneratedTextSchemaID) } if decoded.GeneratedTextRawPath != rawPath || decoded.GeneratedTextResultPath != resultPath || decoded.GeneratedTextPath != generatedPath || decoded.RenderContextPath != contextPath { t.Fatalf("metadata generated-text paths = %#v, want saved artifact paths", decoded) } } func TestSaveMetadataUsesExplicitMetadataPath(t *testing.T) { store := newTestStore(t) resolved := resolveDailyAt(t, "2026-05-29T05:00:00-05:00") briefingMetadata := stateBriefingMetadata(resolved) paths, err := store.Paths(resolved) if err != nil { t.Fatalf("Paths() error = %v", err) } otherDir := filepath.Join(t.TempDir(), "other-artifacts") derivedMetadataPath := filepath.Join(otherDir, resolved.Metadata().RunID+".metadata.json") metadata := BuildMetadataFromBriefingMetadata(resolved, briefingMetadata, ArtifactPaths{ ModuleSnapshot: paths.ModuleSnapshot, Metadata: paths.Metadata, DataPackage: paths.DataPackage, Preflight: paths.Preflight, RenderedReport: paths.RenderedReport, }) metadataPath, err := store.SaveMetadata(context.Background(), metadata) if err != nil { t.Fatalf("SaveMetadata() error = %v", err) } if metadataPath != paths.Metadata { t.Fatalf("SaveMetadata() path = %q, want explicit metadata path %q", metadataPath, paths.Metadata) } if _, err := os.Stat(paths.Metadata); err != nil { t.Fatalf("expected explicit metadata path %q: %v", paths.Metadata, err) } if _, err := os.Stat(derivedMetadataPath); !os.IsNotExist(err) { t.Fatalf("derived metadata path stat error = %v, want not exist", err) } } func TestFindPriorSnapshot(t *testing.T) { store := newTestStore(t) first := resolveDailyAt(t, "2026-05-29T05:00:00-05:00") second := resolveDailyAt(t, "2026-05-29T08:00:00-05:00") paths := savePriorMetadata(t, store, first, stateBriefingMetadata(first)) prior, err := store.FindPriorSnapshot(context.Background(), second) if err != nil { t.Fatalf("FindPriorSnapshot() error = %v", err) } if prior == nil { t.Fatal("FindPriorSnapshot() = nil, want prior snapshot") } if prior.Metadata.RunID != first.Metadata().RunID { t.Fatalf("RunID = %q, want %q", prior.Metadata.RunID, first.Metadata().RunID) } if prior.ModuleSnapshotPath != paths.ModuleSnapshot { t.Fatalf("ModuleSnapshotPath = %q, want %q", prior.ModuleSnapshotPath, paths.ModuleSnapshot) } } func TestFindPriorSnapshotSupportsToday(t *testing.T) { store := newTestStore(t) first := resolveTodayAt(t, "2026-05-29T05:00:00-05:00") second := resolveTodayAt(t, "2026-05-29T08:00:00-05:00") savePriorMetadata(t, store, first, stateBriefingMetadata(first)) prior, err := store.FindPriorSnapshot(context.Background(), second) if err != nil { t.Fatalf("FindPriorSnapshot() error = %v", err) } if prior == nil { t.Fatal("FindPriorSnapshot() = nil, want prior Today snapshot") } if prior.Metadata.RunID != first.Metadata().RunID { t.Fatalf("RunID = %q, want %q", prior.Metadata.RunID, first.Metadata().RunID) } } func TestFindPriorSnapshotUsesValidDate(t *testing.T) { store := newTestStore(t) previousDate := resolveDailyAt(t, "2026-05-28T05:00:00-05:00") currentDate := resolveDailyAt(t, "2026-05-29T05:00:00-05:00") savePriorMetadata(t, store, previousDate, stateBriefingMetadata(previousDate)) prior, err := store.FindPriorSnapshot(context.Background(), currentDate) if err != nil { t.Fatalf("FindPriorSnapshot() error = %v", err) } if prior != nil { t.Fatalf("FindPriorSnapshot() = %#v, want nil for different valid date", prior) } } func TestFindPriorSnapshotSupportsThreeDay(t *testing.T) { store := newTestStore(t) first := resolveThreeDayAt(t, "2026-05-29T05:00:00-05:00") second := resolveThreeDayAt(t, "2026-05-29T08:00:00-05:00") savePriorMetadata(t, store, first, stateBriefingMetadata(first)) prior, err := store.FindPriorSnapshot(context.Background(), second) if err != nil { t.Fatalf("FindPriorSnapshot() error = %v", err) } if prior == nil { t.Fatal("FindPriorSnapshot() = nil, want prior 3-day snapshot") } if prior.Metadata.RunID != first.Metadata().RunID { t.Fatalf("RunID = %q, want %q", prior.Metadata.RunID, first.Metadata().RunID) } } func TestFindPriorSnapshotSupportsWeekend(t *testing.T) { store := newTestStore(t) first := resolveWeekendAt(t, "2026-05-29T05:00:00-05:00") second := resolveWeekendAt(t, "2026-05-29T08:00:00-05:00") savePriorMetadata(t, store, first, stateBriefingMetadata(first)) prior, err := store.FindPriorSnapshot(context.Background(), second) if err != nil { t.Fatalf("FindPriorSnapshot() error = %v", err) } if prior == nil { t.Fatal("FindPriorSnapshot() = nil, want prior weekend snapshot") } if prior.Metadata.RunID != first.Metadata().RunID { t.Fatalf("RunID = %q, want %q", prior.Metadata.RunID, first.Metadata().RunID) } } func TestFindPriorSnapshotSupportsNarrowedWeekendPeriod(t *testing.T) { store := newTestStore(t) first := resolveWeekendAt(t, "2026-05-29T19:00:00-05:00") second := resolveWeekendAt(t, "2026-05-30T08:00:00-05:00") savePriorMetadata(t, store, first, stateBriefingMetadata(first)) prior, err := store.FindPriorSnapshot(context.Background(), second) if err != nil { t.Fatalf("FindPriorSnapshot() error = %v", err) } if prior == nil { t.Fatal("FindPriorSnapshot() = nil, want prior narrowed weekend snapshot") } if prior.Metadata.RunID != first.Metadata().RunID { t.Fatalf("RunID = %q, want %q", prior.Metadata.RunID, first.Metadata().RunID) } } func TestFindPriorSnapshotIgnoresRollingWindowReports(t *testing.T) { store := newTestStore(t) first := resolveHourlyAt(t, "2026-05-29T05:00:00-05:00") second := resolveHourlyAt(t, "2026-05-29T06:00:00-05:00") savePriorMetadata(t, store, first, stateBriefingMetadata(first)) prior, err := store.FindPriorSnapshot(context.Background(), second) if err != nil { t.Fatalf("FindPriorSnapshot() error = %v", err) } if prior != nil { t.Fatalf("FindPriorSnapshot() = %#v, want nil for rolling-window comparison", prior) } } func TestFilesystemStoreRejectsUnsafeDirs(t *testing.T) { cfg := config.Defaults().Workspace cfg.Root = t.TempDir() cfg.SnapshotsDir = "../snapshots" _, err := NewFilesystemStore(cfg) if err == nil { t.Fatal("NewFilesystemStore() error = nil, want unsafe path error") } if !strings.Contains(err.Error(), "within workspace root") { t.Fatalf("error = %q, want path safety context", err.Error()) } } func newTestStore(t *testing.T) *FilesystemStore { t.Helper() cfg := config.Defaults().Workspace cfg.Root = t.TempDir() store, err := NewFilesystemStore(cfg) if err != nil { t.Fatalf("NewFilesystemStore() error = %v", err) } return store } func resolveDailyAt(t *testing.T, value string) report.Resolved { t.Helper() location, err := timeutil.LoadLocation("America/Chicago") if err != nil { t.Fatalf("LoadLocation() error = %v", err) } now, err := time.Parse(time.RFC3339, value) if err != nil { t.Fatalf("parse time: %v", err) } resolved, err := report.DefaultRegistry().Resolve(report.DailyToday, report.ResolveRequest{ Now: now, Location: location, }) if err != nil { t.Fatalf("Resolve() error = %v", err) } return resolved } func resolveTodayAt(t *testing.T, value string) report.Resolved { t.Helper() location, err := timeutil.LoadLocation("America/Chicago") if err != nil { t.Fatalf("LoadLocation() error = %v", err) } now, err := time.Parse(time.RFC3339, value) if err != nil { t.Fatalf("parse time: %v", err) } resolved, err := report.DefaultRegistry().Resolve(report.Today, report.ResolveRequest{ Now: now, Location: location, }) if err != nil { t.Fatalf("Resolve() error = %v", err) } return resolved } func resolveThreeDayAt(t *testing.T, value string) report.Resolved { t.Helper() location, err := timeutil.LoadLocation("America/Chicago") if err != nil { t.Fatalf("LoadLocation() error = %v", err) } now, err := time.Parse(time.RFC3339, value) if err != nil { t.Fatalf("parse time: %v", err) } resolved, err := report.DefaultRegistry().Resolve(report.ThreeDay, report.ResolveRequest{ Now: now, Location: location, }) if err != nil { t.Fatalf("Resolve() error = %v", err) } return resolved } func resolveWeekendAt(t *testing.T, value string) report.Resolved { t.Helper() location, err := timeutil.LoadLocation("America/Chicago") if err != nil { t.Fatalf("LoadLocation() error = %v", err) } now, err := time.Parse(time.RFC3339, value) if err != nil { t.Fatalf("parse time: %v", err) } resolved, err := report.DefaultRegistry().Resolve(report.Weekend, report.ResolveRequest{ Now: now, Location: location, }) if err != nil { t.Fatalf("Resolve() error = %v", err) } return resolved } func resolveHourlyAt(t *testing.T, value string) report.Resolved { t.Helper() location, err := timeutil.LoadLocation("America/Chicago") if err != nil { t.Fatalf("LoadLocation() error = %v", err) } now, err := time.Parse(time.RFC3339, value) if err != nil { t.Fatalf("parse time: %v", err) } resolved, err := report.DefaultRegistry().Resolve(report.Hourly, report.ResolveRequest{ Now: now, Location: location, }) if err != nil { t.Fatalf("Resolve() error = %v", err) } return resolved } func resolveTomorrowAt(t *testing.T, value string) report.Resolved { t.Helper() location, err := timeutil.LoadLocation("America/Chicago") if err != nil { t.Fatalf("LoadLocation() error = %v", err) } now, err := time.Parse(time.RFC3339, value) if err != nil { t.Fatalf("parse time: %v", err) } resolved, err := report.DefaultRegistry().Resolve(report.Tomorrow, report.ResolveRequest{ Now: now, Location: location, }) if err != nil { t.Fatalf("Resolve() error = %v", err) } return resolved } func stateBriefingMetadata(resolved report.Resolved) briefing.Metadata { return briefing.Metadata{ RunID: resolved.Metadata().RunID, ReportID: resolved.Definition.ID, Variant: "today", PromptID: resolved.Definition.PromptID, GeneratedAt: resolved.GeneratedAt, Units: "us", Timezone: resolved.Timezone, Location: &briefing.LocationContext{ ID: "home", Name: "Brentwood", Region: "St. Louis Metro", Timezone: resolved.Timezone, }, ValidPeriod: resolved.ValidPeriod, } } func savePriorMetadata(t *testing.T, store *FilesystemStore, resolved report.Resolved, metadata briefing.Metadata) ArtifactPaths { t.Helper() paths, err := store.Paths(resolved) if err != nil { t.Fatalf("Paths() error = %v", err) } _, err = store.SaveMetadata(context.Background(), BuildMetadataFromBriefingMetadata(resolved, metadata, ArtifactPaths{ ModuleSnapshot: paths.ModuleSnapshot, Metadata: paths.Metadata, DataPackage: paths.DataPackage, Preflight: paths.Preflight, RenderedReport: paths.RenderedReport, })) if err != nil { t.Fatalf("SaveMetadata() error = %v", err) } return paths } func pathsString(paths ArtifactPaths) string { return strings.Join([]string{ paths.Metadata, paths.ModuleSnapshot, paths.DataPackage, paths.Preflight, paths.Notification, paths.RenderedReport, paths.GeneratedTextRaw, paths.GeneratedTextResult, paths.GeneratedText, paths.RenderContext, }, "\n") }