The reload method in our callback was refreshing the object and hence the saved_change_to_assignee_id? Method wasn't working in the following callbacks. This impacted the listeners subscribing to the event `ASSIGNEE_CHANGE`, `TEAM_CHANGE` etc
226 lines
10 KiB
Ruby
226 lines
10 KiB
Ruby
require 'rails_helper'
|
|
|
|
RSpec.describe Sla::EvaluateAppliedSlaService do
|
|
let!(:account) { create(:account) }
|
|
let!(:user_1) { create(:user, account: account) }
|
|
|
|
let!(:sla_policy) do
|
|
create(:sla_policy,
|
|
account: account,
|
|
first_response_time_threshold: nil,
|
|
next_response_time_threshold: nil,
|
|
resolution_time_threshold: nil)
|
|
end
|
|
let!(:conversation) do
|
|
create(:conversation,
|
|
created_at: 6.hours.ago, assignee: user_1,
|
|
account: sla_policy.account,
|
|
sla_policy: sla_policy)
|
|
end
|
|
let!(:applied_sla) { conversation.applied_sla }
|
|
|
|
describe '#perform - SLA misses' do
|
|
context 'when first response SLA is missed' do
|
|
before { applied_sla.sla_policy.update(first_response_time_threshold: 1.hour) }
|
|
|
|
it 'updates the SLA status to missed and logs a warning' do
|
|
allow(Rails.logger).to receive(:warn)
|
|
described_class.new(applied_sla: applied_sla).perform
|
|
expect(Rails.logger).to have_received(:warn).with("SLA frt missed for conversation #{conversation.id} in account " \
|
|
"#{applied_sla.account_id} for sla_policy #{sla_policy.id}")
|
|
expect(applied_sla.reload.sla_status).to eq('active_with_misses')
|
|
end
|
|
|
|
it 'creates SlaEvent only for frt miss' do
|
|
described_class.new(applied_sla: applied_sla).perform
|
|
|
|
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'frt').count).to eq(1)
|
|
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'nrt').count).to eq(0)
|
|
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'rt').count).to eq(0)
|
|
end
|
|
end
|
|
|
|
context 'when next response SLA is missed' do
|
|
before do
|
|
applied_sla.sla_policy.update(next_response_time_threshold: 1.hour)
|
|
conversation.update(first_reply_created_at: 5.hours.ago, waiting_since: 5.hours.ago)
|
|
end
|
|
|
|
it 'updates the SLA status to missed and logs a warning' do
|
|
allow(Rails.logger).to receive(:warn)
|
|
described_class.new(applied_sla: applied_sla).perform
|
|
expect(Rails.logger).to have_received(:warn).with("SLA nrt missed for conversation #{conversation.id} in account " \
|
|
"#{applied_sla.account_id} for sla_policy #{sla_policy.id}")
|
|
expect(applied_sla.reload.sla_status).to eq('active_with_misses')
|
|
end
|
|
|
|
it 'creates SlaEvent only for nrt miss' do
|
|
described_class.new(applied_sla: applied_sla).perform
|
|
|
|
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'frt').count).to eq(0)
|
|
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'nrt').count).to eq(1)
|
|
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'rt').count).to eq(0)
|
|
end
|
|
end
|
|
|
|
context 'when resolution time SLA is missed' do
|
|
before { applied_sla.sla_policy.update(resolution_time_threshold: 1.hour) }
|
|
|
|
it 'updates the SLA status to missed and logs a warning' do
|
|
allow(Rails.logger).to receive(:warn)
|
|
described_class.new(applied_sla: applied_sla).perform
|
|
expect(Rails.logger).to have_received(:warn).with("SLA rt missed for conversation #{conversation.id} in account " \
|
|
"#{applied_sla.account_id} for sla_policy #{sla_policy.id}")
|
|
|
|
expect(applied_sla.reload.sla_status).to eq('active_with_misses')
|
|
end
|
|
|
|
it 'creates SlaEvent only for rt miss' do
|
|
described_class.new(applied_sla: applied_sla).perform
|
|
|
|
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'frt').count).to eq(0)
|
|
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'nrt').count).to eq(0)
|
|
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'rt').count).to eq(1)
|
|
end
|
|
end
|
|
|
|
# We will mark resolved miss only if while processing the SLA
|
|
# if the conversation is resolved and the resolution time is missed by small margins then we will not mark it as missed
|
|
context 'when resolved conversation with resolution time SLA is missed' do
|
|
before do
|
|
conversation.resolved!
|
|
applied_sla.sla_policy.update(resolution_time_threshold: 1.hour)
|
|
end
|
|
|
|
it 'does not update the SLA status to missed' do
|
|
described_class.new(applied_sla: applied_sla).perform
|
|
expect(applied_sla.reload.sla_status).to eq('hit')
|
|
end
|
|
end
|
|
|
|
context 'when multiple SLAs are missed' do
|
|
before do
|
|
applied_sla.sla_policy.update(first_response_time_threshold: 1.hour, next_response_time_threshold: 1.hour, resolution_time_threshold: 1.hour)
|
|
conversation.update(first_reply_created_at: 5.hours.ago, waiting_since: 5.hours.ago)
|
|
end
|
|
|
|
it 'updates the SLA status to missed and logs multiple warnings' do
|
|
allow(Rails.logger).to receive(:warn)
|
|
described_class.new(applied_sla: applied_sla).perform
|
|
expect(Rails.logger).to have_received(:warn).with("SLA rt missed for conversation #{conversation.id} in account " \
|
|
"#{applied_sla.account_id} for sla_policy #{sla_policy.id}").exactly(1).time
|
|
expect(Rails.logger).to have_received(:warn).with("SLA nrt missed for conversation #{conversation.id} in account " \
|
|
"#{applied_sla.account_id} for sla_policy #{sla_policy.id}").exactly(1).time
|
|
expect(applied_sla.reload.sla_status).to eq('active_with_misses')
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#perform - SLA hits' do
|
|
context 'when first response SLA is hit' do
|
|
before do
|
|
applied_sla.sla_policy.update(first_response_time_threshold: 6.hours)
|
|
conversation.update(first_reply_created_at: 30.minutes.ago)
|
|
end
|
|
|
|
it 'sla remains active until conversation is resolved' do
|
|
described_class.new(applied_sla: applied_sla).perform
|
|
expect(applied_sla.reload.sla_status).to eq('active')
|
|
end
|
|
|
|
it 'updates the SLA status to hit and logs an info when conversations is resolved' do
|
|
conversation.resolved!
|
|
allow(Rails.logger).to receive(:info)
|
|
described_class.new(applied_sla: applied_sla).perform
|
|
expect(Rails.logger).to have_received(:info).with("SLA hit for conversation #{conversation.id} in account " \
|
|
"#{applied_sla.account_id} for sla_policy #{sla_policy.id}")
|
|
expect(applied_sla.reload.sla_status).to eq('hit')
|
|
expect(SlaEvent.count).to eq(0)
|
|
expect(Notification.count).to eq(0)
|
|
end
|
|
end
|
|
|
|
context 'when next response SLA is hit' do
|
|
before do
|
|
applied_sla.sla_policy.update(next_response_time_threshold: 6.hours)
|
|
conversation.update(first_reply_created_at: 30.minutes.ago, waiting_since: nil)
|
|
end
|
|
|
|
it 'sla remains active until conversation is resolved' do
|
|
described_class.new(applied_sla: applied_sla).perform
|
|
expect(applied_sla.reload.sla_status).to eq('active')
|
|
end
|
|
|
|
it 'updates the SLA status to hit and logs an info when conversations is resolved' do
|
|
conversation.resolved!
|
|
allow(Rails.logger).to receive(:info)
|
|
described_class.new(applied_sla: applied_sla).perform
|
|
expect(Rails.logger).to have_received(:info).with("SLA hit for conversation #{conversation.id} in account " \
|
|
"#{applied_sla.account_id} for sla_policy #{sla_policy.id}")
|
|
expect(applied_sla.reload.sla_status).to eq('hit')
|
|
expect(SlaEvent.count).to eq(0)
|
|
end
|
|
end
|
|
|
|
context 'when resolution time SLA is hit' do
|
|
before do
|
|
applied_sla.sla_policy.update(resolution_time_threshold: 8.hours)
|
|
conversation.resolved!
|
|
end
|
|
|
|
it 'updates the SLA status to hit and logs an info' do
|
|
allow(Rails.logger).to receive(:info)
|
|
described_class.new(applied_sla: applied_sla).perform
|
|
expect(Rails.logger).to have_received(:info).with("SLA hit for conversation #{conversation.id} in account " \
|
|
"#{applied_sla.account_id} for sla_policy #{sla_policy.id}")
|
|
expect(applied_sla.reload.sla_status).to eq('hit')
|
|
expect(SlaEvent.count).to eq(0)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'SLA evaluation with frt hit, multiple nrt misses and rt miss' do
|
|
before do
|
|
# Setup SLA Policy thresholds
|
|
applied_sla.sla_policy.update(
|
|
first_response_time_threshold: 2.hours, # Hit frt
|
|
next_response_time_threshold: 1.hour, # Miss nrt multiple times
|
|
resolution_time_threshold: 4.hours # Miss rt
|
|
)
|
|
|
|
# Simulate conversation timeline
|
|
# Hit frt
|
|
# incoming message from customer
|
|
create(:message, conversation: conversation, created_at: 6.hours.ago, message_type: :incoming)
|
|
# outgoing message from agent within frt
|
|
create(:message, conversation: conversation, created_at: 5.hours.ago, message_type: :outgoing)
|
|
|
|
# Miss nrt first time
|
|
create(:message, conversation: conversation, created_at: 4.hours.ago, message_type: :incoming)
|
|
described_class.new(applied_sla: applied_sla).perform
|
|
|
|
# Miss nrt second time
|
|
create(:message, conversation: conversation, created_at: 3.hours.ago, message_type: :incoming)
|
|
described_class.new(applied_sla: applied_sla).perform
|
|
|
|
# Conversation is resolved missing rt
|
|
conversation.update(status: 'resolved')
|
|
|
|
# this will not create a new notification for rt miss as conversation is resolved
|
|
# but we would have already created an rt miss notification during previous evaluation
|
|
described_class.new(applied_sla: applied_sla).perform
|
|
end
|
|
|
|
it 'updates the SLA status to missed' do
|
|
# the status would be missed as the conversation is resolved
|
|
expect(applied_sla.reload.sla_status).to eq('missed')
|
|
end
|
|
|
|
it 'creates necessary sla events' do
|
|
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'frt').count).to eq(0)
|
|
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'nrt').count).to eq(2)
|
|
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'rt').count).to eq(1)
|
|
end
|
|
end
|
|
end
|