Files
graphql-monitoring-proxy/safe_uint32_test.go
T
lukaszraczylo cedee416a8 improvements mid may 2025 (#24)
* General improvements and bug fixes.

* Improve tests coverage.

* fixup! Improve tests coverage.

* Update README.md with latest changes.

* Fix the uint32

* Resolve issue with race condition for logging.

* fixup! Merge remote-tracking branch 'origin/main' into improvements-mid-apr-2025

* Fix the test of the rate limiter

* Add default ratelimit.json file

* Update dependencies.

* Significant refactor.

* fixup! Significant refactor.

* fixup! Merge remote-tracking branch 'origin/main' into improvements-mid-apr-2025

* fixup! fixup! Merge remote-tracking branch 'origin/main' into improvements-mid-apr-2025

* fixup! fixup! fixup! Merge remote-tracking branch 'origin/main' into improvements-mid-apr-2025

* fixup! fixup! fixup! fixup! fixup! Merge remote-tracking branch 'origin/main' into improvements-mid-apr-2025

* fixup! fixup! fixup! fixup! fixup! fixup! Merge remote-tracking branch 'origin/main' into improvements-mid-apr-2025

* fixup! fixup! fixup! fixup! fixup! fixup! fixup! Merge remote-tracking branch 'origin/main' into improvements-mid-apr-2025

* fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! Merge remote-tracking branch 'origin/main' into improvements-mid-apr-2025

* fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! Merge remote-tracking branch 'origin/main' into improvements-mid-apr-2025

* fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! Merge remote-tracking branch 'origin/main' into improvements-mid-apr-2025
2025-09-30 18:27:33 +01:00

216 lines
6.3 KiB
Go

package main
import (
"bytes"
"fmt"
"math"
"strings"
"testing"
libpack_logger "github.com/lukaszraczylo/graphql-monitoring-proxy/logging"
"github.com/stretchr/testify/suite"
)
// SafeUint32TestSuite is a test suite for safe integer conversion functionality
type SafeUint32TestSuite struct {
suite.Suite
originalConfig *config
outputBuffer *bytes.Buffer // Used to capture logger output
}
func (suite *SafeUint32TestSuite) SetupTest() {
// Store original config to restore later
suite.originalConfig = cfg
// Create a buffer to capture logger output
suite.outputBuffer = &bytes.Buffer{}
// Setup a new config with a real logger that writes to our buffer
cfg = &config{}
cfg.Logger = libpack_logger.New().SetOutput(suite.outputBuffer)
}
func (suite *SafeUint32TestSuite) TearDownTest() {
// Restore original config
cfg = suite.originalConfig
}
// Helper function to check if a specific message appears in the logger output
func (suite *SafeUint32TestSuite) logContains(substring string) bool {
return strings.Contains(suite.outputBuffer.String(), substring)
}
// TestSafeUint32 tests the safeUint32 function with various input values
func (suite *SafeUint32TestSuite) TestSafeUint32() {
testCases := []struct {
name string
input int
expected uint32
}{
{
name: "negative value",
input: -10,
expected: 0,
},
{
name: "zero value",
input: 0,
expected: 0,
},
{
name: "small positive value",
input: 42,
expected: 42,
},
{
name: "maximum uint32 value",
input: math.MaxUint32,
expected: math.MaxUint32,
},
{
name: "value exceeding uint32 maximum",
input: math.MaxUint32 + 1,
expected: math.MaxUint32,
},
{
name: "large negative value",
input: -1000000,
expected: 0,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
result := safeUint32(tc.input)
suite.Equal(tc.expected, result, fmt.Sprintf("safeUint32(%d) should return %d", tc.input, tc.expected))
})
}
}
// TestSafeMaxRequests tests the safeMaxRequests function
func (suite *SafeUint32TestSuite) TestSafeMaxRequests() {
testCases := []struct {
name string
warningMessage string
input int
expected uint32
expectWarning bool
}{
{
name: "negative value",
input: -10,
expected: uint32(defaultMaxRequestsInHalfOpen),
expectWarning: true,
warningMessage: "Invalid MaxRequestsInHalfOpen value, using default",
},
{
name: "zero value",
input: 0,
expected: 0,
expectWarning: false,
},
{
name: "normal value",
input: 5,
expected: 5,
expectWarning: false,
},
{
name: "value exceeding uint32 maximum",
input: math.MaxUint32 + 1,
expected: uint32(defaultMaxRequestsInHalfOpen),
expectWarning: true,
warningMessage: "Invalid MaxRequestsInHalfOpen value, using default",
},
{
name: "value at uint32 maximum",
input: math.MaxUint32,
expected: math.MaxUint32,
expectWarning: false,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
// Reset the logger buffer before each test case
suite.outputBuffer.Reset()
// Call function
result := safeMaxRequests(tc.input)
// Verify result
suite.Equal(tc.expected, result, fmt.Sprintf("safeMaxRequests(%d) should return %d", tc.input, tc.expected))
// Verify logging behavior
if tc.expectWarning {
suite.True(suite.logContains(tc.warningMessage), "Expected warning message not found in logs")
suite.True(suite.logContains(fmt.Sprintf(`"requested_value":%d`, tc.input)), "Requested value not found in warning log")
suite.True(suite.logContains(fmt.Sprintf(`"default_value":%d`, defaultMaxRequestsInHalfOpen)), "Default value not found in warning log")
} else {
suite.False(suite.logContains("Invalid MaxRequestsInHalfOpen value"), "Unexpected warning message found in logs")
}
})
}
}
// TestSafeMaxRequestsWithNilLogger tests safeMaxRequests when the logger is nil
func (suite *SafeUint32TestSuite) TestSafeMaxRequestsWithNilLogger() {
// Save the current logger
originalLogger := cfg.Logger
// Set logger to nil
cfg.Logger = nil
// Test with values that would normally trigger a warning
result := safeMaxRequests(-5)
suite.Equal(uint32(defaultMaxRequestsInHalfOpen), result, "Even with nil logger, function should return default value for invalid input")
// Restore the logger
cfg.Logger = originalLogger
}
// TestCircuitBreakerWithSafeValues tests that the circuit breaker correctly uses the safe functions
func (suite *SafeUint32TestSuite) TestCircuitBreakerWithSafeValues() {
// Skip circuit breaker integration test since we're only testing the safe conversion functions
// This avoids the need to fully mock the monitoring system
// Just test the trip function logic directly
cfg.CircuitBreaker.MaxFailures = -1 // Negative value should be converted to 0 by safeUint32
// Call safeUint32 directly to verify it handles negative value
safeValue := safeUint32(cfg.CircuitBreaker.MaxFailures)
suite.Equal(uint32(0), safeValue, "safeUint32 should convert negative value to 0")
// A ConsecutiveFailures count of 1 should be >= safeUint32(-1) which is 0
suite.True(uint32(1) >= safeValue, "1 should be >= safeUint32(negative value)")
// Test with excessive MaxRequestsInHalfOpen directly
excessiveValue := math.MaxUint32 + 1
// Reset the logger buffer to verify warning
suite.outputBuffer.Reset()
// Call safeMaxRequests directly
maxRequests := safeMaxRequests(excessiveValue)
// Verify the result
suite.Equal(uint32(defaultMaxRequestsInHalfOpen), maxRequests,
"safeMaxRequests should return default value for excessive input")
// Check the warning was logged
suite.True(suite.logContains("Invalid MaxRequestsInHalfOpen value"),
"Warning about invalid MaxRequestsInHalfOpen should be logged")
// Verify log contains the expected values
suite.True(suite.logContains(fmt.Sprintf(`"requested_value":%d`, excessiveValue)),
"Requested value not found in warning log")
suite.True(suite.logContains(fmt.Sprintf(`"default_value":%d`, defaultMaxRequestsInHalfOpen)),
"Default value not found in warning log")
}
// Start the test suite
func TestSafeUint32Suite(t *testing.T) {
suite.Run(t, new(SafeUint32TestSuite))
}