fixed sonarqube issues

This commit is contained in:
2025-12-17 09:42:18 +08:00
parent d385044237
commit e6b3e3b3ae
9 changed files with 137 additions and 123 deletions
+5 -5
View File
@@ -18,7 +18,7 @@ Your authorization microservice is now **fully horizontally scalable** using Red
#### 2. Cache Architecture #### 2. Cache Architecture
``` ```text
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Instance 1 │ │ Instance 2 │ │ Instance 3 │ │ Instance 1 │ │ Instance 2 │ │ Instance 3 │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘
@@ -39,20 +39,20 @@ Your authorization microservice is now **fully horizontally scalable** using Red
#### 3. Key Features #### 3. Key Features
**Dual-Layer Caching** #### Dual-Layer Caching
- Primary: Redis (distributed, shared across instances) - Primary: Redis (distributed, shared across instances)
- Secondary: Local in-memory (failover, performance boost) - Secondary: Local in-memory (failover, performance boost)
- Automatic fallback when Redis unavailable - Automatic fallback when Redis unavailable
**Consistency Guarantees** #### Consistency Guarantees
- All instances share the same Redis cache - All instances share the same Redis cache
- 30-second automatic cache refresh - 30-second automatic cache refresh
- Manual invalidation via `InvalidateUserCache()` - Manual invalidation via `InvalidateUserCache()`
- Force refresh via `RefreshCacheNow()` - Force refresh via `RefreshCacheNow()`
**Performance Optimizations** #### Performance Optimizations
- JSON serialization for complex objects - JSON serialization for complex objects
- 100ms timeout for Redis operations - 100ms timeout for Redis operations
@@ -313,7 +313,7 @@ var (
| Medium Cluster | 5 | ~10,000 | <20ms | | Medium Cluster | 5 | ~10,000 | <20ms |
| Large Cluster | 10+ | ~20,000+ | <25ms | | Large Cluster | 10+ | ~20,000+ | <25ms |
_Note: Assumes Redis on same network, PostgreSQL optimized_ > **Note:** Assumes Redis on same network, PostgreSQL optimized
### Cache Effectiveness ### Cache Effectiveness
+26 -26
View File
@@ -27,9 +27,9 @@ func TestInitAuthService(t *testing.T) {
t.Log("InitAuthService completed successfully") t.Log("InitAuthService completed successfully")
} }
func TestAuthorizeHandler_NoJWTClaims(t *testing.T) { func TestAuthorizeHandlerNoJWTClaims(t *testing.T) {
// Setup // Setup
req := httptest.NewRequest("POST", "/v1/auth/check", nil) req := httptest.NewRequest("POST", AuthCheckEndpoint, nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
// Execute // Execute
@@ -37,11 +37,11 @@ func TestAuthorizeHandler_NoJWTClaims(t *testing.T) {
// Assert // Assert
if w.Code != http.StatusUnauthorized { if w.Code != http.StatusUnauthorized {
t.Errorf("Expected status %d, got %d", http.StatusUnauthorized, w.Code) t.Errorf(ExpectedStatusMessage, http.StatusUnauthorized, w.Code)
} }
} }
func TestAuthorizeHandler_InvalidJSON(t *testing.T) { func TestAuthorizeHandlerInvalidJSON(t *testing.T) {
// Setup - no need to init service, we're testing JSON parsing before auth // Setup - no need to init service, we're testing JSON parsing before auth
claims := &models.Claims{ claims := &models.Claims{
UserID: "user123", UserID: "user123",
@@ -49,7 +49,7 @@ func TestAuthorizeHandler_InvalidJSON(t *testing.T) {
Role: "admin", Role: "admin",
} }
req := httptest.NewRequest("POST", "/v1/auth/check", bytes.NewBufferString("invalid json")) req := httptest.NewRequest("POST", AuthCheckEndpoint, bytes.NewBufferString("invalid json"))
ctx := context.WithValue(req.Context(), models.ContextKey("claims"), claims) ctx := context.WithValue(req.Context(), models.ContextKey("claims"), claims)
req = req.WithContext(ctx) req = req.WithContext(ctx)
w := httptest.NewRecorder() w := httptest.NewRecorder()
@@ -59,11 +59,11 @@ func TestAuthorizeHandler_InvalidJSON(t *testing.T) {
// Assert // Assert
if w.Code != http.StatusBadRequest { if w.Code != http.StatusBadRequest {
t.Errorf("Expected status %d, got %d", http.StatusBadRequest, w.Code) t.Errorf(ExpectedStatusMessage, http.StatusBadRequest, w.Code)
} }
} }
func TestAuthorizeHandler_MissingRequiredFields(t *testing.T) { func TestAuthorizeHandlerMissingRequiredFields(t *testing.T) {
testCases := []struct { testCases := []struct {
name string name string
payload models.AuthorizationContext payload models.AuthorizationContext
@@ -91,7 +91,7 @@ func TestAuthorizeHandler_MissingRequiredFields(t *testing.T) {
} }
body, _ := json.Marshal(tc.payload) body, _ := json.Marshal(tc.payload)
req := httptest.NewRequest("POST", "/v1/auth/check", bytes.NewBuffer(body)) req := httptest.NewRequest("POST", AuthCheckEndpoint, bytes.NewBuffer(body))
ctx := context.WithValue(req.Context(), models.ContextKey("claims"), claims) ctx := context.WithValue(req.Context(), models.ContextKey("claims"), claims)
req = req.WithContext(ctx) req = req.WithContext(ctx)
w := httptest.NewRecorder() w := httptest.NewRecorder()
@@ -99,13 +99,13 @@ func TestAuthorizeHandler_MissingRequiredFields(t *testing.T) {
AuthorizeHandler(w, req) AuthorizeHandler(w, req)
if w.Code != http.StatusBadRequest { if w.Code != http.StatusBadRequest {
t.Errorf("Expected status %d, got %d", http.StatusBadRequest, w.Code) t.Errorf(ExpectedStatusMessage, http.StatusBadRequest, w.Code)
} }
}) })
} }
} }
func TestAuthorizeHandler_UserIDMismatch(t *testing.T) { func TestAuthorizeHandlerUserIDMismatch(t *testing.T) {
// Setup // Setup
claims := &models.Claims{ claims := &models.Claims{
UserID: "user123", UserID: "user123",
@@ -120,7 +120,7 @@ func TestAuthorizeHandler_UserIDMismatch(t *testing.T) {
} }
body, _ := json.Marshal(payload) body, _ := json.Marshal(payload)
req := httptest.NewRequest("POST", "/v1/auth/check", bytes.NewBuffer(body)) req := httptest.NewRequest("POST", AuthCheckEndpoint, bytes.NewBuffer(body))
ctx := context.WithValue(req.Context(), models.ContextKey("claims"), claims) ctx := context.WithValue(req.Context(), models.ContextKey("claims"), claims)
req = req.WithContext(ctx) req = req.WithContext(ctx)
w := httptest.NewRecorder() w := httptest.NewRecorder()
@@ -130,11 +130,11 @@ func TestAuthorizeHandler_UserIDMismatch(t *testing.T) {
// Assert // Assert
if w.Code != http.StatusForbidden { if w.Code != http.StatusForbidden {
t.Errorf("Expected status %d, got %d", http.StatusForbidden, w.Code) t.Errorf(ExpectedStatusMessage, http.StatusForbidden, w.Code)
} }
} }
func TestAuthorizeHandler_NilMaps(t *testing.T) { func TestAuthorizeHandlerNilMaps(t *testing.T) {
// Test that nil maps don't cause additional panics beyond missing authService // Test that nil maps don't cause additional panics beyond missing authService
claims := &models.Claims{ claims := &models.Claims{
UserID: "user123", UserID: "user123",
@@ -151,7 +151,7 @@ func TestAuthorizeHandler_NilMaps(t *testing.T) {
} }
body, _ := json.Marshal(payload) body, _ := json.Marshal(payload)
req := httptest.NewRequest("POST", "/v1/auth/check", bytes.NewBuffer(body)) req := httptest.NewRequest("POST", AuthCheckEndpoint, bytes.NewBuffer(body))
ctx := context.WithValue(req.Context(), models.ContextKey("claims"), claims) ctx := context.WithValue(req.Context(), models.ContextKey("claims"), claims)
req = req.WithContext(ctx) req = req.WithContext(ctx)
w := httptest.NewRecorder() w := httptest.NewRecorder()
@@ -173,7 +173,7 @@ func TestAuthorizeHandler_NilMaps(t *testing.T) {
// Additional comprehensive test cases // Additional comprehensive test cases
func TestAuthorizeHandler_EmptyUserID(t *testing.T) { func TestAuthorizeHandlerEmptyUserID(t *testing.T) {
claims := &models.Claims{ claims := &models.Claims{
UserID: "user123", UserID: "user123",
Username: "testuser", Username: "testuser",
@@ -187,7 +187,7 @@ func TestAuthorizeHandler_EmptyUserID(t *testing.T) {
} }
body, _ := json.Marshal(payload) body, _ := json.Marshal(payload)
req := httptest.NewRequest("POST", "/v1/auth/check", bytes.NewBuffer(body)) req := httptest.NewRequest("POST", AuthCheckEndpoint, bytes.NewBuffer(body))
ctx := context.WithValue(req.Context(), models.ContextKey("claims"), claims) ctx := context.WithValue(req.Context(), models.ContextKey("claims"), claims)
req = req.WithContext(ctx) req = req.WithContext(ctx)
w := httptest.NewRecorder() w := httptest.NewRecorder()
@@ -199,7 +199,7 @@ func TestAuthorizeHandler_EmptyUserID(t *testing.T) {
} }
} }
func TestAuthorizeHandler_EmptyResource(t *testing.T) { func TestAuthorizeHandlerEmptyResource(t *testing.T) {
claims := &models.Claims{ claims := &models.Claims{
UserID: "user123", UserID: "user123",
Username: "testuser", Username: "testuser",
@@ -213,7 +213,7 @@ func TestAuthorizeHandler_EmptyResource(t *testing.T) {
} }
body, _ := json.Marshal(payload) body, _ := json.Marshal(payload)
req := httptest.NewRequest("POST", "/v1/auth/check", bytes.NewBuffer(body)) req := httptest.NewRequest("POST", AuthCheckEndpoint, bytes.NewBuffer(body))
ctx := context.WithValue(req.Context(), models.ContextKey("claims"), claims) ctx := context.WithValue(req.Context(), models.ContextKey("claims"), claims)
req = req.WithContext(ctx) req = req.WithContext(ctx)
w := httptest.NewRecorder() w := httptest.NewRecorder()
@@ -225,7 +225,7 @@ func TestAuthorizeHandler_EmptyResource(t *testing.T) {
} }
} }
func TestAuthorizeHandler_EmptyAction(t *testing.T) { func TestAuthorizeHandlerEmptyAction(t *testing.T) {
claims := &models.Claims{ claims := &models.Claims{
UserID: "user123", UserID: "user123",
Username: "testuser", Username: "testuser",
@@ -239,7 +239,7 @@ func TestAuthorizeHandler_EmptyAction(t *testing.T) {
} }
body, _ := json.Marshal(payload) body, _ := json.Marshal(payload)
req := httptest.NewRequest("POST", "/v1/auth/check", bytes.NewBuffer(body)) req := httptest.NewRequest("POST", AuthCheckEndpoint, bytes.NewBuffer(body))
ctx := context.WithValue(req.Context(), models.ContextKey("claims"), claims) ctx := context.WithValue(req.Context(), models.ContextKey("claims"), claims)
req = req.WithContext(ctx) req = req.WithContext(ctx)
w := httptest.NewRecorder() w := httptest.NewRecorder()
@@ -251,8 +251,8 @@ func TestAuthorizeHandler_EmptyAction(t *testing.T) {
} }
} }
func TestAuthorizeHandler_InvalidClaimsType(t *testing.T) { func TestAuthorizeHandlerInvalidClaimsType(t *testing.T) {
req := httptest.NewRequest("POST", "/v1/auth/check", bytes.NewBufferString(`{"userId":"user123","resource":"doc","action":"read"}`)) req := httptest.NewRequest("POST", AuthCheckEndpoint, bytes.NewBufferString(`{"userId":"user123","resource":"doc","action":"read"}`))
// Set claims as wrong type // Set claims as wrong type
ctx := context.WithValue(req.Context(), models.ContextKey("claims"), "invalid_claims_type") ctx := context.WithValue(req.Context(), models.ContextKey("claims"), "invalid_claims_type")
@@ -266,7 +266,7 @@ func TestAuthorizeHandler_InvalidClaimsType(t *testing.T) {
} }
} }
func TestAuthorizeHandler_MalformedJSON(t *testing.T) { func TestAuthorizeHandlerMalformedJSON(t *testing.T) {
claims := &models.Claims{ claims := &models.Claims{
UserID: "user123", UserID: "user123",
Username: "testuser", Username: "testuser",
@@ -285,7 +285,7 @@ func TestAuthorizeHandler_MalformedJSON(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
req := httptest.NewRequest("POST", "/v1/auth/check", bytes.NewBufferString(tc.payload)) req := httptest.NewRequest("POST", AuthCheckEndpoint, bytes.NewBufferString(tc.payload))
ctx := context.WithValue(req.Context(), models.ContextKey("claims"), claims) ctx := context.WithValue(req.Context(), models.ContextKey("claims"), claims)
req = req.WithContext(ctx) req = req.WithContext(ctx)
w := httptest.NewRecorder() w := httptest.NewRecorder()
@@ -299,7 +299,7 @@ func TestAuthorizeHandler_MalformedJSON(t *testing.T) {
} }
} }
func TestAuthorizeHandler_SpecialCharactersInFields(t *testing.T) { func TestAuthorizeHandlerSpecialCharactersInFields(t *testing.T) {
testCases := []struct { testCases := []struct {
name string name string
userID string userID string
@@ -321,7 +321,7 @@ func TestAuthorizeHandler_SpecialCharactersInFields(t *testing.T) {
} }
body, _ := json.Marshal(payload) body, _ := json.Marshal(payload)
req := httptest.NewRequest("POST", "/v1/auth/check", bytes.NewBuffer(body)) req := httptest.NewRequest("POST", AuthCheckEndpoint, bytes.NewBuffer(body))
// Update claims to match userID // Update claims to match userID
testClaims := &models.Claims{ testClaims := &models.Claims{
+12
View File
@@ -0,0 +1,12 @@
package handlers
const (
ExpectedStatusMessage = "Expected status %d, got %d"
AuthCheckEndpoint = "/v1/auth/check"
HealthCheckEndpoint = "/health"
StatusMismatchMessage = "status = %v, want %v"
FailedToDecodeResponseMessage = "failed to decode response: %v"
FailedToCreateMockDBMessage = "failed to create mock db: %v"
ReadyCheckEndpoint = "/ready"
ExpectedStatus200Message = "Expected status 200, got %d"
)
+45 -45
View File
@@ -30,7 +30,7 @@ func TestHealthHandler(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/health", nil) req := httptest.NewRequest(http.MethodGet, HealthCheckEndpoint, nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
HealthHandler(w, req) HealthHandler(w, req)
@@ -39,16 +39,16 @@ func TestHealthHandler(t *testing.T) {
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != tt.wantStatus { if resp.StatusCode != tt.wantStatus {
t.Errorf("status = %v, want %v", resp.StatusCode, tt.wantStatus) t.Errorf(StatusMismatchMessage, resp.StatusCode, tt.wantStatus)
} }
var healthResp models.HealthResponse var healthResp models.HealthResponse
if err := json.NewDecoder(resp.Body).Decode(&healthResp); err != nil { if err := json.NewDecoder(resp.Body).Decode(&healthResp); err != nil {
t.Fatalf("failed to decode response: %v", err) t.Fatalf(FailedToDecodeResponseMessage, err)
} }
if healthResp.Status != tt.wantBodyStatus { if healthResp.Status != tt.wantBodyStatus {
t.Errorf("status = %v, want %v", healthResp.Status, tt.wantBodyStatus) t.Errorf(StatusMismatchMessage, healthResp.Status, tt.wantBodyStatus)
} }
contentType := resp.Header.Get("Content-Type") contentType := resp.Header.Get("Content-Type")
@@ -59,11 +59,11 @@ func TestHealthHandler(t *testing.T) {
} }
} }
func TestReadyHandler_AllHealthy(t *testing.T) { func TestReadyHandlerAllHealthy(t *testing.T) {
// Setup mock DB // Setup mock DB
mockDB, mock, err := sqlmock.New(sqlmock.MonitorPingsOption(true)) mockDB, mock, err := sqlmock.New(sqlmock.MonitorPingsOption(true))
if err != nil { if err != nil {
t.Fatalf("failed to create mock db: %v", err) t.Fatalf(FailedToCreateMockDBMessage, err)
} }
defer mockDB.Close() defer mockDB.Close()
@@ -80,7 +80,7 @@ func TestReadyHandler_AllHealthy(t *testing.T) {
redisclient.RDB = nil redisclient.RDB = nil
defer func() { redisclient.RDB = originalRedis }() defer func() { redisclient.RDB = originalRedis }()
req := httptest.NewRequest(http.MethodGet, "/ready", nil) req := httptest.NewRequest(http.MethodGet, ReadyCheckEndpoint, nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
ReadyHandler(w, req) ReadyHandler(w, req)
@@ -90,7 +90,7 @@ func TestReadyHandler_AllHealthy(t *testing.T) {
var healthResp models.HealthResponse var healthResp models.HealthResponse
if err := json.NewDecoder(resp.Body).Decode(&healthResp); err != nil { if err := json.NewDecoder(resp.Body).Decode(&healthResp); err != nil {
t.Fatalf("failed to decode response: %v", err) t.Fatalf(FailedToDecodeResponseMessage, err)
} }
if healthResp.Services["database"] != "healthy" { if healthResp.Services["database"] != "healthy" {
@@ -103,11 +103,11 @@ func TestReadyHandler_AllHealthy(t *testing.T) {
} }
} }
func TestReadyHandler_DBUnhealthy(t *testing.T) { func TestReadyHandlerDBUnhealthy(t *testing.T) {
// Setup mock DB that fails ping // Setup mock DB that fails ping
mockDB, mock, err := sqlmock.New(sqlmock.MonitorPingsOption(true)) mockDB, mock, err := sqlmock.New(sqlmock.MonitorPingsOption(true))
if err != nil { if err != nil {
t.Fatalf("failed to create mock db: %v", err) t.Fatalf(FailedToCreateMockDBMessage, err)
} }
defer mockDB.Close() defer mockDB.Close()
@@ -124,7 +124,7 @@ func TestReadyHandler_DBUnhealthy(t *testing.T) {
redisclient.RDB = nil redisclient.RDB = nil
defer func() { redisclient.RDB = originalRedis }() defer func() { redisclient.RDB = originalRedis }()
req := httptest.NewRequest(http.MethodGet, "/ready", nil) req := httptest.NewRequest(http.MethodGet, ReadyCheckEndpoint, nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
ReadyHandler(w, req) ReadyHandler(w, req)
@@ -133,12 +133,12 @@ func TestReadyHandler_DBUnhealthy(t *testing.T) {
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != http.StatusServiceUnavailable { if resp.StatusCode != http.StatusServiceUnavailable {
t.Errorf("status = %v, want %v", resp.StatusCode, http.StatusServiceUnavailable) t.Errorf(StatusMismatchMessage, resp.StatusCode, http.StatusServiceUnavailable)
} }
var healthResp models.HealthResponse var healthResp models.HealthResponse
if err := json.NewDecoder(resp.Body).Decode(&healthResp); err != nil { if err := json.NewDecoder(resp.Body).Decode(&healthResp); err != nil {
t.Fatalf("failed to decode response: %v", err) t.Fatalf(FailedToDecodeResponseMessage, err)
} }
if healthResp.Status != "not_ready" { if healthResp.Status != "not_ready" {
@@ -154,7 +154,7 @@ func TestReadyHandler_DBUnhealthy(t *testing.T) {
} }
} }
func TestReadyHandler_DBNotInitialized(t *testing.T) { func TestReadyHandlerDBNotInitialized(t *testing.T) {
// Save original and set to nil // Save original and set to nil
originalDB := db.DB originalDB := db.DB
db.DB = nil db.DB = nil
@@ -164,7 +164,7 @@ func TestReadyHandler_DBNotInitialized(t *testing.T) {
redisclient.RDB = nil redisclient.RDB = nil
defer func() { redisclient.RDB = originalRedis }() defer func() { redisclient.RDB = originalRedis }()
req := httptest.NewRequest(http.MethodGet, "/ready", nil) req := httptest.NewRequest(http.MethodGet, ReadyCheckEndpoint, nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
ReadyHandler(w, req) ReadyHandler(w, req)
@@ -173,12 +173,12 @@ func TestReadyHandler_DBNotInitialized(t *testing.T) {
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != http.StatusServiceUnavailable { if resp.StatusCode != http.StatusServiceUnavailable {
t.Errorf("status = %v, want %v", resp.StatusCode, http.StatusServiceUnavailable) t.Errorf(StatusMismatchMessage, resp.StatusCode, http.StatusServiceUnavailable)
} }
var healthResp models.HealthResponse var healthResp models.HealthResponse
if err := json.NewDecoder(resp.Body).Decode(&healthResp); err != nil { if err := json.NewDecoder(resp.Body).Decode(&healthResp); err != nil {
t.Fatalf("failed to decode response: %v", err) t.Fatalf(FailedToDecodeResponseMessage, err)
} }
if healthResp.Status != "not_ready" { if healthResp.Status != "not_ready" {
@@ -194,7 +194,7 @@ func TestReadyHandler_DBNotInitialized(t *testing.T) {
} }
} }
func TestReadyHandler_ContentType(t *testing.T) { func TestReadyHandlerContentType(t *testing.T) {
originalDB := db.DB originalDB := db.DB
db.DB = nil db.DB = nil
defer func() { db.DB = originalDB }() defer func() { db.DB = originalDB }()
@@ -203,7 +203,7 @@ func TestReadyHandler_ContentType(t *testing.T) {
redisclient.RDB = nil redisclient.RDB = nil
defer func() { redisclient.RDB = originalRedis }() defer func() { redisclient.RDB = originalRedis }()
req := httptest.NewRequest(http.MethodGet, "/ready", nil) req := httptest.NewRequest(http.MethodGet, ReadyCheckEndpoint, nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
ReadyHandler(w, req) ReadyHandler(w, req)
@@ -219,19 +219,19 @@ func TestReadyHandler_ContentType(t *testing.T) {
// Additional comprehensive test cases // Additional comprehensive test cases
func TestHealthHandler_MultipleRequests(t *testing.T) { func TestHealthHandlerMultipleRequests(t *testing.T) {
// Test that multiple concurrent requests work correctly // Test that multiple concurrent requests work correctly
concurrency := 10 concurrency := 10
done := make(chan bool, concurrency) done := make(chan bool, concurrency)
for i := 0; i < concurrency; i++ { for i := 0; i < concurrency; i++ {
go func() { go func() {
req := httptest.NewRequest(http.MethodGet, "/health", nil) req := httptest.NewRequest(http.MethodGet, HealthCheckEndpoint, nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
HealthHandler(w, req) HealthHandler(w, req)
if w.Code != http.StatusOK { if w.Code != http.StatusOK {
t.Errorf("Expected status 200, got %d", w.Code) t.Errorf(ExpectedStatus200Message, w.Code)
} }
done <- true done <- true
}() }()
@@ -242,12 +242,12 @@ func TestHealthHandler_MultipleRequests(t *testing.T) {
} }
} }
func TestHealthHandler_DifferentMethods(t *testing.T) { func TestHealthHandlerDifferentMethods(t *testing.T) {
methods := []string{"GET", "POST", "PUT", "DELETE", "PATCH"} methods := []string{"GET", "POST", "PUT", "DELETE", "PATCH"}
for _, method := range methods { for _, method := range methods {
t.Run(method, func(t *testing.T) { t.Run(method, func(t *testing.T) {
req := httptest.NewRequest(method, "/health", nil) req := httptest.NewRequest(method, HealthCheckEndpoint, nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
HealthHandler(w, req) HealthHandler(w, req)
@@ -259,14 +259,14 @@ func TestHealthHandler_DifferentMethods(t *testing.T) {
} }
} }
func TestHealthHandler_ResponseFormat(t *testing.T) { func TestHealthHandlerResponseFormat(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/health", nil) req := httptest.NewRequest(http.MethodGet, HealthCheckEndpoint, nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
HealthHandler(w, req) HealthHandler(w, req)
var response models.HealthResponse var response models.HealthResponse
if err := json.NewDecoder(w.Body).Decode(&response); err != nil { if err := json.NewDecoder(w.Body).Decode(&response); err != nil {
t.Fatalf("Failed to decode response: %v", err) t.Fatalf(FailedToDecodeResponseMessage, err)
} }
if response.Status == "" { if response.Status == "" {
@@ -278,10 +278,10 @@ func TestHealthHandler_ResponseFormat(t *testing.T) {
} }
} }
func TestReadyHandler_DatabaseTimeout(t *testing.T) { func TestReadyHandlerDatabaseTimeout(t *testing.T) {
mockDB, mock, err := sqlmock.New(sqlmock.MonitorPingsOption(true)) mockDB, mock, err := sqlmock.New(sqlmock.MonitorPingsOption(true))
if err != nil { if err != nil {
t.Fatalf("failed to create mock db: %v", err) t.Fatalf(FailedToCreateMockDBMessage, err)
} }
defer mockDB.Close() defer mockDB.Close()
@@ -296,7 +296,7 @@ func TestReadyHandler_DatabaseTimeout(t *testing.T) {
redisclient.RDB = nil redisclient.RDB = nil
defer func() { redisclient.RDB = originalRedis }() defer func() { redisclient.RDB = originalRedis }()
req := httptest.NewRequest(http.MethodGet, "/ready", nil) req := httptest.NewRequest(http.MethodGet, ReadyCheckEndpoint, nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
// This should timeout and return unhealthy // This should timeout and return unhealthy
@@ -307,7 +307,7 @@ func TestReadyHandler_DatabaseTimeout(t *testing.T) {
} }
} }
func TestReadyHandler_BothServicesHealthy(t *testing.T) { func TestReadyHandlerBothServicesHealthy(t *testing.T) {
// Use miniredis for Redis mock // Use miniredis for Redis mock
mr, err := miniredis.Run() mr, err := miniredis.Run()
if err != nil { if err != nil {
@@ -325,7 +325,7 @@ func TestReadyHandler_BothServicesHealthy(t *testing.T) {
// Setup mock database // Setup mock database
mockDB, mock, err := sqlmock.New(sqlmock.MonitorPingsOption(true)) mockDB, mock, err := sqlmock.New(sqlmock.MonitorPingsOption(true))
if err != nil { if err != nil {
t.Fatalf("Failed to create mock DB: %v", err) t.Fatalf(FailedToCreateMockDBMessage, err)
} }
defer mockDB.Close() defer mockDB.Close()
@@ -336,13 +336,13 @@ func TestReadyHandler_BothServicesHealthy(t *testing.T) {
// Expect ping // Expect ping
mock.ExpectPing() mock.ExpectPing()
req := httptest.NewRequest(http.MethodGet, "/ready", nil) req := httptest.NewRequest(http.MethodGet, ReadyCheckEndpoint, nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
ReadyHandler(w, req) ReadyHandler(w, req)
if w.Code != http.StatusOK { if w.Code != http.StatusOK {
t.Errorf("Expected status 200, got %d", w.Code) t.Errorf(ExpectedStatus200Message, w.Code)
} }
var response models.HealthResponse var response models.HealthResponse
@@ -357,7 +357,7 @@ func TestReadyHandler_BothServicesHealthy(t *testing.T) {
} }
} }
func TestReadyHandler_NilDatabaseAndRedis(t *testing.T) { func TestReadyHandlerNilDatabaseAndRedis(t *testing.T) {
originalDB := db.DB originalDB := db.DB
db.DB = nil db.DB = nil
defer func() { db.DB = originalDB }() defer func() { db.DB = originalDB }()
@@ -366,7 +366,7 @@ func TestReadyHandler_NilDatabaseAndRedis(t *testing.T) {
redisclient.RDB = nil redisclient.RDB = nil
defer func() { redisclient.RDB = originalRedis }() defer func() { redisclient.RDB = originalRedis }()
req := httptest.NewRequest(http.MethodGet, "/ready", nil) req := httptest.NewRequest(http.MethodGet, ReadyCheckEndpoint, nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
ReadyHandler(w, req) ReadyHandler(w, req)
@@ -377,7 +377,7 @@ func TestReadyHandler_NilDatabaseAndRedis(t *testing.T) {
var response models.HealthResponse var response models.HealthResponse
if err := json.NewDecoder(w.Body).Decode(&response); err != nil { if err := json.NewDecoder(w.Body).Decode(&response); err != nil {
t.Fatalf("Failed to decode response: %v", err) t.Fatalf(FailedToDecodeResponseMessage, err)
} }
// The handler returns "not_ready" when services are down // The handler returns "not_ready" when services are down
@@ -386,7 +386,7 @@ func TestReadyHandler_NilDatabaseAndRedis(t *testing.T) {
} }
} }
func TestReadyHandler_ResponseStructure(t *testing.T) { func TestReadyHandlerResponseStructure(t *testing.T) {
originalDB := db.DB originalDB := db.DB
db.DB = nil db.DB = nil
defer func() { db.DB = originalDB }() defer func() { db.DB = originalDB }()
@@ -395,7 +395,7 @@ func TestReadyHandler_ResponseStructure(t *testing.T) {
redisclient.RDB = nil redisclient.RDB = nil
defer func() { redisclient.RDB = originalRedis }() defer func() { redisclient.RDB = originalRedis }()
req := httptest.NewRequest(http.MethodGet, "/ready", nil) req := httptest.NewRequest(http.MethodGet, ReadyCheckEndpoint, nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
ReadyHandler(w, req) ReadyHandler(w, req)
@@ -403,7 +403,7 @@ func TestReadyHandler_ResponseStructure(t *testing.T) {
// Verify response is valid JSON // Verify response is valid JSON
var response map[string]interface{} var response map[string]interface{}
if err := json.NewDecoder(w.Body).Decode(&response); err != nil { if err := json.NewDecoder(w.Body).Decode(&response); err != nil {
t.Fatalf("Failed to decode response: %v", err) t.Fatalf(FailedToDecodeResponseMessage, err)
} }
// Check that response has expected fields // Check that response has expected fields
@@ -412,8 +412,8 @@ func TestReadyHandler_ResponseStructure(t *testing.T) {
} }
} }
func TestHealthHandler_WithCustomHeaders(t *testing.T) { func TestHealthHandlerWithCustomHeaders(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/health", nil) req := httptest.NewRequest(http.MethodGet, HealthCheckEndpoint, nil)
req.Header.Set("X-Request-ID", "test-123") req.Header.Set("X-Request-ID", "test-123")
req.Header.Set("User-Agent", "Test-Agent/1.0") req.Header.Set("User-Agent", "Test-Agent/1.0")
@@ -421,11 +421,11 @@ func TestHealthHandler_WithCustomHeaders(t *testing.T) {
HealthHandler(w, req) HealthHandler(w, req)
if w.Code != http.StatusOK { if w.Code != http.StatusOK {
t.Errorf("Expected status 200, got %d", w.Code) t.Errorf(ExpectedStatus200Message, w.Code)
} }
} }
func TestReadyHandler_ConcurrentRequests(t *testing.T) { func TestReadyHandlerConcurrentRequests(t *testing.T) {
originalDB := db.DB originalDB := db.DB
db.DB = nil db.DB = nil
defer func() { db.DB = originalDB }() defer func() { db.DB = originalDB }()
@@ -439,7 +439,7 @@ func TestReadyHandler_ConcurrentRequests(t *testing.T) {
for i := 0; i < concurrency; i++ { for i := 0; i < concurrency; i++ {
go func() { go func() {
req := httptest.NewRequest(http.MethodGet, "/ready", nil) req := httptest.NewRequest(http.MethodGet, ReadyCheckEndpoint, nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
ReadyHandler(w, req) ReadyHandler(w, req)
+37 -37
View File
@@ -45,7 +45,7 @@ func TestNewCircuitBreaker(t *testing.T) {
t.Errorf("timeout = %v, want %v", cb.timeout, tt.timeout) t.Errorf("timeout = %v, want %v", cb.timeout, tt.timeout)
} }
if cb.state != tt.wantState { if cb.state != tt.wantState {
t.Errorf("state = %v, want %v", cb.state, tt.wantState) t.Errorf(StateMismatchMessage, cb.state, tt.wantState)
} }
if cb.resetTimeout != 30*time.Second { if cb.resetTimeout != 30*time.Second {
t.Errorf("resetTimeout = %v, want %v", cb.resetTimeout, 30*time.Second) t.Errorf("resetTimeout = %v, want %v", cb.resetTimeout, 30*time.Second)
@@ -57,7 +57,7 @@ func TestNewCircuitBreaker(t *testing.T) {
} }
} }
func TestCircuitBreaker_Call_Success(t *testing.T) { func TestCircuitBreakerCallSuccess(t *testing.T) {
cb := NewCircuitBreaker("test", 3, 1*time.Second) cb := NewCircuitBreaker("test", 3, 1*time.Second)
successFn := func() error { successFn := func() error {
@@ -70,15 +70,15 @@ func TestCircuitBreaker_Call_Success(t *testing.T) {
} }
if GetState(cb) != StateClosed { if GetState(cb) != StateClosed {
t.Errorf("state = %v, want %v", GetState(cb), StateClosed) t.Errorf(StateMismatchMessage, GetState(cb), StateClosed)
} }
} }
func TestCircuitBreaker_Call_FailuresOpenCircuit(t *testing.T) { func TestCircuitBreakerCallFailuresOpenCircuit(t *testing.T) {
cb := NewCircuitBreaker("test", 3, 1*time.Second) cb := NewCircuitBreaker("test", 3, 1*time.Second)
failFn := func() error { failFn := func() error {
return errors.New("service error") return errors.New(ServiceError)
} }
// First 2 failures - circuit should stay closed // First 2 failures - circuit should stay closed
@@ -98,7 +98,7 @@ func TestCircuitBreaker_Call_FailuresOpenCircuit(t *testing.T) {
t.Error("Call() expected error, got nil") t.Error("Call() expected error, got nil")
} }
if GetState(cb) != StateOpen { if GetState(cb) != StateOpen {
t.Errorf("state = %v, want %v", GetState(cb), StateOpen) t.Errorf(StateMismatchMessage, GetState(cb), StateOpen)
} }
// Next call should immediately return circuit breaker error // Next call should immediately return circuit breaker error
@@ -108,12 +108,12 @@ func TestCircuitBreaker_Call_FailuresOpenCircuit(t *testing.T) {
} }
} }
func TestCircuitBreaker_Call_OpenToHalfOpen(t *testing.T) { func TestCircuitBreakerCallOpenToHalfOpen(t *testing.T) {
cb := NewCircuitBreaker("test", 2, 1*time.Second) cb := NewCircuitBreaker("test", 2, 1*time.Second)
cb.resetTimeout = 100 * time.Millisecond // Shorter reset for testing cb.resetTimeout = 100 * time.Millisecond // Shorter reset for testing
failFn := func() error { failFn := func() error {
return errors.New("service error") return errors.New(ServiceError)
} }
// Open the circuit // Open the circuit
@@ -121,7 +121,7 @@ func TestCircuitBreaker_Call_OpenToHalfOpen(t *testing.T) {
Call(cb, failFn) Call(cb, failFn)
if GetState(cb) != StateOpen { if GetState(cb) != StateOpen {
t.Fatalf("state = %v, want %v", GetState(cb), StateOpen) t.Fatalf(StateMismatchMessage, GetState(cb), StateOpen)
} }
// Wait for reset timeout // Wait for reset timeout
@@ -139,16 +139,16 @@ func TestCircuitBreaker_Call_OpenToHalfOpen(t *testing.T) {
// Should now be closed // Should now be closed
if GetState(cb) != StateClosed { if GetState(cb) != StateClosed {
t.Errorf("state = %v, want %v", GetState(cb), StateClosed) t.Errorf(StateMismatchMessage, GetState(cb), StateClosed)
} }
} }
func TestCircuitBreaker_Call_HalfOpenFailReturnsToOpen(t *testing.T) { func TestCircuitBreakerCallHalfOpenFailReturnsToOpen(t *testing.T) {
cb := NewCircuitBreaker("test", 2, 1*time.Second) cb := NewCircuitBreaker("test", 2, 1*time.Second)
cb.resetTimeout = 100 * time.Millisecond cb.resetTimeout = 100 * time.Millisecond
failFn := func() error { failFn := func() error {
return errors.New("service error") return errors.New(ServiceError)
} }
// Open the circuit // Open the circuit
@@ -156,7 +156,7 @@ func TestCircuitBreaker_Call_HalfOpenFailReturnsToOpen(t *testing.T) {
Call(cb, failFn) Call(cb, failFn)
if GetState(cb) != StateOpen { if GetState(cb) != StateOpen {
t.Fatalf("state = %v, want %v", GetState(cb), StateOpen) t.Fatalf(StateMismatchMessage, GetState(cb), StateOpen)
} }
// Wait for reset timeout to transition to HalfOpen // Wait for reset timeout to transition to HalfOpen
@@ -169,15 +169,15 @@ func TestCircuitBreaker_Call_HalfOpenFailReturnsToOpen(t *testing.T) {
} }
if GetState(cb) != StateOpen { if GetState(cb) != StateOpen {
t.Errorf("state = %v, want %v", GetState(cb), StateOpen) t.Errorf(StateMismatchMessage, GetState(cb), StateOpen)
} }
} }
func TestCircuitBreaker_Call_GradualFailureReduction(t *testing.T) { func TestCircuitBreakerCallGradualFailureReduction(t *testing.T) {
cb := NewCircuitBreaker("test", 5, 1*time.Second) cb := NewCircuitBreaker("test", 5, 1*time.Second)
failFn := func() error { failFn := func() error {
return errors.New("service error") return errors.New(ServiceError)
} }
successFn := func() error { successFn := func() error {
return nil return nil
@@ -208,7 +208,7 @@ func TestCircuitBreaker_Call_GradualFailureReduction(t *testing.T) {
} }
} }
func TestCircuitBreaker_GetState(t *testing.T) { func TestCircuitBreakerGetState(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
setupFunc func(*CircuitBreaker) setupFunc func(*CircuitBreaker)
@@ -250,7 +250,7 @@ func TestCircuitBreaker_GetState(t *testing.T) {
} }
} }
func TestCircuitBreaker_Reset(t *testing.T) { func TestCircuitBreakerReset(t *testing.T) {
cb := NewCircuitBreaker("test", 2, 1*time.Second) cb := NewCircuitBreaker("test", 2, 1*time.Second)
// Open the circuit // Open the circuit
@@ -261,7 +261,7 @@ func TestCircuitBreaker_Reset(t *testing.T) {
Call(cb, failFn) Call(cb, failFn)
if GetState(cb) != StateOpen { if GetState(cb) != StateOpen {
t.Fatalf("state = %v, want %v", GetState(cb), StateOpen) t.Fatalf(StateMismatchMessage, GetState(cb), StateOpen)
} }
// Reset the circuit breaker // Reset the circuit breaker
@@ -280,7 +280,7 @@ func TestCircuitBreaker_Reset(t *testing.T) {
} }
} }
func TestCircuitBreakerError_Error(t *testing.T) { func TestCircuitBreakerErrorError(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
err *CircuitBreakerError err *CircuitBreakerError
@@ -350,7 +350,7 @@ func TestIsCircuitBreakerError(t *testing.T) {
} }
} }
func TestCircuitBreaker_Concurrency(t *testing.T) { func TestCircuitBreakerConcurrency(t *testing.T) {
cb := NewCircuitBreaker("test", 10, 1*time.Second) cb := NewCircuitBreaker("test", 10, 1*time.Second)
var wg sync.WaitGroup var wg sync.WaitGroup
@@ -397,7 +397,7 @@ func TestCircuitBreaker_Concurrency(t *testing.T) {
} }
} }
func TestCircuitBreaker_OpenCircuitRejectsImmediately(t *testing.T) { func TestCircuitBreakerOpenCircuitRejectsImmediately(t *testing.T) {
cb := NewCircuitBreaker("test", 1, 1*time.Second) cb := NewCircuitBreaker("test", 1, 1*time.Second)
// Open the circuit // Open the circuit
@@ -407,7 +407,7 @@ func TestCircuitBreaker_OpenCircuitRejectsImmediately(t *testing.T) {
Call(cb, failFn) Call(cb, failFn)
if GetState(cb) != StateOpen { if GetState(cb) != StateOpen {
t.Fatalf("state = %v, want %v", GetState(cb), StateOpen) t.Fatalf(StateMismatchMessage, GetState(cb), StateOpen)
} }
// Try calling with a function that should not execute // Try calling with a function that should not execute
@@ -428,7 +428,7 @@ func TestCircuitBreaker_OpenCircuitRejectsImmediately(t *testing.T) {
} }
} }
func BenchmarkCircuitBreaker_Call_Success(b *testing.B) { func BenchmarkCircuitBreakerCallSuccess(b *testing.B) {
cb := NewCircuitBreaker("test", 5, 1*time.Second) cb := NewCircuitBreaker("test", 5, 1*time.Second)
fn := func() error { fn := func() error {
return nil return nil
@@ -440,7 +440,7 @@ func BenchmarkCircuitBreaker_Call_Success(b *testing.B) {
} }
} }
func BenchmarkCircuitBreaker_Call_Open(b *testing.B) { func BenchmarkCircuitBreakerCallOpen(b *testing.B) {
cb := NewCircuitBreaker("test", 1, 1*time.Second) cb := NewCircuitBreaker("test", 1, 1*time.Second)
// Open the circuit // Open the circuit
@@ -458,7 +458,7 @@ func BenchmarkCircuitBreaker_Call_Open(b *testing.B) {
} }
} }
func TestCircuitBreaker_StateTransitions(t *testing.T) { func TestCircuitBreakerStateTransitions(t *testing.T) {
cb := NewCircuitBreaker("test", 2, 1*time.Second) cb := NewCircuitBreaker("test", 2, 1*time.Second)
cb.resetTimeout = 100 * time.Millisecond cb.resetTimeout = 100 * time.Millisecond
@@ -497,7 +497,7 @@ func TestCircuitBreaker_StateTransitions(t *testing.T) {
} }
} }
func TestCircuitBreaker_ZeroMaxFailures(t *testing.T) { func TestCircuitBreakerZeroMaxFailures(t *testing.T) {
cb := NewCircuitBreaker("test", 0, 1*time.Second) cb := NewCircuitBreaker("test", 0, 1*time.Second)
// Even one failure should open circuit when maxFailures is 0 // Even one failure should open circuit when maxFailures is 0
@@ -512,7 +512,7 @@ func TestCircuitBreaker_ZeroMaxFailures(t *testing.T) {
} }
} }
func TestCircuitBreaker_NegativeMaxFailures(t *testing.T) { func TestCircuitBreakerNegativeMaxFailures(t *testing.T) {
// Negative maxFailures should be treated as invalid, but won't panic // Negative maxFailures should be treated as invalid, but won't panic
cb := NewCircuitBreaker("test", -1, 1*time.Second) cb := NewCircuitBreaker("test", -1, 1*time.Second)
@@ -526,7 +526,7 @@ func TestCircuitBreaker_NegativeMaxFailures(t *testing.T) {
} }
} }
func TestCircuitBreaker_VeryShortTimeout(t *testing.T) { func TestCircuitBreakerVeryShortTimeout(t *testing.T) {
cb := NewCircuitBreaker("test", 1, 1*time.Nanosecond) cb := NewCircuitBreaker("test", 1, 1*time.Nanosecond)
cb.resetTimeout = 1 * time.Nanosecond cb.resetTimeout = 1 * time.Nanosecond
@@ -542,7 +542,7 @@ func TestCircuitBreaker_VeryShortTimeout(t *testing.T) {
} }
} }
func TestCircuitBreaker_MultipleSuccessesAfterFailure(t *testing.T) { func TestCircuitBreakerMultipleSuccessesAfterFailure(t *testing.T) {
cb := NewCircuitBreaker("test", 3, 1*time.Second) cb := NewCircuitBreaker("test", 3, 1*time.Second)
// Add one failure // Add one failure
@@ -570,7 +570,7 @@ func TestCircuitBreaker_MultipleSuccessesAfterFailure(t *testing.T) {
} }
} }
func TestCircuitBreaker_HighConcurrency(t *testing.T) { func TestCircuitBreakerHighConcurrency(t *testing.T) {
cb := NewCircuitBreaker("test", 10, 1*time.Second) cb := NewCircuitBreaker("test", 10, 1*time.Second)
concurrency := 100 concurrency := 100
@@ -608,7 +608,7 @@ func TestCircuitBreaker_HighConcurrency(t *testing.T) {
} }
} }
func TestCircuitBreaker_HalfOpenSingleRequest(t *testing.T) { func TestCircuitBreakerHalfOpenSingleRequest(t *testing.T) {
cb := NewCircuitBreaker("test", 1, 1*time.Second) cb := NewCircuitBreaker("test", 1, 1*time.Second)
cb.resetTimeout = 50 * time.Millisecond cb.resetTimeout = 50 * time.Millisecond
@@ -637,7 +637,7 @@ func TestCircuitBreaker_HalfOpenSingleRequest(t *testing.T) {
} }
} }
func TestCircuitBreaker_SuccessResetsFailureCount(t *testing.T) { func TestCircuitBreakerSuccessResetsFailureCount(t *testing.T) {
cb := NewCircuitBreaker("test", 3, 1*time.Second) cb := NewCircuitBreaker("test", 3, 1*time.Second)
// 2 failures // 2 failures
@@ -674,7 +674,7 @@ func TestCircuitBreaker_SuccessResetsFailureCount(t *testing.T) {
} }
} }
func TestCircuitBreaker_DifferentErrorTypes(t *testing.T) { func TestCircuitBreakerDifferentErrorTypes(t *testing.T) {
cb := NewCircuitBreaker("test", 2, 1*time.Second) cb := NewCircuitBreaker("test", 2, 1*time.Second)
// Different error types should all count as failures // Different error types should all count as failures
@@ -686,7 +686,7 @@ func TestCircuitBreaker_DifferentErrorTypes(t *testing.T) {
} }
} }
func TestCircuitBreaker_NilFunction(t *testing.T) { func TestCircuitBreakerNilFunction(t *testing.T) {
cb := NewCircuitBreaker("test", 3, 1*time.Second) cb := NewCircuitBreaker("test", 3, 1*time.Second)
// Should handle nil function gracefully (though this is a programming error) // Should handle nil function gracefully (though this is a programming error)
@@ -699,7 +699,7 @@ func TestCircuitBreaker_NilFunction(t *testing.T) {
Call(cb, nil) Call(cb, nil)
} }
func TestCircuitBreaker_LongRunningOperation(t *testing.T) { func TestCircuitBreakerLongRunningOperation(t *testing.T) {
cb := NewCircuitBreaker("test", 2, 100*time.Millisecond) cb := NewCircuitBreaker("test", 2, 100*time.Millisecond)
// Test that timeout works during operation // Test that timeout works during operation
@@ -715,7 +715,7 @@ func TestCircuitBreaker_LongRunningOperation(t *testing.T) {
} }
} }
func TestCircuitBreaker_RapidStateChanges(t *testing.T) { func TestCircuitBreakerRapidStateChanges(t *testing.T) {
cb := NewCircuitBreaker("test", 1, 1*time.Second) cb := NewCircuitBreaker("test", 1, 1*time.Second)
cb.resetTimeout = 10 * time.Millisecond cb.resetTimeout = 10 * time.Millisecond
+2
View File
@@ -8,4 +8,6 @@ const (
ErrorEncodingResponse = "Error encoding response" ErrorEncodingResponse = "Error encoding response"
ErrorFailedtoLogLoginEvent = "Failed to log login event" ErrorFailedtoLogLoginEvent = "Failed to log login event"
WarningLabel = "WARNING:" WarningLabel = "WARNING:"
StateMismatchMessage = "state = %v, want %v"
ServiceError = "service error"
) )
+3 -3
View File
@@ -68,7 +68,7 @@ func TestLogInfo(t *testing.T) {
} }
} }
func TestLogInfo_NoEnvironment(t *testing.T) { func TestLogInfoNoEnvironment(t *testing.T) {
// Setup // Setup
os.Unsetenv("GO_ENV") os.Unsetenv("GO_ENV")
@@ -188,7 +188,7 @@ func TestLogError(t *testing.T) {
} }
} }
func TestLogError_WithNilError(t *testing.T) { func TestLogErrorWithNilError(t *testing.T) {
// Setup // Setup
os.Setenv("GO_ENV", "development") os.Setenv("GO_ENV", "development")
defer os.Unsetenv("GO_ENV") defer os.Unsetenv("GO_ENV")
@@ -223,7 +223,7 @@ func TestLogFatal(t *testing.T) {
}) })
} }
func TestLogging_EnvironmentCheck(t *testing.T) { func TestLoggingEnvironmentCheck(t *testing.T) {
// Test that all logging functions check for GO_ENV // Test that all logging functions check for GO_ENV
originalEnv := os.Getenv("GO_ENV") originalEnv := os.Getenv("GO_ENV")
defer func() { defer func() {
+6 -6
View File
@@ -74,7 +74,7 @@ func TestGetClientIP(t *testing.T) {
} }
} }
func TestCheckRateLimit_AllowedRequests(t *testing.T) { func TestCheckRateLimitAllowedRequests(t *testing.T) {
db, mock := redismock.NewClientMock() db, mock := redismock.NewClientMock()
originalRedis := redisclient.RDB originalRedis := redisclient.RDB
redisclient.RDB = db redisclient.RDB = db
@@ -107,7 +107,7 @@ func TestCheckRateLimit_AllowedRequests(t *testing.T) {
} }
} }
func TestCheckRateLimit_ExceedsLimit(t *testing.T) { func TestCheckRateLimitExceedsLimit(t *testing.T) {
db, mock := redismock.NewClientMock() db, mock := redismock.NewClientMock()
originalRedis := redisclient.RDB originalRedis := redisclient.RDB
redisclient.RDB = db redisclient.RDB = db
@@ -140,7 +140,7 @@ func TestCheckRateLimit_ExceedsLimit(t *testing.T) {
} }
} }
func TestCheckRateLimit_RedisError(t *testing.T) { func TestCheckRateLimitRedisError(t *testing.T) {
db, mock := redismock.NewClientMock() db, mock := redismock.NewClientMock()
originalRedis := redisclient.RDB originalRedis := redisclient.RDB
redisclient.RDB = db redisclient.RDB = db
@@ -169,7 +169,7 @@ func TestCheckRateLimit_RedisError(t *testing.T) {
} }
} }
func TestRateLimiterMiddleware_RedisNotAvailable(t *testing.T) { func TestRateLimiterMiddlewareRedisNotAvailable(t *testing.T) {
originalRedis := redisclient.RDB originalRedis := redisclient.RDB
redisclient.RDB = nil redisclient.RDB = nil
defer func() { redisclient.RDB = originalRedis }() defer func() { redisclient.RDB = originalRedis }()
@@ -243,7 +243,7 @@ func TestRateLimiterMiddleware_AllowsRequest(t *testing.T) {
} }
} }
func TestRateLimiterMiddleware_BlocksRequest(t *testing.T) { func TestRateLimiterMiddlewareBlocksRequest(t *testing.T) {
db, mock := redismock.NewClientMock() db, mock := redismock.NewClientMock()
originalRedis := redisclient.RDB originalRedis := redisclient.RDB
redisclient.RDB = db redisclient.RDB = db
@@ -285,7 +285,7 @@ func TestRateLimiterMiddleware_BlocksRequest(t *testing.T) {
} }
} }
func TestRateLimiterMiddleware_FailsOpenOnError(t *testing.T) { func TestRateLimiterMiddlewareFailsOpenOnError(t *testing.T) {
db, mock := redismock.NewClientMock() db, mock := redismock.NewClientMock()
originalRedis := redisclient.RDB originalRedis := redisclient.RDB
redisclient.RDB = db redisclient.RDB = db
+1 -1
View File
@@ -10,7 +10,7 @@ import (
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
) )
func TestInit_DefaultValues(t *testing.T) { func TestInitDefaultValues(t *testing.T) {
// Save original values // Save original values
originalHost := os.Getenv("REDIS_HOST") originalHost := os.Getenv("REDIS_HOST")
originalPort := os.Getenv("REDIS_PORT") originalPort := os.Getenv("REDIS_PORT")