Files
graphql-monitoring-proxy/connection_pool_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

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()
}
}