Compare commits

...

4 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
5fd393c507 Rename test to TestPingAllByIPRandomClientPort and add to GitHub workflow
Co-authored-by: kradalby <98431+kradalby@users.noreply.github.com>
2025-11-01 08:31:41 +00:00
copilot-swe-agent[bot]
aafe727cb9 Refine direct connection validation logic in TestPingAllByIPDirectConnections
Co-authored-by: kradalby <98431+kradalby@users.noreply.github.com>
2025-11-01 08:22:28 +00:00
copilot-swe-agent[bot]
2ac534dd30 Add TestPingAllByIPDirectConnections test to validate direct connections with randomize_client_port
Co-authored-by: kradalby <98431+kradalby@users.noreply.github.com>
2025-11-01 08:19:37 +00:00
copilot-swe-agent[bot]
c09556dd22 Initial plan 2025-11-01 08:08:53 +00:00
2 changed files with 103 additions and 0 deletions

View File

@@ -62,6 +62,7 @@ jobs:
- TestDERPServerScenario
- TestDERPServerWebsocketScenario
- TestPingAllByIP
- TestPingAllByIPRandomClientPort
- TestPingAllByIPPublicDERP
- TestEphemeral
- TestEphemeralInAlternateTimezone

View File

@@ -86,6 +86,108 @@ func TestPingAllByIP(t *testing.T) {
t.Logf("%d successful pings out of %d", success, len(allClients)*len(allIps))
}
// TestPingAllByIPRandomClientPort is a variant of TestPingAllByIP that validates
// direct connections between nodes with randomize_client_port enabled. This test
// ensures that nodes can establish direct peer-to-peer connections without relying
// on DERP relay servers, and that the randomize_client_port feature works correctly.
func TestPingAllByIPRandomClientPort(t *testing.T) {
IntegrationSkip(t)
spec := ScenarioSpec{
NodesPerUser: len(MustTestVersions),
Users: []string{"user1", "user2"},
MaxWait: dockertestMaxWait(),
}
scenario, err := NewScenario(spec)
require.NoError(t, err)
defer scenario.ShutdownAssertNoPanics(t)
err = scenario.CreateHeadscaleEnv(
[]tsic.Option{},
hsic.WithTestName("pingdirect"),
hsic.WithEmbeddedDERPServerOnly(),
hsic.WithTLS(),
hsic.WithIPAllocationStrategy(types.IPAllocationStrategyRandom),
hsic.WithConfigEnv(map[string]string{
"HEADSCALE_RANDOMIZE_CLIENT_PORT": "true",
}),
)
requireNoErrHeadscaleEnv(t, err)
allClients, err := scenario.ListTailscaleClients()
requireNoErrListClients(t, err)
allIps, err := scenario.ListTailscaleClientsIPs()
requireNoErrListClientIPs(t, err)
err = scenario.WaitForTailscaleSync()
requireNoErrSync(t, err)
hs, err := scenario.Headscale()
require.NoError(t, err)
// Extract node IDs for validation
expectedNodes := make([]types.NodeID, 0, len(allClients))
for _, client := range allClients {
status := client.MustStatus()
nodeID, err := strconv.ParseUint(string(status.Self.ID), 10, 64)
require.NoError(t, err, "failed to parse node ID")
expectedNodes = append(expectedNodes, types.NodeID(nodeID))
}
requireAllClientsOnline(t, hs, expectedNodes, true, "all clients should be online across all systems", 30*time.Second)
allAddrs := lo.Map(allIps, func(x netip.Addr, index int) string {
return x.String()
})
// Perform pings to establish connections
success := pingAllHelper(t, allClients, allAddrs)
t.Logf("%d successful pings out of %d", success, len(allClients)*len(allIps))
// Validate that connections are direct (not relayed through DERP)
// We check that each client has direct connections to its peers
t.Logf("Validating direct connections...")
assert.EventuallyWithT(t, func(ct *assert.CollectT) {
for _, client := range allClients {
status, err := client.Status()
assert.NoError(ct, err, "failed to get status for client %s", client.Hostname())
if err != nil {
continue
}
// Check each peer to see if we have a direct connection
directCount := 0
relayedCount := 0
for _, peerKey := range status.Peers() {
peerStatus := status.Peer[peerKey]
// CurAddr indicates the current address being used to communicate with this peer
// Direct connections have CurAddr set to an actual IP:port
// DERP-relayed connections either have no CurAddr or it contains the DERP magic IP
if peerStatus.CurAddr != "" && !strings.Contains(peerStatus.CurAddr, "127.3.3.40") {
// This is a direct connection - CurAddr contains the actual peer IP:port
directCount++
t.Logf("Client %s -> Peer %s: DIRECT connection via %s (relay: %s)",
client.Hostname(), peerStatus.HostName, peerStatus.CurAddr, peerStatus.Relay)
} else {
// This is a relayed connection through DERP
relayedCount++
t.Logf("Client %s -> Peer %s: RELAYED connection (CurAddr: %s, relay: %s)",
client.Hostname(), peerStatus.HostName, peerStatus.CurAddr, peerStatus.Relay)
}
}
// Assert that we have at least some direct connections
// In a local Docker network, we should be able to establish direct connections
assert.Greater(ct, directCount, 0,
"Client %s should have at least one direct connection, got %d direct and %d relayed",
client.Hostname(), directCount, relayedCount)
}
}, 60*time.Second, 2*time.Second, "validating direct connections between peers")
}
func TestPingAllByIPPublicDERP(t *testing.T) {
IntegrationSkip(t)