* 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>
94 lines
5.0 KiB
Go
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)
|
|
}
|