//go:build integration package process import ( "context" "strings" "testing" "time" "github.com/nats-io/nats.go/jetstream" "git.novox.be/novox/mesh-sdk/go/membership" ) // A process connected pinned to a test bus follows the membership the grants part writes for its node and module in // its state memberships, and reports what is not one (novox/hq issue 1633, AC2); it no longer hears mesh.assignment, // where the grants part stops publishing at the lease write (ADR 0571 clause 10; issue 774, 774/S5/AC1). Without the // state it refuses to follow, naming it. func TestFollowMembershipHearsWhatIsIssuedToTheAccount(t *testing.T) { url, fingerprint := selfSignedServer(t) account := mailSenderAccount(t, url, fingerprint) conn, err := Connect(account) if err != nil { t.Fatal(err) } defer conn.Close() got := make(chan membership.Membership, 4) bad := make(chan error, 4) follow := func() error { return conn.FollowMembership(func(m membership.Membership) { got <- m }, func(e error) { bad <- e }) } if err := follow(); err == nil || !strings.Contains(err.Error(), membership.GrantsBucket) { t.Fatalf("followed with no state memberships: %v", err) } js, err := jetstream.New(conn.nc) if err != nil { t.Fatal(err) } ctx := context.Background() kv, err := js.CreateKeyValue(ctx, jetstream.KeyValueConfig{Bucket: membership.GrantsBucket}) if err != nil { t.Fatal(err) } key := membership.GrantsKey("novox", "mesh-mail") if _, err := kv.Put(ctx, key, []byte("not json")); err != nil { t.Fatal(err) } if err := follow(); err != nil { t.Fatal(err) } // Published on the subject, as the grants part did until the write: not heard. if err := conn.nc.Publish(membership.Subject("novox", "mesh-mail"), []byte(`{"node":"novox","module":"mesh-mail","mesh":["10.0.0.9"]}`)); err != nil { t.Fatal(err) } if _, err := kv.Put(ctx, key, membership.EncodeGrantsMembership(membership.Membership{Node: "novox", Module: "mesh-mail", Mesh: []string{"10.0.0.1"}})); err != nil { t.Fatal(err) } select { case m := <-got: if m.Module != "mesh-mail" || len(m.Mesh) != 1 || m.Mesh[0] != "10.0.0.1" { t.Fatalf("membership: %+v", m) } case <-time.After(5 * time.Second): t.Fatal("no membership followed") } select { case m := <-got: t.Errorf("a second membership was applied, from the subject: %+v", m) case <-time.After(300 * time.Millisecond): } if len(bad) == 0 { t.Error("the value that is not a membership was not reported") } }