speed up tests and update dependencies
- Override wsHandshakeTimeout in 3 websocket tests that waited 30s each - Make initialRetryDelay a package variable for faster retry tests - Reduce time.Sleep calls across agent_test.go (1.5s->150ms, 3s->1s, etc.) - Update Makefile with test-fast and test-short targets, add -count=1 - Update golang.org/x/crypto, x/net, x/sys to latest minors - Fix TestWSDialDefaultPorts to use mocked dials instead of real TCP
This commit is contained in:
parent
b308c3dc2e
commit
217f85fbdd
8 changed files with 135 additions and 57 deletions
|
|
@ -19,7 +19,7 @@ jobs:
|
|||
go-version-file: go.mod
|
||||
|
||||
- name: Run tests
|
||||
run: go test -race -v ./...
|
||||
run: go test -race -v -count=1 -timeout 60s ./...
|
||||
|
||||
- name: Vet
|
||||
run: go vet ./...
|
||||
|
|
|
|||
10
Makefile
10
Makefile
|
|
@ -1,4 +1,4 @@
|
|||
.PHONY: proto test build vet lint
|
||||
.PHONY: proto test test-fast test-race build vet lint
|
||||
|
||||
proto:
|
||||
protoc --go_out=. --go_opt=paths=source_relative proto/agent.proto
|
||||
|
|
@ -6,7 +6,13 @@ proto:
|
|||
mv proto/agent.pb.go pb/agent.pb.go
|
||||
|
||||
test:
|
||||
go test -race -v ./...
|
||||
go test -race -v -count=1 -timeout 60s ./...
|
||||
|
||||
test-fast:
|
||||
go test -count=1 -timeout 60s ./...
|
||||
|
||||
test-short:
|
||||
go test -count=1 -timeout 30s -short ./...
|
||||
|
||||
build:
|
||||
go build -o towerops-agent .
|
||||
|
|
|
|||
7
agent.go
7
agent.go
|
|
@ -26,6 +26,7 @@ var errChannelReloaded = fmt.Errorf("channel reloaded")
|
|||
var joinTimeout = 10 * time.Second
|
||||
var heartbeatInterval = 60 * time.Second
|
||||
var channelHeartbeatInterval = 25 * time.Second
|
||||
var initialRetryDelay = time.Second
|
||||
|
||||
const maxJobPayloadBytes = 4 << 20 // 4 MB — well above any legitimate job list
|
||||
|
||||
|
|
@ -40,7 +41,7 @@ type channelMsg struct {
|
|||
// runAgent connects to the server and runs the event loop with reconnect.
|
||||
func runAgent(ctx context.Context, wsURL, token string) {
|
||||
baseURL := strings.TrimRight(wsURL, "/")
|
||||
retryDelay := time.Second
|
||||
retryDelay := initialRetryDelay
|
||||
maxRetry := 10 * time.Second
|
||||
const successfulConnectionThreshold = 30 * time.Second
|
||||
|
||||
|
|
@ -60,7 +61,7 @@ func runAgent(ctx context.Context, wsURL, token string) {
|
|||
slog.Debug("resetting reconnect backoff after successful session",
|
||||
"duration", sessionDuration,
|
||||
"previous_delay", retryDelay)
|
||||
retryDelay = time.Second
|
||||
retryDelay = initialRetryDelay
|
||||
}
|
||||
|
||||
if ctx.Err() != nil {
|
||||
|
|
@ -68,7 +69,7 @@ func runAgent(ctx context.Context, wsURL, token string) {
|
|||
}
|
||||
if errors.Is(err, errRestartRequested) {
|
||||
slog.Info("restart requested, reconnecting immediately")
|
||||
retryDelay = time.Second
|
||||
retryDelay = initialRetryDelay
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ func TestHandleMessage(t *testing.T) {
|
|||
// Wait for goroutine to finish
|
||||
select {
|
||||
case <-snmpCh:
|
||||
case <-time.After(2 * time.Second):
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
t.Error("timed out waiting for snmp result")
|
||||
}
|
||||
})
|
||||
|
|
@ -337,7 +337,7 @@ func TestHandleMessage(t *testing.T) {
|
|||
_, _ = handleMessage(context.Background(), channelMsg{Event: "check_jobs", Payload: payload}, testPools(t), snmpCh, mtCh, credCh, monCh, checkCh, make(chan *pb.LldpTopologyResult, 1))
|
||||
select {
|
||||
case <-checkCh:
|
||||
case <-time.After(5 * time.Second):
|
||||
case <-time.After(time.Second):
|
||||
t.Error("timed out waiting for check result")
|
||||
}
|
||||
})
|
||||
|
|
@ -400,7 +400,7 @@ func TestHandleMessage(t *testing.T) {
|
|||
_, _ = handleMessage(context.Background(), channelMsg{Event: "discovery_job", Payload: payload}, testPools(t), snmpCh, mtCh, credCh, monCh, checkCh, make(chan *pb.LldpTopologyResult, 1))
|
||||
select {
|
||||
case <-snmpCh:
|
||||
case <-time.After(2 * time.Second):
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
t.Error("timed out waiting for discovery result")
|
||||
}
|
||||
})
|
||||
|
|
@ -431,7 +431,7 @@ func TestHandleMessage(t *testing.T) {
|
|||
if result.Error != "" {
|
||||
t.Errorf("unexpected error: %s", result.Error)
|
||||
}
|
||||
case <-time.After(2 * time.Second):
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
t.Error("timed out waiting for backup result")
|
||||
}
|
||||
})
|
||||
|
|
@ -560,7 +560,7 @@ func TestDispatchJob(t *testing.T) {
|
|||
if result.Error == "" {
|
||||
t.Error("expected error from unreachable device")
|
||||
}
|
||||
case <-time.After(2 * time.Second):
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
t.Error("timed out")
|
||||
}
|
||||
})
|
||||
|
|
@ -589,7 +589,7 @@ func TestDispatchJob(t *testing.T) {
|
|||
if result.Success {
|
||||
t.Error("expected failure")
|
||||
}
|
||||
case <-time.After(2 * time.Second):
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
t.Error("timed out")
|
||||
}
|
||||
})
|
||||
|
|
@ -618,7 +618,7 @@ func TestDispatchJob(t *testing.T) {
|
|||
if result.Status != "success" {
|
||||
t.Errorf("expected success, got %q", result.Status)
|
||||
}
|
||||
case <-time.After(2 * time.Second):
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
t.Error("timed out")
|
||||
}
|
||||
})
|
||||
|
|
@ -648,7 +648,7 @@ func TestDispatchJob(t *testing.T) {
|
|||
|
||||
select {
|
||||
case <-snmpCh:
|
||||
case <-time.After(2 * time.Second):
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
t.Error("timed out")
|
||||
}
|
||||
})
|
||||
|
|
@ -701,7 +701,7 @@ func TestRunSessionRejectsFailedJoin(t *testing.T) {
|
|||
_, _ = conn.Write(frame)
|
||||
|
||||
// Keep connection open for a bit
|
||||
time.Sleep(time.Second)
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}()
|
||||
|
||||
addr := ln.Addr().String()
|
||||
|
|
@ -745,7 +745,7 @@ func TestRunSessionJoinTimeout(t *testing.T) {
|
|||
frameBuf := make([]byte, 4096)
|
||||
_, _ = conn.Read(frameBuf)
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
time.Sleep(2 * time.Second)
|
||||
}()
|
||||
|
||||
addr := ln.Addr().String()
|
||||
|
|
@ -932,8 +932,8 @@ func TestRunSessionCtxCancel(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Errorf("expected nil error on ctx cancel, got: %v", err)
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Error("runSession did not exit after ctx cancel")
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Error("runSession did not exit after ctx cancel")
|
||||
}
|
||||
srv.close()
|
||||
}
|
||||
|
|
@ -1088,6 +1088,10 @@ func TestRunSessionReadErrorDuringJoin(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRunAgentReconnectOnError(t *testing.T) {
|
||||
origRetry := initialRetryDelay
|
||||
defer func() { initialRetryDelay = origRetry }()
|
||||
initialRetryDelay = 50 * time.Millisecond
|
||||
|
||||
// Server that fails first connection then succeeds, then sends restart.
|
||||
// Agent should reconnect (not exit) after both error and restart.
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
|
|
@ -1130,14 +1134,14 @@ func TestRunAgentReconnectOnError(t *testing.T) {
|
|||
Ref: strPtr("1"),
|
||||
})
|
||||
_, _ = conn.Write(makeTextFrame(reply))
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
restart, _ := json.Marshal(channelMsg{
|
||||
Topic: "agent:agent-0",
|
||||
Event: "restart",
|
||||
Payload: json.RawMessage(`{}`),
|
||||
})
|
||||
_, _ = conn.Write(makeTextFrame(restart))
|
||||
time.Sleep(time.Second)
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
_ = conn.Close()
|
||||
default:
|
||||
// Third connection: agent successfully reconnected after restart
|
||||
|
|
@ -1146,7 +1150,7 @@ func TestRunAgentReconnectOnError(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
done := make(chan struct{})
|
||||
|
|
@ -1156,7 +1160,7 @@ func TestRunAgentReconnectOnError(t *testing.T) {
|
|||
}()
|
||||
|
||||
// Wait for 3rd connection attempt (proves agent reconnected after both error and restart)
|
||||
deadline := time.After(10 * time.Second)
|
||||
deadline := time.After(5 * time.Second)
|
||||
for {
|
||||
if connCount.Load() >= 3 {
|
||||
cancel()
|
||||
|
|
@ -1166,7 +1170,7 @@ func TestRunAgentReconnectOnError(t *testing.T) {
|
|||
case <-deadline:
|
||||
t.Fatalf("expected at least 3 connections, got %d", connCount.Load())
|
||||
default:
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1192,6 +1196,10 @@ func TestRunAgentContextCancellation(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRunAgentRestart(t *testing.T) {
|
||||
origRetry := initialRetryDelay
|
||||
defer func() { initialRetryDelay = origRetry }()
|
||||
initialRetryDelay = 50 * time.Millisecond
|
||||
|
||||
// After receiving a restart event, the agent should reconnect (not exit).
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
|
|
@ -1228,20 +1236,20 @@ func TestRunAgentRestart(t *testing.T) {
|
|||
|
||||
if count == 1 {
|
||||
// First connection: send restart event
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
restart, _ := json.Marshal(channelMsg{
|
||||
Topic: "agent:agent-0",
|
||||
Event: "restart",
|
||||
Payload: json.RawMessage(`{}`),
|
||||
})
|
||||
_, _ = conn.Write(makeTextFrame(restart))
|
||||
time.Sleep(time.Second)
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
_ = conn.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
done := make(chan struct{})
|
||||
|
|
@ -1261,7 +1269,7 @@ func TestRunAgentRestart(t *testing.T) {
|
|||
case <-deadline:
|
||||
t.Fatalf("expected at least 2 connections, got %d", connCount.Load())
|
||||
default:
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1401,7 +1409,7 @@ func TestRunSessionProcessesJobResults(t *testing.T) {
|
|||
srv.sendEvent("check_jobs", checkPayload)
|
||||
|
||||
// Wait for results to flow through all channels
|
||||
time.Sleep(2 * time.Second)
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
close(stopDrain)
|
||||
srv.close()
|
||||
}()
|
||||
|
|
@ -1447,7 +1455,7 @@ func TestRunSessionSnmpBatchThreshold(t *testing.T) {
|
|||
}
|
||||
srv.sendEvent("jobs", makeJobPayload(jobs...))
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
time.Sleep(time.Second)
|
||||
close(stopDrain)
|
||||
srv.close()
|
||||
}()
|
||||
|
|
@ -1509,10 +1517,10 @@ func TestExecuteCheckCtxDoneInClosure(t *testing.T) {
|
|||
executeCheck(ctx, check, p, checkCh)
|
||||
|
||||
// Wait for the check to complete (TCP to port 1 fails fast)
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
// Cancel ctx so the closure's select picks ctx.Done instead of blocked channel send
|
||||
cancel()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
|
||||
func TestRunSessionRestartInMainLoop(t *testing.T) {
|
||||
|
|
@ -1523,10 +1531,10 @@ func TestRunSessionRestartInMainLoop(t *testing.T) {
|
|||
stopDrain := make(chan struct{})
|
||||
go drainFrames(srv.conn, stopDrain)
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
// Send restart event — exercised in the main loop select
|
||||
srv.sendEvent("restart", json.RawMessage(`{}`))
|
||||
time.Sleep(time.Second)
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
close(stopDrain)
|
||||
srv.close()
|
||||
}()
|
||||
|
|
@ -1554,7 +1562,7 @@ func TestRunSessionHeartbeats(t *testing.T) {
|
|||
stopDrain := make(chan struct{})
|
||||
go drainFrames(srv.conn, stopDrain)
|
||||
// Let heartbeats fire a few times
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
close(stopDrain)
|
||||
srv.close()
|
||||
}()
|
||||
|
|
@ -1566,6 +1574,10 @@ func TestRunSessionHeartbeats(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRunAgentCancelDuringRetry(t *testing.T) {
|
||||
origRetry := initialRetryDelay
|
||||
defer func() { initialRetryDelay = origRetry }()
|
||||
initialRetryDelay = 100 * time.Millisecond
|
||||
|
||||
// Connects to a port nothing listens on, then cancel during retry delay
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
|
|
@ -1576,13 +1588,13 @@ func TestRunAgentCancelDuringRetry(t *testing.T) {
|
|||
}()
|
||||
|
||||
// Wait for first connection attempt to fail and retry delay to start
|
||||
time.Sleep(1500 * time.Millisecond)
|
||||
time.Sleep(150 * time.Millisecond)
|
||||
cancel()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
// runAgent returned after cancel during retry
|
||||
case <-time.After(5 * time.Second):
|
||||
case <-time.After(time.Second):
|
||||
t.Error("runAgent did not return after cancel during retry")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
6
go.mod
6
go.mod
|
|
@ -4,9 +4,9 @@ go 1.25.6
|
|||
|
||||
require (
|
||||
github.com/gosnmp/gosnmp v1.43.2
|
||||
golang.org/x/crypto v0.49.0
|
||||
golang.org/x/net v0.52.0
|
||||
golang.org/x/crypto v0.52.0
|
||||
golang.org/x/net v0.55.0
|
||||
google.golang.org/protobuf v1.36.11
|
||||
)
|
||||
|
||||
require golang.org/x/sys v0.42.0 // indirect
|
||||
require golang.org/x/sys v0.45.0 // indirect
|
||||
|
|
|
|||
16
go.sum
16
go.sum
|
|
@ -8,14 +8,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
||||
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
||||
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
||||
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
|
||||
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
|
||||
golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
|
||||
golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
|
||||
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
|
||||
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
|
||||
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
|
||||
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
|
||||
golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
|
|
|||
40
ping_test.go
40
ping_test.go
|
|
@ -14,7 +14,10 @@ func TestPingDeviceLocalhost(t *testing.T) {
|
|||
if runtime.GOOS == "windows" {
|
||||
t.Skip("skipping ping test on windows")
|
||||
}
|
||||
ms, err := pingDevice("127.0.0.1", 5000)
|
||||
if testing.Short() {
|
||||
t.Skip("skipping real ICMP ping in short mode")
|
||||
}
|
||||
ms, err := pingDevice("127.0.0.1", 2000)
|
||||
if err != nil {
|
||||
t.Skipf("ping not available: %v", err)
|
||||
}
|
||||
|
|
@ -34,7 +37,10 @@ func TestPingDeviceIPv6(t *testing.T) {
|
|||
if runtime.GOOS == "windows" {
|
||||
t.Skip("skipping ping test on windows")
|
||||
}
|
||||
ms, err := pingDevice("::1", 5000)
|
||||
if testing.Short() {
|
||||
t.Skip("skipping real ICMP ping in short mode")
|
||||
}
|
||||
ms, err := pingDevice("::1", 2000)
|
||||
if err != nil {
|
||||
t.Skipf("IPv6 not available: %v", err)
|
||||
}
|
||||
|
|
@ -44,7 +50,10 @@ func TestPingDeviceIPv6(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIcmpPingLocalhost(t *testing.T) {
|
||||
ms, err := icmpPing("127.0.0.1", 5000)
|
||||
if testing.Short() {
|
||||
t.Skip("skipping real ICMP ping in short mode")
|
||||
}
|
||||
ms, err := icmpPing("127.0.0.1", 2000)
|
||||
if err != nil {
|
||||
t.Skipf("ICMP not available: %v", err)
|
||||
}
|
||||
|
|
@ -54,7 +63,10 @@ func TestIcmpPingLocalhost(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIcmpPingIPv6(t *testing.T) {
|
||||
ms, err := icmpPing("::1", 5000)
|
||||
if testing.Short() {
|
||||
t.Skip("skipping real ICMP ping in short mode")
|
||||
}
|
||||
ms, err := icmpPing("::1", 2000)
|
||||
if err != nil {
|
||||
t.Skipf("IPv6 ICMP not available: %v", err)
|
||||
}
|
||||
|
|
@ -139,7 +151,10 @@ func TestExecPingLocalhost(t *testing.T) {
|
|||
if runtime.GOOS == "windows" {
|
||||
t.Skip("skipping on windows")
|
||||
}
|
||||
ms, err := execPing("127.0.0.1", 5000)
|
||||
if testing.Short() {
|
||||
t.Skip("skipping real exec ping in short mode")
|
||||
}
|
||||
ms, err := execPing("127.0.0.1", 2000)
|
||||
if err != nil {
|
||||
t.Skipf("ping command not available: %v", err)
|
||||
}
|
||||
|
|
@ -159,7 +174,10 @@ func TestExecPingIPv6Localhost(t *testing.T) {
|
|||
if runtime.GOOS == "windows" {
|
||||
t.Skip("skipping on windows")
|
||||
}
|
||||
ms, err := execPing("::1", 5000)
|
||||
if testing.Short() {
|
||||
t.Skip("skipping real exec ping in short mode")
|
||||
}
|
||||
ms, err := execPing("::1", 2000)
|
||||
if err != nil {
|
||||
t.Skipf("ping6 not available: %v", err)
|
||||
}
|
||||
|
|
@ -185,6 +203,9 @@ func TestPingDeviceFallbackToExec(t *testing.T) {
|
|||
if runtime.GOOS == "windows" {
|
||||
t.Skip("skipping on windows")
|
||||
}
|
||||
if testing.Short() {
|
||||
t.Skip("skipping real ping in short mode")
|
||||
}
|
||||
// Mock icmpListenPacket to always fail → forces fallback to execPing
|
||||
origListen := icmpListenPacket
|
||||
defer func() { icmpListenPacket = origListen }()
|
||||
|
|
@ -193,7 +214,7 @@ func TestPingDeviceFallbackToExec(t *testing.T) {
|
|||
return nil, fmt.Errorf("permission denied")
|
||||
}
|
||||
|
||||
ms, err := pingDevice("127.0.0.1", 5000)
|
||||
ms, err := pingDevice("127.0.0.1", 2000)
|
||||
if err != nil {
|
||||
t.Skipf("exec ping fallback not available: %v", err)
|
||||
}
|
||||
|
|
@ -288,6 +309,9 @@ func TestIcmpPingNonICMPUnavailableError(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIcmpPingUDPFallback(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping real ICMP in short mode")
|
||||
}
|
||||
// Mock raw ICMP to fail, forcing UDP fallback path in icmpPing
|
||||
origListen := icmpListenPacket
|
||||
defer func() { icmpListenPacket = origListen }()
|
||||
|
|
@ -303,7 +327,7 @@ func TestIcmpPingUDPFallback(t *testing.T) {
|
|||
return icmp.ListenPacket(network, address)
|
||||
}
|
||||
|
||||
ms, err := icmpPing("127.0.0.1", 5000)
|
||||
ms, err := icmpPing("127.0.0.1", 2000)
|
||||
if err != nil {
|
||||
t.Skipf("UDP ICMP not available: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -712,6 +712,10 @@ func TestWSDialMissingAcceptHeader(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWSDialMissingUpgradeHeader(t *testing.T) {
|
||||
origTimeout := wsHandshakeTimeout
|
||||
defer func() { wsHandshakeTimeout = origTimeout }()
|
||||
wsHandshakeTimeout = time.Second
|
||||
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -743,6 +747,10 @@ func TestWSDialMissingUpgradeHeader(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWSDialRejectsNon101Status(t *testing.T) {
|
||||
origTimeout := wsHandshakeTimeout
|
||||
defer func() { wsHandshakeTimeout = origTimeout }()
|
||||
wsHandshakeTimeout = time.Second
|
||||
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -774,17 +782,44 @@ func TestWSDialRejectsNon101Status(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWSDialDefaultPorts(t *testing.T) {
|
||||
// Test that ws:// defaults to port 80 — will fail to connect but verifies URL parsing
|
||||
origTimeout := wsHandshakeTimeout
|
||||
origDial := netDial
|
||||
origTLS := tlsDial
|
||||
defer func() {
|
||||
wsHandshakeTimeout = origTimeout
|
||||
netDial = origDial
|
||||
tlsDial = origTLS
|
||||
}()
|
||||
wsHandshakeTimeout = time.Second
|
||||
|
||||
var wsCalls, wssCalls int
|
||||
netDial = func(network, addr string) (net.Conn, error) {
|
||||
wsCalls++
|
||||
if addr == "127.0.0.1:80" {
|
||||
return nil, fmt.Errorf("connection refused (mock)")
|
||||
}
|
||||
return nil, fmt.Errorf("mock dial: %s", addr)
|
||||
}
|
||||
tlsDial = func(network, addr string) (net.Conn, error) {
|
||||
wssCalls++
|
||||
return nil, fmt.Errorf("tls dial refused (mock)")
|
||||
}
|
||||
|
||||
_, err := WSDial("ws://127.0.0.1/path")
|
||||
if err == nil {
|
||||
t.Error("expected connection error (nothing on port 80)")
|
||||
}
|
||||
if wsCalls == 0 {
|
||||
t.Error("expected netDial to be called for ws://")
|
||||
}
|
||||
|
||||
// Test that wss:// defaults to port 443
|
||||
_, err = WSDial("wss://127.0.0.1/path")
|
||||
if err == nil {
|
||||
t.Error("expected connection error (nothing on port 443)")
|
||||
}
|
||||
if wssCalls == 0 {
|
||||
t.Error("expected tlsDial to be called for wss://")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWSDialRealHTTPServer(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue