Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ jobs:
with:
go-version: ${{ matrix.go }}

test-windows:
uses: pion/.goassets/.github/workflows/test-windows.reusable.yml@master
strategy:
matrix:
go: ["1.25", "1.24"] # auto-update/supported-go-version-list
fail-fast: false
with:
go-version: ${{ matrix.go }}

test-wasm:
uses: pion/.goassets/.github/workflows/test-wasm.reusable.yml@master
with:
Expand Down
3 changes: 3 additions & 0 deletions active_tcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ func TestActiveTCP(t *testing.T) {
LoggerFactory: loggerFactory,
HostAcceptanceMinWait: &hostAcceptanceMinWait,
InterfaceFilter: problematicNetworkInterfaces,
IncludeLoopback: true,
}
if testCase.useMDNS {
cfg.MulticastDNSMode = MulticastDNSModeQueryAndGather
Expand All @@ -145,7 +146,9 @@ func TestActiveTCP(t *testing.T) {
LoggerFactory: loggerFactory,
HostAcceptanceMinWait: &hostAcceptanceMinWait,
InterfaceFilter: problematicNetworkInterfaces,
IncludeLoopback: true,
})

req.NoError(err)
req.NotNil(activeAgent)

Expand Down
49 changes: 37 additions & 12 deletions agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ func TestInvalidAgentStarts(t *testing.T) {
}()

ctx := context.Background()
ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
ctx, cancel := context.WithTimeout(ctx, 500*time.Millisecond)
defer cancel()

_, err = agent.Dial(ctx, "", "bar")
Expand Down Expand Up @@ -1817,12 +1817,35 @@ func TestAcceptAggressiveNomination(t *testing.T) { //nolint:cyclop
}
}

time.Sleep(1 * time.Second)
select {
case selected := <-selectedCh:
require.True(t, selected.Equal(expectNewSelectedCandidate))
default:
require.False(t, tc.isExpectedToSwitch)
// Wait until either we observe the expected switch or the timeout elapses,
// Ugly but makes the tests less flaky, especially on Windows.
timeout := 3 * time.Second

deadline := time.Now().Add(timeout)
observedExpected := false
waitLoop:
for time.Now().Before(deadline) {
select {
case selected := <-selectedCh:
if tc.isExpectedToSwitch {
if selected.Equal(expectNewSelectedCandidate) {
observedExpected = true

break waitLoop
}
}
default:
time.Sleep(10 * time.Millisecond)
}
}

if tc.isExpectedToSwitch {
if !observedExpected {
// Verify the agent's final selected pair if we didn't observe the event directly.
require.True(t, aAgent.getSelectedPair().Remote.Equal(expectNewSelectedCandidate))
}
} else {
// Ensure no switch happened by checking the agent's final selected pair.
require.True(t, aAgent.getSelectedPair().Remote.Equal(expectNewSelectedCandidate))
}
})
Expand Down Expand Up @@ -1957,11 +1980,13 @@ func TestAlwaysSentKeepAlive(t *testing.T) { //nolint:cyclop
require.NotEqual(t, lastSent, newLastSent)
lastSent = newLastSent

// sleep, so there is difference in sent time of local candidate
time.Sleep(10 * time.Millisecond)
agent.checkKeepalive()
newLastSent = pair.Local.LastSent()
require.NotEqual(t, lastSent, newLastSent)
// Wait for enough time to pass so there is difference in sent time of local candidate.
require.Eventually(t, func() bool {
agent.checkKeepalive()
newLastSent = pair.Local.LastSent()

return !lastSent.Equal(newLastSent)
}, 1*time.Second, 50*time.Millisecond)
}

func TestRoleConflict(t *testing.T) {
Expand Down
39 changes: 32 additions & 7 deletions agent_udpmux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,37 @@ import (
"github.com/stretchr/testify/require"
)

// newMuxForAddr creates a UDPMuxDefault with the correct socket family for the given address.
// This fixes Windows dual-stack issues where IPv6 sockets don't receive IPv4 traffic by default.
func newMuxForAddr(t *testing.T, addr *net.UDPAddr, loggerFactory logging.LoggerFactory) *UDPMuxDefault {
t.Helper()
var (
network string
laddr *net.UDPAddr
)

switch {
case addr.IP == nil || addr.IP.IsUnspecified():
network = "udp4"
laddr = &net.UDPAddr{IP: net.IPv4zero, Port: addr.Port}
case addr.IP.To4() != nil:
network = "udp4"
laddr = &net.UDPAddr{IP: net.IPv4zero, Port: addr.Port}
default:
network = "udp6"
laddr = &net.UDPAddr{IP: net.IPv6unspecified, Port: addr.Port}
}

pc, err := net.ListenUDP(network, laddr)
require.NoError(t, err)
t.Cleanup(func() { _ = pc.Close() })

return NewUDPMuxDefault(UDPMuxParams{
Logger: loggerFactory.NewLogger("ice"),
UDPConn: pc,
})
}

// TestMuxAgent is an end to end test over UDP mux, ensuring two agents could connect over mux.
func TestMuxAgent(t *testing.T) {
defer test.CheckRoutines(t)()
Expand All @@ -32,14 +63,8 @@ func TestMuxAgent(t *testing.T) {
for subTest, addr := range caseAddrs {
muxAddr := addr
t.Run(subTest, func(t *testing.T) {
c, err := net.ListenUDP("udp", muxAddr)
require.NoError(t, err)

loggerFactory := logging.NewDefaultLoggerFactory()
udpMux := NewUDPMuxDefault(UDPMuxParams{
Logger: loggerFactory.NewLogger("ice"),
UDPConn: c,
})
udpMux := newMuxForAddr(t, muxAddr, loggerFactory)

muxedA, err := NewAgent(&AgentConfig{
UDPMux: udpMux,
Expand Down
22 changes: 13 additions & 9 deletions gather_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"io"
"net"
"net/url"
"runtime"
"sort"
"strconv"
"sync"
Expand Down Expand Up @@ -345,15 +346,18 @@ func TestTURNConcurrency(t *testing.T) {
}()

urls := []*stun.URI{}
for i := 0; i <= 10; i++ {
urls = append(urls, &stun.URI{
Scheme: scheme,
Host: localhostIPStr,
Username: "username",
Password: "password",
Proto: protocol,
Port: serverPort + 1 + i,
})
// avoid long delay on unreachable ports on Windows
if runtime.GOOS != "windows" {
for i := 0; i <= 10; i++ {
urls = append(urls, &stun.URI{
Scheme: scheme,
Host: localhostIPStr,
Username: "username",
Password: "password",
Proto: protocol,
Port: serverPort + 1 + i,
})
}
}
urls = append(urls, &stun.URI{
Scheme: scheme,
Expand Down
21 changes: 18 additions & 3 deletions udp_mux_multi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,15 +162,30 @@ func TestMultiUDPMux_GetConn_NoUDPMuxAvailable(t *testing.T) {
_ = multi.Close()
}()

// tweak the port so it doesn't match.
// Pick a port that is guaranteed not to match any listening address
addrs := multi.GetListenAddresses()
require.NotEmpty(t, addrs)

udpAddr, ok := addrs[0].(*net.UDPAddr)
require.True(t, ok, "expected *net.UDPAddr")

// change the port to something different so addr.String() is not in localAddrToMux.
missing := &net.UDPAddr{IP: udpAddr.IP, Port: udpAddr.Port + 1, Zone: udpAddr.Zone}
// Build a set of in-use ports
inUse := make(map[int]struct{}, len(addrs))
for _, a := range addrs {
if ua, ok := a.(*net.UDPAddr); ok {
inUse[ua.Port] = struct{}{}
}
}

// Find a nearby port not in use
newPort := udpAddr.Port + 1
for i := 0; i < 100; i++ {
if _, exists := inUse[newPort]; !exists {
break
}
newPort++
}
missing := &net.UDPAddr{IP: udpAddr.IP, Port: newPort, Zone: udpAddr.Zone}

pc, getErr := multi.GetConn("missing-ufrag", missing)
require.Nil(t, pc)
Expand Down
Loading