mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2026-01-14 15:04:26 +00:00
feat(dbmanager): ✨ update health check interval and add tests
* Change default health check interval from 30s to 15s. * Always start background health checks regardless of auto-reconnect setting. * Add tests for health checker functionality and default configurations.
This commit is contained in:
@@ -128,7 +128,7 @@ func DefaultManagerConfig() ManagerConfig {
|
||||
RetryAttempts: 3,
|
||||
RetryDelay: 1 * time.Second,
|
||||
RetryMaxDelay: 10 * time.Second,
|
||||
HealthCheckInterval: 30 * time.Second,
|
||||
HealthCheckInterval: 15 * time.Second,
|
||||
EnableAutoReconnect: true,
|
||||
}
|
||||
}
|
||||
@@ -161,6 +161,11 @@ func (c *ManagerConfig) ApplyDefaults() {
|
||||
if c.HealthCheckInterval == 0 {
|
||||
c.HealthCheckInterval = defaults.HealthCheckInterval
|
||||
}
|
||||
// EnableAutoReconnect defaults to true - apply if not explicitly set
|
||||
// Since this is a boolean, we apply the default unconditionally when it's false
|
||||
if !c.EnableAutoReconnect {
|
||||
c.EnableAutoReconnect = defaults.EnableAutoReconnect
|
||||
}
|
||||
}
|
||||
|
||||
// Validate validates the manager configuration
|
||||
|
||||
@@ -219,9 +219,10 @@ func (m *connectionManager) Connect(ctx context.Context) error {
|
||||
logger.Info("Database connection established: name=%s, type=%s", name, connCfg.Type)
|
||||
}
|
||||
|
||||
// Start background health checks if enabled
|
||||
if m.config.EnableAutoReconnect && m.config.HealthCheckInterval > 0 {
|
||||
// Always start background health checks
|
||||
if m.config.HealthCheckInterval > 0 {
|
||||
m.startHealthChecker()
|
||||
logger.Info("Background health checker started: interval=%v", m.config.HealthCheckInterval)
|
||||
}
|
||||
|
||||
logger.Info("Database manager initialized: connections=%d", len(m.connections))
|
||||
|
||||
226
pkg/dbmanager/manager_test.go
Normal file
226
pkg/dbmanager/manager_test.go
Normal file
@@ -0,0 +1,226 @@
|
||||
package dbmanager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func TestBackgroundHealthChecker(t *testing.T) {
|
||||
// Create a SQLite in-memory database
|
||||
db, err := sql.Open("sqlite3", ":memory:")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to open database: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Create manager config with a short health check interval for testing
|
||||
cfg := ManagerConfig{
|
||||
DefaultConnection: "test",
|
||||
Connections: map[string]ConnectionConfig{
|
||||
"test": {
|
||||
Name: "test",
|
||||
Type: DatabaseTypeSQLite,
|
||||
FilePath: ":memory:",
|
||||
},
|
||||
},
|
||||
HealthCheckInterval: 1 * time.Second, // Short interval for testing
|
||||
EnableAutoReconnect: true,
|
||||
}
|
||||
|
||||
// Create manager
|
||||
mgr, err := NewManager(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create manager: %v", err)
|
||||
}
|
||||
|
||||
// Connect - this should start the background health checker
|
||||
ctx := context.Background()
|
||||
err = mgr.Connect(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to connect: %v", err)
|
||||
}
|
||||
defer mgr.Close()
|
||||
|
||||
// Get the connection to verify it's healthy
|
||||
conn, err := mgr.Get("test")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get connection: %v", err)
|
||||
}
|
||||
|
||||
// Verify initial health check
|
||||
err = conn.HealthCheck(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("Initial health check failed: %v", err)
|
||||
}
|
||||
|
||||
// Wait for a few health check cycles
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
// Get stats to verify the connection is still healthy
|
||||
stats := conn.Stats()
|
||||
if stats == nil {
|
||||
t.Fatal("Expected stats to be returned")
|
||||
}
|
||||
|
||||
if !stats.Connected {
|
||||
t.Error("Expected connection to still be connected")
|
||||
}
|
||||
|
||||
if stats.HealthCheckStatus == "" {
|
||||
t.Error("Expected health check status to be set")
|
||||
}
|
||||
|
||||
// Verify the manager has started the health checker
|
||||
if cm, ok := mgr.(*connectionManager); ok {
|
||||
if cm.healthTicker == nil {
|
||||
t.Error("Expected health ticker to be running")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultHealthCheckInterval(t *testing.T) {
|
||||
// Verify the default health check interval is 15 seconds
|
||||
defaults := DefaultManagerConfig()
|
||||
|
||||
expectedInterval := 15 * time.Second
|
||||
if defaults.HealthCheckInterval != expectedInterval {
|
||||
t.Errorf("Expected default health check interval to be %v, got %v",
|
||||
expectedInterval, defaults.HealthCheckInterval)
|
||||
}
|
||||
|
||||
if !defaults.EnableAutoReconnect {
|
||||
t.Error("Expected EnableAutoReconnect to be true by default")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyDefaultsEnablesAutoReconnect(t *testing.T) {
|
||||
// Create a config without setting EnableAutoReconnect
|
||||
cfg := ManagerConfig{
|
||||
Connections: map[string]ConnectionConfig{
|
||||
"test": {
|
||||
Name: "test",
|
||||
Type: DatabaseTypeSQLite,
|
||||
FilePath: ":memory:",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Verify it's false initially (Go's zero value for bool)
|
||||
if cfg.EnableAutoReconnect {
|
||||
t.Error("Expected EnableAutoReconnect to be false before ApplyDefaults")
|
||||
}
|
||||
|
||||
// Apply defaults
|
||||
cfg.ApplyDefaults()
|
||||
|
||||
// Verify it's now true
|
||||
if !cfg.EnableAutoReconnect {
|
||||
t.Error("Expected EnableAutoReconnect to be true after ApplyDefaults")
|
||||
}
|
||||
|
||||
// Verify health check interval is also set
|
||||
if cfg.HealthCheckInterval != 15*time.Second {
|
||||
t.Errorf("Expected health check interval to be 15s, got %v", cfg.HealthCheckInterval)
|
||||
}
|
||||
}
|
||||
|
||||
func TestManagerHealthCheck(t *testing.T) {
|
||||
// Create a SQLite in-memory database
|
||||
db, err := sql.Open("sqlite3", ":memory:")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to open database: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Create manager config
|
||||
cfg := ManagerConfig{
|
||||
DefaultConnection: "test",
|
||||
Connections: map[string]ConnectionConfig{
|
||||
"test": {
|
||||
Name: "test",
|
||||
Type: DatabaseTypeSQLite,
|
||||
FilePath: ":memory:",
|
||||
},
|
||||
},
|
||||
HealthCheckInterval: 15 * time.Second,
|
||||
EnableAutoReconnect: true,
|
||||
}
|
||||
|
||||
// Create and connect manager
|
||||
mgr, err := NewManager(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create manager: %v", err)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
err = mgr.Connect(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to connect: %v", err)
|
||||
}
|
||||
defer mgr.Close()
|
||||
|
||||
// Perform health check on all connections
|
||||
err = mgr.HealthCheck(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("Health check failed: %v", err)
|
||||
}
|
||||
|
||||
// Get stats
|
||||
stats := mgr.Stats()
|
||||
if stats == nil {
|
||||
t.Fatal("Expected stats to be returned")
|
||||
}
|
||||
|
||||
if stats.TotalConnections != 1 {
|
||||
t.Errorf("Expected 1 total connection, got %d", stats.TotalConnections)
|
||||
}
|
||||
|
||||
if stats.HealthyCount != 1 {
|
||||
t.Errorf("Expected 1 healthy connection, got %d", stats.HealthyCount)
|
||||
}
|
||||
|
||||
if stats.UnhealthyCount != 0 {
|
||||
t.Errorf("Expected 0 unhealthy connections, got %d", stats.UnhealthyCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestManagerStatsAfterClose(t *testing.T) {
|
||||
cfg := ManagerConfig{
|
||||
DefaultConnection: "test",
|
||||
Connections: map[string]ConnectionConfig{
|
||||
"test": {
|
||||
Name: "test",
|
||||
Type: DatabaseTypeSQLite,
|
||||
FilePath: ":memory:",
|
||||
},
|
||||
},
|
||||
HealthCheckInterval: 15 * time.Second,
|
||||
}
|
||||
|
||||
mgr, err := NewManager(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create manager: %v", err)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
err = mgr.Connect(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to connect: %v", err)
|
||||
}
|
||||
|
||||
// Close the manager
|
||||
err = mgr.Close()
|
||||
if err != nil {
|
||||
t.Errorf("Failed to close manager: %v", err)
|
||||
}
|
||||
|
||||
// Stats should show no connections
|
||||
stats := mgr.Stats()
|
||||
if stats.TotalConnections != 0 {
|
||||
t.Errorf("Expected 0 total connections after close, got %d", stats.TotalConnections)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user