1
0

relay_manager_test.go 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. package nebula
  2. import (
  3. "bytes"
  4. "log/slog"
  5. "net/netip"
  6. "testing"
  7. "github.com/gaissmai/bart"
  8. "github.com/slackhq/nebula/test"
  9. "github.com/stretchr/testify/assert"
  10. )
  11. // TestStartRelaysLogDedupe verifies that repeated attempts with the same relay set drop the log
  12. // chatter to Debug, mirroring how the normal handshake retry loop quiets down once it's already
  13. // announced its targets.
  14. func TestStartRelaysLogDedupe(t *testing.T) {
  15. vpnIp := netip.MustParseAddr("100.64.99.4")
  16. otherRelay := netip.MustParseAddr("100.64.99.5")
  17. newHH := func() *HandshakeHostInfo {
  18. // Use the target's own vpnIp as the "relay" so the loop body skips it without
  19. // touching any sender-side state. That isolates the test to the level-selection
  20. // behavior of the top-level "Attempt to relay through hosts" log.
  21. hostinfo := &HostInfo{
  22. vpnAddrs: []netip.Addr{vpnIp},
  23. localIndexId: 1,
  24. remotes: NewRemoteList([]netip.Addr{vpnIp}, nil),
  25. }
  26. hostinfo.remotes.relays = []netip.Addr{vpnIp}
  27. return &HandshakeHostInfo{hostinfo: hostinfo}
  28. }
  29. // Park any extra relay addresses we'll introduce mid-test in myVpnAddrsTable so the loop
  30. // body always skips before touching f.Handshake (which would need a real handshakeManager).
  31. addrTable := new(bart.Lite)
  32. addrTable.Insert(netip.PrefixFrom(otherRelay, otherRelay.BitLen()))
  33. f := &Interface{myVpnAddrsTable: addrTable}
  34. newRM := func(buf *bytes.Buffer) *relayManager {
  35. l := test.NewLoggerWithOutputAndLevel(buf, slog.LevelDebug)
  36. rm := &relayManager{l: l, hostmap: newHostMap(l)}
  37. rm.useRelays.Store(true)
  38. return rm
  39. }
  40. const msg = `msg="Attempt to relay through hosts"`
  41. t.Run("first attempt logs at Info", func(t *testing.T) {
  42. var buf bytes.Buffer
  43. rm := newRM(&buf)
  44. hh := newHH()
  45. rm.StartRelays(f, vpnIp, hh, nil)
  46. assert.Equal(t, []netip.Addr{vpnIp}, hh.lastRelays, "lastRelays should record the relay set we just attempted")
  47. assert.Contains(t, buf.String(), "level=INFO "+msg, "expected Info level on first attempt")
  48. })
  49. t.Run("repeat attempt with same relays drops to Debug", func(t *testing.T) {
  50. var buf bytes.Buffer
  51. rm := newRM(&buf)
  52. hh := newHH()
  53. rm.StartRelays(f, vpnIp, hh, nil)
  54. first := append([]netip.Addr(nil), hh.lastRelays...)
  55. buf.Reset()
  56. rm.StartRelays(f, vpnIp, hh, nil)
  57. assert.Equal(t, first, hh.lastRelays)
  58. assert.Contains(t, buf.String(), "level=DEBUG "+msg, "expected Debug level on identical retry")
  59. assert.NotContains(t, buf.String(), "level=INFO "+msg, "Info should not fire on identical retry")
  60. })
  61. t.Run("changed relay list bumps back to Info", func(t *testing.T) {
  62. var buf bytes.Buffer
  63. rm := newRM(&buf)
  64. hh := newHH()
  65. rm.StartRelays(f, vpnIp, hh, nil)
  66. buf.Reset()
  67. // The lighthouse handed us a new set this round.
  68. hh.hostinfo.remotes.relays = []netip.Addr{vpnIp, otherRelay}
  69. rm.StartRelays(f, vpnIp, hh, nil)
  70. assert.Equal(t, []netip.Addr{vpnIp, otherRelay}, hh.lastRelays)
  71. assert.Contains(t, buf.String(), "level=INFO "+msg, "expected Info when the relay list changes")
  72. })
  73. t.Run("disabled relays clears lastRelays and emits no Attempt log", func(t *testing.T) {
  74. var buf bytes.Buffer
  75. rm := newRM(&buf)
  76. rm.useRelays.Store(false)
  77. hh := newHH()
  78. hh.lastRelays = []netip.Addr{vpnIp}
  79. rm.StartRelays(f, vpnIp, hh, nil)
  80. assert.Nil(t, hh.lastRelays, "with relays disabled lastRelays should be cleared")
  81. assert.NotContains(t, buf.String(), msg, "should not log when we shortcut out")
  82. })
  83. }