towerops-agent/ping_test.go
Graham McIntire aef770ea83
test: achieve 92%+ coverage with comprehensive integration and edge case tests
Cover WebSocket session lifecycle (result channels, SNMP batch flushing,
heartbeats, restart), MikroTik TLS TOFU verification mismatch, worker pool
exhaustion, plaintext WebSocket rejection, HTTP/TCP/DNS check execution,
IPv4 fallback, and customer network edge cases.

Make heartbeat intervals and toWebSocketURL exit injectable for testing.
2026-03-04 16:06:29 -06:00

132 lines
2.8 KiB
Go

package main
import (
"fmt"
"runtime"
"testing"
)
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 err != nil {
t.Skipf("ping not available: %v", err)
}
if ms <= 0 {
t.Errorf("expected positive response time, got %v", ms)
}
}
func TestPingDeviceInvalidIP(t *testing.T) {
_, err := pingDevice("not-an-ip", 5000)
if err == nil {
t.Error("expected error for invalid IP")
}
}
func TestPingDeviceIPv6(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping ping test on windows")
}
ms, err := pingDevice("::1", 5000)
if err != nil {
t.Skipf("IPv6 not available: %v", err)
}
if ms <= 0 {
t.Errorf("expected positive response time, got %v", ms)
}
}
func TestIcmpPingLocalhost(t *testing.T) {
ms, err := icmpPing("127.0.0.1", 5000)
if err != nil {
t.Skipf("ICMP not available: %v", err)
}
if ms <= 0 {
t.Errorf("expected positive response time, got %v", ms)
}
}
func TestIcmpPingIPv6(t *testing.T) {
ms, err := icmpPing("::1", 5000)
if err != nil {
t.Skipf("IPv6 ICMP not available: %v", err)
}
if ms <= 0 {
t.Errorf("expected positive response time, got %v", ms)
}
}
func TestIcmpPingInvalidIP(t *testing.T) {
_, err := icmpPing("not-an-ip", 5000)
if err == nil {
t.Error("expected error for invalid IP")
}
}
func TestErrICMPUnavailableError(t *testing.T) {
err := &errICMPUnavailable{err: fmt.Errorf("permission denied")}
if err.Error() != "permission denied" {
t.Errorf("got %q, want %q", err.Error(), "permission denied")
}
}
func TestParsePingTime(t *testing.T) {
tests := []struct {
name string
output string
want float64
wantErr bool
}{
{
name: "standard linux",
output: "64 bytes from 8.8.8.8: icmp_seq=1 ttl=118 time=12.3 ms",
want: 12.3,
},
{
name: "localhost",
output: "64 bytes from localhost: icmp_seq=1 ttl=64 time=0.123 ms",
want: 0.123,
},
{
name: "multiline",
output: "PING 8.8.8.8 (8.8.8.8): 56 data bytes\n64 bytes from 8.8.8.8: icmp_seq=0 ttl=118 time=15.7 ms\n--- 8.8.8.8 ping statistics ---",
want: 15.7,
},
{
name: "no time field",
output: "Request timeout for icmp_seq 0",
wantErr: true,
},
{
name: "empty",
output: "",
wantErr: true,
},
{
name: "time= without ms suffix",
output: "64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=1.234\n",
want: 1.234,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parsePingTime(tt.output)
if tt.wantErr {
if err == nil {
t.Errorf("expected error, got %v", got)
}
return
}
if err != nil {
t.Errorf("unexpected error: %v", err)
return
}
if got != tt.want {
t.Errorf("got %v, want %v", got, tt.want)
}
})
}
}