package inventory import ( "encoding/json" "reflect" "strings" "testing" "time" ) // The plan's backups are the contract mesh-delivery reads from `plan-moved` (issue 1065): their JSON field names // are fixed here, and a plan keeps them through a round trip. func TestAPlanKeepsItsBackupsThroughItsJSONUnderTheNamesTheDeliveryReads(t *testing.T) { at := time.Date(2026, 10, 17, 12, 0, 0, 0, time.UTC) p := Plan{ID: "p", Backups: &PlanBackups{State: BackupFailed, NoHolder: []string{"bare"}, Asked: []PlanBackup{{Machine: "ace", Module: "mail", State: BackupFailed, AskedAt: &at, Words: "no space left"}}}} raw, err := json.Marshal(p) if err != nil { t.Fatal(err) } for _, name := range []string{`"backups":{"state":"failed","asked":[{"machine":"ace","module":"mail","state":"failed",` + `"asked_at":"2026-10-17T12:00:00Z","words":"no space left"}],"no_holder":["bare"]}`} { if !strings.Contains(string(raw), name) { t.Fatalf("plan JSON %s lacks %s", raw, name) } } var back Plan if err := json.Unmarshal(raw, &back); err != nil || !reflect.DeepEqual(back.Backups, p.Backups) { t.Fatalf("round trip: %v %+v", err, back.Backups) } raw, _ = json.Marshal(Plan{ID: "q"}) if strings.Contains(string(raw), "backups") { t.Fatalf("a plan with no backups says none: %s", raw) } }