package moves import ( "errors" "strings" "testing" "time" ) // The seal's state class (settings spec rev 11 ยง4.3a, ruling R-SEAL-STATE): // the lane's build state by exact version, at most one object, at the // lane's state/ key, validated like every other class. A seal written // before the class existed has no "state" field and still decodes, with // none; a seal with none encodes without the field. func TestSealStateClass(t *testing.T) { old := sealForTest().Encode() if strings.Contains(old, `"state"`) { t.Fatalf("a seal with no state encodes the field: %s", old) } got, err := DecodeSeal(old) if err != nil || len(got.State) != 0 { t.Fatalf("a seal without the state field: %+v %v", got.State, err) } s := sealForTest() s.State = []SealedObject{{Key: BuildStateKey("h", "mv"), VersionID: "v6", Size: 90}} got, err = DecodeSeal(s.Encode()) if err != nil || len(got.State) != 1 || got.State[0] != s.State[0] { t.Fatalf("round trip: %+v %v", got.State, err) } for name, edit := range map[string]func(*Seal){ "two states": func(s *Seal) { s.State = append(s.State, SealedObject{Key: BuildStateKey("h", "rb"), VersionID: "v7", Size: 1}) }, "another key": func(s *Seal) { s.State[0].Key = "moves/h/mv/replica/build-state.json" }, "no version": func(s *Seal) { s.State[0].VersionID = "" }, "a null version": func(s *Seal) { s.State[0].VersionID = "null" }, "negative size": func(s *Seal) { s.State[0].Size = -1 }, "a key twice": func(s *Seal) { s.Timers = append(s.Timers, s.State[0]) }, } { t.Run(name, func(t *testing.T) { s := sealForTest() s.State = []SealedObject{{Key: BuildStateKey("h", "mv"), VersionID: "v6", Size: 90}} edit(&s) if err := s.Validate(); !errors.Is(err, ErrBadSeal) { t.Fatalf("Validate = %v", err) } if _, err := DecodeSeal(s.Encode()); !errors.Is(err, ErrBadSeal) { t.Fatalf("DecodeSeal = %v", err) } }) } at := time.Date(2026, 10, 7, 9, 0, 0, 0, time.UTC) st := []SealedObject{{Key: BuildStateKey("h", "rb"), VersionID: "v9", Size: 9}} r := ReturnSeal(7, sealForTest().Replica, nil, nil, st, at, at.Add(time.Hour)) if len(r.State) != 1 || r.State[0] != st[0] { t.Fatalf("ReturnSeal state %+v", r.State) } }