diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4d710c7..492a42f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,6 +71,33 @@ jobs: - name: Test run: go test -shuffle=on -count=1 ./... + windows-udp-test: + name: Windows UDP continuity (Go 1.25.13) + runs-on: windows-2022 + timeout-minutes: 10 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + with: + go-version: 1.25.13 + cache: true + - name: Exercise native UDP continuity and platform bind errors + shell: pwsh + run: | + $testOutput = & go test ./internal/tunnel -run '^(TestWebTestAddressInUse|TestQUICDatagramClosedPortPreservesAssociation)$' -count=5 -timeout=60s -json + $testExit = $LASTEXITCODE + $testOutput | Write-Output + if ($testExit -ne 0) { exit $testExit } + $testEvents = @($testOutput | ForEach-Object { $_ | ConvertFrom-Json -ErrorAction Stop }) + foreach ($testName in @('TestWebTestAddressInUse', 'TestQUICDatagramClosedPortPreservesAssociation')) { + $passes = @($testEvents | Where-Object { $_.Test -eq $testName -and $_.Action -eq 'pass' }).Count + $skips = @($testEvents | Where-Object { $_.Test -eq $testName -and $_.Action -eq 'skip' }).Count + if ($passes -ne 5 -or $skips -ne 0) { + throw "$testName requires exactly 5 passes and 0 skips; got $passes passes and $skips skips" + } + Write-Output "Verified ${testName}: $passes passes, $skips skips" + } + race: name: Race detector runs-on: ubuntu-24.04 diff --git a/internal/tunnel/datagram_icmp_recovery_test.go b/internal/tunnel/datagram_icmp_recovery_test.go index a6b5406..77e41ae 100644 --- a/internal/tunnel/datagram_icmp_recovery_test.go +++ b/internal/tunnel/datagram_icmp_recovery_test.go @@ -9,7 +9,6 @@ import ( "runtime" "sync" "sync/atomic" - "syscall" "testing" "time" @@ -205,7 +204,7 @@ func TestQUICDatagramClosedPortPreservesAssociation(t *testing.T) { // closed-destination write attempt before reopening the guard socket. checkEcho([]byte{byte(round), 'o', 'k'}) guard, err = net.ListenUDP("udp4", closedEndpoint) - if errors.Is(err, syscall.EADDRINUSE) { + if isWebTestAddressInUse(err) { t.Skip("closed-port fixture became inconclusive: another socket reused the port") } if err != nil {