Files
gochat/backend/internal/wsevent/coverage3_test.go
T
2026-08-13 01:28:31 +08:00

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)
}