blob: 8f474e0b16b916de437d3c7dacb5607970d942bf [file] [log] [blame]
Sean McCullough364f7412025-06-02 00:55:44 +00001package loop
2
3import (
4 "context"
5 "testing"
6)
7
8// TestPortMonitoring tests the port monitoring functionality
9func TestPortMonitoring(t *testing.T) {
10 // Test with ss output format
11 ssOutput := `Netid State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
12tcp LISTEN 0 1024 127.0.0.1:40975 0.0.0.0:*
13tcp LISTEN 0 4096 *:22 *:*
14tcp LISTEN 0 4096 *:80 *:*
15udp UNCONN 0 0 127.0.0.1:123 0.0.0.0:*
16`
17
18 expected := map[string]bool{
19 "tcp:127.0.0.1:40975": true,
20 "tcp:*:22": true,
21 "tcp:*:80": true,
22 }
23
24 result := parseSSPorts(ssOutput)
25
26 // Check that all expected ports are found
27 for port := range expected {
28 if !result[port] {
29 t.Errorf("Expected port %s not found in ss parsed output", port)
30 }
31 }
32
33 // Check that UDP port is not included (since it's UNCONN, not LISTEN)
34 if result["udp:127.0.0.1:123"] {
35 t.Errorf("UDP UNCONN port should not be included in listening ports")
36 }
37
38 // Check that no extra ports are found
39 for port := range result {
40 if !expected[port] {
41 t.Errorf("Unexpected port %s found in parsed output", port)
42 }
43 }
44}
45
46// TestPortMonitoringLogDifferences tests the port difference logging
47func TestPortMonitoringLogDifferences(t *testing.T) {
48 ctx := context.Background()
49
50 oldPorts := `Netid State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
51tcp LISTEN 0 4096 *:22 *:*
52tcp LISTEN 0 1024 127.0.0.1:8080 0.0.0.0:*
53`
54
55 newPorts := `Netid State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
56tcp LISTEN 0 4096 *:22 *:*
57tcp LISTEN 0 1024 127.0.0.1:9090 0.0.0.0:*
58`
59
60 // Create a port monitor to test the logPortDifferences method
61 pm := NewPortMonitor()
62
63 // This test mainly ensures the method doesn't panic and processes the differences
64 // The actual logging output would need to be captured via a test logger to verify fully
65 pm.logPortDifferences(ctx, oldPorts, newPorts)
66
67 // Test with no differences
68 pm.logPortDifferences(ctx, oldPorts, oldPorts)
69}
70
71// TestPortMonitorCreation tests creating a new port monitor
72func TestPortMonitorCreation(t *testing.T) {
73 pm := NewPortMonitor()
74 if pm == nil {
75 t.Error("NewPortMonitor() returned nil")
76 }
77
78 // Verify initial state
79 pm.mu.Lock()
80 defer pm.mu.Unlock()
81 if pm.lastPorts != "" {
82 t.Error("NewPortMonitor() should have empty lastPorts initially")
83 }
84}
85
86// TestParseSSPortsEdgeCases tests edge cases in ss output parsing
87func TestParseSSPortsEdgeCases(t *testing.T) {
88 tests := []struct {
89 name string
90 output string
91 expected map[string]bool
92 }{
93 {
94 name: "empty output",
95 output: "",
96 expected: map[string]bool{},
97 },
98 {
99 name: "header only",
100 output: "Netid State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess",
101 expected: map[string]bool{},
102 },
103 {
104 name: "non-listen states filtered out",
105 output: "tcp ESTAB 0 0 127.0.0.1:8080 127.0.0.1:45678\nudp UNCONN 0 0 127.0.0.1:123 0.0.0.0:*",
106 expected: map[string]bool{},
107 },
108 {
109 name: "insufficient fields",
110 output: "tcp LISTEN 0",
111 expected: map[string]bool{},
112 },
113 }
114
115 for _, test := range tests {
116 t.Run(test.name, func(t *testing.T) {
117 result := parseSSPorts(test.output)
118 if len(result) != len(test.expected) {
119 t.Errorf("Expected %d ports, got %d", len(test.expected), len(result))
120 }
121 for port := range test.expected {
122 if !result[port] {
123 t.Errorf("Expected port %s not found", port)
124 }
125 }
126 for port := range result {
127 if !test.expected[port] {
128 t.Errorf("Unexpected port %s found", port)
129 }
130 }
131 })
132 }
133}