Files
chatwoot/script/assignment_v2/test_agent_availability.rb
T

208 lines
7.3 KiB
Ruby

# frozen_string_literal: true
# Test: Agent Availability and Status
# Run with: bundle exec rails runner script/assignment_v2/test_agent_availability.rb
#
# Tests:
# - Only online agents receive assignments
# - Offline agents are excluded from assignment pool
# - When agents go offline mid-assignment, remaining conversations go to online agents
# - When agents come online, they become eligible for new assignments
#
# Key Implementation Details:
# - inbox.available_agents filters by online status via OnlineStatusTracker
# - OnlineStatusTracker.update_presence(account_id, 'User', user_id) marks agent as online
# - OnlineStatusTracker.remove_presence(account_id, 'User', user_id) marks agent as offline
# - Availability is checked for EACH conversation assignment (not cached for the batch)
# - This ensures real-time status changes affect assignment within a single job run
require_relative 'test_helpers'
class TestAgentAvailability
include AssignmentV2TestHelpers
def run
section('TEST: Agent Availability and Status')
account = get_test_account
inbox = nil
begin
# Setup test inbox and policy
inbox = create_test_inbox(account, name: 'Availability Test Inbox')
policy = create_test_policy(account, name: 'Availability Test Policy')
link_policy_to_inbox(inbox, policy)
# Test 1: Only online agents receive assignments
section('Test 1: Only Online Agents Get Assigned')
# Create 3 agents: 2 online, 1 offline
agent_online_1 = create_test_agent(account, inbox, name: 'Agent Online 1', online: true)
agent_online_2 = create_test_agent(account, inbox, name: 'Agent Online 2', online: true)
agent_offline = create_test_agent(account, inbox, name: 'Agent Offline', online: false)
info("Online agents: #{agent_online_1.name}, #{agent_online_2.name}")
info("Offline agent: #{agent_offline.name}")
# Create 6 conversations (should be split between 2 online agents only)
create_bulk_conversations(inbox, count: 6)
# Run assignment
assigned_count = run_assignment(inbox)
# Verify only online agents got assignments
log('Verifying only online agents assigned...', color: :blue)
# Should assign all 6 conversations (2 online agents available)
all_assigned = assert_equal(
assigned_count,
6,
'All 6 conversations assigned'
)
# Each online agent should have 3 conversations (round-robin between 2)
online_1_count = inbox.conversations.where(assignee: agent_online_1).count
online_2_count = inbox.conversations.where(assignee: agent_online_2).count
offline_count = inbox.conversations.where(assignee: agent_offline).count
distribution_ok = assert_equal(
online_1_count,
3,
"#{agent_online_1.name} has 3 conversations"
)
distribution_ok &= assert_equal(
online_2_count,
3,
"#{agent_online_2.name} has 3 conversations"
)
# Offline agent should have 0
offline_excluded = assert_equal(
offline_count,
0,
"#{agent_offline.name} has 0 conversations (offline)"
)
test1_ok = all_assigned && distribution_ok && offline_excluded
# Test 2: When agent goes offline, new assignments skip them
section('Test 2: Agent Goes Offline Mid-Test')
# Take agent_online_2 offline by setting status to 'offline'
OnlineStatusTracker.set_status(account.id, agent_online_2.id, 'offline')
info("Took #{agent_online_2.name} offline")
# Create 3 more conversations
create_bulk_conversations(inbox, count: 3)
# Run assignment again
assigned_count_2 = run_assignment(inbox)
# Verify only agent_online_1 gets the new assignments
log('Verifying offline agent excluded...', color: :blue)
# Should assign all 3 new conversations
all_assigned_2 = assert_equal(
assigned_count_2,
3,
'All 3 new conversations assigned'
)
# Agent_online_1 should now have 6 total (3 + 3 new)
online_1_new_count = inbox.conversations.where(assignee: agent_online_1).count
online_1_got_all = assert_equal(
online_1_new_count,
6,
"#{agent_online_1.name} has 6 conversations (got all new ones)"
)
# Agent_online_2 should still have 3 (no new assignments)
online_2_still_count = inbox.conversations.where(assignee: agent_online_2).count
online_2_unchanged = assert_equal(
online_2_still_count,
3,
"#{agent_online_2.name} still has 3 conversations (offline, no new ones)"
)
test2_ok = all_assigned_2 && online_1_got_all && online_2_unchanged
# Test 3: When agent comes online, they become eligible
section('Test 3: Agent Comes Online')
# Bring agent_online_2 back online by updating presence and setting status
OnlineStatusTracker.update_presence(account.id, 'User', agent_online_2.id)
OnlineStatusTracker.set_status(account.id, agent_online_2.id, 'online')
info("Brought #{agent_online_2.name} back online")
# Bring offline agent online too
OnlineStatusTracker.update_presence(account.id, 'User', agent_offline.id)
OnlineStatusTracker.set_status(account.id, agent_offline.id, 'online')
info("Brought #{agent_offline.name} online")
# Create 6 more conversations (should distribute across all 3 now)
create_bulk_conversations(inbox, count: 6)
# Run assignment
assigned_count_3 = run_assignment(inbox)
# Verify all 3 agents get assignments
log('Verifying all online agents get assignments...', color: :blue)
# Should assign all 6 conversations
all_assigned_3 = assert_equal(
assigned_count_3,
6,
'All 6 final conversations assigned'
)
# Each agent should get 2 more (round-robin across 3)
agent_online_1_final = inbox.conversations.where(assignee: agent_online_1).count
agent_online_2_final = inbox.conversations.where(assignee: agent_online_2).count
agent_offline_final = inbox.conversations.where(assignee: agent_offline).count
online_1_increased = assert_equal(
agent_online_1_final,
8, # 6 + 2
"#{agent_online_1.name} has 8 conversations (6 + 2 new)"
)
online_2_increased = assert_equal(
agent_online_2_final,
5, # 3 + 2
"#{agent_online_2.name} has 5 conversations (3 + 2 new)"
)
# Previously offline agent should now have assignments
previously_offline_assigned = assert_equal(
agent_offline_final,
2, # 0 + 2
"#{agent_offline.name} has 2 conversations (came online, got 2 new)"
)
test3_ok = all_assigned_3 && online_1_increased && online_2_increased && previously_offline_assigned
# Show final distribution
show_assignment_distribution(inbox, [agent_online_1, agent_online_2, agent_offline])
# Final result
if test1_ok && test2_ok && test3_ok
section('✓ ALL TESTS PASSED')
true
else
section('✗ SOME TESTS FAILED')
false
end
rescue StandardError => e
error("Test failed with error: #{e.message}")
puts e.backtrace.first(5).join("\n")
false
ensure
cleanup_test_data(account, inbox: inbox) if inbox
end
end
end
# Run test and exit with appropriate code
exit(TestAgentAvailability.new.run ? 0 : 1)