fix(ticket): harden lightweight backend core

This commit is contained in:
mlogclub
2026-05-02 19:19:18 +08:00
parent a06ce7074e
commit fa9d431cbe
9 changed files with 232 additions and 51 deletions
+68 -4
View File
@@ -208,6 +208,43 @@ func TestTicketServiceAssignTicketRequiresTargetUser(t *testing.T) {
}
}
func TestTicketServiceAssignTicketRejectsDisabledUser(t *testing.T) {
setupTicketTestDB(t)
operator := createTestOperator(t, "assign-disabled-operator")
disabledUserID := createTestUserWithStatus(t, "assign-disabled-user", enums.StatusDisabled)
ticket, err := services.TicketService.CreateTicket(createTestTicketRequest("assign-disabled-ticket"), operator)
if err != nil {
t.Fatalf("CreateTicket() error = %v", err)
}
err = services.TicketService.AssignTicket(request.AssignTicketRequest{
TicketID: ticket.ID,
ToUserID: disabledUserID,
Reason: "disabled assignment",
}, operator)
if err == nil {
t.Fatalf("expected AssignTicket() to reject disabled target user")
}
}
func TestTicketServiceCreateTicketRejectsMismatchedCustomerConversation(t *testing.T) {
setupTicketTestDB(t)
operator := createTestOperator(t, "mismatch-operator")
customerID := createTestCustomer(t, "mismatch-customer")
otherCustomerID := createTestCustomer(t, "mismatch-other-customer")
conversationID := createTestConversation(t, otherCustomerID, "mismatch-conversation")
_, err := services.TicketService.CreateTicket(request.CreateTicketRequest{
Title: "mismatch ticket",
Description: "mismatch ticket description",
CustomerID: customerID,
ConversationID: conversationID,
}, operator)
if err == nil {
t.Fatalf("expected CreateTicket() to reject mismatched customer and conversation")
}
}
func TestTicketServiceSummaryCountsStaleTickets(t *testing.T) {
setupTicketTestDB(t)
operator := createTestOperator(t, "summary-operator")
@@ -284,9 +321,9 @@ func TestTicketServiceFindPageAggregateEnrichesLookups(t *testing.T) {
}
func TestTicketServiceTicketNoNextConcurrent(t *testing.T) {
setupTicketTestDB(t)
setupTicketTestDBWithMaxOpenConns(t, 8)
const count = 20
const count = 50
results := make(chan string, count)
errs := make(chan error, count)
var wg sync.WaitGroup
@@ -332,6 +369,10 @@ func TestTicketServiceTicketNoNextConcurrent(t *testing.T) {
}
func setupTicketTestDB(t *testing.T) {
setupTicketTestDBWithMaxOpenConns(t, 0)
}
func setupTicketTestDBWithMaxOpenConns(t *testing.T, maxOpenConns int) {
t.Helper()
dbPath := filepath.Join(t.TempDir(), "ticket-test.db")
@@ -339,7 +380,7 @@ func setupTicketTestDB(t *testing.T) {
Type: "sqlite",
DSN: "file:" + dbPath + "?_busy_timeout=5000",
MaxIdleConns: 1,
MaxOpenConns: 1,
MaxOpenConns: maxOpenConns,
})
if err != nil {
t.Fatalf("InitDB() error = %v", err)
@@ -369,13 +410,17 @@ func createTestOperator(t *testing.T, prefix string) *dto.AuthPrincipal {
}
func createTestUser(t *testing.T, prefix string) int64 {
return createTestUserWithStatus(t, prefix, enums.StatusOk)
}
func createTestUserWithStatus(t *testing.T, prefix string, status enums.Status) int64 {
t.Helper()
now := time.Now()
username := fmt.Sprintf("%s_%d", prefix, now.UnixNano())
user := &models.User{
Username: username,
Nickname: prefix,
Status: enums.StatusOk,
Status: status,
AuditFields: models.AuditFields{
CreatedAt: now,
CreateUserID: 1,
@@ -391,6 +436,25 @@ func createTestUser(t *testing.T, prefix string) int64 {
return user.ID
}
func createTestConversation(t *testing.T, customerID int64, prefix string) int64 {
t.Helper()
now := time.Now()
item := &models.Conversation{
CustomerID: customerID,
CustomerName: prefix,
Status: enums.IMConversationStatusActive,
ServiceMode: enums.IMConversationServiceModeAIOnly,
LastMessageAt: now,
LastActiveAt: now,
AuditFields: models.AuditFields{CreatedAt: now, UpdatedAt: now},
}
if err := repositories.ConversationRepository.Create(sqls.DB(), item); err != nil {
t.Fatalf("create conversation error = %v", err)
}
return item.ID
}
func createTestCustomer(t *testing.T, prefix string) int64 {
t.Helper()