add the feature for observability
This commit is contained in:
346
pkg/metrics/requests_test.go
Normal file
346
pkg/metrics/requests_test.go
Normal file
@@ -0,0 +1,346 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestInitRequestMetrics(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
enabled bool
|
||||
wantError bool
|
||||
}{
|
||||
{
|
||||
name: "metrics enabled",
|
||||
enabled: true,
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "metrics disabled",
|
||||
enabled: false,
|
||||
wantError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Setup: Initialize metrics with enabled state
|
||||
cfg := Config{
|
||||
Enabled: tt.enabled,
|
||||
ExporterType: ExporterPrometheus,
|
||||
ServiceName: "test-service",
|
||||
}
|
||||
err := InitMetrics(cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test InitRequestMetrics
|
||||
err = InitRequestMetrics()
|
||||
if tt.wantError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
Shutdown(context.Background())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecordInboundRequest(t *testing.T) {
|
||||
// Setup
|
||||
cfg := Config{
|
||||
Enabled: true,
|
||||
ExporterType: ExporterPrometheus,
|
||||
ServiceName: "test-service",
|
||||
}
|
||||
err := InitMetrics(cfg)
|
||||
require.NoError(t, err)
|
||||
defer Shutdown(context.Background())
|
||||
|
||||
err = InitRequestMetrics()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
host := "example.com"
|
||||
|
||||
// Test: Record inbound request
|
||||
RecordInboundRequest(ctx, host)
|
||||
|
||||
// Verify: No error should occur
|
||||
// Note: We can't easily verify the metric value without exporting,
|
||||
// but we can verify the function doesn't panic
|
||||
assert.NotPanics(t, func() {
|
||||
RecordInboundRequest(ctx, host)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRecordInboundSignValidation(t *testing.T) {
|
||||
// Setup
|
||||
cfg := Config{
|
||||
Enabled: true,
|
||||
ExporterType: ExporterPrometheus,
|
||||
ServiceName: "test-service",
|
||||
}
|
||||
err := InitMetrics(cfg)
|
||||
require.NoError(t, err)
|
||||
defer Shutdown(context.Background())
|
||||
|
||||
err = InitRequestMetrics()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
host := "example.com"
|
||||
|
||||
// Test: Record sign validation
|
||||
RecordInboundSignValidation(ctx, host)
|
||||
|
||||
// Verify: No error should occur
|
||||
assert.NotPanics(t, func() {
|
||||
RecordInboundSignValidation(ctx, host)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRecordInboundSchemaValidation(t *testing.T) {
|
||||
// Setup
|
||||
cfg := Config{
|
||||
Enabled: true,
|
||||
ExporterType: ExporterPrometheus,
|
||||
ServiceName: "test-service",
|
||||
}
|
||||
err := InitMetrics(cfg)
|
||||
require.NoError(t, err)
|
||||
defer Shutdown(context.Background())
|
||||
|
||||
err = InitRequestMetrics()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
host := "example.com"
|
||||
|
||||
// Test: Record schema validation
|
||||
RecordInboundSchemaValidation(ctx, host)
|
||||
|
||||
// Verify: No error should occur
|
||||
assert.NotPanics(t, func() {
|
||||
RecordInboundSchemaValidation(ctx, host)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRecordOutboundRequest(t *testing.T) {
|
||||
// Setup
|
||||
cfg := Config{
|
||||
Enabled: true,
|
||||
ExporterType: ExporterPrometheus,
|
||||
ServiceName: "test-service",
|
||||
}
|
||||
err := InitMetrics(cfg)
|
||||
require.NoError(t, err)
|
||||
defer Shutdown(context.Background())
|
||||
|
||||
err = InitRequestMetrics()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
host := "example.com"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
statusCode int
|
||||
duration time.Duration
|
||||
}{
|
||||
{
|
||||
name: "2XX status code",
|
||||
statusCode: 200,
|
||||
duration: 100 * time.Millisecond,
|
||||
},
|
||||
{
|
||||
name: "4XX status code",
|
||||
statusCode: 404,
|
||||
duration: 50 * time.Millisecond,
|
||||
},
|
||||
{
|
||||
name: "5XX status code",
|
||||
statusCode: 500,
|
||||
duration: 200 * time.Millisecond,
|
||||
},
|
||||
{
|
||||
name: "3XX status code",
|
||||
statusCode: 301,
|
||||
duration: 75 * time.Millisecond,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Test: Record outbound request
|
||||
RecordOutboundRequest(ctx, host, tt.statusCode, tt.duration)
|
||||
|
||||
// Verify: No error should occur
|
||||
assert.NotPanics(t, func() {
|
||||
RecordOutboundRequest(ctx, host, tt.statusCode, tt.duration)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPTransport_RoundTrip(t *testing.T) {
|
||||
// Setup
|
||||
cfg := Config{
|
||||
Enabled: true,
|
||||
ExporterType: ExporterPrometheus,
|
||||
ServiceName: "test-service",
|
||||
}
|
||||
err := InitMetrics(cfg)
|
||||
require.NoError(t, err)
|
||||
defer Shutdown(context.Background())
|
||||
|
||||
err = InitRequestMetrics()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a test server
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("OK"))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
// Create transport wrapper
|
||||
transport := &HTTPTransport{
|
||||
Transport: http.DefaultTransport,
|
||||
}
|
||||
|
||||
// Create request
|
||||
req, err := http.NewRequest("GET", server.URL, nil)
|
||||
require.NoError(t, err)
|
||||
req = req.WithContext(context.Background())
|
||||
|
||||
// Test: RoundTrip should track metrics
|
||||
resp, err := transport.RoundTrip(req)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
// Verify: Metrics should be recorded
|
||||
assert.NotPanics(t, func() {
|
||||
resp, err = transport.RoundTrip(req)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, resp)
|
||||
})
|
||||
}
|
||||
|
||||
func TestHTTPTransport_RoundTrip_Error(t *testing.T) {
|
||||
// Setup
|
||||
cfg := Config{
|
||||
Enabled: true,
|
||||
ExporterType: ExporterPrometheus,
|
||||
ServiceName: "test-service",
|
||||
}
|
||||
err := InitMetrics(cfg)
|
||||
require.NoError(t, err)
|
||||
defer Shutdown(context.Background())
|
||||
|
||||
err = InitRequestMetrics()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create transport with invalid URL to cause error
|
||||
transport := &HTTPTransport{
|
||||
Transport: http.DefaultTransport,
|
||||
}
|
||||
|
||||
// Create request with invalid URL
|
||||
req, err := http.NewRequest("GET", "http://invalid-host-that-does-not-exist:9999", nil)
|
||||
require.NoError(t, err)
|
||||
req = req.WithContext(context.Background())
|
||||
|
||||
// Test: RoundTrip should handle error and still record metrics
|
||||
resp, err := transport.RoundTrip(req)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, resp)
|
||||
|
||||
// Verify: Metrics should still be recorded (with 500 status)
|
||||
assert.NotPanics(t, func() {
|
||||
_, _ = transport.RoundTrip(req)
|
||||
})
|
||||
}
|
||||
|
||||
func TestWrapHTTPTransport_Enabled(t *testing.T) {
|
||||
// Setup
|
||||
cfg := Config{
|
||||
Enabled: true,
|
||||
ExporterType: ExporterPrometheus,
|
||||
ServiceName: "test-service",
|
||||
}
|
||||
err := InitMetrics(cfg)
|
||||
require.NoError(t, err)
|
||||
defer Shutdown(context.Background())
|
||||
|
||||
// Create a new transport
|
||||
transport := http.DefaultTransport.(*http.Transport).Clone()
|
||||
|
||||
// Test: Wrap transport
|
||||
wrapped := WrapHTTPTransport(transport)
|
||||
|
||||
// Verify: Should be wrapped
|
||||
assert.NotEqual(t, transport, wrapped)
|
||||
_, ok := wrapped.(*HTTPTransport)
|
||||
assert.True(t, ok, "Should be wrapped with HTTPTransport")
|
||||
}
|
||||
|
||||
func TestWrapHTTPTransport_Disabled(t *testing.T) {
|
||||
// Setup: Initialize metrics with disabled state
|
||||
cfg := Config{
|
||||
Enabled: false,
|
||||
ExporterType: ExporterPrometheus,
|
||||
ServiceName: "test-service",
|
||||
}
|
||||
err := InitMetrics(cfg)
|
||||
require.NoError(t, err)
|
||||
defer Shutdown(context.Background())
|
||||
|
||||
// Create a new transport
|
||||
transport := http.DefaultTransport.(*http.Transport).Clone()
|
||||
|
||||
// Test: Wrap transport when metrics disabled
|
||||
wrapped := WrapHTTPTransport(transport)
|
||||
|
||||
// Verify: When metrics are disabled, IsEnabled() returns false
|
||||
// So WrapHTTPTransport should return the original transport
|
||||
// Note: This test verifies the behavior when IsEnabled() returns false
|
||||
if !IsEnabled() {
|
||||
assert.Equal(t, transport, wrapped, "Should return original transport when metrics disabled")
|
||||
} else {
|
||||
// If metrics are still enabled from previous test, just verify it doesn't panic
|
||||
assert.NotNil(t, wrapped)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecordInboundRequest_WhenDisabled(t *testing.T) {
|
||||
// Setup: Metrics disabled
|
||||
cfg := Config{
|
||||
Enabled: false,
|
||||
ExporterType: ExporterPrometheus,
|
||||
ServiceName: "test-service",
|
||||
}
|
||||
err := InitMetrics(cfg)
|
||||
require.NoError(t, err)
|
||||
defer Shutdown(context.Background())
|
||||
|
||||
ctx := context.Background()
|
||||
host := "example.com"
|
||||
|
||||
// Test: Should not panic when metrics are disabled
|
||||
assert.NotPanics(t, func() {
|
||||
RecordInboundRequest(ctx, host)
|
||||
RecordInboundSignValidation(ctx, host)
|
||||
RecordInboundSchemaValidation(ctx, host)
|
||||
RecordOutboundRequest(ctx, host, 200, time.Second)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user