fix specs

This commit is contained in:
Tanmay Deep Sharma
2025-09-04 19:11:18 +07:00
parent d483974ef1
commit b015c61d71
3 changed files with 109 additions and 55 deletions
@@ -4,7 +4,7 @@ RSpec.describe AutoAssignment::PeriodicAssignmentJob, type: :job do
let(:account) { create(:account) }
let(:inbox) { create(:inbox, account: account, enable_auto_assignment: true) }
let(:assignment_policy) { create(:assignment_policy, account: account) }
let!(:inbox_assignment_policy) { create(:inbox_assignment_policy, inbox: inbox, assignment_policy: assignment_policy) }
let(:inbox_assignment_policy) { create(:inbox_assignment_policy, inbox: inbox, assignment_policy: assignment_policy) }
let(:agent) { create(:user, account: account, role: :agent) }
before do
@@ -14,26 +14,43 @@ RSpec.describe AutoAssignment::PeriodicAssignmentJob, type: :job do
describe '#perform' do
context 'when account has assignment_v2 feature enabled' do
before do
allow_any_instance_of(Account).to receive(:feature_enabled?).with('assignment_v2').and_return(true)
allow(account).to receive(:feature_enabled?).with('assignment_v2').and_return(true)
allow(Account).to receive(:find_in_batches).and_yield([account])
end
context 'when inbox has auto_assignment_v2 enabled' do
before do
allow_any_instance_of(Inbox).to receive(:auto_assignment_v2_enabled?).and_return(true)
allow(inbox).to receive(:auto_assignment_v2_enabled?).and_return(true)
inbox_relation = instance_double(ActiveRecord::Relation)
allow(account).to receive(:inboxes).and_return(inbox_relation)
allow(inbox_relation).to receive(:joins).with(:assignment_policy).and_return(inbox_relation)
allow(inbox_relation).to receive(:find_in_batches).and_yield([inbox])
end
it 'queues assignment job for eligible inboxes' do
inbox_assignment_policy # ensure it exists
expect(AutoAssignment::AssignmentJob).to receive(:perform_later).with(inbox_id: inbox.id)
described_class.new.perform
end
it 'processes multiple accounts' do
inbox_assignment_policy # ensure it exists
account2 = create(:account)
inbox2 = create(:inbox, account: account2, enable_auto_assignment: true)
policy2 = create(:assignment_policy, account: account2)
create(:inbox_assignment_policy, inbox: inbox2, assignment_policy: policy2)
allow(account2).to receive(:feature_enabled?).with('assignment_v2').and_return(true)
allow(inbox2).to receive(:auto_assignment_v2_enabled?).and_return(true)
inbox_relation2 = instance_double(ActiveRecord::Relation)
allow(account2).to receive(:inboxes).and_return(inbox_relation2)
allow(inbox_relation2).to receive(:joins).with(:assignment_policy).and_return(inbox_relation2)
allow(inbox_relation2).to receive(:find_in_batches).and_yield([inbox2])
allow(Account).to receive(:find_in_batches).and_yield([account]).and_yield([account2])
expect(AutoAssignment::AssignmentJob).to receive(:perform_later).with(inbox_id: inbox.id)
expect(AutoAssignment::AssignmentJob).to receive(:perform_later).with(inbox_id: inbox2.id)
@@ -43,7 +60,7 @@ RSpec.describe AutoAssignment::PeriodicAssignmentJob, type: :job do
context 'when inbox does not have auto_assignment_v2 enabled' do
before do
allow_any_instance_of(Inbox).to receive(:auto_assignment_v2_enabled?).and_return(false)
allow(inbox).to receive(:auto_assignment_v2_enabled?).and_return(false)
end
it 'does not queue assignment job' do
@@ -56,7 +73,8 @@ RSpec.describe AutoAssignment::PeriodicAssignmentJob, type: :job do
context 'when account does not have assignment_v2 feature enabled' do
before do
allow_any_instance_of(Account).to receive(:feature_enabled?).with('assignment_v2').and_return(false)
allow(account).to receive(:feature_enabled?).with('assignment_v2').and_return(false)
allow(Account).to receive(:find_in_batches).and_yield([account])
end
it 'does not process the account' do
@@ -68,12 +86,26 @@ RSpec.describe AutoAssignment::PeriodicAssignmentJob, type: :job do
context 'with batch processing' do
it 'processes accounts in batches' do
accounts = []
# Create multiple accounts
5.times do |_i|
acc = create(:account)
inb = create(:inbox, account: acc, enable_auto_assignment: true)
policy = create(:assignment_policy, account: acc)
create(:inbox_assignment_policy, inbox: inb, assignment_policy: policy)
allow(acc).to receive(:feature_enabled?).with('assignment_v2').and_return(true)
allow(inb).to receive(:auto_assignment_v2_enabled?).and_return(true)
inbox_relation = instance_double(ActiveRecord::Relation)
allow(acc).to receive(:inboxes).and_return(inbox_relation)
allow(inbox_relation).to receive(:joins).with(:assignment_policy).and_return(inbox_relation)
allow(inbox_relation).to receive(:find_in_batches).and_yield([inb])
accounts << acc
end
allow(Account).to receive(:find_in_batches) do |&block|
accounts.each { |acc| block.call([acc]) }
end
expect(Account).to receive(:find_in_batches).and_call_original
@@ -14,24 +14,27 @@ RSpec.describe AutoAssignment::AssignmentService do
describe '#perform_bulk_assignment' do
context 'when auto assignment is enabled' do
let(:rate_limiter) { instance_double(AutoAssignment::RateLimiter) }
before do
allow(OnlineStatusTracker).to receive(:get_available_users).and_return({ agent.id.to_s => 'online' })
# Mock RoundRobinSelector to return the agent
round_robin_selector = instance_double(AutoAssignment::RoundRobinSelector)
allow(AutoAssignment::RoundRobinSelector).to receive(:new).and_return(round_robin_selector)
allow(round_robin_selector).to receive(:select_agent).and_return(agent)
# Mock RateLimiter to allow all assignments by default
allow_any_instance_of(AutoAssignment::RateLimiter).to receive(:within_limit?).and_return(true)
allow_any_instance_of(AutoAssignment::RateLimiter).to receive(:track_assignment)
allow(AutoAssignment::RateLimiter).to receive(:new).and_return(rate_limiter)
allow(rate_limiter).to receive(:within_limit?).and_return(true)
allow(rate_limiter).to receive(:track_assignment)
end
it 'assigns conversations to available agents' do
# Create conversation and ensure it's unassigned
conv = create(:conversation, inbox: inbox, status: 'open')
conv.update!(assignee_id: nil)
assigned_count = service.perform_bulk_assignment(limit: 1)
expect(assigned_count).to eq(1)
@@ -88,7 +91,7 @@ RSpec.describe AutoAssignment::AssignmentService do
it 'dispatches assignee changed event' do
conversation # ensure it exists
conversation.update!(assignee_id: nil)
# The conversation model also dispatches a conversation.updated event
allow(Rails.configuration.dispatcher).to receive(:dispatch)
expect(Rails.configuration.dispatcher).to receive(:dispatch).with(
@@ -113,17 +116,20 @@ RSpec.describe AutoAssignment::AssignmentService do
end
context 'with conversation priority' do
let(:rate_limiter) { instance_double(AutoAssignment::RateLimiter) }
before do
allow(OnlineStatusTracker).to receive(:get_available_users).and_return({ agent.id.to_s => 'online' })
# Mock RoundRobinSelector to return the agent
round_robin_selector = instance_double(AutoAssignment::RoundRobinSelector)
allow(AutoAssignment::RoundRobinSelector).to receive(:new).and_return(round_robin_selector)
allow(round_robin_selector).to receive(:select_agent).and_return(agent)
# Mock RateLimiter to allow all assignments by default
allow_any_instance_of(AutoAssignment::RateLimiter).to receive(:within_limit?).and_return(true)
allow_any_instance_of(AutoAssignment::RateLimiter).to receive(:track_assignment)
allow(AutoAssignment::RateLimiter).to receive(:new).and_return(rate_limiter)
allow(rate_limiter).to receive(:within_limit?).and_return(true)
allow(rate_limiter).to receive(:track_assignment)
end
context 'when priority is longest_waiting' do
@@ -189,12 +195,17 @@ RSpec.describe AutoAssignment::AssignmentService do
round_robin_selector = instance_double(AutoAssignment::RoundRobinSelector)
allow(AutoAssignment::RoundRobinSelector).to receive(:new).and_return(round_robin_selector)
allow(round_robin_selector).to receive(:select_agent).and_return(agent2)
# Mock agent1 at limit, agent2 not at limit
allow_any_instance_of(AutoAssignment::RateLimiter).to receive(:within_limit?) do |limiter|
limiter.instance_variable_get(:@agent) != agent
end
allow_any_instance_of(AutoAssignment::RateLimiter).to receive(:track_assignment)
agent1_limiter = instance_double(AutoAssignment::RateLimiter)
agent2_limiter = instance_double(AutoAssignment::RateLimiter)
allow(AutoAssignment::RateLimiter).to receive(:new).with(inbox: inbox, agent: agent).and_return(agent1_limiter)
allow(AutoAssignment::RateLimiter).to receive(:new).with(inbox: inbox, agent: agent2).and_return(agent2_limiter)
allow(agent1_limiter).to receive(:within_limit?).and_return(false)
allow(agent2_limiter).to receive(:within_limit?).and_return(true)
allow(agent2_limiter).to receive(:track_assignment)
unassigned_conversation = create(:conversation, inbox: inbox, status: 'open')
unassigned_conversation.update!(assignee_id: nil)
@@ -207,14 +218,16 @@ RSpec.describe AutoAssignment::AssignmentService do
it 'tracks assignments in Redis' do
conversation # ensure it exists
conversation.update!(assignee_id: nil)
# Mock RoundRobinSelector
round_robin_selector = instance_double(AutoAssignment::RoundRobinSelector)
allow(AutoAssignment::RoundRobinSelector).to receive(:new).and_return(round_robin_selector)
allow(round_robin_selector).to receive(:select_agent).and_return(agent)
allow_any_instance_of(AutoAssignment::RateLimiter).to receive(:within_limit?).and_return(true)
expect_any_instance_of(AutoAssignment::RateLimiter).to receive(:track_assignment)
limiter = instance_double(AutoAssignment::RateLimiter)
allow(AutoAssignment::RateLimiter).to receive(:new).and_return(limiter)
allow(limiter).to receive(:within_limit?).and_return(true)
expect(limiter).to receive(:track_assignment)
service.perform_bulk_assignment(limit: 1)
end
@@ -224,13 +237,15 @@ RSpec.describe AutoAssignment::AssignmentService do
round_robin_selector = instance_double(AutoAssignment::RoundRobinSelector)
allow(AutoAssignment::RoundRobinSelector).to receive(:new).and_return(round_robin_selector)
allow(round_robin_selector).to receive(:select_agent).and_return(agent, agent2)
# Mock RateLimiter to allow all
allow_any_instance_of(AutoAssignment::RateLimiter).to receive(:within_limit?).and_return(true)
allow_any_instance_of(AutoAssignment::RateLimiter).to receive(:track_assignment)
limiter = instance_double(AutoAssignment::RateLimiter)
allow(AutoAssignment::RateLimiter).to receive(:new).and_return(limiter)
allow(limiter).to receive(:within_limit?).and_return(true)
allow(limiter).to receive(:track_assignment)
# Simulate time passing for rate limit window
travel_to(Time.current) do
freeze_time do
2.times do
conversation_new = create(:conversation, inbox: inbox, status: 'open')
conversation_new.update!(assignee_id: nil)
@@ -255,15 +270,17 @@ RSpec.describe AutoAssignment::AssignmentService do
conv = create(:conversation, inbox: inbox, status: 'open')
conv.update!(assignee_id: nil)
end
# Mock RoundRobinSelector
round_robin_selector = instance_double(AutoAssignment::RoundRobinSelector)
allow(AutoAssignment::RoundRobinSelector).to receive(:new).and_return(round_robin_selector)
allow(round_robin_selector).to receive(:select_agent).and_return(agent)
# Mock RateLimiter to allow all
allow_any_instance_of(AutoAssignment::RateLimiter).to receive(:within_limit?).and_return(true)
allow_any_instance_of(AutoAssignment::RateLimiter).to receive(:track_assignment)
limiter = instance_double(AutoAssignment::RateLimiter)
allow(AutoAssignment::RateLimiter).to receive(:new).and_return(limiter)
allow(limiter).to receive(:within_limit?).and_return(true)
allow(limiter).to receive(:track_assignment)
assigned_count = service.perform_bulk_assignment(limit: 5)
expect(assigned_count).to eq(5)
@@ -7,16 +7,33 @@ RSpec.describe AutoAssignment::RoundRobinSelector do
let(:agent1) { create(:user, account: account, role: :agent, availability: :online) }
let(:agent2) { create(:user, account: account, role: :agent, availability: :online) }
let(:agent3) { create(:user, account: account, role: :agent, availability: :online) }
let(:member1) { create(:inbox_member, inbox: inbox, user: agent1) }
let(:member2) { create(:inbox_member, inbox: inbox, user: agent2) }
let(:member3) { create(:inbox_member, inbox: inbox, user: agent3) }
let(:round_robin_service) { instance_double(AutoAssignment::InboxRoundRobinService) }
let(:member1) do
allow(AutoAssignment::InboxRoundRobinService).to receive(:new).and_return(round_robin_service)
allow(round_robin_service).to receive(:add_agent_to_queue)
create(:inbox_member, inbox: inbox, user: agent1)
end
let(:member2) do
allow(AutoAssignment::InboxRoundRobinService).to receive(:new).and_return(round_robin_service)
allow(round_robin_service).to receive(:add_agent_to_queue)
create(:inbox_member, inbox: inbox, user: agent2)
end
let(:member3) do
allow(AutoAssignment::InboxRoundRobinService).to receive(:new).and_return(round_robin_service)
allow(round_robin_service).to receive(:add_agent_to_queue)
create(:inbox_member, inbox: inbox, user: agent3)
end
before do
# Mock the round robin service to avoid Redis calls
allow_any_instance_of(AutoAssignment::InboxRoundRobinService).to receive(:add_agent_to_queue)
allow_any_instance_of(AutoAssignment::InboxRoundRobinService).to receive(:reset_queue)
allow_any_instance_of(AutoAssignment::InboxRoundRobinService).to receive(:validate_queue?).and_return(true)
allow_any_instance_of(AutoAssignment::InboxRoundRobinService).to receive(:available_agent).and_return(nil)
allow(AutoAssignment::InboxRoundRobinService).to receive(:new).and_return(round_robin_service)
allow(round_robin_service).to receive(:add_agent_to_queue)
allow(round_robin_service).to receive(:reset_queue)
allow(round_robin_service).to receive(:validate_queue?).and_return(true)
end
describe '#select_agent' do
@@ -24,12 +41,8 @@ RSpec.describe AutoAssignment::RoundRobinSelector do
let(:available_agents) { [member1, member2, member3] }
it 'returns an agent from the available list' do
# Mock the round robin service to return an agent
round_robin_service = instance_double(AutoAssignment::InboxRoundRobinService)
allow(round_robin_service).to receive(:add_agent_to_queue)
allow(AutoAssignment::InboxRoundRobinService).to receive(:new).and_return(round_robin_service)
allow(round_robin_service).to receive(:available_agent).and_return(agent1)
selected_agent = selector.select_agent(available_agents)
expect(selected_agent).not_to be_nil
@@ -37,10 +50,6 @@ RSpec.describe AutoAssignment::RoundRobinSelector do
end
it 'uses round robin service for selection' do
round_robin_service = instance_double(AutoAssignment::InboxRoundRobinService)
allow(round_robin_service).to receive(:add_agent_to_queue)
allow(AutoAssignment::InboxRoundRobinService).to receive(:new).and_return(round_robin_service)
expect(round_robin_service).to receive(:available_agent).with(
allowed_agent_ids: [agent1.id.to_s, agent2.id.to_s, agent3.id.to_s]
).and_return(agent1)
@@ -59,12 +68,8 @@ RSpec.describe AutoAssignment::RoundRobinSelector do
context 'when one agent is available' do
it 'returns that agent' do
# Mock the round robin service to return the agent
round_robin_service = instance_double(AutoAssignment::InboxRoundRobinService)
allow(round_robin_service).to receive(:add_agent_to_queue)
allow(AutoAssignment::InboxRoundRobinService).to receive(:new).and_return(round_robin_service)
allow(round_robin_service).to receive(:available_agent).and_return(agent1)
selected_agent = selector.select_agent([member1])
expect(selected_agent).to eq(agent1)
end