Files
gochat/backend/internal/autoassignment/runtime_policy_test.go
T
Rogeeandrogee 17244bcc9d HH-554: connect auto-assignment runtime policy (#135)
* fix(HH-554): connect auto-assignment runtime policy

* fix(HH-554): bound and coalesce assignment jobs

* fix(HH-554): drain assignment backlog safely

* fix(HH-554): hold assignment claim through retries

---------

Co-authored-by: Rogee <rogee@ipao.vip>
2026-08-23 22:28:43 +08:00

94 lines
5.0 KiB
Go

package autoassignment
import (
"context"
"testing"
"time"
"github.com/gochat/gochat/internal/channel"
"github.com/gochat/gochat/internal/model"
"github.com/stretchr/testify/require"
)
func TestAutoAssignmentListenerUsesChannelEventIDs(t *testing.T) {
db, rdb := setupFullAADB_Cov9(t)
account, agent, inbox, conversation := seedAssignableConversation_Cov9(t, db)
event := channel.NewChannelEvent(channel.EventConversationCreated, channel.ChannelWebWidget, account.ID, inbox.ID)
event.ConversationID = conversation.ID
require.NoError(t, NewAutoAssignmentListener(db, rdb).OnEvent(context.Background(), event))
require.NoError(t, db.First(conversation, conversation.ID).Error)
require.Equal(t, &agent.ID, conversation.AssigneeID)
}
func TestAssignmentServiceUsesLinkedCurrentPolicy(t *testing.T) {
db, rdb := setupFullAADB_Cov9(t)
account, firstAgent, inbox, conversation := seedAssignableConversation_Cov9(t, db)
secondAgent := &model.User{AccountID: account.ID, Name: "second", Email: "second-policy@example.com", Password: "p", Active: true, Available: true}
require.NoError(t, db.Create(secondAgent).Error)
require.NoError(t, db.Create(&model.AccountUser{AccountID: account.ID, UserID: secondAgent.ID, Role: "agent"}).Error)
require.NoError(t, db.Create(&model.InboxMember{InboxID: inbox.ID, UserID: secondAgent.ID, Role: "agent", AvailabilityStatus: "online"}).Error)
contact := &model.Contact{AccountID: account.ID, Name: "load", Email: "load-policy@example.com"}
require.NoError(t, db.Create(contact).Error)
load := &model.Conversation{AccountID: account.ID, InboxID: inbox.ID, ContactID: contact.ID, AssigneeID: &firstAgent.ID, Status: string(model.ConversationStatusOpen)}
require.NoError(t, db.Create(load).Error)
require.NoError(t, db.Model(account).Update("feature_flags", `{"advanced_assignment":true}`).Error)
policy := &model.AssignmentPolicy{AccountID: account.ID, Name: "Runtime", AssignmentOrder: 1, FairDistributionLimit: 100, FairDistributionWindow: 3600, Enabled: true}
require.NoError(t, db.Create(policy).Error)
require.NoError(t, db.Create(&model.InboxAssignmentPolicy{InboxID: inbox.ID, AssignmentPolicyID: policy.ID}).Error)
service := NewAssignmentService(db, rdb)
assigned, err := service.AssignConversation(context.Background(), conversation.ID, inbox.ID, account.ID)
require.NoError(t, err)
require.Equal(t, secondAgent.ID, assigned, "balanced policy should choose the least-loaded agent")
policy.AssignmentOrder = 0
require.NoError(t, db.Save(policy).Error)
next := &model.Conversation{AccountID: account.ID, InboxID: inbox.ID, ContactID: contact.ID, Status: string(model.ConversationStatusOpen)}
require.NoError(t, db.Create(next).Error)
assigned, err = service.AssignConversation(context.Background(), next.ID, inbox.ID, account.ID)
require.NoError(t, err)
require.Equal(t, firstAgent.ID, assigned, "round-robin policy should use the queue order")
}
func TestListenerAppliesConversationPriorityToInboxBacklog(t *testing.T) {
db, rdb := setupFullAADB_Cov9(t)
account, agent, inbox, newest := seedAssignableConversation_Cov9(t, db)
now := time.Now().Unix()
require.NoError(t, db.Model(newest).Update("last_activity_at", now).Error)
contact := &model.Contact{AccountID: account.ID, Name: "old", Email: "old-policy@example.com"}
require.NoError(t, db.Create(contact).Error)
oldActivity := now - int64((2 * time.Hour).Seconds())
oldest := &model.Conversation{AccountID: account.ID, InboxID: inbox.ID, ContactID: contact.ID, Status: string(model.ConversationStatusOpen), LastActivityAt: &oldActivity}
require.NoError(t, db.Create(oldest).Error)
policy := &model.AssignmentPolicy{AccountID: account.ID, Name: "Oldest first", ConversationPriority: 1, FairDistributionLimit: 1, FairDistributionWindow: 3600, Enabled: true}
require.NoError(t, db.Create(policy).Error)
require.NoError(t, db.Create(&model.InboxAssignmentPolicy{InboxID: inbox.ID, AssignmentPolicyID: policy.ID}).Error)
event := channel.NewChannelEvent(channel.EventConversationCreated, channel.ChannelWebWidget, account.ID, inbox.ID)
event.ConversationID = newest.ID
require.NoError(t, NewAutoAssignmentListener(db, rdb).OnEvent(context.Background(), event))
require.NoError(t, db.First(oldest, oldest.ID).Error)
require.NoError(t, db.First(newest, newest.ID).Error)
require.Equal(t, &agent.ID, oldest.AssigneeID)
require.Nil(t, newest.AssigneeID)
}
func TestDisabledLinkedPolicyStopsAssignment(t *testing.T) {
db, rdb := setupFullAADB_Cov9(t)
account, _, inbox, conversation := seedAssignableConversation_Cov9(t, db)
policy := &model.AssignmentPolicy{AccountID: account.ID, Name: "Paused", Enabled: true}
require.NoError(t, db.Create(policy).Error)
require.NoError(t, db.Model(policy).Update("enabled", false).Error)
require.NoError(t, db.Create(&model.InboxAssignmentPolicy{InboxID: inbox.ID, AssignmentPolicyID: policy.ID}).Error)
assigned, err := NewAssignmentService(db, rdb).AssignConversation(context.Background(), conversation.ID, inbox.ID, account.ID)
require.NoError(t, err)
require.Zero(t, assigned)
}