package stdio import ( "bufio" "encoding/json" "io" "strings" "testing" "time" "git.novox.be/novox/mesh-sdk/go/announce" ) // A Go bundle says what it keeps from its code (novox/hq ADR 0495 clauses 1 and 2): Keeps, called before Serve, // announces through the runtime once the bundle serves, as the module the runtime names; and a state of its own that it // did not announce is refused at the call, naming it, so code and announcement cannot drift. func TestABundleAnnouncesWhatItKeepsAndBindsNothingElse(t *testing.T) { t.Setenv(ServedAs, "chime") t.Setenv("MESH_MODULE", "chime") t.Setenv("MESH_NODE", "anchor") defer forgetKeeps() // Not yet serving: an earlier test's channel is gone with its test. currentMu.Lock() current = nil currentMu.Unlock() if err := Keeps(announce.State{Name: "rings", Readable: true}, announce.State{Name: "own"}); err != nil { t.Fatal(err) } if _, err := State("other").Get("k"); err == nil || !strings.Contains(err.Error(), `"other"`) { t.Fatalf("a state not announced was bound: %v", err) } inR, inW := io.Pipe() outR, outW := io.Pipe() go func() { _ = ServeOn("", nil, inR, outW) }() defer inW.Close() lines := bufio.NewScanner(outR) got := make(chan map[string]any, 1) go func() { if lines.Scan() { var m map[string]any _ = json.Unmarshal(lines.Bytes(), &m) got <- m } }() var asked map[string]any select { case asked = <-got: case <-time.After(3 * time.Second): t.Fatal("the bundle announced nothing") } p, _ := asked["params"].(map[string]any) if asked["method"] != "mesh/publish" || p["key"] != announce.Event { t.Fatalf("the announcement was not published through the runtime: %v", asked) } raw, _ := json.Marshal(p["body"]) s, err := announce.Decode(raw) if err != nil || s.Module != "chime" || s.Node != "anchor" || !s.Readable("rings") || !s.Keeps("own") || s.Readable("own") { t.Fatalf("announced %s (%v)", raw, err) } if err := Keeps(announce.State{Name: "bad_name"}); err == nil { t.Fatal("an announcement no bucket could be named by was accepted") } }