Added a field with the current local date to the data package
This commit is contained in:
@@ -125,7 +125,7 @@ types in `internal/forecast/bundle.go`, including:
|
|||||||
- current condition values
|
- current condition values
|
||||||
- forecast run metadata and `periods`
|
- forecast run metadata and `periods`
|
||||||
- active alert run data
|
- active alert run data
|
||||||
- discussion metadata, key messages, and short/long-term sections
|
- discussion metadata, key messages, and short/long-term section text
|
||||||
|
|
||||||
The adapter intentionally keeps upstream transport and envelope details inside
|
The adapter intentionally keeps upstream transport and envelope details inside
|
||||||
`internal/adapters/weatherapi`; downstream packages consume the normalized
|
`internal/adapters/weatherapi`; downstream packages consume the normalized
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ Outputs:
|
|||||||
includes configured location context, current conditions when available,
|
includes configured location context, current conditions when available,
|
||||||
discussion key messages, and short/long-term AFD narratives when the Weather
|
discussion key messages, and short/long-term AFD narratives when the Weather
|
||||||
API provides them.
|
API provides them.
|
||||||
|
- report metadata includes `currentLocalDate`, the generation date formatted as
|
||||||
|
`YYYY-MM-DD` in the effective report timezone.
|
||||||
- optional JSON file written by `promptinput.Save`
|
- optional JSON file written by `promptinput.Save`
|
||||||
|
|
||||||
## Boundaries
|
## Boundaries
|
||||||
@@ -31,8 +33,8 @@ Outputs:
|
|||||||
|
|
||||||
## Config Fields Used
|
## Config Fields Used
|
||||||
|
|
||||||
None directly. Config-derived values, including prompt location context, are
|
None directly. Config-derived values, including timezone and prompt location
|
||||||
already present in briefing metadata before this package runs.
|
context, are already present in briefing metadata before this package runs.
|
||||||
|
|
||||||
## External Adapters Used
|
## External Adapters Used
|
||||||
|
|
||||||
|
|||||||
@@ -43,11 +43,11 @@ func TestFetchBundleFromFixtures(t *testing.T) {
|
|||||||
if bundle.Discussion == nil || len(bundle.Discussion.KeyMessages) != 2 {
|
if bundle.Discussion == nil || len(bundle.Discussion.KeyMessages) != 2 {
|
||||||
t.Fatalf("Discussion = %#v, want key messages", bundle.Discussion)
|
t.Fatalf("Discussion = %#v, want key messages", bundle.Discussion)
|
||||||
}
|
}
|
||||||
if bundle.Discussion.ShortTerm == nil || bundle.Discussion.ShortTerm.Narrative != "A weak boundary may trigger isolated showers." {
|
if bundle.Discussion.ShortTerm == nil || bundle.Discussion.ShortTerm.Text != "A weak boundary may trigger isolated showers." {
|
||||||
t.Fatalf("Discussion.ShortTerm = %#v, want short-term AFD narrative", bundle.Discussion.ShortTerm)
|
t.Fatalf("Discussion.ShortTerm = %#v, want short-term AFD text", bundle.Discussion.ShortTerm)
|
||||||
}
|
}
|
||||||
if bundle.Discussion.LongTerm == nil || bundle.Discussion.LongTerm.Narrative != "Warmer temperatures and periodic rain chances continue into the weekend." {
|
if bundle.Discussion.LongTerm == nil || bundle.Discussion.LongTerm.Text != "Warmer temperatures and periodic rain chances continue into the weekend." {
|
||||||
t.Fatalf("Discussion.LongTerm = %#v, want long-term AFD narrative", bundle.Discussion.LongTerm)
|
t.Fatalf("Discussion.LongTerm = %#v, want long-term AFD text", bundle.Discussion.LongTerm)
|
||||||
}
|
}
|
||||||
if len(bundle.Sources) != 8 {
|
if len(bundle.Sources) != 8 {
|
||||||
t.Fatalf("Sources length = %d, want 8", len(bundle.Sources))
|
t.Fatalf("Sources length = %d, want 8", len(bundle.Sources))
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
"Warmer temperatures this weekend."
|
"Warmer temperatures this weekend."
|
||||||
],
|
],
|
||||||
"shortTerm": {
|
"shortTerm": {
|
||||||
"title": "Short Term",
|
"qualifier": "(Through This Evening)",
|
||||||
"narrative": "A weak boundary may trigger isolated showers."
|
"text": "A weak boundary may trigger isolated showers."
|
||||||
},
|
},
|
||||||
"longTerm": {
|
"longTerm": {
|
||||||
"title": "Long Term",
|
"qualifier": "(This Weekend)",
|
||||||
"narrative": "Warmer temperatures and periodic rain chances continue into the weekend."
|
"text": "Warmer temperatures and periodic rain chances continue into the weekend."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ func TestFetchAndSaveBundle(t *testing.T) {
|
|||||||
case "/alerts/active":
|
case "/alerts/active":
|
||||||
_, _ = w.Write([]byte(`{"data":{"alerts":[]}}`))
|
_, _ = w.Write([]byte(`{"data":{"alerts":[]}}`))
|
||||||
case "/discussion":
|
case "/discussion":
|
||||||
_, _ = w.Write([]byte(`{"data":{"product":"discussion","issuedAt":"2026-05-29T09:25:00-05:00","keyMessages":[],"shortTerm":{"title":"Short Term","narrative":"Short-term AFD narrative for saved bundle."},"longTerm":{"title":"Long Term","narrative":"Long-term AFD narrative for saved bundle."}}}`))
|
_, _ = w.Write([]byte(`{"data":{"product":"discussion","issuedAt":"2026-05-29T09:25:00-05:00","keyMessages":[],"shortTerm":{"qualifier":"(Short Term)","text":"Short-term AFD narrative for saved bundle."},"longTerm":{"qualifier":"(Long Term)","text":"Long-term AFD narrative for saved bundle."}}}`))
|
||||||
default:
|
default:
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
}
|
}
|
||||||
@@ -197,11 +197,17 @@ func TestGenerateReportWritesReportAndPreflight(t *testing.T) {
|
|||||||
t.Fatalf("data package missing expected content:\n%s", string(data))
|
t.Fatalf("data package missing expected content:\n%s", string(data))
|
||||||
}
|
}
|
||||||
var savedDataPackage struct {
|
var savedDataPackage struct {
|
||||||
|
Report struct {
|
||||||
|
CurrentLocalDate string `json:"currentLocalDate"`
|
||||||
|
} `json:"report"`
|
||||||
Briefing briefing.Package `json:"briefing"`
|
Briefing briefing.Package `json:"briefing"`
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(data, &savedDataPackage); err != nil {
|
if err := json.Unmarshal(data, &savedDataPackage); err != nil {
|
||||||
t.Fatalf("decode data package: %v", err)
|
t.Fatalf("decode data package: %v", err)
|
||||||
}
|
}
|
||||||
|
if savedDataPackage.Report.CurrentLocalDate != "2026-05-29" {
|
||||||
|
t.Fatalf("data package currentLocalDate = %q, want 2026-05-29", savedDataPackage.Report.CurrentLocalDate)
|
||||||
|
}
|
||||||
location := savedDataPackage.Briefing.Metadata.Location
|
location := savedDataPackage.Briefing.Metadata.Location
|
||||||
if location == nil || location.ID != "home" || location.Name != "Brentwood" || location.Region != "St. Louis Metro" || location.Timezone != "America/Chicago" {
|
if location == nil || location.ID != "home" || location.Name != "Brentwood" || location.Region != "St. Louis Metro" || location.Timezone != "America/Chicago" {
|
||||||
t.Fatalf("data package location = %#v, want configured prompt location", location)
|
t.Fatalf("data package location = %#v, want configured prompt location", location)
|
||||||
@@ -899,7 +905,7 @@ func dailyBundleServer(t *testing.T) *httptest.Server {
|
|||||||
case "/alerts/active":
|
case "/alerts/active":
|
||||||
_, _ = w.Write([]byte(`{"data":{"alerts":[{"event":"Flood Watch","effective":"2026-05-29T05:00:00-05:00","expires":"2026-05-29T09:00:00-05:00"}]}}`))
|
_, _ = w.Write([]byte(`{"data":{"alerts":[{"event":"Flood Watch","effective":"2026-05-29T05:00:00-05:00","expires":"2026-05-29T09:00:00-05:00"}]}}`))
|
||||||
case "/discussion":
|
case "/discussion":
|
||||||
_, _ = w.Write([]byte(`{"data":{"product":"discussion","issuedAt":"2026-05-29T09:25:00-05:00","keyMessages":["Storms are most likely during the morning."],"shortTerm":{"title":"Short Term","narrative":"Short-term AFD narrative for generated report."},"longTerm":{"title":"Long Term","narrative":"Long-term AFD narrative for generated report."}}}`))
|
_, _ = w.Write([]byte(`{"data":{"product":"discussion","issuedAt":"2026-05-29T09:25:00-05:00","keyMessages":["Storms are most likely during the morning."],"shortTerm":{"qualifier":"(Short Term)","text":"Short-term AFD narrative for generated report."},"longTerm":{"qualifier":"(Long Term)","text":"Long-term AFD narrative for generated report."}}}`))
|
||||||
default:
|
default:
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -249,10 +249,10 @@ func buildDiscussion(discussion *forecast.Discussion) DiscussionContext {
|
|||||||
KeyMessages: discussion.KeyMessages,
|
KeyMessages: discussion.KeyMessages,
|
||||||
}
|
}
|
||||||
if discussion.ShortTerm != nil {
|
if discussion.ShortTerm != nil {
|
||||||
ctx.ShortTerm = discussion.ShortTerm.Narrative
|
ctx.ShortTerm = discussion.ShortTerm.Text
|
||||||
}
|
}
|
||||||
if discussion.LongTerm != nil {
|
if discussion.LongTerm != nil {
|
||||||
ctx.LongTerm = discussion.LongTerm.Narrative
|
ctx.LongTerm = discussion.LongTerm.Text
|
||||||
}
|
}
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ func stormConfidenceInputs(bundle *forecast.Bundle) []string {
|
|||||||
}
|
}
|
||||||
if bundle.Discussion != nil {
|
if bundle.Discussion != nil {
|
||||||
items = appendUnique(items, bundle.Discussion.KeyMessages...)
|
items = appendUnique(items, bundle.Discussion.KeyMessages...)
|
||||||
if bundle.Discussion.ShortTerm != nil && bundle.Discussion.ShortTerm.Narrative != "" {
|
if bundle.Discussion.ShortTerm != nil && bundle.Discussion.ShortTerm.Text != "" {
|
||||||
items = appendUnique(items, "Short-term discussion is available for confidence context.")
|
items = appendUnique(items, "Short-term discussion is available for confidence context.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ func TestStormBriefingWithActiveAlert(t *testing.T) {
|
|||||||
Discussion: &forecast.Discussion{
|
Discussion: &forecast.Discussion{
|
||||||
Product: "discussion",
|
Product: "discussion",
|
||||||
KeyMessages: []string{"Storms may intensify quickly."},
|
KeyMessages: []string{"Storms may intensify quickly."},
|
||||||
ShortTerm: &forecast.DiscussionSection{Narrative: "Short-term storm coverage peaks this morning."},
|
ShortTerm: &forecast.DiscussionSection{Text: "Short-term storm coverage peaks this morning."},
|
||||||
LongTerm: &forecast.DiscussionSection{Narrative: "Long-term pattern stays unsettled after the event."},
|
LongTerm: &forecast.DiscussionSection{Text: "Long-term pattern stays unsettled after the event."},
|
||||||
},
|
},
|
||||||
WeatherStory: &forecast.WeatherStory{Raw: json.RawMessage(`{"headline":"Storm risk"}`)},
|
WeatherStory: &forecast.WeatherStory{Raw: json.RawMessage(`{"headline":"Storm risk"}`)},
|
||||||
Sources: []forecast.Source{{Name: "hourly", FetchedAt: time.Now()}},
|
Sources: []forecast.Source{{Name: "hourly", FetchedAt: time.Now()}},
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ func TestThreeDayBriefingBuildsOutlookDays(t *testing.T) {
|
|||||||
Discussion: &forecast.Discussion{
|
Discussion: &forecast.Discussion{
|
||||||
Product: "discussion",
|
Product: "discussion",
|
||||||
KeyMessages: []string{"Unsettled stretch."},
|
KeyMessages: []string{"Unsettled stretch."},
|
||||||
ShortTerm: &forecast.DiscussionSection{Narrative: "Short-term rain chances remain focused today."},
|
ShortTerm: &forecast.DiscussionSection{Text: "Short-term rain chances remain focused today."},
|
||||||
LongTerm: &forecast.DiscussionSection{Narrative: "Long-term warmth builds into the weekend."},
|
LongTerm: &forecast.DiscussionSection{Text: "Long-term warmth builds into the weekend."},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ func TestWeekendBriefingBuildsPlanningInputs(t *testing.T) {
|
|||||||
Discussion: &forecast.Discussion{
|
Discussion: &forecast.Discussion{
|
||||||
Product: "discussion",
|
Product: "discussion",
|
||||||
KeyMessages: []string{"Timing may shift."},
|
KeyMessages: []string{"Timing may shift."},
|
||||||
ShortTerm: &forecast.DiscussionSection{Narrative: "Short-term showers exit before the weekend."},
|
ShortTerm: &forecast.DiscussionSection{Text: "Short-term showers exit before the weekend."},
|
||||||
LongTerm: &forecast.DiscussionSection{Narrative: "Long-term weekend rain timing remains uncertain."},
|
LongTerm: &forecast.DiscussionSection{Text: "Long-term weekend rain timing remains uncertain."},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,8 +149,8 @@ type Discussion struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DiscussionSection struct {
|
type DiscussionSection struct {
|
||||||
Title string `json:"title,omitempty"`
|
Qualifier string `json:"qualifier,omitempty"`
|
||||||
Narrative string `json:"narrative,omitempty"`
|
Text string `json:"text,omitempty"`
|
||||||
IssuedAt *time.Time `json:"issuedAt,omitempty"`
|
IssuedAt *time.Time `json:"issuedAt,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
8
internal/forecast/testdata/daily_bundle.json
vendored
8
internal/forecast/testdata/daily_bundle.json
vendored
@@ -56,12 +56,12 @@
|
|||||||
"Storms are most likely during the morning."
|
"Storms are most likely during the morning."
|
||||||
],
|
],
|
||||||
"shortTerm": {
|
"shortTerm": {
|
||||||
"title": "Short Term",
|
"qualifier": "(Through This Evening)",
|
||||||
"narrative": "Morning showers taper as a weak boundary shifts east."
|
"text": "Morning showers taper as a weak boundary shifts east."
|
||||||
},
|
},
|
||||||
"longTerm": {
|
"longTerm": {
|
||||||
"title": "Long Term",
|
"qualifier": "(This Weekend)",
|
||||||
"narrative": "Warmer and more humid conditions return with periodic rain chances."
|
"text": "Warmer and more humid conditions return with periodic rain chances."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sources": [
|
"sources": [
|
||||||
|
|||||||
@@ -25,12 +25,13 @@ type Package struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Report struct {
|
type Report struct {
|
||||||
ID report.ID `json:"id"`
|
ID report.ID `json:"id"`
|
||||||
Variant string `json:"variant,omitempty"`
|
Variant string `json:"variant,omitempty"`
|
||||||
PromptID string `json:"promptId"`
|
PromptID string `json:"promptId"`
|
||||||
GeneratedAt time.Time `json:"generatedAt"`
|
GeneratedAt time.Time `json:"generatedAt"`
|
||||||
Timezone string `json:"timezone"`
|
Timezone string `json:"timezone"`
|
||||||
ValidPeriod timeutil.Period `json:"validPeriod"`
|
CurrentLocalDate string `json:"currentLocalDate"`
|
||||||
|
ValidPeriod timeutil.Period `json:"validPeriod"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RecentChanges struct {
|
type RecentChanges struct {
|
||||||
@@ -42,6 +43,10 @@ func Build(briefingPackage briefing.Package) (Package, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BuildWithRecentChanges(briefingPackage briefing.Package, recentChanges []changes.Change) (Package, error) {
|
func BuildWithRecentChanges(briefingPackage briefing.Package, recentChanges []changes.Change) (Package, error) {
|
||||||
|
localDate, err := currentLocalDate(briefingPackage.Metadata.GeneratedAt, briefingPackage.Metadata.Timezone)
|
||||||
|
if err != nil {
|
||||||
|
return Package{}, err
|
||||||
|
}
|
||||||
items := make([]changes.Change, len(recentChanges))
|
items := make([]changes.Change, len(recentChanges))
|
||||||
copy(items, recentChanges)
|
copy(items, recentChanges)
|
||||||
if items == nil {
|
if items == nil {
|
||||||
@@ -51,12 +56,13 @@ func BuildWithRecentChanges(briefingPackage briefing.Package, recentChanges []ch
|
|||||||
SchemaVersion: SchemaVersion,
|
SchemaVersion: SchemaVersion,
|
||||||
RunID: briefingPackage.Metadata.RunID,
|
RunID: briefingPackage.Metadata.RunID,
|
||||||
Report: Report{
|
Report: Report{
|
||||||
ID: briefingPackage.Metadata.ReportID,
|
ID: briefingPackage.Metadata.ReportID,
|
||||||
Variant: briefingPackage.Metadata.Variant,
|
Variant: briefingPackage.Metadata.Variant,
|
||||||
PromptID: briefingPackage.Metadata.PromptID,
|
PromptID: briefingPackage.Metadata.PromptID,
|
||||||
GeneratedAt: briefingPackage.Metadata.GeneratedAt,
|
GeneratedAt: briefingPackage.Metadata.GeneratedAt,
|
||||||
Timezone: briefingPackage.Metadata.Timezone,
|
Timezone: briefingPackage.Metadata.Timezone,
|
||||||
ValidPeriod: briefingPackage.Metadata.ValidPeriod,
|
CurrentLocalDate: localDate,
|
||||||
|
ValidPeriod: briefingPackage.Metadata.ValidPeriod,
|
||||||
},
|
},
|
||||||
Briefing: briefingPackage,
|
Briefing: briefingPackage,
|
||||||
RecentChanges: RecentChanges{Items: items},
|
RecentChanges: RecentChanges{Items: items},
|
||||||
@@ -68,6 +74,14 @@ func BuildWithRecentChanges(briefingPackage briefing.Package, recentChanges []ch
|
|||||||
return pkg, nil
|
return pkg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func currentLocalDate(generatedAt time.Time, timezone string) (string, error) {
|
||||||
|
location, err := timeutil.LoadLocation(timezone)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("load report timezone %q: %w", timezone, err)
|
||||||
|
}
|
||||||
|
return generatedAt.In(location).Format(timeutil.DateLayout), nil
|
||||||
|
}
|
||||||
|
|
||||||
func Validate(pkg Package) error {
|
func Validate(pkg Package) error {
|
||||||
if pkg.SchemaVersion == "" {
|
if pkg.SchemaVersion == "" {
|
||||||
return fmt.Errorf("schemaVersion is required")
|
return fmt.Errorf("schemaVersion is required")
|
||||||
@@ -87,6 +101,9 @@ func Validate(pkg Package) error {
|
|||||||
if pkg.Report.Timezone == "" {
|
if pkg.Report.Timezone == "" {
|
||||||
return fmt.Errorf("report.timezone is required")
|
return fmt.Errorf("report.timezone is required")
|
||||||
}
|
}
|
||||||
|
if pkg.Report.CurrentLocalDate == "" {
|
||||||
|
return fmt.Errorf("report.currentLocalDate is required")
|
||||||
|
}
|
||||||
if !pkg.Report.ValidPeriod.IsValid() {
|
if !pkg.Report.ValidPeriod.IsValid() {
|
||||||
return fmt.Errorf("report.validPeriod must be valid")
|
return fmt.Errorf("report.validPeriod must be valid")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ func TestBuildDailyDataPackage(t *testing.T) {
|
|||||||
if pkg.Report.PromptID != "weather.daily_report" {
|
if pkg.Report.PromptID != "weather.daily_report" {
|
||||||
t.Fatalf("PromptID = %q, want weather.daily_report", pkg.Report.PromptID)
|
t.Fatalf("PromptID = %q, want weather.daily_report", pkg.Report.PromptID)
|
||||||
}
|
}
|
||||||
|
if pkg.Report.CurrentLocalDate != "2026-05-29" {
|
||||||
|
t.Fatalf("CurrentLocalDate = %q, want 2026-05-29", pkg.Report.CurrentLocalDate)
|
||||||
|
}
|
||||||
if pkg.Briefing.Daily == nil {
|
if pkg.Briefing.Daily == nil {
|
||||||
t.Fatal("Briefing.Daily = nil")
|
t.Fatal("Briefing.Daily = nil")
|
||||||
}
|
}
|
||||||
@@ -42,6 +45,34 @@ func TestBuildDailyDataPackage(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBuildCurrentLocalDateUsesReportTimezone(t *testing.T) {
|
||||||
|
briefingPackage := validBriefingPackage()
|
||||||
|
briefingPackage.Metadata.GeneratedAt = time.Date(2026, 5, 30, 2, 30, 0, 0, time.UTC)
|
||||||
|
briefingPackage.Metadata.Timezone = "America/Chicago"
|
||||||
|
|
||||||
|
pkg, err := Build(briefingPackage)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Build() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pkg.Report.CurrentLocalDate != "2026-05-29" {
|
||||||
|
t.Fatalf("CurrentLocalDate = %q, want local Chicago date 2026-05-29", pkg.Report.CurrentLocalDate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildRejectsInvalidReportTimezone(t *testing.T) {
|
||||||
|
briefingPackage := validBriefingPackage()
|
||||||
|
briefingPackage.Metadata.Timezone = "Not/AZone"
|
||||||
|
|
||||||
|
_, err := Build(briefingPackage)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Build() error = nil, want invalid timezone error")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "report timezone") {
|
||||||
|
t.Fatalf("error = %q, want report timezone context", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestValidateRequiresFields(t *testing.T) {
|
func TestValidateRequiresFields(t *testing.T) {
|
||||||
pkg, err := Build(validBriefingPackage())
|
pkg, err := Build(validBriefingPackage())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -58,6 +89,22 @@ func TestValidateRequiresFields(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateRequiresCurrentLocalDate(t *testing.T) {
|
||||||
|
pkg, err := Build(validBriefingPackage())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Build() error = %v", err)
|
||||||
|
}
|
||||||
|
pkg.Report.CurrentLocalDate = ""
|
||||||
|
|
||||||
|
err = Validate(pkg)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Validate() error = nil, want required field error")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "currentLocalDate") {
|
||||||
|
t.Fatalf("error = %q, want currentLocalDate context", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBuildThreeDayDataPackage(t *testing.T) {
|
func TestBuildThreeDayDataPackage(t *testing.T) {
|
||||||
briefingPackage := validBriefingPackage()
|
briefingPackage := validBriefingPackage()
|
||||||
briefingPackage.Metadata.RunID = "20260529T100000Z_three_day"
|
briefingPackage.Metadata.RunID = "20260529T100000Z_three_day"
|
||||||
|
|||||||
Reference in New Issue
Block a user