network/pkg/rqlite/ports_test.go

195 lines
5.0 KiB
Go

package rqlite
import (
"testing"
)
func TestPortManager_AllocatePortPair(t *testing.T) {
pm := NewPortManager(
PortRange{Start: 5001, End: 5010},
PortRange{Start: 7001, End: 7010},
)
ports, err := pm.AllocatePortPair("testdb")
if err != nil {
t.Fatalf("Failed to allocate port pair: %v", err)
}
// Verify HTTP port in range
if ports.HTTPPort < 5001 || ports.HTTPPort > 5010 {
t.Errorf("HTTP port %d out of range [5001-5010]", ports.HTTPPort)
}
// Verify Raft port in range
if ports.RaftPort < 7001 || ports.RaftPort > 7010 {
t.Errorf("Raft port %d out of range [7001-7010]", ports.RaftPort)
}
// Verify ports are different
if ports.HTTPPort == ports.RaftPort {
t.Error("HTTP and Raft ports should be different")
}
}
func TestPortManager_ReleasePortPair(t *testing.T) {
pm := NewPortManager(
PortRange{Start: 5001, End: 5010},
PortRange{Start: 7001, End: 7010},
)
// Allocate
ports, err := pm.AllocatePortPair("testdb")
if err != nil {
t.Fatalf("Failed to allocate port pair: %v", err)
}
// Release
pm.ReleasePortPair(ports)
// Should be able to allocate again
ports2, err := pm.AllocatePortPair("testdb2")
if err != nil {
t.Fatalf("Failed to allocate after release: %v", err)
}
// Might get same ports back (that's OK)
if ports2.HTTPPort == 0 || ports2.RaftPort == 0 {
t.Error("Got zero ports after release and reallocation")
}
}
func TestPortManager_IsPortAllocated(t *testing.T) {
pm := NewPortManager(
PortRange{Start: 5001, End: 5010},
PortRange{Start: 7001, End: 7010},
)
// Initially not allocated
if pm.IsPortAllocated(5001) {
t.Error("Port should not be allocated initially")
}
// Allocate
ports, err := pm.AllocatePortPair("testdb")
if err != nil {
t.Fatalf("Failed to allocate: %v", err)
}
// Should be allocated now
if !pm.IsPortAllocated(ports.HTTPPort) {
t.Error("HTTP port should be allocated")
}
if !pm.IsPortAllocated(ports.RaftPort) {
t.Error("Raft port should be allocated")
}
// Release
pm.ReleasePortPair(ports)
// Should not be allocated anymore
if pm.IsPortAllocated(ports.HTTPPort) {
t.Error("HTTP port should not be allocated after release")
}
if pm.IsPortAllocated(ports.RaftPort) {
t.Error("Raft port should not be allocated after release")
}
}
func TestPortManager_AllocateSpecificPorts(t *testing.T) {
pm := NewPortManager(
PortRange{Start: 5001, End: 5010},
PortRange{Start: 7001, End: 7010},
)
specificPorts := PortPair{HTTPPort: 5005, RaftPort: 7005}
// Allocate specific ports
err := pm.AllocateSpecificPorts("testdb", specificPorts)
if err != nil {
t.Fatalf("Failed to allocate specific ports: %v", err)
}
// Verify allocated
if !pm.IsPortAllocated(5005) {
t.Error("Port 5005 should be allocated")
}
if !pm.IsPortAllocated(7005) {
t.Error("Port 7005 should be allocated")
}
// Try to allocate same ports again - should fail
err = pm.AllocateSpecificPorts("testdb2", specificPorts)
if err == nil {
t.Error("Expected error when allocating already-allocated ports")
}
}
func TestPortManager_Exhaustion(t *testing.T) {
// Very small range
pm := NewPortManager(
PortRange{Start: 5001, End: 5002}, // Only 2 ports
PortRange{Start: 7001, End: 7002}, // Only 2 ports
)
// Allocate first pair (uses 2 ports)
_, err := pm.AllocatePortPair("db1")
if err != nil {
t.Fatalf("First allocation should succeed: %v", err)
}
// Try to allocate second pair - might fail due to limited ports
// Note: This test is probabilistic due to random selection
// In a real scenario with only 2 ports per range, we can only fit 1 database
_, err = pm.AllocatePortPair("db2")
// We expect this to eventually fail after retries
// The actual behavior depends on random selection
// For a more deterministic test, allocate specific ports
pm2 := NewPortManager(
PortRange{Start: 5001, End: 5002},
PortRange{Start: 7001, End: 7002},
)
_ = pm2.AllocateSpecificPorts("db1", PortPair{HTTPPort: 5001, RaftPort: 7001})
_ = pm2.AllocateSpecificPorts("db2", PortPair{HTTPPort: 5002, RaftPort: 7002})
// Now exhausted
err = pm2.AllocateSpecificPorts("db3", PortPair{HTTPPort: 5001, RaftPort: 7001})
if err == nil {
t.Error("Expected error when ports exhausted")
}
}
func TestPortManager_MultipleDatabases(t *testing.T) {
pm := NewPortManager(
PortRange{Start: 5001, End: 5020},
PortRange{Start: 7001, End: 7020},
)
databases := []string{"db1", "db2", "db3", "db4", "db5"}
allocatedPorts := make(map[int]bool)
for _, db := range databases {
ports, err := pm.AllocatePortPair(db)
if err != nil {
t.Fatalf("Failed to allocate for %s: %v", db, err)
}
// Verify no port conflicts
if allocatedPorts[ports.HTTPPort] {
t.Errorf("HTTP port %d already allocated", ports.HTTPPort)
}
if allocatedPorts[ports.RaftPort] {
t.Errorf("Raft port %d already allocated", ports.RaftPort)
}
allocatedPorts[ports.HTTPPort] = true
allocatedPorts[ports.RaftPort] = true
}
// Should have allocated 10 unique ports (5 HTTP + 5 Raft)
if len(allocatedPorts) != 10 {
t.Errorf("Expected 10 unique ports, got %d", len(allocatedPorts))
}
}