refactor: remove dead timeseries wrappers
This commit is contained in:
@@ -1,2 +0,0 @@
|
||||
class V2::Reports::Timeseries::AverageReportBuilder < V2::Reports::Timeseries::ReportBuilder
|
||||
end
|
||||
@@ -1,2 +0,0 @@
|
||||
class V2::Reports::Timeseries::CountReportBuilder < V2::Reports::Timeseries::ReportBuilder
|
||||
end
|
||||
@@ -1,286 +0,0 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe V2::Reports::Timeseries::AverageReportBuilder do
|
||||
subject { described_class.new(account, params) }
|
||||
|
||||
let(:account) { create(:account) }
|
||||
let(:team) { create(:team, account: account) }
|
||||
let(:inbox) { create(:inbox, account: account) }
|
||||
let(:label) { create(:label, title: 'spec-billing', account: account) }
|
||||
let!(:conversation) { create(:conversation, account: account, inbox: inbox, team: team) }
|
||||
let(:current_time) { '26.10.2020 10:00'.to_datetime }
|
||||
|
||||
let(:params) do
|
||||
{
|
||||
type: filter_type,
|
||||
business_hours: business_hours,
|
||||
timezone_offset: timezone_offset,
|
||||
group_by: group_by,
|
||||
metric: metric,
|
||||
since: (current_time - 1.week).beginning_of_day.to_i.to_s,
|
||||
until: current_time.end_of_day.to_i.to_s,
|
||||
id: filter_id
|
||||
}
|
||||
end
|
||||
let(:timezone_offset) { nil }
|
||||
let(:group_by) { 'day' }
|
||||
let(:metric) { 'avg_first_response_time' }
|
||||
let(:business_hours) { false }
|
||||
let(:filter_type) { :account }
|
||||
let(:filter_id) { '' }
|
||||
|
||||
before do
|
||||
travel_to current_time
|
||||
conversation.label_list.add(label.title)
|
||||
conversation.save!
|
||||
create(:reporting_event, name: 'first_response', value: 80, value_in_business_hours: 10, account: account, created_at: Time.zone.now,
|
||||
conversation: conversation, inbox: inbox)
|
||||
create(:reporting_event, name: 'first_response', value: 100, value_in_business_hours: 20, account: account, created_at: 1.hour.ago)
|
||||
create(:reporting_event, name: 'first_response', value: 93, value_in_business_hours: 30, account: account, created_at: 1.week.ago)
|
||||
end
|
||||
|
||||
describe '#timeseries' do
|
||||
context 'when there is no filter applied' do
|
||||
it 'returns the correct values' do
|
||||
timeseries_values = subject.timeseries
|
||||
|
||||
expect(timeseries_values).to eq(
|
||||
[
|
||||
{ count: 1, timestamp: 1_603_065_600, value: 93.0 },
|
||||
{ count: 0, timestamp: 1_603_152_000, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_238_400, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_324_800, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_411_200, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_497_600, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_584_000, value: 0 },
|
||||
{ count: 2, timestamp: 1_603_670_400, value: 90.0 }
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
context 'when business hours is provided' do
|
||||
let(:business_hours) { true }
|
||||
|
||||
it 'returns correct timeseries' do
|
||||
timeseries_values = subject.timeseries
|
||||
|
||||
expect(timeseries_values).to eq(
|
||||
[
|
||||
{ count: 1, timestamp: 1_603_065_600, value: 30.0 },
|
||||
{ count: 0, timestamp: 1_603_152_000, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_238_400, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_324_800, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_411_200, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_497_600, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_584_000, value: 0 },
|
||||
{ count: 2, timestamp: 1_603_670_400, value: 15.0 }
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when rollups are enabled' do
|
||||
let(:timezone_offset) { '5.5' }
|
||||
|
||||
before do
|
||||
account.update!(reporting_timezone: 'Chennai')
|
||||
allow(account).to receive(:feature_enabled?).with('reporting_events_rollup').and_return(true)
|
||||
|
||||
create(:reporting_events_rollup,
|
||||
account: account,
|
||||
date: (current_time - 1.week).to_date,
|
||||
dimension_type: 'account',
|
||||
dimension_id: account.id,
|
||||
metric: 'first_response',
|
||||
count: 1,
|
||||
sum_value: 93.0,
|
||||
sum_value_business_hours: 30.0)
|
||||
|
||||
create(:reporting_events_rollup,
|
||||
account: account,
|
||||
date: current_time.to_date,
|
||||
dimension_type: 'account',
|
||||
dimension_id: account.id,
|
||||
metric: 'first_response',
|
||||
count: 2,
|
||||
sum_value: 180.0,
|
||||
sum_value_business_hours: 30.0)
|
||||
end
|
||||
|
||||
it 'preserves empty buckets in the timeseries' do
|
||||
rollup_timezone = ActiveSupport::TimeZone['Chennai']
|
||||
rollup_start_date = DateTime.strptime(params[:since], '%s').in_time_zone(rollup_timezone).to_date
|
||||
rollup_end_date = (DateTime.strptime(params[:until], '%s') - 1.second).in_time_zone(rollup_timezone).to_date
|
||||
rollup_dates = rollup_start_date..rollup_end_date
|
||||
|
||||
expected_timeseries = rollup_dates.map do |date|
|
||||
value = if date == (current_time - 1.week).to_date
|
||||
93.0
|
||||
elsif date == current_time.to_date
|
||||
90.0
|
||||
else
|
||||
0
|
||||
end
|
||||
|
||||
count = if date == (current_time - 1.week).to_date
|
||||
1
|
||||
elsif date == current_time.to_date
|
||||
2
|
||||
else
|
||||
0
|
||||
end
|
||||
|
||||
{ count: count, timestamp: date.in_time_zone('Chennai').to_i, value: value }
|
||||
end
|
||||
|
||||
expect(subject.timeseries).to eq(expected_timeseries)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when group_by is provided' do
|
||||
let(:group_by) { 'week' }
|
||||
|
||||
it 'returns correct timeseries' do
|
||||
timeseries_values = subject.timeseries
|
||||
expect(timeseries_values).to eq(
|
||||
[
|
||||
{ count: 1, timestamp: (current_time - 1.week).beginning_of_week(:sunday).to_i, value: 93.0 },
|
||||
{ count: 2, timestamp: current_time.beginning_of_week(:sunday).to_i, value: 90.0 }
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when timezone offset is provided' do
|
||||
let(:timezone_offset) { '5.5' }
|
||||
let(:group_by) { 'week' }
|
||||
|
||||
it 'returns correct timeseries' do
|
||||
timeseries_values = subject.timeseries
|
||||
expect(timeseries_values).to eq(
|
||||
[
|
||||
{ count: 1, timestamp: (current_time - 1.week).in_time_zone('Chennai').beginning_of_week(:sunday).to_i, value: 93.0 },
|
||||
{ count: 2, timestamp: current_time.in_time_zone('Chennai').beginning_of_week(:sunday).to_i, value: 90.0 }
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when weekly rollups are enabled' do
|
||||
let(:group_by) { 'week' }
|
||||
let(:timezone_offset) { '5.5' }
|
||||
|
||||
before do
|
||||
account.update!(reporting_timezone: 'Chennai')
|
||||
allow(account).to receive(:feature_enabled?).with('reporting_events_rollup').and_return(true)
|
||||
|
||||
create(:reporting_events_rollup,
|
||||
account: account,
|
||||
date: current_time.to_date - 1.day,
|
||||
dimension_type: 'account',
|
||||
dimension_id: account.id,
|
||||
metric: 'first_response',
|
||||
count: 1,
|
||||
sum_value: 80.0,
|
||||
sum_value_business_hours: 10.0)
|
||||
|
||||
create(:reporting_events_rollup,
|
||||
account: account,
|
||||
date: current_time.to_date,
|
||||
dimension_type: 'account',
|
||||
dimension_id: account.id,
|
||||
metric: 'first_response',
|
||||
count: 1,
|
||||
sum_value: 100.0,
|
||||
sum_value_business_hours: 20.0)
|
||||
end
|
||||
|
||||
it 'groups weeks using sunday boundaries' do
|
||||
expect(subject.timeseries).to eq(
|
||||
[
|
||||
{ count: 0, timestamp: (current_time - 1.week).in_time_zone('Chennai').beginning_of_week(:sunday).to_i, value: 0 },
|
||||
{ count: 2, timestamp: current_time.in_time_zone('Chennai').beginning_of_week(:sunday).to_i, value: 90.0 }
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the label filter is applied' do
|
||||
let(:group_by) { 'week' }
|
||||
let(:filter_type) { 'label' }
|
||||
let(:filter_id) { label.id }
|
||||
|
||||
it 'returns correct timeseries' do
|
||||
timeseries_values = subject.timeseries
|
||||
start_of_the_week = current_time.beginning_of_week(:sunday).to_i
|
||||
last_week_start_of_the_week = (current_time - 1.week).beginning_of_week(:sunday).to_i
|
||||
expect(timeseries_values).to eq(
|
||||
[
|
||||
{ count: 0, timestamp: last_week_start_of_the_week, value: 0 },
|
||||
{ count: 1, timestamp: start_of_the_week, value: 80.0 }
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the inbox filter is applied' do
|
||||
let(:group_by) { 'week' }
|
||||
let(:filter_type) { 'inbox' }
|
||||
let(:filter_id) { inbox.id }
|
||||
|
||||
it 'returns correct timeseries' do
|
||||
timeseries_values = subject.timeseries
|
||||
start_of_the_week = current_time.beginning_of_week(:sunday).to_i
|
||||
last_week_start_of_the_week = (current_time - 1.week).beginning_of_week(:sunday).to_i
|
||||
expect(timeseries_values).to eq(
|
||||
[
|
||||
{ count: 0, timestamp: last_week_start_of_the_week, value: 0 },
|
||||
{ count: 1, timestamp: start_of_the_week, value: 80.0 }
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the team filter is applied' do
|
||||
let(:group_by) { 'week' }
|
||||
let(:filter_type) { 'team' }
|
||||
let(:filter_id) { team.id }
|
||||
|
||||
it 'returns correct timeseries' do
|
||||
timeseries_values = subject.timeseries
|
||||
start_of_the_week = current_time.beginning_of_week(:sunday).to_i
|
||||
last_week_start_of_the_week = (current_time - 1.week).beginning_of_week(:sunday).to_i
|
||||
expect(timeseries_values).to eq(
|
||||
[
|
||||
{ count: 0, timestamp: last_week_start_of_the_week, value: 0 },
|
||||
{ count: 1, timestamp: start_of_the_week, value: 80.0 }
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#aggregate_value' do
|
||||
context 'when there is no filter applied' do
|
||||
it 'returns the correct average value' do
|
||||
expect(subject.aggregate_value).to eq 91.0
|
||||
end
|
||||
end
|
||||
|
||||
context 'when rollups are enabled and the agent does not exist' do
|
||||
let(:filter_type) { :agent }
|
||||
let(:filter_id) { '999999' }
|
||||
let(:timezone_offset) { '0' }
|
||||
|
||||
before do
|
||||
account.update!(reporting_timezone: 'Etc/UTC')
|
||||
allow(account).to receive(:feature_enabled?).with('reporting_events_rollup').and_return(true)
|
||||
end
|
||||
|
||||
it 'raises record not found to preserve raw path behavior' do
|
||||
expect { subject.aggregate_value }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,176 +0,0 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe V2::Reports::Timeseries::CountReportBuilder do
|
||||
subject { described_class.new(account, params) }
|
||||
|
||||
let(:account) { create(:account) }
|
||||
let(:account2) { create(:account) }
|
||||
let(:user) { create(:user, email: 'agent1@example.com') }
|
||||
let(:inbox) { create(:inbox, account: account) }
|
||||
let(:inbox2) { create(:inbox, account: account2) }
|
||||
let(:current_time) { Time.current }
|
||||
|
||||
let(:params) do
|
||||
{
|
||||
type: 'agent',
|
||||
metric: 'resolutions_count',
|
||||
since: since_time.beginning_of_day.to_i.to_s,
|
||||
until: current_time.end_of_day.to_i.to_s,
|
||||
timezone_offset: timezone_offset,
|
||||
group_by: group_by,
|
||||
id: user.id.to_s
|
||||
}
|
||||
end
|
||||
let(:group_by) { 'day' }
|
||||
let(:since_time) { current_time - 1.day }
|
||||
let(:timezone_offset) { nil }
|
||||
|
||||
before do
|
||||
travel_to current_time
|
||||
|
||||
# Add the same user to both accounts
|
||||
create(:account_user, account: account, user: user)
|
||||
create(:account_user, account: account2, user: user)
|
||||
|
||||
# Create conversations in account1
|
||||
conversation1 = create(:conversation, account: account, inbox: inbox, assignee: user)
|
||||
conversation2 = create(:conversation, account: account, inbox: inbox, assignee: user)
|
||||
|
||||
# Create conversations in account2
|
||||
conversation3 = create(:conversation, account: account2, inbox: inbox2, assignee: user)
|
||||
conversation4 = create(:conversation, account: account2, inbox: inbox2, assignee: user)
|
||||
|
||||
# User resolves 2 conversations in account1
|
||||
create(:reporting_event,
|
||||
name: 'conversation_resolved',
|
||||
account: account,
|
||||
user: user,
|
||||
conversation: conversation1,
|
||||
created_at: current_time - 12.hours)
|
||||
|
||||
create(:reporting_event,
|
||||
name: 'conversation_resolved',
|
||||
account: account,
|
||||
user: user,
|
||||
conversation: conversation2,
|
||||
created_at: current_time - 6.hours)
|
||||
|
||||
# Same user resolves 3 conversations in account2 - these should NOT be counted for account1
|
||||
create(:reporting_event,
|
||||
name: 'conversation_resolved',
|
||||
account: account2,
|
||||
user: user,
|
||||
conversation: conversation3,
|
||||
created_at: current_time - 8.hours)
|
||||
|
||||
create(:reporting_event,
|
||||
name: 'conversation_resolved',
|
||||
account: account2,
|
||||
user: user,
|
||||
conversation: conversation4,
|
||||
created_at: current_time - 4.hours)
|
||||
|
||||
# Create another conversation in account2 for testing
|
||||
conversation5 = create(:conversation, account: account2, inbox: inbox2, assignee: user)
|
||||
create(:reporting_event,
|
||||
name: 'conversation_resolved',
|
||||
account: account2,
|
||||
user: user,
|
||||
conversation: conversation5,
|
||||
created_at: current_time - 2.hours)
|
||||
end
|
||||
|
||||
describe '#aggregate_value' do
|
||||
it 'returns only resolutions performed by the user in the specified account' do
|
||||
# User should have 2 resolutions in account1, not 5 (total across both accounts)
|
||||
expect(subject.aggregate_value).to eq(2)
|
||||
end
|
||||
|
||||
context 'when rollups are enabled and the agent does not exist' do
|
||||
let(:timezone_offset) { '0' }
|
||||
|
||||
let(:params) do
|
||||
super().merge(id: '999999')
|
||||
end
|
||||
|
||||
before do
|
||||
account.update!(reporting_timezone: 'Etc/UTC')
|
||||
allow(account).to receive(:feature_enabled?).with('reporting_events_rollup').and_return(true)
|
||||
end
|
||||
|
||||
it 'raises record not found to preserve raw path behavior' do
|
||||
expect { subject.aggregate_value }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when querying account2' do
|
||||
subject { described_class.new(account2, params) }
|
||||
|
||||
it 'returns only resolutions for account2' do
|
||||
# User should have 3 resolutions in account2
|
||||
expect(subject.aggregate_value).to eq(3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#timeseries' do
|
||||
it 'filters resolutions by account' do
|
||||
result = subject.timeseries
|
||||
# Should only count the 2 resolutions from account1
|
||||
total_count = result.sum { |r| r[:value] }
|
||||
expect(total_count).to eq(2)
|
||||
end
|
||||
|
||||
context 'when rollups are enabled and grouped by week' do
|
||||
let(:group_by) { 'week' }
|
||||
let(:current_time) { Time.zone.parse('2020-10-26 10:00:00 UTC') }
|
||||
let(:since_time) { current_time - 1.week }
|
||||
let(:timezone_offset) { '5.5' }
|
||||
|
||||
before do
|
||||
account.update!(reporting_timezone: 'Chennai')
|
||||
allow(account).to receive(:feature_enabled?).with('reporting_events_rollup').and_return(true)
|
||||
|
||||
create(:reporting_events_rollup,
|
||||
account: account,
|
||||
date: current_time.to_date - 1.day,
|
||||
dimension_type: 'agent',
|
||||
dimension_id: user.id,
|
||||
metric: 'resolutions_count',
|
||||
count: 1,
|
||||
sum_value: 0.0,
|
||||
sum_value_business_hours: 0.0)
|
||||
|
||||
create(:reporting_events_rollup,
|
||||
account: account,
|
||||
date: current_time.to_date,
|
||||
dimension_type: 'agent',
|
||||
dimension_id: user.id,
|
||||
metric: 'resolutions_count',
|
||||
count: 1,
|
||||
sum_value: 0.0,
|
||||
sum_value_business_hours: 0.0)
|
||||
end
|
||||
|
||||
it 'groups weeks using sunday boundaries' do
|
||||
expect(subject.timeseries).to eq(
|
||||
[
|
||||
{ value: 0, timestamp: (current_time - 1.week).in_time_zone('Chennai').beginning_of_week(:sunday).to_i },
|
||||
{ value: 2, timestamp: current_time.in_time_zone('Chennai').beginning_of_week(:sunday).to_i }
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'account isolation' do
|
||||
it 'does not leak data between accounts' do
|
||||
# If account isolation works correctly, the counts should be different
|
||||
account1_count = described_class.new(account, params).aggregate_value
|
||||
account2_count = described_class.new(account2, params).aggregate_value
|
||||
|
||||
expect(account1_count).to eq(2)
|
||||
expect(account2_count).to eq(3)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,451 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe V2::Reports::Timeseries::ReportBuilder do
|
||||
describe 'average metrics' do
|
||||
subject { described_class.new(account, params) }
|
||||
|
||||
let(:account) { create(:account) }
|
||||
let(:team) { create(:team, account: account) }
|
||||
let(:inbox) { create(:inbox, account: account) }
|
||||
let(:label) { create(:label, title: 'spec-billing', account: account) }
|
||||
let!(:conversation) { create(:conversation, account: account, inbox: inbox, team: team) }
|
||||
let(:current_time) { '26.10.2020 10:00'.to_datetime }
|
||||
|
||||
let(:params) do
|
||||
{
|
||||
type: filter_type,
|
||||
business_hours: business_hours,
|
||||
timezone_offset: timezone_offset,
|
||||
group_by: group_by,
|
||||
metric: metric,
|
||||
since: (current_time - 1.week).beginning_of_day.to_i.to_s,
|
||||
until: current_time.end_of_day.to_i.to_s,
|
||||
id: filter_id
|
||||
}
|
||||
end
|
||||
let(:timezone_offset) { nil }
|
||||
let(:group_by) { 'day' }
|
||||
let(:metric) { 'avg_first_response_time' }
|
||||
let(:business_hours) { false }
|
||||
let(:filter_type) { :account }
|
||||
let(:filter_id) { '' }
|
||||
|
||||
before do
|
||||
travel_to current_time
|
||||
conversation.label_list.add(label.title)
|
||||
conversation.save!
|
||||
create(:reporting_event, name: 'first_response', value: 80, value_in_business_hours: 10, account: account, created_at: Time.zone.now,
|
||||
conversation: conversation, inbox: inbox)
|
||||
create(:reporting_event, name: 'first_response', value: 100, value_in_business_hours: 20, account: account, created_at: 1.hour.ago)
|
||||
create(:reporting_event, name: 'first_response', value: 93, value_in_business_hours: 30, account: account, created_at: 1.week.ago)
|
||||
end
|
||||
|
||||
describe '#timeseries' do
|
||||
it 'returns the correct values' do
|
||||
timeseries_values = subject.timeseries
|
||||
|
||||
expect(timeseries_values).to eq(
|
||||
[
|
||||
{ count: 1, timestamp: 1_603_065_600, value: 93.0 },
|
||||
{ count: 0, timestamp: 1_603_152_000, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_238_400, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_324_800, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_411_200, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_497_600, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_584_000, value: 0 },
|
||||
{ count: 2, timestamp: 1_603_670_400, value: 90.0 }
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
context 'when business hours is provided' do
|
||||
let(:business_hours) { true }
|
||||
|
||||
it 'returns correct timeseries' do
|
||||
timeseries_values = subject.timeseries
|
||||
|
||||
expect(timeseries_values).to eq(
|
||||
[
|
||||
{ count: 1, timestamp: 1_603_065_600, value: 30.0 },
|
||||
{ count: 0, timestamp: 1_603_152_000, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_238_400, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_324_800, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_411_200, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_497_600, value: 0 },
|
||||
{ count: 0, timestamp: 1_603_584_000, value: 0 },
|
||||
{ count: 2, timestamp: 1_603_670_400, value: 15.0 }
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when rollups are enabled' do
|
||||
let(:timezone_offset) { '5.5' }
|
||||
|
||||
before do
|
||||
account.update!(reporting_timezone: 'Chennai')
|
||||
allow(account).to receive(:feature_enabled?).with('reporting_events_rollup').and_return(true)
|
||||
|
||||
create(:reporting_events_rollup,
|
||||
account: account,
|
||||
date: (current_time - 1.week).to_date,
|
||||
dimension_type: 'account',
|
||||
dimension_id: account.id,
|
||||
metric: 'first_response',
|
||||
count: 1,
|
||||
sum_value: 93.0,
|
||||
sum_value_business_hours: 30.0)
|
||||
|
||||
create(:reporting_events_rollup,
|
||||
account: account,
|
||||
date: current_time.to_date,
|
||||
dimension_type: 'account',
|
||||
dimension_id: account.id,
|
||||
metric: 'first_response',
|
||||
count: 2,
|
||||
sum_value: 180.0,
|
||||
sum_value_business_hours: 30.0)
|
||||
end
|
||||
|
||||
it 'preserves empty buckets in the timeseries' do
|
||||
rollup_timezone = ActiveSupport::TimeZone['Chennai']
|
||||
rollup_start_date = DateTime.strptime(params[:since], '%s').in_time_zone(rollup_timezone).to_date
|
||||
rollup_end_date = (DateTime.strptime(params[:until], '%s') - 1.second).in_time_zone(rollup_timezone).to_date
|
||||
rollup_dates = rollup_start_date..rollup_end_date
|
||||
|
||||
expected_timeseries = rollup_dates.map do |date|
|
||||
value = if date == (current_time - 1.week).to_date
|
||||
93.0
|
||||
elsif date == current_time.to_date
|
||||
90.0
|
||||
else
|
||||
0
|
||||
end
|
||||
|
||||
count = if date == (current_time - 1.week).to_date
|
||||
1
|
||||
elsif date == current_time.to_date
|
||||
2
|
||||
else
|
||||
0
|
||||
end
|
||||
|
||||
{ count: count, timestamp: date.in_time_zone('Chennai').to_i, value: value }
|
||||
end
|
||||
|
||||
expect(subject.timeseries).to eq(expected_timeseries)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when group_by is provided' do
|
||||
let(:group_by) { 'week' }
|
||||
|
||||
it 'returns correct timeseries' do
|
||||
timeseries_values = subject.timeseries
|
||||
expect(timeseries_values).to eq(
|
||||
[
|
||||
{ count: 1, timestamp: (current_time - 1.week).beginning_of_week(:sunday).to_i, value: 93.0 },
|
||||
{ count: 2, timestamp: current_time.beginning_of_week(:sunday).to_i, value: 90.0 }
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when timezone offset is provided' do
|
||||
let(:timezone_offset) { '5.5' }
|
||||
let(:group_by) { 'week' }
|
||||
|
||||
it 'returns correct timeseries' do
|
||||
timeseries_values = subject.timeseries
|
||||
expect(timeseries_values).to eq(
|
||||
[
|
||||
{ count: 1, timestamp: (current_time - 1.week).in_time_zone('Chennai').beginning_of_week(:sunday).to_i, value: 93.0 },
|
||||
{ count: 2, timestamp: current_time.in_time_zone('Chennai').beginning_of_week(:sunday).to_i, value: 90.0 }
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when weekly rollups are enabled' do
|
||||
let(:group_by) { 'week' }
|
||||
let(:timezone_offset) { '5.5' }
|
||||
|
||||
before do
|
||||
account.update!(reporting_timezone: 'Chennai')
|
||||
allow(account).to receive(:feature_enabled?).with('reporting_events_rollup').and_return(true)
|
||||
|
||||
create(:reporting_events_rollup,
|
||||
account: account,
|
||||
date: current_time.to_date - 1.day,
|
||||
dimension_type: 'account',
|
||||
dimension_id: account.id,
|
||||
metric: 'first_response',
|
||||
count: 1,
|
||||
sum_value: 80.0,
|
||||
sum_value_business_hours: 10.0)
|
||||
|
||||
create(:reporting_events_rollup,
|
||||
account: account,
|
||||
date: current_time.to_date,
|
||||
dimension_type: 'account',
|
||||
dimension_id: account.id,
|
||||
metric: 'first_response',
|
||||
count: 1,
|
||||
sum_value: 100.0,
|
||||
sum_value_business_hours: 20.0)
|
||||
end
|
||||
|
||||
it 'groups weeks using sunday boundaries' do
|
||||
expect(subject.timeseries).to eq(
|
||||
[
|
||||
{ count: 0, timestamp: (current_time - 1.week).in_time_zone('Chennai').beginning_of_week(:sunday).to_i, value: 0 },
|
||||
{ count: 2, timestamp: current_time.in_time_zone('Chennai').beginning_of_week(:sunday).to_i, value: 90.0 }
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the label filter is applied' do
|
||||
let(:group_by) { 'week' }
|
||||
let(:filter_type) { 'label' }
|
||||
let(:filter_id) { label.id }
|
||||
|
||||
it 'returns correct timeseries' do
|
||||
timeseries_values = subject.timeseries
|
||||
start_of_the_week = current_time.beginning_of_week(:sunday).to_i
|
||||
last_week_start_of_the_week = (current_time - 1.week).beginning_of_week(:sunday).to_i
|
||||
expect(timeseries_values).to eq(
|
||||
[
|
||||
{ count: 0, timestamp: last_week_start_of_the_week, value: 0 },
|
||||
{ count: 1, timestamp: start_of_the_week, value: 80.0 }
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the inbox filter is applied' do
|
||||
let(:group_by) { 'week' }
|
||||
let(:filter_type) { 'inbox' }
|
||||
let(:filter_id) { inbox.id }
|
||||
|
||||
it 'returns correct timeseries' do
|
||||
timeseries_values = subject.timeseries
|
||||
start_of_the_week = current_time.beginning_of_week(:sunday).to_i
|
||||
last_week_start_of_the_week = (current_time - 1.week).beginning_of_week(:sunday).to_i
|
||||
expect(timeseries_values).to eq(
|
||||
[
|
||||
{ count: 0, timestamp: last_week_start_of_the_week, value: 0 },
|
||||
{ count: 1, timestamp: start_of_the_week, value: 80.0 }
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the team filter is applied' do
|
||||
let(:group_by) { 'week' }
|
||||
let(:filter_type) { 'team' }
|
||||
let(:filter_id) { team.id }
|
||||
|
||||
it 'returns correct timeseries' do
|
||||
timeseries_values = subject.timeseries
|
||||
start_of_the_week = current_time.beginning_of_week(:sunday).to_i
|
||||
last_week_start_of_the_week = (current_time - 1.week).beginning_of_week(:sunday).to_i
|
||||
expect(timeseries_values).to eq(
|
||||
[
|
||||
{ count: 0, timestamp: last_week_start_of_the_week, value: 0 },
|
||||
{ count: 1, timestamp: start_of_the_week, value: 80.0 }
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#aggregate_value' do
|
||||
context 'when there is no filter applied' do
|
||||
it 'returns the correct average value' do
|
||||
expect(subject.aggregate_value).to eq 91.0
|
||||
end
|
||||
end
|
||||
|
||||
context 'when rollups are enabled and the agent does not exist' do
|
||||
let(:filter_type) { :agent }
|
||||
let(:filter_id) { '999999' }
|
||||
let(:timezone_offset) { '0' }
|
||||
|
||||
before do
|
||||
account.update!(reporting_timezone: 'Etc/UTC')
|
||||
allow(account).to receive(:feature_enabled?).with('reporting_events_rollup').and_return(true)
|
||||
end
|
||||
|
||||
it 'raises record not found to preserve raw path behavior' do
|
||||
expect { subject.aggregate_value }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'count metrics' do
|
||||
subject { described_class.new(account, params) }
|
||||
|
||||
let(:account) { create(:account) }
|
||||
let(:account2) { create(:account) }
|
||||
let(:user) { create(:user, email: 'agent1@example.com') }
|
||||
let(:inbox) { create(:inbox, account: account) }
|
||||
let(:inbox2) { create(:inbox, account: account2) }
|
||||
let(:current_time) { Time.current }
|
||||
|
||||
let(:params) do
|
||||
{
|
||||
type: 'agent',
|
||||
metric: 'resolutions_count',
|
||||
since: since_time.beginning_of_day.to_i.to_s,
|
||||
until: current_time.end_of_day.to_i.to_s,
|
||||
timezone_offset: timezone_offset,
|
||||
group_by: group_by,
|
||||
id: user.id.to_s
|
||||
}
|
||||
end
|
||||
let(:group_by) { 'day' }
|
||||
let(:since_time) { current_time - 1.day }
|
||||
let(:timezone_offset) { nil }
|
||||
|
||||
before do
|
||||
travel_to current_time
|
||||
|
||||
create(:account_user, account: account, user: user)
|
||||
create(:account_user, account: account2, user: user)
|
||||
|
||||
conversation1 = create(:conversation, account: account, inbox: inbox, assignee: user)
|
||||
conversation2 = create(:conversation, account: account, inbox: inbox, assignee: user)
|
||||
|
||||
conversation3 = create(:conversation, account: account2, inbox: inbox2, assignee: user)
|
||||
conversation4 = create(:conversation, account: account2, inbox: inbox2, assignee: user)
|
||||
|
||||
create(:reporting_event,
|
||||
name: 'conversation_resolved',
|
||||
account: account,
|
||||
user: user,
|
||||
conversation: conversation1,
|
||||
created_at: current_time - 12.hours)
|
||||
|
||||
create(:reporting_event,
|
||||
name: 'conversation_resolved',
|
||||
account: account,
|
||||
user: user,
|
||||
conversation: conversation2,
|
||||
created_at: current_time - 6.hours)
|
||||
|
||||
create(:reporting_event,
|
||||
name: 'conversation_resolved',
|
||||
account: account2,
|
||||
user: user,
|
||||
conversation: conversation3,
|
||||
created_at: current_time - 8.hours)
|
||||
|
||||
create(:reporting_event,
|
||||
name: 'conversation_resolved',
|
||||
account: account2,
|
||||
user: user,
|
||||
conversation: conversation4,
|
||||
created_at: current_time - 4.hours)
|
||||
|
||||
conversation5 = create(:conversation, account: account2, inbox: inbox2, assignee: user)
|
||||
create(:reporting_event,
|
||||
name: 'conversation_resolved',
|
||||
account: account2,
|
||||
user: user,
|
||||
conversation: conversation5,
|
||||
created_at: current_time - 2.hours)
|
||||
end
|
||||
|
||||
describe '#aggregate_value' do
|
||||
it 'returns only resolutions performed by the user in the specified account' do
|
||||
expect(subject.aggregate_value).to eq(2)
|
||||
end
|
||||
|
||||
context 'when rollups are enabled and the agent does not exist' do
|
||||
let(:timezone_offset) { '0' }
|
||||
|
||||
let(:params) do
|
||||
super().merge(id: '999999')
|
||||
end
|
||||
|
||||
before do
|
||||
account.update!(reporting_timezone: 'Etc/UTC')
|
||||
allow(account).to receive(:feature_enabled?).with('reporting_events_rollup').and_return(true)
|
||||
end
|
||||
|
||||
it 'raises record not found to preserve raw path behavior' do
|
||||
expect { subject.aggregate_value }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when querying account2' do
|
||||
subject { described_class.new(account2, params) }
|
||||
|
||||
it 'returns only resolutions for account2' do
|
||||
expect(subject.aggregate_value).to eq(3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#timeseries' do
|
||||
it 'filters resolutions by account' do
|
||||
result = subject.timeseries
|
||||
total_count = result.sum { |row| row[:value] }
|
||||
expect(total_count).to eq(2)
|
||||
end
|
||||
|
||||
context 'when rollups are enabled and grouped by week' do
|
||||
let(:group_by) { 'week' }
|
||||
let(:current_time) { Time.zone.parse('2020-10-26 10:00:00 UTC') }
|
||||
let(:since_time) { current_time - 1.week }
|
||||
let(:timezone_offset) { '5.5' }
|
||||
|
||||
before do
|
||||
account.update!(reporting_timezone: 'Chennai')
|
||||
allow(account).to receive(:feature_enabled?).with('reporting_events_rollup').and_return(true)
|
||||
|
||||
create(:reporting_events_rollup,
|
||||
account: account,
|
||||
date: current_time.to_date - 1.day,
|
||||
dimension_type: 'agent',
|
||||
dimension_id: user.id,
|
||||
metric: 'resolutions_count',
|
||||
count: 1,
|
||||
sum_value: 0.0,
|
||||
sum_value_business_hours: 0.0)
|
||||
|
||||
create(:reporting_events_rollup,
|
||||
account: account,
|
||||
date: current_time.to_date,
|
||||
dimension_type: 'agent',
|
||||
dimension_id: user.id,
|
||||
metric: 'resolutions_count',
|
||||
count: 1,
|
||||
sum_value: 0.0,
|
||||
sum_value_business_hours: 0.0)
|
||||
end
|
||||
|
||||
it 'groups weeks using sunday boundaries' do
|
||||
expect(subject.timeseries).to eq(
|
||||
[
|
||||
{ value: 0, timestamp: (current_time - 1.week).in_time_zone('Chennai').beginning_of_week(:sunday).to_i },
|
||||
{ value: 2, timestamp: current_time.in_time_zone('Chennai').beginning_of_week(:sunday).to_i }
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'account isolation' do
|
||||
it 'does not leak data between accounts' do
|
||||
account1_count = described_class.new(account, params).aggregate_value
|
||||
account2_count = described_class.new(account2, params).aggregate_value
|
||||
|
||||
expect(account1_count).to eq(2)
|
||||
expect(account2_count).to eq(3)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user