mesh-sdk holds neither asks nor asker, nor the vault's answer types, and mesh-delivery's sdk/views is mesh-sdk's go/views (a1-progress.md, the rewrite map for the join): thirteen modules switch to the operatorchannel contract and client, mesh-sdk's channel package and meshvault, with go.mod requiring each at the group pin (nats: meshbroker too). The gate holds the checks mesh-sdk dropped (an ask's id is its key's asking, at least one option), with a row that fails without them; claude-code refuses a router record whose times do not parse, as its JSON decode did, with a row. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
97 lines
3.2 KiB
Go
97 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
occ "git.novox.be/novox/mesh-contracts/go/clients/operatorchannelclient"
|
|
)
|
|
|
|
// The router says when an ask starts and ends (ADR 0616 §7): `offered` once when an ask is offered, `closed` once for each of the five ends
|
|
// (answered, expired, cancelled by its asker, replaced, ended by the router), with how it ended and never an option, a ticket or a
|
|
// proof; a held ask is said when it is released.
|
|
func TestTheRouterSaysWhenAnAskIsOfferedAndWhenItEnds(t *testing.T) {
|
|
h, tg, _, c, store, _ := newRouter(t)
|
|
link(h, store, c, "42", c.now().Add(-2*time.Hour))
|
|
type said struct {
|
|
event string
|
|
body map[string]any
|
|
}
|
|
var got []said
|
|
h.Emit = func(event string, body any) error {
|
|
raw, _ := json.Marshal(body)
|
|
var m map[string]any
|
|
_ = json.Unmarshal(raw, &m)
|
|
got = append(got, said{event, m})
|
|
return nil
|
|
}
|
|
ends := func() (out []string) {
|
|
for _, s := range got {
|
|
if s.event == "closed" {
|
|
out = append(out, s.body["asker"].(string)+"."+s.body["id"].(string)+"="+s.body["how"].(string))
|
|
}
|
|
}
|
|
return
|
|
}
|
|
// Answered.
|
|
submit(t, h, "mesh-delivery", heldAsk(c, "d-1"))
|
|
settle(h, c)
|
|
if len(got) != 1 || got[0].event != "offered" || got[0].body["id"] != "d-1" || got[0].body["asker"] != "mesh-delivery" {
|
|
t.Fatalf("%+v", got)
|
|
}
|
|
release := ticketFor(tg.sends[0], "Release")
|
|
if _, err := h.Chosen("telegram", choiceOf(release, "42", c.now())); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Replaced, then cancelled by its asker.
|
|
a := ackAsk(c, "d-2")
|
|
a.About = "delivery.hq"
|
|
submit(t, h, "mesh-delivery", a)
|
|
b := ackAsk(c, "d-3")
|
|
b.About = "delivery.hq"
|
|
submit(t, h, "mesh-delivery", b)
|
|
if err := h.TakeAsk("cancel", "mesh-delivery", json.RawMessage(`{"id":"d-3"}`)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Expired.
|
|
e := heldAsk(c, "d-4")
|
|
e.About = "other"
|
|
submit(t, h, "mesh-delivery", e)
|
|
settle(h, c)
|
|
c.pass(3 * time.Hour)
|
|
stand(h, c)
|
|
h.Tick()
|
|
// Ended by the router itself (an unlink or allow-link ends its own asks the same way).
|
|
f := ackAsk(c, "d-5")
|
|
f.About = "third"
|
|
submit(t, h, "mesh-delivery", f)
|
|
if err := h.closeAsk("mesh-delivery.d-5", occ.OutcomeCancelled, "root decided to allow a link", nil, "", nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := "mesh-delivery.d-1=answered mesh-delivery.d-2=replaced mesh-delivery.d-3=cancelled mesh-delivery.d-4=expired mesh-delivery.d-5=ended by the router"
|
|
if gotEnds := strings.Join(ends(), " "); gotEnds != want {
|
|
t.Fatalf("the ends %q, want %q", gotEnds, want)
|
|
}
|
|
// Once each: a second close loses and says nothing; five asks were offered, once each; no option, ticket or proof is in a body.
|
|
_ = h.closeAsk("mesh-delivery.d-1", occ.OutcomeCancelled, "again", nil, "", nil)
|
|
offered := 0
|
|
for _, s := range got {
|
|
if s.event == "offered" {
|
|
offered++
|
|
}
|
|
for k := range s.body {
|
|
if k != "id" && k != "asker" && k != "headline" && k != "channels" && k != "how" {
|
|
t.Errorf("%s carries %s, which the seat's contract does not have", s.event, k)
|
|
}
|
|
if k == "options" || k == "tickets" || k == "token" || k == "proofs" || k == "warrant" {
|
|
t.Errorf("%s carries %s", s.event, k)
|
|
}
|
|
}
|
|
}
|
|
if offered != 5 || len(ends()) != 5 {
|
|
t.Fatalf("%d offered, %d closed", offered, len(ends()))
|
|
}
|
|
}
|