mirror of
https://github.com/lukaszraczylo/graphql-monitoring-proxy.git
synced 2026-06-05 23:03:48 +00:00
cedee416a8
* 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
335 lines
7.0 KiB
Go
335 lines
7.0 KiB
Go
package main
|
|
|
|
import (
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
libpack_logging "github.com/lukaszraczylo/graphql-monitoring-proxy/logging"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/suite"
|
|
"github.com/valyala/fasthttp"
|
|
)
|
|
|
|
type ConnectionPoolTestSuite struct {
|
|
suite.Suite
|
|
origCfg *config
|
|
origConnectionManager *ConnectionPoolManager
|
|
}
|
|
|
|
func TestConnectionPoolTestSuite(t *testing.T) {
|
|
suite.Run(t, new(ConnectionPoolTestSuite))
|
|
}
|
|
|
|
func (suite *ConnectionPoolTestSuite) SetupTest() {
|
|
suite.origCfg = cfg
|
|
cfg = &config{
|
|
Logger: libpack_logging.New(),
|
|
}
|
|
suite.origConnectionManager = connectionPoolManager
|
|
connectionPoolManager = nil
|
|
}
|
|
|
|
func (suite *ConnectionPoolTestSuite) TearDownTest() {
|
|
if connectionPoolManager != nil {
|
|
connectionPoolManager.Shutdown()
|
|
connectionPoolManager = nil
|
|
}
|
|
cfg = suite.origCfg
|
|
connectionPoolManager = suite.origConnectionManager
|
|
}
|
|
|
|
func (suite *ConnectionPoolTestSuite) TestNewConnectionPoolManager() {
|
|
client := &fasthttp.Client{
|
|
MaxConnsPerHost: 100,
|
|
}
|
|
|
|
cpm := NewConnectionPoolManager(client)
|
|
assert.NotNil(suite.T(), cpm)
|
|
assert.NotNil(suite.T(), cpm.client)
|
|
assert.NotNil(suite.T(), cpm.ctx)
|
|
assert.NotNil(suite.T(), cpm.cancel)
|
|
|
|
// Cleanup
|
|
cpm.Shutdown()
|
|
}
|
|
|
|
func (suite *ConnectionPoolTestSuite) TestGetClient() {
|
|
client := &fasthttp.Client{
|
|
MaxConnsPerHost: 100,
|
|
}
|
|
|
|
cpm := NewConnectionPoolManager(client)
|
|
defer cpm.Shutdown()
|
|
|
|
retrievedClient := cpm.GetClient()
|
|
assert.Equal(suite.T(), client, retrievedClient)
|
|
}
|
|
|
|
func (suite *ConnectionPoolTestSuite) TestShutdown() {
|
|
client := &fasthttp.Client{
|
|
MaxConnsPerHost: 100,
|
|
}
|
|
|
|
cpm := NewConnectionPoolManager(client)
|
|
|
|
// Shutdown should be safe
|
|
err := cpm.Shutdown()
|
|
assert.NoError(suite.T(), err)
|
|
|
|
// Multiple shutdowns should be safe
|
|
err = cpm.Shutdown()
|
|
assert.NoError(suite.T(), err)
|
|
}
|
|
|
|
func (suite *ConnectionPoolTestSuite) TestShutdownNil() {
|
|
var cpm *ConnectionPoolManager
|
|
err := cpm.Shutdown()
|
|
assert.NoError(suite.T(), err)
|
|
}
|
|
|
|
func (suite *ConnectionPoolTestSuite) TestPeriodicCleanup() {
|
|
client := &fasthttp.Client{
|
|
MaxConnsPerHost: 100,
|
|
}
|
|
|
|
cpm := NewConnectionPoolManager(client)
|
|
|
|
// Let the cleanup goroutine run
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
// Shutdown should stop the cleanup goroutine
|
|
err := cpm.Shutdown()
|
|
assert.NoError(suite.T(), err)
|
|
}
|
|
|
|
func (suite *ConnectionPoolTestSuite) TestCleanIdleConnections() {
|
|
client := &fasthttp.Client{
|
|
MaxConnsPerHost: 100,
|
|
}
|
|
|
|
cpm := NewConnectionPoolManager(client)
|
|
defer cpm.Shutdown()
|
|
|
|
// Manually trigger cleanup
|
|
cpm.cleanIdleConnections()
|
|
|
|
// Should not panic or error
|
|
assert.NotNil(suite.T(), cpm.client)
|
|
}
|
|
|
|
func (suite *ConnectionPoolTestSuite) TestConcurrentAccess() {
|
|
client := &fasthttp.Client{
|
|
MaxConnsPerHost: 100,
|
|
}
|
|
|
|
cpm := NewConnectionPoolManager(client)
|
|
defer cpm.Shutdown()
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
// Concurrent reads
|
|
for i := 0; i < 10; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
for j := 0; j < 100; j++ {
|
|
c := cpm.GetClient()
|
|
assert.NotNil(suite.T(), c)
|
|
time.Sleep(time.Microsecond)
|
|
}
|
|
}()
|
|
}
|
|
|
|
// Concurrent cleanups
|
|
for i := 0; i < 5; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
for j := 0; j < 10; j++ {
|
|
cpm.cleanIdleConnections()
|
|
time.Sleep(time.Millisecond)
|
|
}
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
}
|
|
|
|
func (suite *ConnectionPoolTestSuite) TestInitializeConnectionPool() {
|
|
client := &fasthttp.Client{
|
|
MaxConnsPerHost: 200,
|
|
}
|
|
|
|
InitializeConnectionPool(client)
|
|
assert.NotNil(suite.T(), connectionPoolManager)
|
|
assert.Equal(suite.T(), client, connectionPoolManager.GetClient())
|
|
|
|
// Initialize again should replace the old one
|
|
newClient := &fasthttp.Client{
|
|
MaxConnsPerHost: 300,
|
|
}
|
|
InitializeConnectionPool(newClient)
|
|
assert.Equal(suite.T(), newClient, connectionPoolManager.GetClient())
|
|
}
|
|
|
|
func (suite *ConnectionPoolTestSuite) TestShutdownConnectionPool() {
|
|
client := &fasthttp.Client{
|
|
MaxConnsPerHost: 100,
|
|
}
|
|
|
|
InitializeConnectionPool(client)
|
|
assert.NotNil(suite.T(), connectionPoolManager)
|
|
|
|
ShutdownConnectionPool()
|
|
assert.Nil(suite.T(), connectionPoolManager)
|
|
|
|
// Shutdown again should be safe
|
|
ShutdownConnectionPool()
|
|
assert.Nil(suite.T(), connectionPoolManager)
|
|
}
|
|
|
|
func (suite *ConnectionPoolTestSuite) TestGetConnectionPoolManager() {
|
|
assert.Nil(suite.T(), GetConnectionPoolManager())
|
|
|
|
client := &fasthttp.Client{
|
|
MaxConnsPerHost: 100,
|
|
}
|
|
InitializeConnectionPool(client)
|
|
|
|
manager := GetConnectionPoolManager()
|
|
assert.NotNil(suite.T(), manager)
|
|
assert.Equal(suite.T(), connectionPoolManager, manager)
|
|
|
|
ShutdownConnectionPool()
|
|
assert.Nil(suite.T(), GetConnectionPoolManager())
|
|
}
|
|
|
|
func (suite *ConnectionPoolTestSuite) TestContextCancellation() {
|
|
client := &fasthttp.Client{
|
|
MaxConnsPerHost: 100,
|
|
}
|
|
|
|
cpm := NewConnectionPoolManager(client)
|
|
|
|
// Cancel the context
|
|
cpm.cancel()
|
|
|
|
// Give the cleanup goroutine time to exit
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
// Shutdown should still work
|
|
err := cpm.Shutdown()
|
|
assert.NoError(suite.T(), err)
|
|
}
|
|
|
|
func (suite *ConnectionPoolTestSuite) TestRaceConditions() {
|
|
client := &fasthttp.Client{
|
|
MaxConnsPerHost: 100,
|
|
}
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
// Concurrent initialization and shutdown
|
|
for i := 0; i < 10; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
InitializeConnectionPool(client)
|
|
}()
|
|
}
|
|
|
|
for i := 0; i < 5; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
time.Sleep(time.Microsecond)
|
|
ShutdownConnectionPool()
|
|
}()
|
|
}
|
|
|
|
for i := 0; i < 10; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
manager := GetConnectionPoolManager()
|
|
if manager != nil {
|
|
_ = manager.GetClient()
|
|
}
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
}
|
|
|
|
func (suite *ConnectionPoolTestSuite) TestCleanupWithNilLogger() {
|
|
// Test cleanup when cfg or logger is nil
|
|
origCfg := cfg
|
|
cfg = nil
|
|
|
|
client := &fasthttp.Client{
|
|
MaxConnsPerHost: 100,
|
|
}
|
|
|
|
cpm := NewConnectionPoolManager(client)
|
|
|
|
// Should not panic
|
|
cpm.cleanIdleConnections()
|
|
err := cpm.Shutdown()
|
|
assert.NoError(suite.T(), err)
|
|
|
|
cfg = origCfg
|
|
}
|
|
|
|
func (suite *ConnectionPoolTestSuite) TestMemoryManagement() {
|
|
// Test that connection pool properly manages memory
|
|
client := &fasthttp.Client{
|
|
MaxConnsPerHost: 10,
|
|
MaxIdleConnDuration: 100 * time.Millisecond,
|
|
}
|
|
|
|
cpm := NewConnectionPoolManager(client)
|
|
defer cpm.Shutdown()
|
|
|
|
// Simulate connections being created and becoming idle
|
|
// The periodic cleanup should handle them
|
|
time.Sleep(150 * time.Millisecond)
|
|
|
|
// Manual cleanup to ensure connections are released
|
|
cpm.cleanIdleConnections()
|
|
|
|
// Verify client is still accessible
|
|
assert.NotNil(suite.T(), cpm.GetClient())
|
|
}
|
|
|
|
// Benchmark tests
|
|
func BenchmarkConnectionPoolGetClient(b *testing.B) {
|
|
client := &fasthttp.Client{
|
|
MaxConnsPerHost: 100,
|
|
}
|
|
|
|
cpm := NewConnectionPoolManager(client)
|
|
defer cpm.Shutdown()
|
|
|
|
b.ResetTimer()
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
_ = cpm.GetClient()
|
|
}
|
|
})
|
|
}
|
|
|
|
func BenchmarkConnectionPoolCleanup(b *testing.B) {
|
|
client := &fasthttp.Client{
|
|
MaxConnsPerHost: 100,
|
|
}
|
|
|
|
cpm := NewConnectionPoolManager(client)
|
|
defer cpm.Shutdown()
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
cpm.cleanIdleConnections()
|
|
}
|
|
}
|