566 lines
16 KiB
Go
566 lines
16 KiB
Go
package wsevent
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/gochat/gochat/internal/channel"
|
|
"github.com/gochat/gochat/internal/model"
|
|
wspkg "github.com/gochat/gochat/internal/ws"
|
|
)
|
|
|
|
func makeMessage_Cov3(id uint) *model.Message {
|
|
return &model.Message{
|
|
Base: model.Base{ID: id, CreatedAt: time.Now(), UpdatedAt: time.Now()},
|
|
ConversationID: 10,
|
|
AccountID: 1,
|
|
InboxID: 5,
|
|
Content: "hello",
|
|
MessageType: "incoming",
|
|
ContentType: "text",
|
|
Status: "sent",
|
|
SenderType: "contact",
|
|
}
|
|
}
|
|
|
|
func makeConversation_Cov3(id uint) *model.Conversation {
|
|
displayID := uint(200)
|
|
return &model.Conversation{
|
|
Base: model.Base{ID: id, CreatedAt: time.Now(), UpdatedAt: time.Now()},
|
|
DisplayID: &displayID,
|
|
AccountID: 1,
|
|
InboxID: 5,
|
|
ContactID: 3,
|
|
Status: "open",
|
|
ChannelType: "web_widget",
|
|
}
|
|
}
|
|
|
|
func makeContact_Cov3(id uint) *model.Contact {
|
|
return &model.Contact{
|
|
Base: model.Base{ID: id, CreatedAt: time.Now(), UpdatedAt: time.Now()},
|
|
AccountID: 1,
|
|
Name: "Alice",
|
|
Email: "alice@test.com",
|
|
}
|
|
}
|
|
|
|
func makeInbox_Cov3(id uint) *model.Inbox {
|
|
return &model.Inbox{
|
|
Base: model.Base{ID: id},
|
|
AccountID: 1,
|
|
ChannelType: "web_widget",
|
|
Name: "Test Inbox",
|
|
}
|
|
}
|
|
|
|
// captureHub_Cov3 implements ws.MessageHandler for testing
|
|
type captureHub_Cov3 struct {
|
|
accountID uint
|
|
data []byte
|
|
}
|
|
|
|
func (h *captureHub_Cov3) SendToAccount(accountID uint, data []byte) {
|
|
h.accountID = accountID
|
|
h.data = append([]byte(nil), data...)
|
|
}
|
|
|
|
func (h *captureHub_Cov3) SendToRoom(string, []byte) {}
|
|
|
|
// === eventMessage tests ===
|
|
|
|
func TestEventMessage_Ptr_Cov3(t *testing.T) {
|
|
msg := makeMessage_Cov3(1)
|
|
data := map[string]interface{}{"message": msg}
|
|
result, ok := eventMessage(data)
|
|
assert.True(t, ok)
|
|
assert.NotNil(t, result)
|
|
assert.Equal(t, uint(1), result.ID)
|
|
}
|
|
|
|
func TestEventMessage_NilPtr_Cov3(t *testing.T) {
|
|
data := map[string]interface{}{"message": (*model.Message)(nil)}
|
|
_, ok := eventMessage(data)
|
|
assert.False(t, ok)
|
|
}
|
|
|
|
func TestEventMessage_Value_Cov3(t *testing.T) {
|
|
msg := *makeMessage_Cov3(2)
|
|
data := map[string]interface{}{"message": msg}
|
|
result, ok := eventMessage(data)
|
|
assert.True(t, ok)
|
|
assert.NotNil(t, result)
|
|
assert.Equal(t, uint(2), result.ID)
|
|
}
|
|
|
|
func TestEventMessage_Missing_Cov3(t *testing.T) {
|
|
data := map[string]interface{}{}
|
|
_, ok := eventMessage(data)
|
|
assert.False(t, ok)
|
|
}
|
|
|
|
func TestEventMessage_WrongType_Cov3(t *testing.T) {
|
|
data := map[string]interface{}{"message": "not a message"}
|
|
_, ok := eventMessage(data)
|
|
assert.False(t, ok)
|
|
}
|
|
|
|
// === eventConversation tests ===
|
|
|
|
func TestEventConversation_Ptr_Cov3(t *testing.T) {
|
|
conv := makeConversation_Cov3(1)
|
|
data := map[string]interface{}{"conversation": conv}
|
|
result, ok := eventConversation(data)
|
|
assert.True(t, ok)
|
|
assert.NotNil(t, result)
|
|
assert.Equal(t, uint(1), result.ID)
|
|
}
|
|
|
|
func TestEventConversation_NilPtr_Cov3(t *testing.T) {
|
|
data := map[string]interface{}{"conversation": (*model.Conversation)(nil)}
|
|
_, ok := eventConversation(data)
|
|
assert.False(t, ok)
|
|
}
|
|
|
|
func TestEventConversation_Value_Cov3(t *testing.T) {
|
|
conv := *makeConversation_Cov3(2)
|
|
data := map[string]interface{}{"conversation": conv}
|
|
result, ok := eventConversation(data)
|
|
assert.True(t, ok)
|
|
assert.NotNil(t, result)
|
|
assert.Equal(t, uint(2), result.ID)
|
|
}
|
|
|
|
func TestEventConversation_Missing_Cov3(t *testing.T) {
|
|
data := map[string]interface{}{}
|
|
_, ok := eventConversation(data)
|
|
assert.False(t, ok)
|
|
}
|
|
|
|
func TestEventConversation_WrongType_Cov3(t *testing.T) {
|
|
data := map[string]interface{}{"conversation": 123}
|
|
_, ok := eventConversation(data)
|
|
assert.False(t, ok)
|
|
}
|
|
|
|
// === eventContact tests ===
|
|
|
|
func TestEventContact_Ptr_Cov3(t *testing.T) {
|
|
contact := makeContact_Cov3(1)
|
|
data := map[string]interface{}{"contact": contact}
|
|
result, ok := eventContact(data)
|
|
assert.True(t, ok)
|
|
assert.NotNil(t, result)
|
|
assert.Equal(t, uint(1), result.ID)
|
|
}
|
|
|
|
func TestEventContact_NilPtr_Cov3(t *testing.T) {
|
|
data := map[string]interface{}{"contact": (*model.Contact)(nil)}
|
|
_, ok := eventContact(data)
|
|
assert.False(t, ok)
|
|
}
|
|
|
|
func TestEventContact_Value_Cov3(t *testing.T) {
|
|
contact := *makeContact_Cov3(2)
|
|
data := map[string]interface{}{"contact": contact}
|
|
result, ok := eventContact(data)
|
|
assert.True(t, ok)
|
|
assert.NotNil(t, result)
|
|
assert.Equal(t, uint(2), result.ID)
|
|
}
|
|
|
|
func TestEventContact_Missing_Cov3(t *testing.T) {
|
|
data := map[string]interface{}{}
|
|
_, ok := eventContact(data)
|
|
assert.False(t, ok)
|
|
}
|
|
|
|
func TestEventContact_WrongType_Cov3(t *testing.T) {
|
|
data := map[string]interface{}{"contact": true}
|
|
_, ok := eventContact(data)
|
|
assert.False(t, ok)
|
|
}
|
|
|
|
// === eventInbox tests ===
|
|
|
|
func TestEventInbox_Ptr_Cov3(t *testing.T) {
|
|
inbox := makeInbox_Cov3(1)
|
|
data := map[string]interface{}{"inbox": inbox}
|
|
result, ok := eventInbox(data)
|
|
assert.True(t, ok)
|
|
assert.NotNil(t, result)
|
|
assert.Equal(t, uint(1), result.ID)
|
|
}
|
|
|
|
func TestEventInbox_NilPtr_Cov3(t *testing.T) {
|
|
data := map[string]interface{}{"inbox": (*model.Inbox)(nil)}
|
|
_, ok := eventInbox(data)
|
|
assert.False(t, ok)
|
|
}
|
|
|
|
func TestEventInbox_Value_Cov3(t *testing.T) {
|
|
inbox := *makeInbox_Cov3(2)
|
|
data := map[string]interface{}{"inbox": inbox}
|
|
result, ok := eventInbox(data)
|
|
assert.True(t, ok)
|
|
assert.NotNil(t, result)
|
|
assert.Equal(t, uint(2), result.ID)
|
|
}
|
|
|
|
func TestEventInbox_Missing_Cov3(t *testing.T) {
|
|
data := map[string]interface{}{}
|
|
_, ok := eventInbox(data)
|
|
assert.False(t, ok)
|
|
}
|
|
|
|
func TestEventInbox_WrongType_Cov3(t *testing.T) {
|
|
data := map[string]interface{}{"inbox": 3.14}
|
|
_, ok := eventInbox(data)
|
|
assert.False(t, ok)
|
|
}
|
|
|
|
// === messageTypeValue & nonEmpty ===
|
|
|
|
func TestMessageTypeValue_Cov3(t *testing.T) {
|
|
assert.Equal(t, 0, messageTypeValue("incoming"))
|
|
assert.Equal(t, 0, messageTypeValue(" INCOMING "))
|
|
assert.Equal(t, 2, messageTypeValue("activity"))
|
|
assert.Equal(t, 3, messageTypeValue("template"))
|
|
assert.Equal(t, 1, messageTypeValue("outgoing"))
|
|
assert.Equal(t, 1, messageTypeValue(""))
|
|
assert.Equal(t, 1, messageTypeValue("unknown"))
|
|
}
|
|
|
|
func TestNonEmpty_Cov3(t *testing.T) {
|
|
assert.Equal(t, "fallback", nonEmpty("", "fallback"))
|
|
assert.Equal(t, "fallback", nonEmpty(" ", "fallback"))
|
|
assert.Equal(t, "value", nonEmpty("value", "fallback"))
|
|
}
|
|
|
|
// === modelMap ===
|
|
|
|
func TestModelMap_Cov3(t *testing.T) {
|
|
msg := makeMessage_Cov3(1)
|
|
result := modelMap(msg)
|
|
assert.NotEmpty(t, result)
|
|
assert.Equal(t, "hello", result["content"])
|
|
}
|
|
|
|
func TestModelMap_Nil_Cov3(t *testing.T) {
|
|
result := modelMap(nil)
|
|
assert.Empty(t, result)
|
|
}
|
|
|
|
// === wsEventPayload ===
|
|
|
|
func TestWsEventPayload_Nil_Cov3(t *testing.T) {
|
|
result := wsEventPayload(nil)
|
|
assert.Empty(t, result)
|
|
}
|
|
|
|
func TestWsEventPayload_UnknownType_Cov3(t *testing.T) {
|
|
event := &channel.ChannelEvent{
|
|
Type: "unknown.event",
|
|
Data: map[string]interface{}{"foo": "bar"},
|
|
}
|
|
result := wsEventPayload(event)
|
|
assert.Equal(t, "bar", result["foo"])
|
|
}
|
|
|
|
func TestWsEventPayload_MessageCreated_Cov3(t *testing.T) {
|
|
msg := makeMessage_Cov3(1)
|
|
conv := makeConversation_Cov3(10)
|
|
contact := makeContact_Cov3(3)
|
|
event := &channel.ChannelEvent{
|
|
Type: channel.EventMessageCreated,
|
|
Data: map[string]interface{}{
|
|
"message": msg,
|
|
"conversation": conv,
|
|
"contact": contact,
|
|
},
|
|
}
|
|
result := wsEventPayload(event)
|
|
assert.NotEmpty(t, result)
|
|
assert.NotNil(t, result["sender"])
|
|
assert.NotNil(t, result["conversation"])
|
|
}
|
|
|
|
func TestWsEventPayload_MessageCreatedValue_Cov3(t *testing.T) {
|
|
msg := *makeMessage_Cov3(1)
|
|
event := &channel.ChannelEvent{
|
|
Type: channel.EventMessageUpdated,
|
|
Data: map[string]interface{}{"message": msg},
|
|
}
|
|
result := wsEventPayload(event)
|
|
assert.NotEmpty(t, result)
|
|
}
|
|
|
|
func TestWsEventPayload_MessageDeleted_Cov3(t *testing.T) {
|
|
msg := makeMessage_Cov3(1)
|
|
event := &channel.ChannelEvent{
|
|
Type: channel.EventMessageDeleted,
|
|
Data: map[string]interface{}{"message": msg},
|
|
}
|
|
result := wsEventPayload(event)
|
|
assert.NotEmpty(t, result)
|
|
}
|
|
|
|
func TestWsEventPayload_ConversationCreated_Cov3(t *testing.T) {
|
|
conv := makeConversation_Cov3(1)
|
|
contact := makeContact_Cov3(3)
|
|
inbox := makeInbox_Cov3(5)
|
|
event := &channel.ChannelEvent{
|
|
Type: channel.EventConversationCreated,
|
|
Data: map[string]interface{}{
|
|
"conversation": conv,
|
|
"contact": contact,
|
|
"inbox": inbox,
|
|
},
|
|
}
|
|
result := wsEventPayload(event)
|
|
assert.NotEmpty(t, result)
|
|
assert.NotNil(t, result["meta"])
|
|
}
|
|
|
|
func TestWsEventPayload_ConversationResolved_Cov3(t *testing.T) {
|
|
conv := makeConversation_Cov3(1)
|
|
event := &channel.ChannelEvent{
|
|
Type: channel.EventConversationResolved,
|
|
Data: map[string]interface{}{"conversation": conv},
|
|
}
|
|
result := wsEventPayload(event)
|
|
assert.NotEmpty(t, result)
|
|
}
|
|
|
|
func TestWsEventPayload_ContactCreated_Cov3(t *testing.T) {
|
|
contact := makeContact_Cov3(1)
|
|
event := &channel.ChannelEvent{
|
|
Type: channel.EventContactCreated,
|
|
Data: map[string]interface{}{"contact": contact},
|
|
}
|
|
result := wsEventPayload(event)
|
|
assert.NotEmpty(t, result)
|
|
assert.Equal(t, "offline", result["availability_status"])
|
|
}
|
|
|
|
func TestWsEventPayload_ContactUpdated_NilAttrs_Cov3(t *testing.T) {
|
|
contact := makeContact_Cov3(1)
|
|
contact.CustomAttributes = nil
|
|
contact.AdditionalAttributes = nil
|
|
event := &channel.ChannelEvent{
|
|
Type: channel.EventContactUpdated,
|
|
Data: map[string]interface{}{"contact": contact},
|
|
}
|
|
result := wsEventPayload(event)
|
|
assert.NotEmpty(t, result)
|
|
assert.NotNil(t, result["additional_attributes"])
|
|
assert.NotNil(t, result["custom_attributes"])
|
|
}
|
|
|
|
func TestWsEventPayload_ContactDeleted_Cov3(t *testing.T) {
|
|
contact := makeContact_Cov3(1)
|
|
event := &channel.ChannelEvent{
|
|
Type: channel.EventContactDeleted,
|
|
Data: map[string]interface{}{"contact": contact},
|
|
}
|
|
result := wsEventPayload(event)
|
|
assert.NotEmpty(t, result)
|
|
}
|
|
|
|
// === conversationPushPayload ===
|
|
|
|
func TestConversationPushPayload_Cov3(t *testing.T) {
|
|
conv := makeConversation_Cov3(1)
|
|
lastActivity := time.Now().Unix()
|
|
conv.LastActivityAt = &lastActivity
|
|
contact := makeContact_Cov3(3)
|
|
inbox := makeInbox_Cov3(5)
|
|
data := map[string]interface{}{
|
|
"contact": contact,
|
|
"inbox": inbox,
|
|
}
|
|
result := conversationPushPayload(conv, data)
|
|
assert.NotEmpty(t, result)
|
|
assert.Equal(t, uint(200), result["id"])
|
|
assert.NotNil(t, result["meta"])
|
|
assert.NotNil(t, result["messages"])
|
|
assert.Equal(t, false, result["ai_takeover_active"])
|
|
|
|
botID := uint(9)
|
|
conv.AssigneeAgentBotID = &botID
|
|
conv.Status = string(model.ConversationStatusPending)
|
|
assert.Equal(t, true, conversationPushPayload(conv, data)["ai_takeover_active"])
|
|
}
|
|
|
|
// === messagePushPayload ===
|
|
|
|
func TestMessagePushPayload_Cov3(t *testing.T) {
|
|
msg := makeMessage_Cov3(1)
|
|
conv := makeConversation_Cov3(10)
|
|
contact := makeContact_Cov3(3)
|
|
data := map[string]interface{}{
|
|
"conversation": conv,
|
|
"contact": contact,
|
|
}
|
|
result := messagePushPayload(msg, data)
|
|
assert.NotEmpty(t, result)
|
|
assert.NotNil(t, result["sender"])
|
|
assert.NotNil(t, result["conversation"])
|
|
}
|
|
|
|
func TestMessagePushPayload_NilContentAttributes_Cov3(t *testing.T) {
|
|
msg := makeMessage_Cov3(1)
|
|
msg.ContentAttributes = nil
|
|
data := map[string]interface{}{}
|
|
result := messagePushPayload(msg, data)
|
|
assert.NotEmpty(t, result)
|
|
assert.NotNil(t, result["content_attributes"])
|
|
}
|
|
|
|
// === contactPushPayload ===
|
|
|
|
func TestContactPushPayload_NilAttributes_Cov3(t *testing.T) {
|
|
contact := makeContact_Cov3(1)
|
|
contact.AdditionalAttributes = nil
|
|
contact.CustomAttributes = nil
|
|
result := contactPushPayload(contact)
|
|
assert.NotEmpty(t, result)
|
|
assert.NotNil(t, result["additional_attributes"])
|
|
assert.NotNil(t, result["custom_attributes"])
|
|
}
|
|
|
|
// === isWSEventType ===
|
|
|
|
func TestIsWSEventType_AllTypes_Cov3(t *testing.T) {
|
|
types := []string{
|
|
"message.created", "message.updated", "message.deleted",
|
|
"conversation.created", "conversation.updated",
|
|
"conversation.resolved", "conversation.opened",
|
|
"conversation.assigned", "conversation.unassigned",
|
|
"conversation.status_changed", "conversation.typing_on",
|
|
"conversation.typing_off", "conversation.mentioned", "conversation.read",
|
|
"contact.created", "contact.updated", "contact.deleted", "contact.merged",
|
|
"inbox.created", "inbox.updated", "inbox.deleted",
|
|
"presence.update", "agent.typing_on", "agent.typing_off",
|
|
"agent.online", "agent.offline",
|
|
"notification.created", "notification.updated", "notification.deleted",
|
|
}
|
|
for _, tp := range types {
|
|
assert.True(t, isWSEventType(tp), "expected true for %s", tp)
|
|
}
|
|
}
|
|
|
|
func TestIsWSEventType_Unknown_Cov3(t *testing.T) {
|
|
assert.False(t, isWSEventType("unknown.event"))
|
|
assert.False(t, isWSEventType(""))
|
|
}
|
|
|
|
// === OnEvent ===
|
|
|
|
func TestOnEvent_NonWSEventType_Cov3(t *testing.T) {
|
|
hub := &captureHub_Cov3{}
|
|
l := New(wspkg.NewEventPublisherLocal(hub, nil))
|
|
event := &channel.ChannelEvent{
|
|
Type: "unknown.event",
|
|
AccountID: 1,
|
|
Data: map[string]interface{}{},
|
|
}
|
|
err := l.OnEvent(context.Background(), event)
|
|
require.NoError(t, err)
|
|
assert.Nil(t, hub.data) // nothing published
|
|
}
|
|
|
|
func TestOnEvent_MessageCreated_Cov3(t *testing.T) {
|
|
hub := &captureHub_Cov3{}
|
|
l := New(wspkg.NewEventPublisherLocal(hub, nil))
|
|
msg := makeMessage_Cov3(1)
|
|
event := &channel.ChannelEvent{
|
|
Type: channel.EventMessageCreated,
|
|
AccountID: 1,
|
|
ConversationID: 10,
|
|
InboxID: 5,
|
|
Data: map[string]interface{}{"message": msg},
|
|
}
|
|
err := l.OnEvent(context.Background(), event)
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, hub.data)
|
|
|
|
var envelope map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(hub.data, &envelope))
|
|
payload, ok := envelope["data"].(map[string]interface{})
|
|
require.True(t, ok)
|
|
assert.Equal(t, float64(1), payload["account_id"])
|
|
}
|
|
|
|
func TestOnEvent_ConversationCreated_Cov3(t *testing.T) {
|
|
hub := &captureHub_Cov3{}
|
|
l := New(wspkg.NewEventPublisherLocal(hub, nil))
|
|
conv := makeConversation_Cov3(1)
|
|
event := &channel.ChannelEvent{
|
|
Type: channel.EventConversationCreated,
|
|
AccountID: 1,
|
|
ConversationID: 1,
|
|
InboxID: 5,
|
|
Data: map[string]interface{}{"conversation": conv},
|
|
}
|
|
err := l.OnEvent(context.Background(), event)
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, hub.data)
|
|
}
|
|
|
|
func TestOnEvent_ConversationUpdatedPublishesInactiveTakeover_Cov3(t *testing.T) {
|
|
hub := &captureHub_Cov3{}
|
|
l := New(wspkg.NewEventPublisherLocal(hub, nil))
|
|
conv := makeConversation_Cov3(1)
|
|
event := &channel.ChannelEvent{
|
|
Type: channel.EventConversationUpdated,
|
|
AccountID: 1,
|
|
ConversationID: 1,
|
|
Data: map[string]interface{}{"conversation": conv},
|
|
}
|
|
|
|
require.NoError(t, l.OnEvent(context.Background(), event))
|
|
var envelope map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(hub.data, &envelope))
|
|
payload := envelope["data"].(map[string]interface{})
|
|
assert.Equal(t, false, payload["ai_takeover_active"])
|
|
}
|
|
|
|
func TestOnEvent_WithInboxID_Cov3(t *testing.T) {
|
|
hub := &captureHub_Cov3{}
|
|
l := New(wspkg.NewEventPublisherLocal(hub, nil))
|
|
event := &channel.ChannelEvent{
|
|
Type: "conversation.updated",
|
|
AccountID: 1,
|
|
InboxID: 5,
|
|
Data: map[string]interface{}{"foo": "bar"},
|
|
}
|
|
err := l.OnEvent(context.Background(), event)
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, hub.data)
|
|
}
|
|
|
|
func TestOnEvent_ConversationIDAlreadySet_Cov3(t *testing.T) {
|
|
hub := &captureHub_Cov3{}
|
|
l := New(wspkg.NewEventPublisherLocal(hub, nil))
|
|
conv := makeConversation_Cov3(42)
|
|
event := &channel.ChannelEvent{
|
|
Type: channel.EventConversationResolved,
|
|
AccountID: 1,
|
|
ConversationID: 42,
|
|
InboxID: 5,
|
|
Data: map[string]interface{}{
|
|
"conversation": conv,
|
|
"conversation_id": float64(999), // already set in data
|
|
},
|
|
}
|
|
err := l.OnEvent(context.Background(), event)
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, hub.data)
|
|
}
|