feat(audit): cover operational mutations

This commit is contained in:
2026-06-05 10:45:55 +08:00
parent 4597d404fd
commit 2ec5366d7c
8 changed files with 321 additions and 24 deletions
@@ -41,6 +41,7 @@ func setupSlaPolicyHandlerTest(t *testing.T) (*SlaPolicyHandler, *gorm.DB) {
&model.Conversation{},
&model.User{},
&model.Team{},
&model.Audit{},
))
t.Cleanup(func() {
sqlDB, _ := db.DB()
@@ -52,7 +53,8 @@ func setupSlaPolicyHandlerTest(t *testing.T) (*SlaPolicyHandler, *gorm.DB) {
slaEventRepo := repository.NewSlaEventRepo(db)
slaPolicyInboxRepo := repository.NewSlaPolicyInboxRepo(db)
svc := service.NewSlaPolicyService(slaPolicyRepo, appliedSlaRepo, slaEventRepo, slaPolicyInboxRepo)
handler := NewSlaPolicyHandler(svc)
auditSvc := service.NewAuditService(repository.NewAuditRepo(db))
handler := NewSlaPolicyHandler(svc).WithAuditService(auditSvc)
// Seed an account for all tests
account := &model.Account{Name: "SlaHandlerOrg", Locale: "en", Active: true}
@@ -101,6 +103,21 @@ func setupSlaPolicyTestRouter(handler *SlaPolicyHandler) *gin.Engine {
return r
}
func setupSlaPolicyAuditRouter(handler *SlaPolicyHandler, accountID uint, userID uint) *gin.Engine {
gin.SetMode(gin.TestMode)
r := gin.New()
r.Use(func(c *gin.Context) {
c.Set("account_id", accountID)
c.Set("user_id", userID)
c.Next()
})
rg := r.Group("/api/v1/accounts/:account_id")
rg.POST("/sla_policies", handler.Create)
rg.PUT("/sla_policies/:id", handler.Update)
rg.DELETE("/sla_policies/:id", handler.Delete)
return r
}
// ========== List ==========
func TestSlaPolicyHandler_List_Success(t *testing.T) {
@@ -211,6 +228,62 @@ func TestSlaPolicyHandler_Create_ValidationError(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestSlaPolicyHandler_MutationsWriteAuditEntries(t *testing.T) {
handler, db := setupSlaPolicyHandlerTest(t)
accountID := slaHandlerAccountIDUint(db)
router := setupSlaPolicyAuditRouter(handler, accountID, 88)
createBody, _ := json.Marshal(map[string]any{"sla_policy": map[string]any{
"name": "Audit SLA",
"first_response_time_threshold": 15,
"next_response_time_threshold": 30,
"resolution_time_threshold": 90,
}})
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodPost, "/api/v1/accounts/"+strconv.FormatUint(uint64(accountID), 10)+"/sla_policies", bytes.NewBuffer(createBody))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Request-ID", "sla-audit-create")
router.ServeHTTP(w, req)
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
var created map[string]any
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &created))
policyID := uint(created["payload"].(map[string]any)["id"].(float64))
updateBody, _ := json.Marshal(map[string]any{"sla_policy": map[string]any{
"name": "Audit SLA Updated",
"first_response_time_threshold": 20,
"next_response_time_threshold": 40,
"resolution_time_threshold": 100,
}})
w = httptest.NewRecorder()
req, _ = http.NewRequest(http.MethodPut, "/api/v1/accounts/"+strconv.FormatUint(uint64(accountID), 10)+"/sla_policies/"+strconv.FormatUint(uint64(policyID), 10), bytes.NewBuffer(updateBody))
req.Header.Set("Content-Type", "application/json")
router.ServeHTTP(w, req)
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
w = httptest.NewRecorder()
req, _ = http.NewRequest(http.MethodDelete, "/api/v1/accounts/"+strconv.FormatUint(uint64(accountID), 10)+"/sla_policies/"+strconv.FormatUint(uint64(policyID), 10), nil)
router.ServeHTTP(w, req)
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
var audits []model.Audit
require.NoError(t, db.Order("id ASC").Find(&audits).Error)
require.Len(t, audits, 3)
for _, audit := range audits {
assert.Equal(t, accountID, *audit.AccountID)
assert.Equal(t, "Account", audit.AssociatedType)
assert.Equal(t, accountID, *audit.AssociatedID)
assert.Equal(t, uint(88), *audit.UserID)
assert.Equal(t, "SlaPolicy", audit.AuditableType)
assert.Equal(t, policyID, audit.AuditableID)
assert.NotEmpty(t, audit.AuditedChanges)
}
assert.Equal(t, "create", audits[0].Action)
assert.Equal(t, "sla-audit-create", audits[0].RequestUUID)
assert.Equal(t, "update", audits[1].Action)
assert.Equal(t, "destroy", audits[2].Action)
}
func TestSlaPolicyHandler_Create_NoAccountID(t *testing.T) {
gin.SetMode(gin.TestMode)
r := gin.New()