test: add comprehensive tests for all Epic 1 stories
Some checks failed
CI / Test (pull_request) Failing after 17s
CI / Lint (pull_request) Failing after 18s
CI / Build (pull_request) Successful in 12s
CI / Format Check (pull_request) Successful in 2s

Story 1.2: Database Layer
- Test database client creation, connection, ping, and close
- Test connection pooling configuration
- Tests skip if database is not available (short mode)

Story 1.3: Health Monitoring and Metrics
- Test health registry registration and checking
- Test database health checker
- Test liveness and readiness checks
- Test metrics creation, middleware, and handler
- Test Prometheus metrics endpoint

Story 1.4: Error Handling and Error Bus
- Test channel-based error bus creation
- Test error publishing with context
- Test nil error handling
- Test channel full scenario
- Test graceful shutdown
- Fix Close() method to handle multiple calls safely

Story 1.5: HTTP Server and Middleware
- Test server creation with all middleware
- Test request ID middleware
- Test logging middleware
- Test panic recovery middleware
- Test CORS middleware
- Test timeout middleware
- Test health and metrics endpoints
- Test server shutdown

Story 1.6: OpenTelemetry Tracing
- Test tracer initialization (enabled/disabled)
- Test development and production modes
- Test OTLP exporter configuration
- Test graceful shutdown
- Test no-op tracer provider

All tests follow Go testing best practices:
- Table-driven tests where appropriate
- Parallel execution
- Proper mocking of interfaces
- Skip tests requiring external dependencies in short mode
This commit is contained in:
2025-11-05 21:03:27 +01:00
parent 278a727b8c
commit 5fdbb729bd
11 changed files with 1537 additions and 22 deletions

View File

@@ -0,0 +1,160 @@
package database
import (
"context"
"testing"
"time"
)
func TestNewClient_InvalidDSN(t *testing.T) {
t.Parallel()
cfg := Config{
DSN: "invalid-dsn",
MaxConnections: 10,
MaxIdleConns: 5,
}
client, err := NewClient(cfg)
if err == nil {
if client != nil {
_ = client.Close()
}
t.Error("Expected error for invalid DSN, got nil")
}
}
func TestNewClient_ValidConfig(t *testing.T) {
t.Parallel()
// This test requires a real database connection
// Skip if DSN is not set
dsn := "postgres://goplt:goplt_password@localhost:5432/goplt?sslmode=disable"
if testing.Short() {
t.Skip("Skipping database test in short mode")
}
cfg := Config{
DSN: dsn,
MaxConnections: 10,
MaxIdleConns: 5,
ConnMaxLifetime: 5 * time.Minute,
ConnMaxIdleTime: 10 * time.Minute,
}
client, err := NewClient(cfg)
if err != nil {
t.Skipf("Skipping test - database not available: %v", err)
}
defer func() {
if err := client.Close(); err != nil {
t.Logf("Failed to close client: %v", err)
}
}()
if client == nil {
t.Fatal("Expected client, got nil")
}
if client.Client == nil {
t.Error("Expected Ent client, got nil")
}
if client.db == nil {
t.Error("Expected sql.DB, got nil")
}
}
func TestClient_Ping(t *testing.T) {
t.Parallel()
dsn := "postgres://goplt:goplt_password@localhost:5432/goplt?sslmode=disable"
if testing.Short() {
t.Skip("Skipping database test in short mode")
}
cfg := Config{
DSN: dsn,
MaxConnections: 10,
MaxIdleConns: 5,
}
client, err := NewClient(cfg)
if err != nil {
t.Skipf("Skipping test - database not available: %v", err)
}
defer func() {
if err := client.Close(); err != nil {
t.Logf("Failed to close client: %v", err)
}
}()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := client.Ping(ctx); err != nil {
t.Errorf("Ping failed: %v", err)
}
}
func TestClient_Close(t *testing.T) {
t.Parallel()
dsn := "postgres://goplt:goplt_password@localhost:5432/goplt?sslmode=disable"
if testing.Short() {
t.Skip("Skipping database test in short mode")
}
cfg := Config{
DSN: dsn,
MaxConnections: 10,
MaxIdleConns: 5,
}
client, err := NewClient(cfg)
if err != nil {
t.Skipf("Skipping test - database not available: %v", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := client.Close(); err != nil {
t.Errorf("Close failed: %v", err)
}
// Ping should fail after close
if err := client.Ping(ctx); err == nil {
t.Error("Expected Ping to fail after Close, got nil error")
}
}
func TestClient_DB(t *testing.T) {
t.Parallel()
dsn := "postgres://goplt:goplt_password@localhost:5432/goplt?sslmode=disable"
if testing.Short() {
t.Skip("Skipping database test in short mode")
}
cfg := Config{
DSN: dsn,
MaxConnections: 10,
MaxIdleConns: 5,
}
client, err := NewClient(cfg)
if err != nil {
t.Skipf("Skipping test - database not available: %v", err)
}
defer func() {
if err := client.Close(); err != nil {
t.Logf("Failed to close client: %v", err)
}
}()
db := client.DB()
if db == nil {
t.Error("Expected sql.DB from DB(), got nil")
}
}