Files
Authorization/handlers/health_test.go
T
2025-12-16 10:57:26 +08:00

217 lines
5.4 KiB
Go

package handlers
import (
"authorization/db"
"authorization/models"
"authorization/redisclient"
"database/sql"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/DATA-DOG/go-sqlmock"
)
func TestHealthHandler(t *testing.T) {
tests := []struct {
name string
wantStatus int
wantBodyStatus string
}{
{
name: "returns 200 OK with ok status",
wantStatus: http.StatusOK,
wantBodyStatus: "ok",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/health", nil)
w := httptest.NewRecorder()
HealthHandler(w, req)
resp := w.Result()
defer resp.Body.Close()
if resp.StatusCode != tt.wantStatus {
t.Errorf("status = %v, want %v", resp.StatusCode, tt.wantStatus)
}
var healthResp models.HealthResponse
if err := json.NewDecoder(resp.Body).Decode(&healthResp); err != nil {
t.Fatalf("failed to decode response: %v", err)
}
if healthResp.Status != tt.wantBodyStatus {
t.Errorf("status = %v, want %v", healthResp.Status, tt.wantBodyStatus)
}
contentType := resp.Header.Get("Content-Type")
if contentType != "application/json" {
t.Errorf("Content-Type = %v, want application/json", contentType)
}
})
}
}
func TestReadyHandler_AllHealthy(t *testing.T) {
// Setup mock DB
mockDB, mock, err := sqlmock.New(sqlmock.MonitorPingsOption(true))
if err != nil {
t.Fatalf("failed to create mock db: %v", err)
}
defer mockDB.Close()
// Expect successful ping
mock.ExpectPing()
// Save original and set mock
originalDB := db.DB
db.DB = mockDB
defer func() { db.DB = originalDB }()
// Save original Redis and set to nil (not checking Redis in this test)
originalRedis := redisclient.RDB
redisclient.RDB = nil
defer func() { redisclient.RDB = originalRedis }()
req := httptest.NewRequest(http.MethodGet, "/ready", nil)
w := httptest.NewRecorder()
ReadyHandler(w, req)
resp := w.Result()
defer resp.Body.Close()
var healthResp models.HealthResponse
if err := json.NewDecoder(resp.Body).Decode(&healthResp); err != nil {
t.Fatalf("failed to decode response: %v", err)
}
if healthResp.Services["database"] != "healthy" {
t.Errorf("database status = %v, want healthy", healthResp.Services["database"])
}
// Verify mock expectations
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("unfulfilled mock expectations: %v", err)
}
}
func TestReadyHandler_DBUnhealthy(t *testing.T) {
// Setup mock DB that fails ping
mockDB, mock, err := sqlmock.New(sqlmock.MonitorPingsOption(true))
if err != nil {
t.Fatalf("failed to create mock db: %v", err)
}
defer mockDB.Close()
// Expect ping to fail
mock.ExpectPing().WillReturnError(sql.ErrConnDone)
// Save original and set mock
originalDB := db.DB
db.DB = mockDB
defer func() { db.DB = originalDB }()
// Save original Redis and set to nil
originalRedis := redisclient.RDB
redisclient.RDB = nil
defer func() { redisclient.RDB = originalRedis }()
req := httptest.NewRequest(http.MethodGet, "/ready", nil)
w := httptest.NewRecorder()
ReadyHandler(w, req)
resp := w.Result()
defer resp.Body.Close()
if resp.StatusCode != http.StatusServiceUnavailable {
t.Errorf("status = %v, want %v", resp.StatusCode, http.StatusServiceUnavailable)
}
var healthResp models.HealthResponse
if err := json.NewDecoder(resp.Body).Decode(&healthResp); err != nil {
t.Fatalf("failed to decode response: %v", err)
}
if healthResp.Status != "not_ready" {
t.Errorf("status = %v, want not_ready", healthResp.Status)
}
if healthResp.Services["database"] != "unhealthy" {
t.Errorf("database status = %v, want unhealthy", healthResp.Services["database"])
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("unfulfilled mock expectations: %v", err)
}
}
func TestReadyHandler_DBNotInitialized(t *testing.T) {
// Save original and set to nil
originalDB := db.DB
db.DB = nil
defer func() { db.DB = originalDB }()
originalRedis := redisclient.RDB
redisclient.RDB = nil
defer func() { redisclient.RDB = originalRedis }()
req := httptest.NewRequest(http.MethodGet, "/ready", nil)
w := httptest.NewRecorder()
ReadyHandler(w, req)
resp := w.Result()
defer resp.Body.Close()
if resp.StatusCode != http.StatusServiceUnavailable {
t.Errorf("status = %v, want %v", resp.StatusCode, http.StatusServiceUnavailable)
}
var healthResp models.HealthResponse
if err := json.NewDecoder(resp.Body).Decode(&healthResp); err != nil {
t.Fatalf("failed to decode response: %v", err)
}
if healthResp.Status != "not_ready" {
t.Errorf("status = %v, want not_ready", healthResp.Status)
}
if healthResp.Services["database"] != "not_initialized" {
t.Errorf("database status = %v, want not_initialized", healthResp.Services["database"])
}
if healthResp.Services["redis"] != "not_initialized" {
t.Errorf("redis status = %v, want not_initialized", healthResp.Services["redis"])
}
}
func TestReadyHandler_ContentType(t *testing.T) {
originalDB := db.DB
db.DB = nil
defer func() { db.DB = originalDB }()
originalRedis := redisclient.RDB
redisclient.RDB = nil
defer func() { redisclient.RDB = originalRedis }()
req := httptest.NewRequest(http.MethodGet, "/ready", nil)
w := httptest.NewRecorder()
ReadyHandler(w, req)
resp := w.Result()
defer resp.Body.Close()
contentType := resp.Header.Get("Content-Type")
if contentType != "application/json" {
t.Errorf("Content-Type = %v, want application/json", contentType)
}
}