mirror of
https://github.com/lukaszraczylo/kportal.git
synced 2026-06-11 00:09:31 +00:00
230 lines
7.3 KiB
Go
230 lines
7.3 KiB
Go
package forward
|
|
|
|
import (
|
|
"net"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestPortChecker_IsAvailable(t *testing.T) {
|
|
pc := NewPortChecker()
|
|
|
|
// Test that isPortAvailable returns a bool
|
|
// We use a high port that's likely to be available
|
|
result := pc.isPortAvailable(54321)
|
|
assert.IsType(t, false, result, "isPortAvailable should return bool")
|
|
}
|
|
|
|
func TestPortChecker_CheckAvailability_EmptyPorts(t *testing.T) {
|
|
pc := NewPortChecker()
|
|
|
|
// Test with empty ports slice
|
|
conflicts := pc.CheckAvailability([]int{}, nil)
|
|
assert.Empty(t, conflicts, "should return empty conflicts for empty ports")
|
|
|
|
// Test with nil exclude map
|
|
conflicts = pc.CheckAvailability([]int{}, nil)
|
|
assert.Empty(t, conflicts, "should return empty conflicts for nil exclude map")
|
|
}
|
|
|
|
func TestPortChecker_CheckAvailability_ExcludeMap(t *testing.T) {
|
|
pc := NewPortChecker()
|
|
|
|
// Create a listener to occupy a port
|
|
listener, err := net.Listen("tcp", ":0")
|
|
assert.NoError(t, err, "should create listener")
|
|
defer listener.Close()
|
|
|
|
// Get the port that's now occupied
|
|
addr := listener.Addr().(*net.TCPAddr)
|
|
occupiedPort := addr.Port
|
|
|
|
// Test that the occupied port shows as conflicted
|
|
conflicts := pc.CheckAvailability([]int{occupiedPort}, nil)
|
|
assert.Len(t, conflicts, 1, "should detect conflict for occupied port")
|
|
assert.Equal(t, occupiedPort, conflicts[0].Port)
|
|
|
|
// Test that skipPorts map excludes the port from conflict detection
|
|
skipPorts := map[int]bool{
|
|
occupiedPort: true,
|
|
}
|
|
conflicts = pc.CheckAvailability([]int{occupiedPort}, skipPorts)
|
|
assert.Empty(t, conflicts, "should skip ports in exclude map")
|
|
}
|
|
|
|
func TestPortChecker_CheckAvailability_MultipleSkipPorts(t *testing.T) {
|
|
pc := NewPortChecker()
|
|
|
|
// Create multiple listeners
|
|
listener1, err := net.Listen("tcp", ":0")
|
|
assert.NoError(t, err)
|
|
defer listener1.Close()
|
|
|
|
listener2, err := net.Listen("tcp", ":0")
|
|
assert.NoError(t, err)
|
|
defer listener2.Close()
|
|
|
|
port1 := listener1.Addr().(*net.TCPAddr).Port
|
|
port2 := listener2.Addr().(*net.TCPAddr).Port
|
|
|
|
// Test with both ports occupied
|
|
conflicts := pc.CheckAvailability([]int{port1, port2}, nil)
|
|
assert.Len(t, conflicts, 2, "should detect both conflicts")
|
|
|
|
// Test excluding one port
|
|
skipPorts := map[int]bool{port1: true}
|
|
conflicts = pc.CheckAvailability([]int{port1, port2}, skipPorts)
|
|
assert.Len(t, conflicts, 1, "should detect only non-excluded port")
|
|
assert.Equal(t, port2, conflicts[0].Port)
|
|
|
|
// Test excluding both ports
|
|
skipPorts = map[int]bool{port1: true, port2: true}
|
|
conflicts = pc.CheckAvailability([]int{port1, port2}, skipPorts)
|
|
assert.Empty(t, conflicts, "should skip all excluded ports")
|
|
}
|
|
|
|
func TestPortChecker_GetProcessInfo(t *testing.T) {
|
|
pc := NewPortChecker()
|
|
|
|
// Test that getProcessUsingPort returns a string
|
|
// We don't test actual process detection to avoid flakiness
|
|
result := pc.getProcessUsingPort(12345)
|
|
assert.IsType(t, "", result, "getProcessUsingPort should return string")
|
|
assert.NotEmpty(t, result, "should return some string (even if 'unknown')")
|
|
}
|
|
|
|
func TestFormatConflicts_Empty(t *testing.T) {
|
|
// Test with empty conflicts
|
|
output := FormatConflicts([]PortConflict{})
|
|
assert.Empty(t, output, "should return empty string for no conflicts")
|
|
}
|
|
|
|
func TestFormatConflicts_SingleConflict(t *testing.T) {
|
|
conflicts := []PortConflict{
|
|
{
|
|
Port: 8080,
|
|
Resource: "dev/default/pod/my-app:8080",
|
|
UsedBy: "nginx (PID 1234)",
|
|
},
|
|
}
|
|
|
|
output := FormatConflicts(conflicts)
|
|
assert.NotEmpty(t, output, "should return non-empty output")
|
|
assert.Contains(t, output, "Port Conflicts Detected", "should contain header")
|
|
assert.Contains(t, output, "Port 8080", "should contain port number")
|
|
assert.Contains(t, output, "dev/default/pod/my-app:8080", "should contain resource")
|
|
assert.Contains(t, output, "nginx (PID 1234)", "should contain process info")
|
|
}
|
|
|
|
func TestFormatConflicts_MultipleConflicts(t *testing.T) {
|
|
conflicts := []PortConflict{
|
|
{
|
|
Port: 8080,
|
|
Resource: "dev/default/pod/app1:8080",
|
|
UsedBy: "nginx (PID 1234)",
|
|
},
|
|
{
|
|
Port: 5432,
|
|
Resource: "prod/database/service/postgres:5432",
|
|
UsedBy: "postgres (PID 5678)",
|
|
},
|
|
}
|
|
|
|
output := FormatConflicts(conflicts)
|
|
assert.NotEmpty(t, output, "should return non-empty output")
|
|
assert.Contains(t, output, "Port Conflicts Detected", "should contain header")
|
|
assert.Contains(t, output, "Port 8080", "should contain first port")
|
|
assert.Contains(t, output, "Port 5432", "should contain second port")
|
|
assert.Contains(t, output, "nginx (PID 1234)", "should contain first process")
|
|
assert.Contains(t, output, "postgres (PID 5678)", "should contain second process")
|
|
assert.Contains(t, output, "Action:", "should contain action message")
|
|
}
|
|
|
|
func TestFormatConflicts_WithoutResource(t *testing.T) {
|
|
conflicts := []PortConflict{
|
|
{
|
|
Port: 8080,
|
|
UsedBy: "nginx (PID 1234)",
|
|
},
|
|
}
|
|
|
|
output := FormatConflicts(conflicts)
|
|
assert.NotEmpty(t, output, "should return non-empty output")
|
|
assert.Contains(t, output, "Port 8080", "should contain port")
|
|
assert.Contains(t, output, "nginx (PID 1234)", "should contain process info")
|
|
// Should not crash or include empty "Needed for:" line
|
|
assert.NotContains(t, output, "Needed for: \n", "should not have empty resource line")
|
|
}
|
|
|
|
func TestPortConflict_Structure(t *testing.T) {
|
|
// Test that PortConflict structure works correctly
|
|
conflict := PortConflict{
|
|
Port: 8080,
|
|
Resource: "dev/default/pod/app:8080",
|
|
UsedBy: "nginx (PID 1234)",
|
|
}
|
|
|
|
assert.Equal(t, 8080, conflict.Port)
|
|
assert.Equal(t, "dev/default/pod/app:8080", conflict.Resource)
|
|
assert.Equal(t, "nginx (PID 1234)", conflict.UsedBy)
|
|
}
|
|
|
|
func TestNewPortChecker(t *testing.T) {
|
|
pc := NewPortChecker()
|
|
assert.NotNil(t, pc, "NewPortChecker should return non-nil instance")
|
|
}
|
|
|
|
func TestPortChecker_PortAvailability_Integration(t *testing.T) {
|
|
pc := NewPortChecker()
|
|
|
|
// Create a listener to occupy a port
|
|
listener, err := net.Listen("tcp", ":0")
|
|
assert.NoError(t, err, "should create listener")
|
|
defer listener.Close()
|
|
|
|
// Get the occupied port
|
|
occupiedPort := listener.Addr().(*net.TCPAddr).Port
|
|
|
|
// Test that the port is correctly detected as unavailable
|
|
available := pc.isPortAvailable(occupiedPort)
|
|
assert.False(t, available, "occupied port should not be available")
|
|
|
|
// Close the listener
|
|
listener.Close()
|
|
|
|
// The port should now be available (though there might be a brief delay)
|
|
// We don't assert this to avoid flakiness in CI environments
|
|
}
|
|
|
|
func TestPortChecker_CheckAvailability_AvailablePorts(t *testing.T) {
|
|
pc := NewPortChecker()
|
|
|
|
// Use high port numbers that are very unlikely to be in use
|
|
// This test might be slightly flaky in unusual environments, but should be stable
|
|
unlikelyPorts := []int{54321, 54322, 54323}
|
|
|
|
conflicts := pc.CheckAvailability(unlikelyPorts, nil)
|
|
|
|
// Most likely all ports will be available
|
|
// The function returns nil or empty slice when there are no conflicts
|
|
// We just verify the function executes without panicking
|
|
_ = conflicts
|
|
}
|
|
|
|
func TestFormatConflicts_Formatting(t *testing.T) {
|
|
conflicts := []PortConflict{
|
|
{
|
|
Port: 8080,
|
|
Resource: "dev/default/pod/my-app:8080",
|
|
UsedBy: "nginx (PID 1234)",
|
|
},
|
|
}
|
|
|
|
output := FormatConflicts(conflicts)
|
|
|
|
// Check formatting details
|
|
assert.Contains(t, output, "==================================================", "should contain separator line")
|
|
assert.Contains(t, output, "\n", "should contain newlines")
|
|
}
|