196 lines
5.3 KiB
Go
196 lines
5.3 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestNewHTTPClient(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
config HttpClientConfig
|
|
expected struct {
|
|
maxIdleConns int
|
|
maxIdleConnsPerHost int
|
|
idleConnTimeout time.Duration
|
|
responseHeaderTimeout time.Duration
|
|
}
|
|
}{
|
|
{
|
|
name: "all values configured",
|
|
config: HttpClientConfig{
|
|
MaxIdleConns: 1000,
|
|
MaxIdleConnsPerHost: 200,
|
|
IdleConnTimeout: 300 * time.Second,
|
|
ResponseHeaderTimeout: 5 * time.Second,
|
|
},
|
|
expected: struct {
|
|
maxIdleConns int
|
|
maxIdleConnsPerHost int
|
|
idleConnTimeout time.Duration
|
|
responseHeaderTimeout time.Duration
|
|
}{
|
|
maxIdleConns: 1000,
|
|
maxIdleConnsPerHost: 200,
|
|
idleConnTimeout: 300 * time.Second,
|
|
responseHeaderTimeout: 5 * time.Second,
|
|
},
|
|
},
|
|
{
|
|
name: "zero values use defaults",
|
|
config: HttpClientConfig{},
|
|
expected: struct {
|
|
maxIdleConns int
|
|
maxIdleConnsPerHost int
|
|
idleConnTimeout time.Duration
|
|
responseHeaderTimeout time.Duration
|
|
}{
|
|
maxIdleConns: 100, // Go default
|
|
maxIdleConnsPerHost: 0, // Go default (unlimited per host)
|
|
idleConnTimeout: 90 * time.Second,
|
|
responseHeaderTimeout: 0,
|
|
},
|
|
},
|
|
{
|
|
name: "partial configuration",
|
|
config: HttpClientConfig{
|
|
MaxIdleConns: 500,
|
|
IdleConnTimeout: 180 * time.Second,
|
|
},
|
|
expected: struct {
|
|
maxIdleConns int
|
|
maxIdleConnsPerHost int
|
|
idleConnTimeout time.Duration
|
|
responseHeaderTimeout time.Duration
|
|
}{
|
|
maxIdleConns: 500,
|
|
maxIdleConnsPerHost: 0, // Go default (unlimited per host)
|
|
idleConnTimeout: 180 * time.Second,
|
|
responseHeaderTimeout: 0,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
client := newHTTPClient(&tt.config, nil)
|
|
|
|
if client == nil {
|
|
t.Fatal("newHTTPClient returned nil")
|
|
}
|
|
|
|
transport, ok := client.Transport.(*http.Transport)
|
|
if !ok {
|
|
t.Fatal("client transport is not *http.Transport")
|
|
}
|
|
|
|
if transport.MaxIdleConns != tt.expected.maxIdleConns {
|
|
t.Errorf("MaxIdleConns = %d, want %d", transport.MaxIdleConns, tt.expected.maxIdleConns)
|
|
}
|
|
|
|
if transport.MaxIdleConnsPerHost != tt.expected.maxIdleConnsPerHost {
|
|
t.Errorf("MaxIdleConnsPerHost = %d, want %d", transport.MaxIdleConnsPerHost, tt.expected.maxIdleConnsPerHost)
|
|
}
|
|
|
|
if transport.IdleConnTimeout != tt.expected.idleConnTimeout {
|
|
t.Errorf("IdleConnTimeout = %v, want %v", transport.IdleConnTimeout, tt.expected.idleConnTimeout)
|
|
}
|
|
|
|
if transport.ResponseHeaderTimeout != tt.expected.responseHeaderTimeout {
|
|
t.Errorf("ResponseHeaderTimeout = %v, want %v", transport.ResponseHeaderTimeout, tt.expected.responseHeaderTimeout)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestHttpClientConfigDefaults(t *testing.T) {
|
|
// Test that zero config values don't override defaults
|
|
config := &HttpClientConfig{}
|
|
client := newHTTPClient(config, nil)
|
|
|
|
transport := client.Transport.(*http.Transport)
|
|
|
|
// Verify defaults are preserved when config values are zero
|
|
if transport.MaxIdleConns == 0 {
|
|
t.Error("MaxIdleConns should not be zero when using defaults")
|
|
}
|
|
|
|
// MaxIdleConnsPerHost default is 0 (unlimited), which is correct
|
|
if transport.MaxIdleConns != 100 {
|
|
t.Errorf("Expected default MaxIdleConns=100, got %d", transport.MaxIdleConns)
|
|
}
|
|
}
|
|
|
|
func TestHttpClientConfigPerformanceValues(t *testing.T) {
|
|
// Test the specific performance-optimized values from the document
|
|
config := &HttpClientConfig{
|
|
MaxIdleConns: 1000,
|
|
MaxIdleConnsPerHost: 200,
|
|
IdleConnTimeout: 300 * time.Second,
|
|
ResponseHeaderTimeout: 5 * time.Second,
|
|
}
|
|
|
|
client := newHTTPClient(config, nil)
|
|
transport := client.Transport.(*http.Transport)
|
|
|
|
// Verify performance-optimized values
|
|
if transport.MaxIdleConns != 1000 {
|
|
t.Errorf("Expected MaxIdleConns=1000, got %d", transport.MaxIdleConns)
|
|
}
|
|
|
|
if transport.MaxIdleConnsPerHost != 200 {
|
|
t.Errorf("Expected MaxIdleConnsPerHost=200, got %d", transport.MaxIdleConnsPerHost)
|
|
}
|
|
|
|
if transport.IdleConnTimeout != 300*time.Second {
|
|
t.Errorf("Expected IdleConnTimeout=300s, got %v", transport.IdleConnTimeout)
|
|
}
|
|
|
|
if transport.ResponseHeaderTimeout != 5*time.Second {
|
|
t.Errorf("Expected ResponseHeaderTimeout=5s, got %v", transport.ResponseHeaderTimeout)
|
|
}
|
|
}
|
|
|
|
func TestNewHTTPClientWithTransportWrapper(t *testing.T) {
|
|
wrappedTransport := &mockRoundTripper{}
|
|
wrapper := &mockTransportWrapper{
|
|
returnTransport: wrappedTransport,
|
|
}
|
|
|
|
client := newHTTPClient(&HttpClientConfig{}, wrapper)
|
|
|
|
if !wrapper.wrapCalled {
|
|
t.Fatal("expected transport wrapper to be invoked")
|
|
}
|
|
|
|
if wrapper.wrappedTransport == nil {
|
|
t.Fatal("expected base transport to be passed to wrapper")
|
|
}
|
|
|
|
if client.Transport != wrappedTransport {
|
|
t.Errorf("expected client transport to use wrapper transport")
|
|
}
|
|
}
|
|
|
|
type mockTransportWrapper struct {
|
|
wrapCalled bool
|
|
wrappedTransport http.RoundTripper
|
|
returnTransport http.RoundTripper
|
|
}
|
|
|
|
func (m *mockTransportWrapper) Wrap(base http.RoundTripper) http.RoundTripper {
|
|
m.wrapCalled = true
|
|
m.wrappedTransport = base
|
|
if m.returnTransport != nil {
|
|
return m.returnTransport
|
|
}
|
|
return base
|
|
}
|
|
|
|
type mockRoundTripper struct{}
|
|
|
|
func (m *mockRoundTripper) RoundTrip(_ *http.Request) (*http.Response, error) {
|
|
return nil, nil
|
|
}
|