Complete lint remediation addressing errcheck, gosec, and staticcheck violations across backend test files. Tighten pre-commit configuration to prevent future blind spots. Key Changes: - Fix 61 Go linting issues (errcheck, gosec G115/G301/G304/G306, bodyclose) - Add proper error handling for json.Unmarshal, os.Setenv, db.Close(), w.Write() - Fix gosec G115 integer overflow with strconv.FormatUint - Add #nosec annotations with justifications for test fixtures - Fix SecurityService goroutine leaks (add Close() calls) - Fix CrowdSec tar.gz non-deterministic ordering with sorted keys Pre-commit Hardening: - Remove test file exclusion from golangci-lint hook - Add gosec to .golangci-fast.yml with critical checks (G101, G110, G305) - Replace broad .golangci.yml exclusions with targeted path-specific rules - Test files now linted on every commit Test Fixes: - Fix emergency route count assertions (1→2 for dual-port setup) - Fix DNS provider service tests with proper mock setup - Fix certificate service tests with deterministic behavior Backend: 27 packages pass, 83.5% coverage Frontend: 0 lint warnings, 0 TypeScript errors Pre-commit: All 14 hooks pass (~37s)
652 lines
17 KiB
Go
652 lines
17 KiB
Go
package handlers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/Wikid82/charon/backend/internal/models"
|
|
"github.com/Wikid82/charon/backend/internal/services"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/stretchr/testify/assert"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func setupAuditLogTestDB(t *testing.T) *gorm.DB {
|
|
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
|
if err != nil {
|
|
t.Fatalf("failed to open test database: %v", err)
|
|
}
|
|
|
|
if err := db.AutoMigrate(&models.SecurityAudit{}); err != nil {
|
|
t.Fatalf("failed to migrate test database: %v", err)
|
|
}
|
|
|
|
return db
|
|
}
|
|
|
|
func TestAuditLogHandler_List(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
db := setupAuditLogTestDB(t)
|
|
securityService := services.NewSecurityService(db)
|
|
defer securityService.Close()
|
|
handler := NewAuditLogHandler(securityService)
|
|
|
|
// Create test audit logs
|
|
now := time.Now()
|
|
testAudits := []models.SecurityAudit{
|
|
{
|
|
UUID: "audit-1",
|
|
Actor: "user-1",
|
|
Action: "dns_provider_create",
|
|
EventCategory: "dns_provider",
|
|
ResourceUUID: "provider-1",
|
|
Details: `{"name":"Test Provider"}`,
|
|
IPAddress: "192.168.1.1",
|
|
UserAgent: "Mozilla/5.0",
|
|
CreatedAt: now,
|
|
},
|
|
{
|
|
UUID: "audit-2",
|
|
Actor: "user-2",
|
|
Action: "dns_provider_update",
|
|
EventCategory: "dns_provider",
|
|
ResourceUUID: "provider-2",
|
|
Details: `{"changed_fields":{"name":true}}`,
|
|
IPAddress: "192.168.1.2",
|
|
UserAgent: "Mozilla/5.0",
|
|
CreatedAt: now.Add(-1 * time.Hour),
|
|
},
|
|
}
|
|
|
|
for _, audit := range testAudits {
|
|
if err := db.Create(&audit).Error; err != nil {
|
|
t.Fatalf("failed to create test audit: %v", err)
|
|
}
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
queryParams string
|
|
expectedStatus int
|
|
expectedCount int
|
|
}{
|
|
{
|
|
name: "List all audit logs",
|
|
queryParams: "",
|
|
expectedStatus: http.StatusOK,
|
|
expectedCount: 2,
|
|
},
|
|
{
|
|
name: "Filter by actor",
|
|
queryParams: "?actor=user-1",
|
|
expectedStatus: http.StatusOK,
|
|
expectedCount: 1,
|
|
},
|
|
{
|
|
name: "Filter by action",
|
|
queryParams: "?action=dns_provider_create",
|
|
expectedStatus: http.StatusOK,
|
|
expectedCount: 1,
|
|
},
|
|
{
|
|
name: "Filter by event_category",
|
|
queryParams: "?event_category=dns_provider",
|
|
expectedStatus: http.StatusOK,
|
|
expectedCount: 2,
|
|
},
|
|
{
|
|
name: "Pagination - page 1, limit 1",
|
|
queryParams: "?page=1&limit=1",
|
|
expectedStatus: http.StatusOK,
|
|
expectedCount: 1,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request, _ = http.NewRequest(http.MethodGet, "/api/v1/audit-logs"+tt.queryParams, nil)
|
|
|
|
handler.List(c)
|
|
|
|
assert.Equal(t, tt.expectedStatus, w.Code)
|
|
|
|
if w.Code == http.StatusOK {
|
|
var response map[string]interface{}
|
|
err := json.Unmarshal(w.Body.Bytes(), &response)
|
|
assert.NoError(t, err)
|
|
|
|
audits := response["audit_logs"].([]interface{})
|
|
assert.Equal(t, tt.expectedCount, len(audits))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAuditLogHandler_Get(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
db := setupAuditLogTestDB(t)
|
|
securityService := services.NewSecurityService(db)
|
|
defer securityService.Close()
|
|
handler := NewAuditLogHandler(securityService)
|
|
|
|
// Create test audit log
|
|
testAudit := models.SecurityAudit{
|
|
UUID: "audit-test-uuid",
|
|
Actor: "user-1",
|
|
Action: "dns_provider_create",
|
|
EventCategory: "dns_provider",
|
|
ResourceUUID: "provider-1",
|
|
Details: `{"name":"Test Provider"}`,
|
|
IPAddress: "192.168.1.1",
|
|
UserAgent: "Mozilla/5.0",
|
|
CreatedAt: time.Now(),
|
|
}
|
|
|
|
if err := db.Create(&testAudit).Error; err != nil {
|
|
t.Fatalf("failed to create test audit: %v", err)
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
uuid string
|
|
expectedStatus int
|
|
}{
|
|
{
|
|
name: "Get existing audit log",
|
|
uuid: "audit-test-uuid",
|
|
expectedStatus: http.StatusOK,
|
|
},
|
|
{
|
|
name: "Get non-existent audit log",
|
|
uuid: "non-existent-uuid",
|
|
expectedStatus: http.StatusNotFound,
|
|
},
|
|
{
|
|
name: "Get with empty UUID",
|
|
uuid: "",
|
|
expectedStatus: http.StatusBadRequest,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Params = gin.Params{gin.Param{Key: "uuid", Value: tt.uuid}}
|
|
c.Request, _ = http.NewRequest(http.MethodGet, "/api/v1/audit-logs/"+tt.uuid, nil)
|
|
|
|
handler.Get(c)
|
|
|
|
assert.Equal(t, tt.expectedStatus, w.Code)
|
|
|
|
if w.Code == http.StatusOK {
|
|
var response models.SecurityAudit
|
|
err := json.Unmarshal(w.Body.Bytes(), &response)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, testAudit.UUID, response.UUID)
|
|
assert.Equal(t, testAudit.Actor, response.Actor)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAuditLogHandler_ListByProvider(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
db := setupAuditLogTestDB(t)
|
|
securityService := services.NewSecurityService(db)
|
|
defer securityService.Close()
|
|
handler := NewAuditLogHandler(securityService)
|
|
|
|
// Create test audit logs
|
|
providerID := uint(123)
|
|
now := time.Now()
|
|
testAudits := []models.SecurityAudit{
|
|
{
|
|
UUID: "audit-provider-1",
|
|
Actor: "user-1",
|
|
Action: "dns_provider_create",
|
|
EventCategory: "dns_provider",
|
|
ResourceID: &providerID,
|
|
ResourceUUID: "provider-uuid-1",
|
|
Details: `{"name":"Test Provider"}`,
|
|
CreatedAt: now,
|
|
},
|
|
{
|
|
UUID: "audit-provider-2",
|
|
Actor: "user-1",
|
|
Action: "dns_provider_update",
|
|
EventCategory: "dns_provider",
|
|
ResourceID: &providerID,
|
|
ResourceUUID: "provider-uuid-1",
|
|
Details: `{"changed_fields":{"name":true}}`,
|
|
CreatedAt: now.Add(-1 * time.Hour),
|
|
},
|
|
}
|
|
|
|
for _, audit := range testAudits {
|
|
if err := db.Create(&audit).Error; err != nil {
|
|
t.Fatalf("failed to create test audit: %v", err)
|
|
}
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
providerID string
|
|
expectedStatus int
|
|
expectedCount int
|
|
}{
|
|
{
|
|
name: "List audit logs for provider",
|
|
providerID: "123",
|
|
expectedStatus: http.StatusOK,
|
|
expectedCount: 2,
|
|
},
|
|
{
|
|
name: "List audit logs for non-existent provider",
|
|
providerID: "999",
|
|
expectedStatus: http.StatusOK,
|
|
expectedCount: 0,
|
|
},
|
|
{
|
|
name: "Invalid provider ID",
|
|
providerID: "invalid",
|
|
expectedStatus: http.StatusBadRequest,
|
|
expectedCount: 0,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Params = gin.Params{gin.Param{Key: "id", Value: tt.providerID}}
|
|
c.Request, _ = http.NewRequest(http.MethodGet, "/api/v1/dns-providers/"+tt.providerID+"/audit-logs", nil)
|
|
|
|
handler.ListByProvider(c)
|
|
|
|
assert.Equal(t, tt.expectedStatus, w.Code)
|
|
|
|
if w.Code == http.StatusOK {
|
|
var response map[string]interface{}
|
|
err := json.Unmarshal(w.Body.Bytes(), &response)
|
|
assert.NoError(t, err)
|
|
|
|
audits := response["audit_logs"].([]interface{})
|
|
assert.Equal(t, tt.expectedCount, len(audits))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAuditLogHandler_ListWithDateFilters(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
db := setupAuditLogTestDB(t)
|
|
securityService := services.NewSecurityService(db)
|
|
defer securityService.Close()
|
|
handler := NewAuditLogHandler(securityService)
|
|
|
|
// Create test audit logs with different timestamps
|
|
now := time.Now()
|
|
yesterday := now.Add(-24 * time.Hour)
|
|
twoDaysAgo := now.Add(-48 * time.Hour)
|
|
|
|
testAudits := []models.SecurityAudit{
|
|
{
|
|
UUID: "audit-today",
|
|
Actor: "user-1",
|
|
Action: "dns_provider_create",
|
|
EventCategory: "dns_provider",
|
|
CreatedAt: now,
|
|
},
|
|
{
|
|
UUID: "audit-yesterday",
|
|
Actor: "user-1",
|
|
Action: "dns_provider_update",
|
|
EventCategory: "dns_provider",
|
|
CreatedAt: yesterday,
|
|
},
|
|
{
|
|
UUID: "audit-two-days-ago",
|
|
Actor: "user-1",
|
|
Action: "dns_provider_delete",
|
|
EventCategory: "dns_provider",
|
|
CreatedAt: twoDaysAgo,
|
|
},
|
|
}
|
|
|
|
for _, audit := range testAudits {
|
|
if err := db.Create(&audit).Error; err != nil {
|
|
t.Fatalf("failed to create test audit: %v", err)
|
|
}
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
queryParams string
|
|
expectedCount int
|
|
}{
|
|
{
|
|
name: "Filter by start_date",
|
|
queryParams: "?start_date=" + yesterday.Add(-1*time.Hour).Format(time.RFC3339),
|
|
expectedCount: 2,
|
|
},
|
|
{
|
|
name: "Filter by end_date",
|
|
queryParams: "?end_date=" + yesterday.Add(1*time.Hour).Format(time.RFC3339),
|
|
expectedCount: 2,
|
|
},
|
|
{
|
|
name: "Filter by date range",
|
|
queryParams: "?start_date=" + twoDaysAgo.Add(-1*time.Hour).Format(time.RFC3339) + "&end_date=" + yesterday.Add(1*time.Hour).Format(time.RFC3339),
|
|
expectedCount: 2,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request, _ = http.NewRequest(http.MethodGet, "/api/v1/audit-logs"+tt.queryParams, nil)
|
|
|
|
handler.List(c)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
var response map[string]interface{}
|
|
err := json.Unmarshal(w.Body.Bytes(), &response)
|
|
assert.NoError(t, err)
|
|
|
|
audits := response["audit_logs"].([]interface{})
|
|
assert.Equal(t, tt.expectedCount, len(audits))
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestAuditLogHandler_ServiceErrors tests error handling when service layer fails
|
|
func TestAuditLogHandler_ServiceErrors(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
db := setupAuditLogTestDB(t)
|
|
securityService := services.NewSecurityService(db)
|
|
defer securityService.Close()
|
|
handler := NewAuditLogHandler(securityService)
|
|
|
|
t.Run("List fails when database unavailable", func(t *testing.T) {
|
|
// Close the database to trigger error
|
|
sqlDB, err := db.DB()
|
|
assert.NoError(t, err)
|
|
_ = sqlDB.Close()
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request, _ = http.NewRequest(http.MethodGet, "/api/v1/audit-logs", nil)
|
|
|
|
handler.List(c)
|
|
|
|
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
|
assert.Contains(t, w.Body.String(), "Failed to retrieve audit logs")
|
|
})
|
|
|
|
t.Run("ListByProvider fails when database unavailable", func(t *testing.T) {
|
|
// Database is already closed from previous test
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Params = gin.Params{gin.Param{Key: "id", Value: "123"}}
|
|
c.Request, _ = http.NewRequest(http.MethodGet, "/api/v1/dns-providers/123/audit-logs", nil)
|
|
|
|
handler.ListByProvider(c)
|
|
|
|
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
|
assert.Contains(t, w.Body.String(), "Failed to retrieve audit logs")
|
|
})
|
|
|
|
t.Run("Get fails when database unavailable", func(t *testing.T) {
|
|
// Database is already closed from previous tests
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Params = gin.Params{gin.Param{Key: "uuid", Value: "some-uuid"}}
|
|
c.Request, _ = http.NewRequest(http.MethodGet, "/api/v1/audit-logs/some-uuid", nil)
|
|
|
|
handler.Get(c)
|
|
|
|
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
|
assert.Contains(t, w.Body.String(), "Failed to retrieve audit log")
|
|
})
|
|
}
|
|
|
|
// TestAuditLogHandler_List_PaginationBoundaryEdgeCases tests pagination boundary edge cases
|
|
func TestAuditLogHandler_List_PaginationBoundaryEdgeCases(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
db := setupAuditLogTestDB(t)
|
|
securityService := services.NewSecurityService(db)
|
|
defer securityService.Close()
|
|
handler := NewAuditLogHandler(securityService)
|
|
|
|
// Create test audit logs
|
|
for i := 0; i < 5; i++ {
|
|
audit := models.SecurityAudit{
|
|
UUID: fmt.Sprintf("audit-%d", i),
|
|
Actor: "user-1",
|
|
Action: "test_action",
|
|
EventCategory: "test",
|
|
CreatedAt: time.Now(),
|
|
}
|
|
db.Create(&audit)
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
queryParams string
|
|
expectPage int
|
|
expectLimit int
|
|
}{
|
|
{
|
|
name: "Negative page defaults to 1",
|
|
queryParams: "?page=-5",
|
|
expectPage: 1,
|
|
expectLimit: 50,
|
|
},
|
|
{
|
|
name: "Zero page defaults to 1",
|
|
queryParams: "?page=0",
|
|
expectPage: 1,
|
|
expectLimit: 50,
|
|
},
|
|
{
|
|
name: "Negative limit defaults to 50",
|
|
queryParams: "?limit=-10",
|
|
expectPage: 1,
|
|
expectLimit: 50,
|
|
},
|
|
{
|
|
name: "Zero limit defaults to 50",
|
|
queryParams: "?limit=0",
|
|
expectPage: 1,
|
|
expectLimit: 50,
|
|
},
|
|
{
|
|
name: "Limit over 100 defaults to 50",
|
|
queryParams: "?limit=200",
|
|
expectPage: 1,
|
|
expectLimit: 50,
|
|
},
|
|
{
|
|
name: "Non-numeric page ignored",
|
|
queryParams: "?page=abc",
|
|
expectPage: 1,
|
|
expectLimit: 50,
|
|
},
|
|
{
|
|
name: "Non-numeric limit ignored",
|
|
queryParams: "?limit=xyz",
|
|
expectPage: 1,
|
|
expectLimit: 50,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request, _ = http.NewRequest(http.MethodGet, "/api/v1/audit-logs"+tt.queryParams, nil)
|
|
|
|
handler.List(c)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
var response map[string]interface{}
|
|
err := json.Unmarshal(w.Body.Bytes(), &response)
|
|
assert.NoError(t, err)
|
|
|
|
pagination := response["pagination"].(map[string]interface{})
|
|
assert.Equal(t, float64(tt.expectPage), pagination["page"])
|
|
assert.Equal(t, float64(tt.expectLimit), pagination["limit"])
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestAuditLogHandler_ListByProvider_PaginationBoundaryEdgeCases tests pagination boundary edge cases for provider list
|
|
func TestAuditLogHandler_ListByProvider_PaginationBoundaryEdgeCases(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
db := setupAuditLogTestDB(t)
|
|
securityService := services.NewSecurityService(db)
|
|
defer securityService.Close()
|
|
handler := NewAuditLogHandler(securityService)
|
|
|
|
providerID := uint(999)
|
|
// Create test audit logs for this provider
|
|
for i := 0; i < 3; i++ {
|
|
audit := models.SecurityAudit{
|
|
UUID: fmt.Sprintf("provider-audit-%d", i),
|
|
Actor: "user-1",
|
|
Action: "dns_provider_update",
|
|
EventCategory: "dns_provider",
|
|
ResourceID: &providerID,
|
|
CreatedAt: time.Now(),
|
|
}
|
|
db.Create(&audit)
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
queryParams string
|
|
expectPage int
|
|
expectLimit int
|
|
}{
|
|
{
|
|
name: "Negative page defaults to 1",
|
|
queryParams: "?page=-1",
|
|
expectPage: 1,
|
|
expectLimit: 50,
|
|
},
|
|
{
|
|
name: "Zero limit defaults to 50",
|
|
queryParams: "?limit=0",
|
|
expectPage: 1,
|
|
expectLimit: 50,
|
|
},
|
|
{
|
|
name: "Limit over 100 defaults to 50",
|
|
queryParams: "?limit=150",
|
|
expectPage: 1,
|
|
expectLimit: 50,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Params = gin.Params{gin.Param{Key: "id", Value: "999"}}
|
|
c.Request, _ = http.NewRequest(http.MethodGet, "/api/v1/dns-providers/999/audit-logs"+tt.queryParams, nil)
|
|
|
|
handler.ListByProvider(c)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
var response map[string]interface{}
|
|
err := json.Unmarshal(w.Body.Bytes(), &response)
|
|
assert.NoError(t, err)
|
|
|
|
pagination := response["pagination"].(map[string]interface{})
|
|
assert.Equal(t, float64(tt.expectPage), pagination["page"])
|
|
assert.Equal(t, float64(tt.expectLimit), pagination["limit"])
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestAuditLogHandler_List_InvalidDateFormats tests handling of invalid date formats
|
|
func TestAuditLogHandler_List_InvalidDateFormats(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
db := setupAuditLogTestDB(t)
|
|
securityService := services.NewSecurityService(db)
|
|
defer securityService.Close()
|
|
handler := NewAuditLogHandler(securityService)
|
|
|
|
// Invalid date formats should be ignored (not cause errors)
|
|
tests := []struct {
|
|
name string
|
|
queryParams string
|
|
}{
|
|
{
|
|
name: "Invalid start_date format",
|
|
queryParams: "?start_date=not-a-date",
|
|
},
|
|
{
|
|
name: "Invalid end_date format",
|
|
queryParams: "?end_date=invalid-format",
|
|
},
|
|
{
|
|
name: "Both dates invalid",
|
|
queryParams: "?start_date=bad&end_date=also-bad",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request, _ = http.NewRequest(http.MethodGet, "/api/v1/audit-logs"+tt.queryParams, nil)
|
|
|
|
handler.List(c)
|
|
|
|
// Should succeed (invalid dates are ignored, not errors)
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestAuditLogHandler_Get_InternalError tests Get when service returns internal error
|
|
func TestAuditLogHandler_Get_InternalError(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
|
|
// Create a fresh DB and immediately close it to simulate internal error
|
|
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
|
assert.NoError(t, err)
|
|
_ = db.AutoMigrate(&models.SecurityAudit{})
|
|
|
|
securityService := services.NewSecurityService(db)
|
|
defer securityService.Close()
|
|
handler := NewAuditLogHandler(securityService)
|
|
|
|
// Close the DB to force internal error (not "not found")
|
|
sqlDB, _ := db.DB()
|
|
_ = sqlDB.Close()
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Params = gin.Params{gin.Param{Key: "uuid", Value: "test-uuid"}}
|
|
c.Request, _ = http.NewRequest(http.MethodGet, "/api/v1/audit-logs/test-uuid", nil)
|
|
|
|
handler.Get(c)
|
|
|
|
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
|
assert.Contains(t, w.Body.String(), "Failed to retrieve audit log")
|
|
}
|