82 lines
4.8 KiB
Go
82 lines
4.8 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
mdc "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshdeliveryclient"
|
|
)
|
|
|
|
// What go/delivery wrote into the seat's states, key order and all, must decode as it did and encode to the same
|
|
// content (ADR 0634 §2): the gate's working values are converted to the seat's types at the edge.
|
|
func TestStoredValuesOfTheEarlierLayoutDecodeUnchanged(t *testing.T) {
|
|
approved := time.Date(2026, 11, 5, 10, 0, 0, 0, time.UTC)
|
|
since := time.Date(2026, 11, 5, 10, 5, 0, 0, time.UTC)
|
|
head := mdc.Head{Repository: "novox/app", Number: 7, Head: "0123456789abcdef0123456789abcdef01234567"}
|
|
rows := []struct {
|
|
name string
|
|
stored string
|
|
decode func(string) (any, error)
|
|
encode func(any) ([]byte, error)
|
|
want any
|
|
}{
|
|
{"merge with a merged and a refused pull", `{"v":1,"group":"feat/x","ask":"merge.feat_x.0123456789ab","approved":{"novox/app@7":"` + head.Head + `","novox/web@8":"abc"},` +
|
|
`"pulls":[{"repository":"novox/app","number":7,"head":"` + head.Head + `","state":"merged","commit":"c0ffee"},` +
|
|
`{"repository":"novox/web","number":8,"head":"abc","state":"refused","words":"mesh/check (missing)"}]}`,
|
|
func(s string) (any, error) { return DecodeMerge([]byte(s)) }, func(v any) ([]byte, error) { return EncodeMerge(v.(Merge)) },
|
|
Merge{V: 1, Group: "feat/x", Ask: "merge.feat_x.0123456789ab", Approved: map[string]string{"novox/app@7": head.Head, "novox/web@8": "abc"}, Pulls: []MergePull{
|
|
{Head: head, State: mdc.MergeMerged, Commit: "c0ffee"},
|
|
{Head: mdc.Head{Repository: "novox/web", Number: 8, Head: "abc"}, State: mdc.MergeRefused, Words: "mesh/check (missing)"}}}},
|
|
{"ask keeps the router's ask as bytes", `{"v":1,"group":"feat/x","heads":[{"repository":"novox/app","number":7,"head":"` + head.Head + `"}],"ask":{"id":"a","options":["Approve"]},"asking":2}`,
|
|
func(s string) (any, error) { return DecodeAsk([]byte(s)) }, func(v any) ([]byte, error) { return EncodeAsk(v.(Ask)) },
|
|
Ask{V: 1, Group: "feat/x", Heads: []mdc.Head{head}, Ask: json.RawMessage(`{"id":"a","options":["Approve"]}`), Asking: 2}},
|
|
{"turn without and with a check waited for", `{"v":1,"repository":"novox/app","waiting":[` +
|
|
`{"group":"feat/x","heads":"0123456789ab","ask":"merge.x","approved":"2026-11-05T10:00:00Z","since":"2026-11-05T10:00:00Z"},` +
|
|
`{"group":"feat/y","heads":"ba9876543210","approved":"2026-11-05T10:00:00Z","since":"2026-11-05T10:00:00Z","waits-for":"feat/x.0123456789ab","waits-since":"2026-11-05T10:05:00Z","step":"unit"}]}`,
|
|
func(s string) (any, error) { return DecodeTurn([]byte(s)) }, func(v any) ([]byte, error) { return EncodeTurn(v.(Turn)) },
|
|
Turn{V: 1, Repository: "novox/app", Waiting: []TurnWait{
|
|
{Group: "feat/x", Heads: "0123456789ab", Ask: "merge.x", Approved: approved, Since: approved},
|
|
{Group: "feat/y", Heads: "ba9876543210", Approved: approved, Since: approved, WaitsFor: "feat/x.0123456789ab", WaitsSince: since, Step: "unit"}}}},
|
|
{"source", `{"v":1,"group":"feat/x","heads":{"novox/app":"c0ffee"}}`,
|
|
func(s string) (any, error) { return mdc.DecodeSource([]byte(s)) }, func(v any) ([]byte, error) { return mdc.EncodeSource(v.(Source)) },
|
|
Source{V: 1, Group: "feat/x", Heads: map[string]string{"novox/app": "c0ffee"}}},
|
|
{"owed status", `{"v":1,"act":"status","context":"mesh/delivery","target":"https://x/y","state":"pending"}`,
|
|
func(s string) (any, error) { return mdc.DecodeOwed([]byte(s)) }, func(v any) ([]byte, error) { return mdc.EncodeOwed(v.(Owed)) },
|
|
Owed{V: 1, Act: "status", Context: "mesh/delivery", Target: "https://x/y", State: "pending"}},
|
|
{"answer", `{"v":1,"option":"Approve","warrant":"w@2026-11-05T10:00:00Z","words":"chose Approve"}`,
|
|
func(s string) (any, error) { return mdc.DecodeAnswer([]byte(s)) }, func(v any) ([]byte, error) { return mdc.EncodeAnswer(v.(Answer)) },
|
|
Answer{V: 1, Option: "Approve", Warrant: "w@2026-11-05T10:00:00Z", Words: "chose Approve"}},
|
|
}
|
|
for _, r := range rows {
|
|
t.Run(r.name, func(t *testing.T) {
|
|
got, err := r.decode(r.stored)
|
|
if err != nil {
|
|
t.Fatalf("the earlier layout does not decode: %v", err)
|
|
}
|
|
if !sameValue(got, r.want) {
|
|
t.Fatalf("decoded %+v, want %+v", got, r.want)
|
|
}
|
|
raw, err := r.encode(got)
|
|
if err != nil {
|
|
t.Fatalf("encode: %v", err)
|
|
}
|
|
var a, b any
|
|
if json.Unmarshal(raw, &a) != nil || json.Unmarshal([]byte(r.stored), &b) != nil || !reflect.DeepEqual(a, b) {
|
|
t.Fatalf("encoded %s, the earlier layout was %s", raw, r.stored)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func sameValue(a, b any) bool {
|
|
if x, ok := a.(Ask); ok {
|
|
return SameAsk(x, b.(Ask))
|
|
}
|
|
if x, ok := a.(Turn); ok {
|
|
return SameTurn(x, b.(Turn)) && reflect.DeepEqual(len(x.Waiting), len(b.(Turn).Waiting)) && x.Waiting[len(x.Waiting)-1].WaitsSince.Equal(b.(Turn).Waiting[len(x.Waiting)-1].WaitsSince)
|
|
}
|
|
return reflect.DeepEqual(a, b)
|
|
}
|