443 lines
13 KiB
Go
443 lines
13 KiB
Go
package reporting
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/gochat/gochat/internal/channel"
|
|
"github.com/gochat/gochat/internal/model"
|
|
)
|
|
|
|
func TestReportingEventListener_OnConversationCreated_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
l := NewReportingEventListener(db)
|
|
|
|
assigneeID := uint(5)
|
|
conv := &model.Conversation{
|
|
Base: model.Base{ID: 1, CreatedAt: time.Now()},
|
|
AccountID: 1,
|
|
InboxID: 2,
|
|
AssigneeID: &assigneeID,
|
|
}
|
|
event := channel.NewChannelEvent(channel.EventConversationCreated, channel.ChannelAPI, 1, 2)
|
|
event.Data["conversation"] = conv
|
|
|
|
err := l.OnEvent(context.Background(), event)
|
|
require.NoError(t, err)
|
|
|
|
// Verify reporting event was created
|
|
var events []ReportingEvent
|
|
db.Find(&events)
|
|
require.Len(t, events, 1)
|
|
assert.Equal(t, "conversation_created", events[0].Name)
|
|
assert.Equal(t, uint(1), events[0].AccountID)
|
|
assert.NotNil(t, events[0].UserID)
|
|
assert.Equal(t, assigneeID, *events[0].UserID)
|
|
}
|
|
|
|
func TestReportingEventListener_OnConversationCreated_NoAssignee_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
l := NewReportingEventListener(db)
|
|
|
|
conv := &model.Conversation{
|
|
Base: model.Base{ID: 1, CreatedAt: time.Now()},
|
|
AccountID: 1,
|
|
InboxID: 2,
|
|
}
|
|
event := channel.NewChannelEvent(channel.EventConversationCreated, channel.ChannelAPI, 1, 2)
|
|
event.Data["conversation"] = conv
|
|
|
|
err := l.OnEvent(context.Background(), event)
|
|
require.NoError(t, err)
|
|
|
|
var events []ReportingEvent
|
|
db.Find(&events)
|
|
require.Len(t, events, 1)
|
|
assert.Nil(t, events[0].UserID)
|
|
}
|
|
|
|
func TestReportingEventListener_OnConversationCreated_ExtractError_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
l := NewReportingEventListener(db)
|
|
|
|
// Event without conversation data — should return error
|
|
event := channel.NewChannelEvent(channel.EventConversationCreated, channel.ChannelAPI, 1, 2)
|
|
event.Data = map[string]interface{}{}
|
|
|
|
err := l.OnEvent(context.Background(), event)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestReportingEventListener_OnConversationResolved_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
l := NewReportingEventListener(db)
|
|
|
|
assigneeID := uint(5)
|
|
createdAt := time.Now().Add(-1 * time.Hour)
|
|
conv := &model.Conversation{
|
|
Base: model.Base{ID: 1, CreatedAt: createdAt},
|
|
AccountID: 1,
|
|
InboxID: 2,
|
|
AssigneeID: &assigneeID,
|
|
}
|
|
event := channel.NewChannelEvent(channel.EventConversationResolved, channel.ChannelAPI, 1, 2)
|
|
event.Data["conversation"] = conv
|
|
|
|
err := l.OnEvent(context.Background(), event)
|
|
require.NoError(t, err)
|
|
|
|
var events []ReportingEvent
|
|
db.Find(&events)
|
|
require.Len(t, events, 2)
|
|
// First event is resolution_time
|
|
assert.Equal(t, "resolution_time", events[0].Name)
|
|
assert.Greater(t, events[0].Value, 0.0)
|
|
// Second is resolutions_count
|
|
assert.Equal(t, "resolutions_count", events[1].Name)
|
|
assert.Equal(t, 1.0, events[1].Value)
|
|
}
|
|
|
|
func TestReportingEventListener_OnConversationResolved_ExtractError_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
l := NewReportingEventListener(db)
|
|
|
|
event := channel.NewChannelEvent(channel.EventConversationResolved, channel.ChannelAPI, 1, 2)
|
|
event.Data = map[string]interface{}{}
|
|
|
|
err := l.OnEvent(context.Background(), event)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestReportingEventListener_OnConversationResolved_DBError_Cov3(t *testing.T) {
|
|
// Close the db to trigger a DB error
|
|
db := newTestDB(t)
|
|
sqlDB, _ := db.DB()
|
|
sqlDB.Close()
|
|
|
|
l := NewReportingEventListener(db)
|
|
|
|
conv := &model.Conversation{
|
|
Base: model.Base{ID: 1, CreatedAt: time.Now()},
|
|
AccountID: 1,
|
|
InboxID: 2,
|
|
}
|
|
event := channel.NewChannelEvent(channel.EventConversationResolved, channel.ChannelAPI, 1, 2)
|
|
event.Data["conversation"] = conv
|
|
|
|
err := l.OnEvent(context.Background(), event)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestReportingEventListener_OnConversationAssigned_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
l := NewReportingEventListener(db)
|
|
|
|
assigneeID := uint(5)
|
|
conv := &model.Conversation{
|
|
Base: model.Base{ID: 1, CreatedAt: time.Now()},
|
|
AccountID: 1,
|
|
InboxID: 2,
|
|
AssigneeID: &assigneeID,
|
|
}
|
|
event := channel.NewChannelEvent(channel.EventConversationAssigned, channel.ChannelAPI, 1, 2)
|
|
event.Data["conversation"] = conv
|
|
|
|
err := l.OnEvent(context.Background(), event)
|
|
require.NoError(t, err)
|
|
|
|
var events []ReportingEvent
|
|
db.Find(&events)
|
|
require.Len(t, events, 1)
|
|
assert.Equal(t, "first_response", events[0].Name)
|
|
}
|
|
|
|
func TestReportingEventListener_OnConversationAssigned_ExtractError_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
l := NewReportingEventListener(db)
|
|
|
|
event := channel.NewChannelEvent(channel.EventConversationAssigned, channel.ChannelAPI, 1, 2)
|
|
event.Data = map[string]interface{}{}
|
|
|
|
err := l.OnEvent(context.Background(), event)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestReportingEventListener_OnMessageCreated_Outgoing_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
l := NewReportingEventListener(db)
|
|
|
|
senderID := uint(5)
|
|
msg := &model.Message{
|
|
Base: model.Base{ID: 1, CreatedAt: time.Now()},
|
|
AccountID: 1,
|
|
InboxID: 2,
|
|
ConversationID: 3,
|
|
MessageType: "outgoing",
|
|
SenderType: "agent",
|
|
SenderID: &senderID,
|
|
}
|
|
event := channel.NewChannelEvent(channel.EventMessageCreated, channel.ChannelAPI, 1, 2)
|
|
event.Data["message"] = msg
|
|
|
|
err := l.OnEvent(context.Background(), event)
|
|
require.NoError(t, err)
|
|
|
|
var events []ReportingEvent
|
|
db.Find(&events)
|
|
require.Len(t, events, 1)
|
|
assert.Equal(t, "reply_time", events[0].Name)
|
|
assert.Equal(t, senderID, *events[0].UserID)
|
|
}
|
|
|
|
func TestReportingEventListener_OnMessageCreated_Incoming_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
l := NewReportingEventListener(db)
|
|
|
|
msg := &model.Message{
|
|
Base: model.Base{ID: 1, CreatedAt: time.Now()},
|
|
AccountID: 1,
|
|
InboxID: 2,
|
|
ConversationID: 3,
|
|
MessageType: "incoming",
|
|
SenderType: "contact",
|
|
}
|
|
event := channel.NewChannelEvent(channel.EventMessageCreated, channel.ChannelAPI, 1, 2)
|
|
event.Data["message"] = msg
|
|
|
|
err := l.OnEvent(context.Background(), event)
|
|
require.NoError(t, err)
|
|
|
|
// Incoming messages are not tracked
|
|
var events []ReportingEvent
|
|
db.Find(&events)
|
|
assert.Empty(t, events)
|
|
}
|
|
|
|
func TestReportingEventListener_OnMessageCreated_NoMessage_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
l := NewReportingEventListener(db)
|
|
|
|
event := channel.NewChannelEvent(channel.EventMessageCreated, channel.ChannelAPI, 1, 2)
|
|
event.Data = map[string]interface{}{}
|
|
|
|
err := l.OnEvent(context.Background(), event)
|
|
require.NoError(t, err) // returns nil when no message
|
|
}
|
|
|
|
func TestReportingEventListener_OnMessageCreated_DBError_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
sqlDB, _ := db.DB()
|
|
sqlDB.Close()
|
|
|
|
l := NewReportingEventListener(db)
|
|
|
|
senderID := uint(5)
|
|
msg := &model.Message{
|
|
Base: model.Base{ID: 1, CreatedAt: time.Now()},
|
|
AccountID: 1,
|
|
InboxID: 2,
|
|
ConversationID: 3,
|
|
MessageType: "outgoing",
|
|
SenderType: "agent",
|
|
SenderID: &senderID,
|
|
}
|
|
event := channel.NewChannelEvent(channel.EventMessageCreated, channel.ChannelAPI, 1, 2)
|
|
event.Data["message"] = msg
|
|
|
|
err := l.OnEvent(context.Background(), event)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestReportingEventListener_OnEvent_Unknown_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
l := NewReportingEventListener(db)
|
|
|
|
event := channel.NewChannelEvent("unknown.event", channel.ChannelAPI, 1, 2)
|
|
err := l.OnEvent(context.Background(), event)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestReportingEventListener_Name_Cov3(t *testing.T) {
|
|
l := NewReportingEventListener(nil)
|
|
assert.Equal(t, "reporting_event_listener", l.Name())
|
|
}
|
|
|
|
func TestReportingService_CreateEvent_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
svc := NewReportingService(db)
|
|
|
|
now := time.Now()
|
|
event := &ReportingEvent{
|
|
AccountID: 1,
|
|
Name: "test_metric",
|
|
Value: 42.0,
|
|
EventStartTime: now,
|
|
EventEndTime: now,
|
|
}
|
|
err := svc.CreateEvent(context.Background(), event)
|
|
require.NoError(t, err)
|
|
assert.NotZero(t, event.ID)
|
|
}
|
|
|
|
func TestReportingService_GetEvent_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
svc := NewReportingService(db)
|
|
|
|
now := time.Now()
|
|
event := &ReportingEvent{
|
|
AccountID: 1,
|
|
Name: "test_metric",
|
|
Value: 42.0,
|
|
EventStartTime: now,
|
|
EventEndTime: now,
|
|
}
|
|
require.NoError(t, svc.CreateEvent(context.Background(), event))
|
|
|
|
got, err := svc.GetEvent(context.Background(), event.ID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "test_metric", got.Name)
|
|
}
|
|
|
|
func TestReportingService_GetEvent_NotFound_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
svc := NewReportingService(db)
|
|
|
|
_, err := svc.GetEvent(context.Background(), 999)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestReportingService_ListEventsByAccount_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
svc := NewReportingService(db)
|
|
|
|
now := time.Now()
|
|
event1 := &ReportingEvent{AccountID: 1, Name: "m1", Value: 1, EventStartTime: now, EventEndTime: now}
|
|
event2 := &ReportingEvent{AccountID: 1, Name: "m2", Value: 2, EventStartTime: now, EventEndTime: now}
|
|
event3 := &ReportingEvent{AccountID: 2, Name: "m3", Value: 3, EventStartTime: now, EventEndTime: now}
|
|
require.NoError(t, svc.CreateEvent(context.Background(), event1))
|
|
require.NoError(t, svc.CreateEvent(context.Background(), event2))
|
|
require.NoError(t, svc.CreateEvent(context.Background(), event3))
|
|
|
|
events, err := svc.ListEventsByAccount(context.Background(), 1, now.Add(-1*time.Hour), now.Add(1*time.Hour))
|
|
require.NoError(t, err)
|
|
assert.Len(t, events, 2)
|
|
}
|
|
|
|
func TestReportingService_ListEventsByAccountAndName_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
svc := NewReportingService(db)
|
|
|
|
now := time.Now()
|
|
event1 := &ReportingEvent{AccountID: 1, Name: "reply_time", Value: 1, EventStartTime: now, EventEndTime: now}
|
|
event2 := &ReportingEvent{AccountID: 1, Name: "resolution_time", Value: 2, EventStartTime: now, EventEndTime: now}
|
|
require.NoError(t, svc.CreateEvent(context.Background(), event1))
|
|
require.NoError(t, svc.CreateEvent(context.Background(), event2))
|
|
|
|
events, err := svc.ListEventsByAccountAndName(context.Background(), 1, "reply_time", now.Add(-1*time.Hour), now.Add(1*time.Hour))
|
|
require.NoError(t, err)
|
|
assert.Len(t, events, 1)
|
|
assert.Equal(t, "reply_time", events[0].Name)
|
|
}
|
|
|
|
func TestReportingService_CreateRollup_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
svc := NewReportingService(db)
|
|
|
|
rollup := &ReportingEventsRollup{
|
|
AccountID: 1,
|
|
Date: time.Now().Truncate(24 * time.Hour),
|
|
DimensionType: DimensionAccount,
|
|
DimensionID: 1,
|
|
Metric: MetricResolutionsCount,
|
|
Count: 5,
|
|
SumValue: 100.0,
|
|
}
|
|
err := svc.CreateRollup(context.Background(), rollup)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestReportingService_GetRollups_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
svc := NewReportingService(db)
|
|
|
|
now := time.Now().Truncate(24 * time.Hour)
|
|
rollup := &ReportingEventsRollup{
|
|
AccountID: 1,
|
|
Date: now,
|
|
DimensionType: DimensionAccount,
|
|
DimensionID: 1,
|
|
Metric: MetricResolutionsCount,
|
|
Count: 5,
|
|
}
|
|
require.NoError(t, svc.CreateRollup(context.Background(), rollup))
|
|
|
|
rollups, err := svc.GetRollups(context.Background(), 1, DimensionAccount, 1, now.Add(-1*time.Hour), now.Add(1*time.Hour))
|
|
require.NoError(t, err)
|
|
assert.Len(t, rollups, 1)
|
|
}
|
|
|
|
func TestReportingService_GetRollupsByMetric_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
svc := NewReportingService(db)
|
|
|
|
now := time.Now().Truncate(24 * time.Hour)
|
|
rollup := &ReportingEventsRollup{
|
|
AccountID: 1,
|
|
Date: now,
|
|
DimensionType: DimensionAccount,
|
|
DimensionID: 1,
|
|
Metric: MetricReplyTime,
|
|
Count: 3,
|
|
}
|
|
require.NoError(t, svc.CreateRollup(context.Background(), rollup))
|
|
|
|
rollups, err := svc.GetRollupsByMetric(context.Background(), 1, DimensionAccount, 1, MetricReplyTime, now.Add(-1*time.Hour), now.Add(1*time.Hour))
|
|
require.NoError(t, err)
|
|
assert.Len(t, rollups, 1)
|
|
}
|
|
|
|
func TestReportingService_DeleteRollupsByDate_Cov3(t *testing.T) {
|
|
db := newTestDB(t)
|
|
svc := NewReportingService(db)
|
|
|
|
now := time.Now().Truncate(24 * time.Hour)
|
|
rollup := &ReportingEventsRollup{
|
|
AccountID: 1,
|
|
Date: now,
|
|
DimensionType: DimensionAccount,
|
|
DimensionID: 1,
|
|
Metric: MetricReplyTime,
|
|
}
|
|
require.NoError(t, svc.CreateRollup(context.Background(), rollup))
|
|
|
|
err := svc.DeleteRollupsByDate(context.Background(), 1, now.Add(-1*time.Hour), now.Add(1*time.Hour))
|
|
require.NoError(t, err)
|
|
|
|
rollups, _ := svc.GetRollups(context.Background(), 1, DimensionAccount, 1, now.Add(-1*time.Hour), now.Add(1*time.Hour))
|
|
assert.Empty(t, rollups)
|
|
}
|
|
|
|
// --- Metric registry tests ---
|
|
|
|
func TestGetMetricDefinition_Cov3(t *testing.T) {
|
|
def, ok := GetMetricDefinition("avg_first_response_time")
|
|
assert.True(t, ok)
|
|
assert.Equal(t, "first_response", def.RawEventName)
|
|
}
|
|
|
|
func TestGetMetricDefinition_NotFound_Cov3(t *testing.T) {
|
|
_, ok := GetMetricDefinition("nonexistent")
|
|
assert.False(t, ok)
|
|
}
|
|
|
|
func TestAllMetricKeys_Cov3(t *testing.T) {
|
|
keys := AllMetricKeys()
|
|
assert.NotEmpty(t, keys)
|
|
assert.Contains(t, keys, "avg_first_response_time")
|
|
assert.Contains(t, keys, "resolutions_count")
|
|
}
|