| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 |
- package nebula
- import (
- "bytes"
- "log/slog"
- "net/netip"
- "testing"
- "github.com/gaissmai/bart"
- "github.com/slackhq/nebula/test"
- "github.com/stretchr/testify/assert"
- )
- // TestStartRelaysLogDedupe verifies that repeated attempts with the same relay set drop the log
- // chatter to Debug, mirroring how the normal handshake retry loop quiets down once it's already
- // announced its targets.
- func TestStartRelaysLogDedupe(t *testing.T) {
- vpnIp := netip.MustParseAddr("100.64.99.4")
- otherRelay := netip.MustParseAddr("100.64.99.5")
- newHH := func() *HandshakeHostInfo {
- // Use the target's own vpnIp as the "relay" so the loop body skips it without
- // touching any sender-side state. That isolates the test to the level-selection
- // behavior of the top-level "Attempt to relay through hosts" log.
- hostinfo := &HostInfo{
- vpnAddrs: []netip.Addr{vpnIp},
- localIndexId: 1,
- remotes: NewRemoteList([]netip.Addr{vpnIp}, nil),
- }
- hostinfo.remotes.relays = []netip.Addr{vpnIp}
- return &HandshakeHostInfo{hostinfo: hostinfo}
- }
- // Park any extra relay addresses we'll introduce mid-test in myVpnAddrsTable so the loop
- // body always skips before touching f.Handshake (which would need a real handshakeManager).
- addrTable := new(bart.Lite)
- addrTable.Insert(netip.PrefixFrom(otherRelay, otherRelay.BitLen()))
- f := &Interface{myVpnAddrsTable: addrTable}
- newRM := func(buf *bytes.Buffer) *relayManager {
- l := test.NewLoggerWithOutputAndLevel(buf, slog.LevelDebug)
- rm := &relayManager{l: l, hostmap: newHostMap(l)}
- rm.useRelays.Store(true)
- return rm
- }
- const msg = `msg="Attempt to relay through hosts"`
- t.Run("first attempt logs at Info", func(t *testing.T) {
- var buf bytes.Buffer
- rm := newRM(&buf)
- hh := newHH()
- rm.StartRelays(f, vpnIp, hh, nil, nil)
- assert.Equal(t, []netip.Addr{vpnIp}, hh.lastRelays, "lastRelays should record the relay set we just attempted")
- assert.Contains(t, buf.String(), "level=INFO "+msg, "expected Info level on first attempt")
- })
- t.Run("repeat attempt with same relays drops to Debug", func(t *testing.T) {
- var buf bytes.Buffer
- rm := newRM(&buf)
- hh := newHH()
- rm.StartRelays(f, vpnIp, hh, nil, nil)
- first := append([]netip.Addr(nil), hh.lastRelays...)
- buf.Reset()
- rm.StartRelays(f, vpnIp, hh, nil, nil)
- assert.Equal(t, first, hh.lastRelays)
- assert.Contains(t, buf.String(), "level=DEBUG "+msg, "expected Debug level on identical retry")
- assert.NotContains(t, buf.String(), "level=INFO "+msg, "Info should not fire on identical retry")
- })
- t.Run("changed relay list bumps back to Info", func(t *testing.T) {
- var buf bytes.Buffer
- rm := newRM(&buf)
- hh := newHH()
- rm.StartRelays(f, vpnIp, hh, nil, nil)
- buf.Reset()
- // The lighthouse handed us a new set this round.
- hh.hostinfo.remotes.relays = []netip.Addr{vpnIp, otherRelay}
- rm.StartRelays(f, vpnIp, hh, nil, nil)
- assert.Equal(t, []netip.Addr{vpnIp, otherRelay}, hh.lastRelays)
- assert.Contains(t, buf.String(), "level=INFO "+msg, "expected Info when the relay list changes")
- })
- t.Run("disabled relays clears lastRelays and emits no Attempt log", func(t *testing.T) {
- var buf bytes.Buffer
- rm := newRM(&buf)
- rm.useRelays.Store(false)
- hh := newHH()
- hh.lastRelays = []netip.Addr{vpnIp}
- rm.StartRelays(f, vpnIp, hh, nil, nil)
- assert.Nil(t, hh.lastRelays, "with relays disabled lastRelays should be cleared")
- assert.NotContains(t, buf.String(), msg, "should not log when we shortcut out")
- })
- }
|