- Add gotestsum for real-time test progress visibility - Parallelize 174 tests across 14 files for faster execution - Add -short mode support skipping 21 heavy integration tests - Create testutil/db.go helper for future transaction rollbacks - Fix data race in notification_service_test.go - Fix 4 CrowdSec LAPI test failures with permissive validator Performance improvements: - Tests now run in parallel (174 tests with t.Parallel()) - Quick feedback loop via -short mode - Zero race conditions detected - Coverage maintained at 87.7% Closes test optimization initiative
254 lines
7.1 KiB
Go
254 lines
7.1 KiB
Go
package network
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestNewInternalServiceHTTPClient(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
timeout time.Duration
|
|
}{
|
|
{"with 1 second timeout", 1 * time.Second},
|
|
{"with 5 second timeout", 5 * time.Second},
|
|
{"with 30 second timeout", 30 * time.Second},
|
|
{"with 100ms timeout", 100 * time.Millisecond},
|
|
{"with zero timeout", 0},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
client := NewInternalServiceHTTPClient(tt.timeout)
|
|
if client == nil {
|
|
t.Fatal("NewInternalServiceHTTPClient() returned nil")
|
|
}
|
|
if client.Timeout != tt.timeout {
|
|
t.Errorf("expected timeout %v, got %v", tt.timeout, client.Timeout)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewInternalServiceHTTPClient_TransportConfiguration(t *testing.T) {
|
|
timeout := 5 * time.Second
|
|
client := NewInternalServiceHTTPClient(timeout)
|
|
|
|
if client.Transport == nil {
|
|
t.Fatal("expected Transport to be set")
|
|
}
|
|
|
|
transport, ok := client.Transport.(*http.Transport)
|
|
if !ok {
|
|
t.Fatal("expected Transport to be *http.Transport")
|
|
}
|
|
|
|
// Verify proxy is nil (ignores proxy environment variables)
|
|
if transport.Proxy != nil {
|
|
t.Error("expected Proxy to be nil for SSRF protection")
|
|
}
|
|
|
|
// Verify keep-alives are disabled
|
|
if !transport.DisableKeepAlives {
|
|
t.Error("expected DisableKeepAlives to be true")
|
|
}
|
|
|
|
// Verify MaxIdleConns
|
|
if transport.MaxIdleConns != 1 {
|
|
t.Errorf("expected MaxIdleConns to be 1, got %d", transport.MaxIdleConns)
|
|
}
|
|
|
|
// Verify timeout settings
|
|
if transport.IdleConnTimeout != timeout {
|
|
t.Errorf("expected IdleConnTimeout %v, got %v", timeout, transport.IdleConnTimeout)
|
|
}
|
|
if transport.TLSHandshakeTimeout != timeout {
|
|
t.Errorf("expected TLSHandshakeTimeout %v, got %v", timeout, transport.TLSHandshakeTimeout)
|
|
}
|
|
if transport.ResponseHeaderTimeout != timeout {
|
|
t.Errorf("expected ResponseHeaderTimeout %v, got %v", timeout, transport.ResponseHeaderTimeout)
|
|
}
|
|
}
|
|
|
|
func TestNewInternalServiceHTTPClient_RedirectsDisabled(t *testing.T) {
|
|
// Create a test server that redirects
|
|
redirectCount := 0
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
redirectCount++
|
|
if r.URL.Path == "/" {
|
|
http.Redirect(w, r, "/redirected", http.StatusFound)
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte("redirected"))
|
|
}))
|
|
defer server.Close()
|
|
|
|
client := NewInternalServiceHTTPClient(5 * time.Second)
|
|
|
|
resp, err := client.Get(server.URL)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
// Should receive the redirect response, not follow it
|
|
if resp.StatusCode != http.StatusFound {
|
|
t.Errorf("expected status %d (redirect not followed), got %d", http.StatusFound, resp.StatusCode)
|
|
}
|
|
|
|
// Verify only one request was made (redirect was not followed)
|
|
if redirectCount != 1 {
|
|
t.Errorf("expected exactly 1 request, got %d (redirect was followed)", redirectCount)
|
|
}
|
|
}
|
|
|
|
func TestNewInternalServiceHTTPClient_CheckRedirectReturnsErrUseLastResponse(t *testing.T) {
|
|
client := NewInternalServiceHTTPClient(5 * time.Second)
|
|
|
|
if client.CheckRedirect == nil {
|
|
t.Fatal("expected CheckRedirect to be set")
|
|
}
|
|
|
|
// Create a dummy request to test CheckRedirect
|
|
req, _ := http.NewRequest("GET", "http://example.com", http.NoBody)
|
|
err := client.CheckRedirect(req, nil)
|
|
|
|
if err != http.ErrUseLastResponse {
|
|
t.Errorf("expected CheckRedirect to return http.ErrUseLastResponse, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestNewInternalServiceHTTPClient_ActualRequest(t *testing.T) {
|
|
// Create a test server
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(`{"status":"ok"}`))
|
|
}))
|
|
defer server.Close()
|
|
|
|
client := NewInternalServiceHTTPClient(5 * time.Second)
|
|
|
|
resp, err := client.Get(server.URL)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Errorf("expected status 200, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestNewInternalServiceHTTPClient_TimeoutEnforced(t *testing.T) {
|
|
// Create a slow server that delays longer than the timeout
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
time.Sleep(500 * time.Millisecond)
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer server.Close()
|
|
|
|
// Use a very short timeout
|
|
client := NewInternalServiceHTTPClient(100 * time.Millisecond)
|
|
|
|
_, err := client.Get(server.URL)
|
|
if err == nil {
|
|
t.Error("expected timeout error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestNewInternalServiceHTTPClient_MultipleClients(t *testing.T) {
|
|
// Verify that multiple clients can be created with different timeouts
|
|
client1 := NewInternalServiceHTTPClient(1 * time.Second)
|
|
client2 := NewInternalServiceHTTPClient(10 * time.Second)
|
|
|
|
if client1 == client2 {
|
|
t.Error("expected different client instances")
|
|
}
|
|
|
|
if client1.Timeout != 1*time.Second {
|
|
t.Errorf("client1 expected timeout 1s, got %v", client1.Timeout)
|
|
}
|
|
if client2.Timeout != 10*time.Second {
|
|
t.Errorf("client2 expected timeout 10s, got %v", client2.Timeout)
|
|
}
|
|
}
|
|
|
|
func TestNewInternalServiceHTTPClient_ProxyIgnored(t *testing.T) {
|
|
// Set up a server to verify no proxy is used
|
|
directServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte("direct"))
|
|
}))
|
|
defer directServer.Close()
|
|
|
|
client := NewInternalServiceHTTPClient(5 * time.Second)
|
|
|
|
// Even if environment has proxy settings, this client should ignore them
|
|
// because transport.Proxy is set to nil
|
|
transport := client.Transport.(*http.Transport)
|
|
if transport.Proxy != nil {
|
|
t.Error("expected Proxy to be nil (proxy env vars should be ignored)")
|
|
}
|
|
|
|
resp, err := client.Get(directServer.URL)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Errorf("expected status 200, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestNewInternalServiceHTTPClient_PostRequest(t *testing.T) {
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
t.Errorf("expected POST method, got %s", r.Method)
|
|
}
|
|
w.WriteHeader(http.StatusCreated)
|
|
}))
|
|
defer server.Close()
|
|
|
|
client := NewInternalServiceHTTPClient(5 * time.Second)
|
|
|
|
resp, err := client.Post(server.URL, "application/json", nil)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusCreated {
|
|
t.Errorf("expected status 201, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
// Benchmark tests
|
|
|
|
func BenchmarkNewInternalServiceHTTPClient(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
NewInternalServiceHTTPClient(5 * time.Second)
|
|
}
|
|
}
|
|
|
|
func BenchmarkNewInternalServiceHTTPClient_Request(b *testing.B) {
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer server.Close()
|
|
|
|
client := NewInternalServiceHTTPClient(5 * time.Second)
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
resp, err := client.Get(server.URL)
|
|
if err == nil {
|
|
resp.Body.Close()
|
|
}
|
|
}
|
|
}
|