Files
olm/peers/exitnode_routes_test.go
T

107 lines
3.5 KiB
Go

package peers
import "testing"
// newExitNodeTestManager returns a PeerManager for exercising the
// DisableRoutesAndAliasesOnExitNode state machine (resourceRoutesSuppressed,
// exitNodeActive, gatewayActive) without touching the OS routing table, a
// WireGuard device, or a DNS proxy - safe as long as pm.peers stays empty,
// same constraint as newGatewayTestManager in gateway_test.go. Unlike
// NewPeerManager, disableRoutesAndAliasesOnExitNode is the only state seeded
// here; exitNodeActive/gatewayActive/resourceRoutesSuppressed always start
// false, matching NewPeerManager's real (purely reactive, no pre-seeding)
// behavior.
func newExitNodeTestManager(disableRoutesAndAliasesOnExitNode bool) *PeerManager {
return &PeerManager{
peers: make(map[int]SiteConfig),
allowedIPOwners: make(map[string]int),
allowedIPClaims: make(map[string]map[int]bool),
disableRoutesAndAliasesOnExitNode: disableRoutesAndAliasesOnExitNode,
}
}
func TestSetClearExitNodeSuppressesResourceRoutesWhenEnabled(t *testing.T) {
pm := newExitNodeTestManager(true)
if pm.resourceRoutesSuppressed {
t.Fatalf("must start unsuppressed")
}
pm.SetExitNode("100.64.0.1", "100.64.0.2")
if !pm.exitNodeActive {
t.Fatalf("SetExitNode must mark the exit node active")
}
if !pm.resourceRoutesSuppressed {
t.Fatalf("SetExitNode must suppress resource routes when the feature is enabled")
}
pm.ClearExitNode()
if pm.exitNodeActive {
t.Fatalf("ClearExitNode must mark the exit node inactive")
}
if pm.resourceRoutesSuppressed {
t.Fatalf("ClearExitNode must restore resource routes")
}
}
func TestSetClearExitNodeNoopWhenDisabled(t *testing.T) {
pm := newExitNodeTestManager(false)
pm.SetExitNode("100.64.0.1", "100.64.0.2")
if pm.resourceRoutesSuppressed {
t.Fatalf("resource routes must never be suppressed when the feature is disabled")
}
pm.ClearExitNode()
if pm.resourceRoutesSuppressed {
t.Fatalf("resource routes must stay unsuppressed when the feature is disabled")
}
}
// TestClearExitNodeKeepsSuppressedWhileGatewayActive covers the two
// independent "exit node" signals (see exitNodeOrGatewayActiveLocked):
// disconnecting the ExitNodeConfig WireGuard peer must not restore resource
// routes if gateway/full-tunnel mode - what client apps and the CLI actually
// call "select exit node" - is still active. gatewayActive is set directly
// here (bypassing SetGateway, which touches the OS routing table) purely to
// exercise ClearExitNode's OR-check.
func TestClearExitNodeKeepsSuppressedWhileGatewayActive(t *testing.T) {
pm := newExitNodeTestManager(true)
pm.SetExitNode("100.64.0.1", "100.64.0.2")
if !pm.resourceRoutesSuppressed {
t.Fatalf("SetExitNode must suppress resource routes")
}
pm.mu.Lock()
pm.gatewayActive = true
pm.mu.Unlock()
pm.ClearExitNode()
if pm.exitNodeActive {
t.Fatalf("ClearExitNode must mark the exit node inactive regardless of gateway state")
}
if !pm.resourceRoutesSuppressed {
t.Fatalf("resource routes must stay suppressed while gateway mode is still active")
}
}
func TestExitNodeOrGatewayActiveLocked(t *testing.T) {
pm := newExitNodeTestManager(true)
if pm.exitNodeOrGatewayActiveLocked() {
t.Fatalf("neither signal is active yet")
}
pm.exitNodeActive = true
if !pm.exitNodeOrGatewayActiveLocked() {
t.Fatalf("exit node signal alone must count as active")
}
pm.exitNodeActive = false
pm.gatewayActive = true
if !pm.exitNodeOrGatewayActiveLocked() {
t.Fatalf("gateway signal alone must count as active")
}
}