151 lines
3.7 KiB
Go
151 lines
3.7 KiB
Go
package main
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// TestHTTPClientTimeout verifies that the HTTP client has a timeout configured
|
|
func TestHTTPClientTimeout(t *testing.T) {
|
|
if httpClient.Timeout == 0 {
|
|
t.Error("HTTP client timeout is not configured")
|
|
}
|
|
|
|
expectedTimeout := 30 * time.Second
|
|
if httpClient.Timeout != expectedTimeout {
|
|
t.Errorf("HTTP client timeout = %v, want %v", httpClient.Timeout, expectedTimeout)
|
|
}
|
|
}
|
|
|
|
// TestHTTPClientTimeoutActuallyWorks verifies the timeout actually prevents indefinite hangs
|
|
func TestHTTPClientTimeoutActuallyWorks(t *testing.T) {
|
|
// Create a server that delays response longer than timeout
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
time.Sleep(35 * time.Second) // Sleep longer than our 30s timeout
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer server.Close()
|
|
|
|
start := time.Now()
|
|
_, err := httpClient.Get(server.URL)
|
|
duration := time.Since(start)
|
|
|
|
if err == nil {
|
|
t.Error("Expected timeout error, got nil")
|
|
}
|
|
|
|
// Should timeout in ~30 seconds, give 3s buffer for slow systems
|
|
if duration < 28*time.Second || duration > 33*time.Second {
|
|
t.Logf("Request took %v (expected ~30s)", duration)
|
|
}
|
|
}
|
|
|
|
// TestCooldownCacheBasic verifies basic cooldown functionality
|
|
func TestCooldownCacheBasic(t *testing.T) {
|
|
cacheMux.Lock()
|
|
cooldownCache = make(map[string]time.Time) // Reset
|
|
cacheMux.Unlock()
|
|
|
|
ip := "192.0.2.1"
|
|
|
|
// First check - should be allowed
|
|
if isInCooldown(ip, 10) {
|
|
t.Error("IP should not be in cooldown on first check")
|
|
}
|
|
|
|
// Add to cache
|
|
cacheMux.Lock()
|
|
cooldownCache[ip] = time.Now()
|
|
cacheMux.Unlock()
|
|
|
|
// Second check - should be in cooldown
|
|
if !isInCooldown(ip, 10) {
|
|
t.Error("IP should be in cooldown after being added")
|
|
}
|
|
|
|
// Wait for cooldown to expire
|
|
cacheMux.Lock()
|
|
cooldownCache[ip] = time.Now().Add(-11 * time.Minute)
|
|
cacheMux.Unlock()
|
|
|
|
// Third check - should be allowed again
|
|
if isInCooldown(ip, 10) {
|
|
t.Error("IP should not be in cooldown after expiry")
|
|
}
|
|
}
|
|
|
|
// TestCooldownCacheConcurrency verifies thread-safe cache access
|
|
func TestCooldownCacheConcurrency(t *testing.T) {
|
|
cacheMux.Lock()
|
|
cooldownCache = make(map[string]time.Time)
|
|
cacheMux.Unlock()
|
|
|
|
done := make(chan bool)
|
|
|
|
// Spawn multiple goroutines accessing cache concurrently
|
|
for i := 0; i < 10; i++ {
|
|
go func(id int) {
|
|
for j := 0; j < 100; j++ {
|
|
ip := "192.0.2." + string(rune(id))
|
|
isInCooldown(ip, 10)
|
|
|
|
cacheMux.Lock()
|
|
cooldownCache[ip] = time.Now()
|
|
cacheMux.Unlock()
|
|
}
|
|
done <- true
|
|
}(i)
|
|
}
|
|
|
|
// Wait for all goroutines
|
|
for i := 0; i < 10; i++ {
|
|
<-done
|
|
}
|
|
|
|
// If we got here without a race condition, test passes
|
|
}
|
|
|
|
// Helper function from ping_service.go
|
|
func isInCooldown(ip string, cooldownMinutes int) bool {
|
|
cacheMux.Lock()
|
|
defer cacheMux.Unlock()
|
|
|
|
lastPing, exists := cooldownCache[ip]
|
|
if !exists {
|
|
return false
|
|
}
|
|
|
|
elapsed := time.Since(lastPing)
|
|
cooldownDuration := time.Duration(cooldownMinutes) * time.Minute
|
|
return elapsed < cooldownDuration
|
|
}
|
|
|
|
// TestConfigParsing verifies config file parsing works correctly
|
|
func TestConfigDefaults(t *testing.T) {
|
|
config := Config{
|
|
IntervalSeconds: 30,
|
|
CooldownMinutes: 10,
|
|
EnableTraceroute: true,
|
|
TracerouteMaxHops: 30,
|
|
HealthCheckPort: 8090,
|
|
}
|
|
|
|
if config.IntervalSeconds <= 0 {
|
|
t.Error("IntervalSeconds should be positive")
|
|
}
|
|
|
|
if config.CooldownMinutes <= 0 {
|
|
t.Error("CooldownMinutes should be positive")
|
|
}
|
|
|
|
if config.TracerouteMaxHops <= 0 || config.TracerouteMaxHops > 255 {
|
|
t.Error("TracerouteMaxHops should be between 1 and 255")
|
|
}
|
|
|
|
if config.HealthCheckPort <= 0 || config.HealthCheckPort > 65535 {
|
|
t.Error("HealthCheckPort should be between 1 and 65535")
|
|
}
|
|
}
|