Enhancement: Move reporting metrics to postgres (#606)
This commit is contained in:
133
spec/builders/v2/report_builder_spec.rb
Normal file
133
spec/builders/v2/report_builder_spec.rb
Normal file
@@ -0,0 +1,133 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe ::V2::ReportBuilder do
|
||||
let!(:account) { create(:account) }
|
||||
let!(:user) { create(:user, account: account) }
|
||||
let!(:inbox) { create(:inbox, account: account) }
|
||||
let(:inbox_member) { create(:inbox_member, user: user, inbox: inbox) }
|
||||
|
||||
describe '#timeseries' do
|
||||
context 'when report type is account' do
|
||||
before do
|
||||
10.times do
|
||||
conversation = create(:conversation, account: account,
|
||||
inbox: inbox, assignee: user,
|
||||
created_at: Time.zone.today)
|
||||
create_list(:message, 5, message_type: 'outgoing',
|
||||
account: account, inbox: inbox,
|
||||
conversation: conversation, created_at: Time.zone.today + 2.hours)
|
||||
create_list(:message, 2, message_type: 'incoming',
|
||||
account: account, inbox: inbox,
|
||||
conversation: conversation,
|
||||
created_at: Time.zone.today + 3.hours)
|
||||
end
|
||||
5.times do
|
||||
conversation = create(:conversation, account: account,
|
||||
inbox: inbox, assignee: user,
|
||||
created_at: (Time.zone.today - 2.days))
|
||||
create_list(:message, 3, message_type: 'outgoing',
|
||||
account: account, inbox: inbox,
|
||||
conversation: conversation,
|
||||
created_at: (Time.zone.today - 2.days))
|
||||
create_list(:message, 1, message_type: 'incoming',
|
||||
account: account, inbox: inbox,
|
||||
conversation: conversation,
|
||||
created_at: (Time.zone.today - 2.days))
|
||||
end
|
||||
end
|
||||
|
||||
it 'return conversations count' do
|
||||
params = {
|
||||
metric: 'conversations_count',
|
||||
type: :account,
|
||||
since: (Time.zone.today - 3.days).to_time.to_i.to_s,
|
||||
until: Time.zone.today.to_time.to_i.to_s
|
||||
}
|
||||
|
||||
builder = V2::ReportBuilder.new(account, params)
|
||||
metrics = builder.timeseries
|
||||
|
||||
expect(metrics[Time.zone.today]).to be 10
|
||||
expect(metrics[Time.zone.today - 2.days]).to be 5
|
||||
end
|
||||
|
||||
it 'return incoming messages count' do
|
||||
params = {
|
||||
metric: 'incoming_messages_count',
|
||||
type: :account,
|
||||
since: (Time.zone.today - 3.days).to_time.to_i.to_s,
|
||||
until: Time.zone.today.to_time.to_i.to_s
|
||||
}
|
||||
|
||||
builder = V2::ReportBuilder.new(account, params)
|
||||
metrics = builder.timeseries
|
||||
|
||||
expect(metrics[Time.zone.today]).to be 20
|
||||
expect(metrics[Time.zone.today - 2.days]).to be 5
|
||||
end
|
||||
|
||||
it 'return outgoing messages count' do
|
||||
params = {
|
||||
metric: 'outgoing_messages_count',
|
||||
type: :account,
|
||||
since: (Time.zone.today - 3.days).to_time.to_i.to_s,
|
||||
until: Time.zone.today.to_time.to_i.to_s
|
||||
}
|
||||
|
||||
builder = V2::ReportBuilder.new(account, params)
|
||||
metrics = builder.timeseries
|
||||
|
||||
expect(metrics[Time.zone.today]).to be 50
|
||||
expect(metrics[Time.zone.today - 2.days]).to be 15
|
||||
end
|
||||
|
||||
it 'return resolutions count' do
|
||||
params = {
|
||||
metric: 'resolutions_count',
|
||||
type: :account,
|
||||
since: (Time.zone.today - 3.days).to_time.to_i.to_s,
|
||||
until: Time.zone.today.to_time.to_i.to_s
|
||||
}
|
||||
|
||||
conversations = account.conversations.where('created_at < ?', 1.day.ago)
|
||||
conversations.each(&:resolved!)
|
||||
builder = V2::ReportBuilder.new(account, params)
|
||||
metrics = builder.timeseries
|
||||
|
||||
expect(metrics[Time.zone.today]).to be 0
|
||||
expect(metrics[Time.zone.today - 2.days]).to be 5
|
||||
end
|
||||
|
||||
it 'returns average first response time' do
|
||||
params = {
|
||||
metric: 'avg_first_response_time',
|
||||
type: :account,
|
||||
since: (Time.zone.today - 3.days).to_time.to_i.to_s,
|
||||
until: Time.zone.today.to_time.to_i.to_s
|
||||
}
|
||||
|
||||
builder = V2::ReportBuilder.new(account, params)
|
||||
metrics = builder.timeseries
|
||||
|
||||
expect(metrics[Time.zone.today].to_f).to be 0.48e4
|
||||
end
|
||||
|
||||
it 'returns summary' do
|
||||
params = {
|
||||
type: :account,
|
||||
since: (Time.zone.today - 3.days).to_time.to_i.to_s,
|
||||
until: Time.zone.today.to_time.to_i.to_s
|
||||
}
|
||||
|
||||
builder = V2::ReportBuilder.new(account, params)
|
||||
metrics = builder.summary
|
||||
|
||||
expect(metrics[:conversations_count]).to be 15
|
||||
expect(metrics[:incoming_messages_count]).to be 25
|
||||
expect(metrics[:outgoing_messages_count]).to be 65
|
||||
expect(metrics[:avg_resolution_time]).to be 0
|
||||
expect(metrics[:resolutions_count]).to be 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
80
spec/controllers/api/v2/accounts/report_controller_spec.rb
Normal file
80
spec/controllers/api/v2/accounts/report_controller_spec.rb
Normal file
@@ -0,0 +1,80 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Reports API', type: :request do
|
||||
let(:account) { create(:account) }
|
||||
let!(:user) { create(:user, account: account) }
|
||||
let!(:inbox) { create(:inbox, account: account) }
|
||||
let(:inbox_member) { create(:inbox_member, user: user, inbox: inbox) }
|
||||
|
||||
before do
|
||||
create_list(:conversation, 10, account: account, inbox: inbox,
|
||||
assignee: user, created_at: Time.zone.today)
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/accounts/:account_id/reports/account' do
|
||||
context 'when it is an unauthenticated user' do
|
||||
it 'returns unauthorized' do
|
||||
get "/api/v2/accounts/#{account.id}/reports/account"
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
it 'return timeseries metrics' do
|
||||
params = {
|
||||
metric: 'conversations_count',
|
||||
type: :account,
|
||||
since: Time.zone.today.to_time.to_i.to_s,
|
||||
until: Time.zone.today.to_time.to_i.to_s
|
||||
}
|
||||
|
||||
get "/api/v2/accounts/#{account.id}/reports/account",
|
||||
params: params,
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = JSON.parse(response.body)
|
||||
|
||||
current_day_metric = json_response.select { |x| x['timestamp'] == Time.zone.today.to_time.to_i }
|
||||
expect(current_day_metric.length).to eq(1)
|
||||
expect(current_day_metric[0]['value']).to eq(10)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/accounts/:account_id/reports/:id/account_summary' do
|
||||
context 'when it is an unauthenticated user' do
|
||||
it 'returns unauthorized' do
|
||||
get "/api/v2/accounts/#{account.id}/reports/#{account.id}/account_summary"
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
|
||||
it 'returns summary metrics' do
|
||||
params = {
|
||||
type: :account,
|
||||
since: Time.zone.today.to_time.to_i.to_s,
|
||||
until: Time.zone.today.to_time.to_i.to_s
|
||||
}
|
||||
|
||||
get "/api/v2/accounts/#{account.id}/reports/#{account.id}/account_summary",
|
||||
params: params,
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = JSON.parse(response.body)
|
||||
|
||||
expect(json_response['conversations_count']).to eq(10)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
10
spec/factories/events.rb
Normal file
10
spec/factories/events.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
FactoryBot.define do
|
||||
factory :event do
|
||||
name { 'MyString' }
|
||||
value { 1.5 }
|
||||
account_id { 1 }
|
||||
inbox_id { 1 }
|
||||
user_id { 1 }
|
||||
conversation_id { 1 }
|
||||
end
|
||||
end
|
||||
@@ -13,7 +13,7 @@ FactoryBot.define do
|
||||
uid { SecureRandom.uuid }
|
||||
name { Faker::Name.name }
|
||||
nickname { Faker::Name.first_name }
|
||||
email { nickname + '@example.com' }
|
||||
email { nickname + "@#{SecureRandom.uuid}.com" }
|
||||
password { 'password' }
|
||||
|
||||
after(:build) do |user, evaluator|
|
||||
|
||||
30
spec/listeners/event_listener_spec.rb
Normal file
30
spec/listeners/event_listener_spec.rb
Normal file
@@ -0,0 +1,30 @@
|
||||
require 'rails_helper'
|
||||
describe EventListener do
|
||||
let(:listener) { described_class.instance }
|
||||
let!(:account) { create(:account) }
|
||||
let!(:user) { create(:user, account: account) }
|
||||
let!(:inbox) { create(:inbox, account: account) }
|
||||
let!(:conversation) { create(:conversation, account: account, inbox: inbox, assignee: user) }
|
||||
let!(:message) do
|
||||
create(:message, message_type: 'outgoing',
|
||||
account: account, inbox: inbox, conversation: conversation)
|
||||
end
|
||||
|
||||
describe '#conversation_resolved' do
|
||||
it 'creates conversation_resolved event' do
|
||||
expect(account.events.where(name: 'conversation_resolved').count).to be 0
|
||||
event = Events::Base.new('conversation.resolved', Time.zone.now, conversation: conversation)
|
||||
listener.conversation_resolved(event)
|
||||
expect(account.events.where(name: 'conversation_resolved').count).to be 1
|
||||
end
|
||||
end
|
||||
|
||||
describe '#first_reply_created' do
|
||||
it 'creates first_response event' do
|
||||
previous_count = account.events.where(name: 'first_response').count
|
||||
event = Events::Base.new('first.reply.created', Time.zone.now, message: message)
|
||||
listener.first_reply_created(event)
|
||||
expect(account.events.where(name: 'first_response').count).to eql previous_count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -17,4 +17,5 @@ RSpec.describe Account do
|
||||
it { is_expected.to have_one(:subscription).dependent(:destroy) }
|
||||
it { is_expected.to have_many(:webhooks).dependent(:destroy) }
|
||||
it { is_expected.to have_many(:notification_settings).dependent(:destroy) }
|
||||
it { is_expected.to have_many(:events) }
|
||||
end
|
||||
|
||||
16
spec/models/event_spec.rb
Normal file
16
spec/models/event_spec.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Event, type: :model do
|
||||
describe 'validations' do
|
||||
it { is_expected.to validate_presence_of(:account_id) }
|
||||
it { is_expected.to validate_presence_of(:name) }
|
||||
it { is_expected.to validate_presence_of(:value) }
|
||||
end
|
||||
|
||||
describe 'associations' do
|
||||
it { is_expected.to belong_to(:account) }
|
||||
it { is_expected.to belong_to(:inbox).optional }
|
||||
it { is_expected.to belong_to(:user).optional }
|
||||
it { is_expected.to belong_to(:conversation).optional }
|
||||
end
|
||||
end
|
||||
@@ -27,6 +27,8 @@ RSpec.describe Inbox do
|
||||
it { is_expected.to have_one(:agent_bot_inbox) }
|
||||
|
||||
it { is_expected.to have_many(:webhooks).dependent(:destroy) }
|
||||
|
||||
it { is_expected.to have_many(:events) }
|
||||
end
|
||||
|
||||
describe '#add_member' do
|
||||
|
||||
@@ -18,6 +18,7 @@ RSpec.describe User do
|
||||
it { is_expected.to have_many(:notification_settings).dependent(:destroy) }
|
||||
it { is_expected.to have_many(:assigned_inboxes).through(:inbox_members) }
|
||||
it { is_expected.to have_many(:messages) }
|
||||
it { is_expected.to have_many(:events) }
|
||||
end
|
||||
|
||||
describe 'pubsub_token' do
|
||||
|
||||
Reference in New Issue
Block a user