//go:build integration package main import ( "context" "testing" "time" "github.com/nats-io/nats.go" "github.com/nats-io/nats.go/jetstream" "github.com/novox/mesh-controller/internal/broker" "github.com/novox/mesh-controller/internal/testbus" ) func silentOnABus(t *testing.T) (*busSilent, <-chan silentWait) { t.Helper() js, err := broker.Dial(testbus.URL(t)) if err != nil { t.Fatal(err) } t.Cleanup(js.Close) if err := js.EnsureControllerBuckets(); err != nil { t.Fatal(err) } conn, err := nats.Connect(testbus.URL(t)) if err != nil { t.Fatal(err) } t.Cleanup(conn.Close) api, err := jetstream.New(conn) if err != nil { t.Fatal(err) } heard := make(chan silentWait, 16) ctx, stop := context.WithCancel(context.Background()) t.Cleanup(stop) s, err := newBusSilent(ctx, api, func(w silentWait) { heard <- w }) if err != nil { t.Fatal(err) } return s, heard } func TestAKeyLeftAloneExpiresAndTheWatcherNamesTheMachineSilent(t *testing.T) { // 1157/AC3: the send keys stay until release 6 (ADR 0433 ยง5) s, heard := silentOnABus(t) want := silentWait{Plan: "plan.7", Tier: 2, Node: "ace"} if err := s.Arm(t.Context(), want, time.Second, time.Now()); err != nil { t.Fatal(err) } if got, ok := hearsSilent(t, heard, 10*time.Second); !ok || got != want { t.Fatalf("heard %+v (%v); want %+v", got, ok, want) } } func TestAReportDeletesTheKeyAndNoOneIsNamedSilent(t *testing.T) { s, heard := silentOnABus(t) ctx := t.Context() w := silentWait{Plan: "plan-1", Tier: 0, Node: "g14"} if err := s.Arm(ctx, w, time.Second, time.Now()); err != nil { t.Fatal(err) } if err := s.Reported(ctx, w); err != nil { t.Fatal(err) } if got, ok := hearsSilent(t, heard, 2500*time.Millisecond); ok { t.Fatalf("%+v was named silent after it reported", got) } // Reporting twice, or on a send that put no key, is no error. if err := s.Reported(ctx, w); err != nil { t.Fatalf("a second report: %v", err) } } func TestASendMadeAgainPutsTheKeyAgain(t *testing.T) { s, heard := silentOnABus(t) ctx := t.Context() w := silentWait{Plan: "plan-3", Tier: 1, Node: "novox"} if err := s.Arm(ctx, w, 2*time.Second, time.Now()); err != nil { t.Fatal(err) } time.Sleep(1200 * time.Millisecond) if err := s.Arm(ctx, w, 2*time.Second, time.Now()); err != nil { t.Fatal(err) } if got, ok := hearsSilent(t, heard, 1500*time.Millisecond); ok { t.Fatalf("%+v expired at the first send's time, not the second's", got) } if got, ok := hearsSilent(t, heard, 5*time.Second); !ok || got != w { t.Fatalf("heard %+v (%v); want %+v after the second send's time", got, ok, w) } }