package activator import ( "strings" "testing" ) // The key IS the membership record (one LIST, no GETs), so the encoding must // round-trip any peer URL and reject foreign objects. func TestHeartbeatKeyRoundTrip(t *testing.T) { for _, peer := range []string{ "http://10.0.0.5:8080", "https://box-a.internal", "https://box-b.mesh.example.com:8443", } { leaf := encodeHeartbeatKey(peer) if got, err := decodeHeartbeatKey(leaf); err != nil || got != peer { t.Fatalf("round-trip %q: got %q, %v", peer, got, err) } } // A foreign object's key leaf must fail decode (List skips it) rather than // turn into a phantom member. if _, err := decodeHeartbeatKey("not/base64!"); err == nil { t.Fatal("garbage key leaf decoded without error") } } // statsKey must live under a SIBLING prefix, never collide with (or nest // inside) the membership heartbeat's own key — the hot membership List path // must never accidentally pick up a stats object. func TestStatsKeySibling(t *testing.T) { s := &HeartbeatStore{prefix: "prod"} peer := "https://box-b.internal" hbKey := s.key(peer) statsKey := s.statsKey(peer) if statsKey == hbKey { t.Fatal("stats key must differ from the membership heartbeat key") } if strings.HasPrefix(statsKey, s.prefix+"/") { t.Fatalf("stats key %q must not live under the plain membership prefix %q", statsKey, s.prefix) } if !strings.HasPrefix(statsKey, s.prefix+"-stats/") { t.Fatalf("stats key %q should live under %q", statsKey, s.prefix+"-stats/") } }