244 lines
7.3 KiB
Go
244 lines
7.3 KiB
Go
package ws
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// === Event type constants tests ===
|
|
// Verify all Chatwoot-style dot-separated event naming conventions.
|
|
|
|
func TestMessageEventConstants(t *testing.T) {
|
|
assert.Equal(t, "message.created", EventMessageCreated)
|
|
assert.Equal(t, "message.updated", EventMessageUpdated)
|
|
assert.Equal(t, "message.deleted", EventMessageDeleted)
|
|
}
|
|
|
|
func TestConversationEventConstants(t *testing.T) {
|
|
assert.Equal(t, "conversation.created", EventConversationCreated)
|
|
assert.Equal(t, "conversation.updated", EventConversationUpdated)
|
|
assert.Equal(t, "conversation.resolved", EventConversationResolved)
|
|
assert.Equal(t, "conversation.opened", EventConversationOpened)
|
|
assert.Equal(t, "conversation.assigned", EventConversationAssigned)
|
|
assert.Equal(t, "conversation.unassigned", EventConversationUnassigned)
|
|
assert.Equal(t, "conversation.status_changed", EventConversationStatusChanged)
|
|
assert.Equal(t, "conversation.typing_on", EventConversationTypingOn)
|
|
assert.Equal(t, "conversation.typing_off", EventConversationTypingOff)
|
|
assert.Equal(t, "conversation.mentioned", EventConversationMentioned)
|
|
assert.Equal(t, "conversation.read", EventConversationRead)
|
|
}
|
|
|
|
func TestContactEventConstants(t *testing.T) {
|
|
assert.Equal(t, "contact.created", EventContactCreated)
|
|
assert.Equal(t, "contact.updated", EventContactUpdated)
|
|
assert.Equal(t, "contact.deleted", EventContactDeleted)
|
|
assert.Equal(t, "contact.merged", EventContactMerged)
|
|
}
|
|
|
|
func TestInboxEventConstants(t *testing.T) {
|
|
assert.Equal(t, "inbox.created", EventInboxCreated)
|
|
assert.Equal(t, "inbox.updated", EventInboxUpdated)
|
|
assert.Equal(t, "inbox.deleted", EventInboxDeleted)
|
|
}
|
|
|
|
func TestNotificationEventConstants(t *testing.T) {
|
|
assert.Equal(t, "notification.created", EventNotificationCreated)
|
|
assert.Equal(t, "notification.updated", EventNotificationUpdated)
|
|
assert.Equal(t, "notification.deleted", EventNotificationDeleted)
|
|
}
|
|
|
|
func TestPresenceEventConstants(t *testing.T) {
|
|
assert.Equal(t, "presence.update", EventPresenceUpdate)
|
|
assert.Equal(t, "account.cache_invalidated", EventAccountCacheInvalidated)
|
|
}
|
|
|
|
func TestAgentTypingEventConstants(t *testing.T) {
|
|
assert.Equal(t, "agent.typing_on", EventAgentTypingOn)
|
|
assert.Equal(t, "agent.typing_off", EventAgentTypingOff)
|
|
assert.Equal(t, "agent.online", EventAgentOnline)
|
|
assert.Equal(t, "agent.offline", EventAgentOffline)
|
|
}
|
|
|
|
func TestProtocolControlConstants(t *testing.T) {
|
|
assert.Equal(t, "subscribe.confirm", EventSubscribeConfirm)
|
|
assert.Equal(t, "unsubscribe.confirm", EventUnsubscribeConfirm)
|
|
assert.Equal(t, "subscribe.reject", EventSubscribeReject)
|
|
assert.Equal(t, "ping.response", EventPingResponse)
|
|
assert.Equal(t, "welcome", EventWelcome)
|
|
assert.Equal(t, "disconnect", EventDisconnect)
|
|
}
|
|
|
|
func TestEventNamingConvention_DotSeparated(t *testing.T) {
|
|
// All business events should follow Chatwoot's resource.action naming
|
|
events := []string{
|
|
EventMessageCreated, EventMessageUpdated, EventMessageDeleted,
|
|
EventConversationCreated, EventConversationUpdated, EventConversationResolved,
|
|
EventContactCreated, EventContactUpdated, EventContactDeleted, EventContactMerged,
|
|
EventInboxCreated, EventInboxUpdated, EventInboxDeleted,
|
|
EventNotificationCreated, EventNotificationUpdated, EventNotificationDeleted,
|
|
EventPresenceUpdate, EventAccountCacheInvalidated,
|
|
EventAgentTypingOn, EventAgentTypingOff, EventAgentOnline, EventAgentOffline,
|
|
}
|
|
for _, event := range events {
|
|
assert.Contains(t, event, ".", "event %s should follow resource.action naming", event)
|
|
}
|
|
}
|
|
|
|
// === WSMessage struct tests ===
|
|
|
|
func TestWSMessage_MarshalUnmarshal(t *testing.T) {
|
|
msg := WSMessage{
|
|
Event: EventMessageCreated,
|
|
Data: map[string]interface{}{"id": 1, "content": "hello"},
|
|
AccountID: 100,
|
|
}
|
|
data, err := json.Marshal(msg)
|
|
assert.NoError(t, err)
|
|
assert.Contains(t, string(data), "message.created")
|
|
assert.Contains(t, string(data), "account_id")
|
|
|
|
var decoded WSMessage
|
|
err = json.Unmarshal(data, &decoded)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, EventMessageCreated, decoded.Event)
|
|
assert.Equal(t, uint(100), decoded.AccountID)
|
|
}
|
|
|
|
func TestWSMessage_WithPerformer(t *testing.T) {
|
|
msg := WSMessage{
|
|
Event: EventConversationUpdated,
|
|
Data: map[string]interface{}{"status": "resolved"},
|
|
Performer: &Performer{
|
|
ID: 1,
|
|
Name: "Agent Smith",
|
|
Type: "user",
|
|
AvatarURL: "https://example.com/avatar.png",
|
|
},
|
|
}
|
|
data, err := json.Marshal(msg)
|
|
assert.NoError(t, err)
|
|
assert.Contains(t, string(data), "performer")
|
|
assert.Contains(t, string(data), "Agent Smith")
|
|
}
|
|
|
|
// === WSCommand struct tests ===
|
|
|
|
func TestWSCommand_MarshalUnmarshal(t *testing.T) {
|
|
cmd := WSCommand{
|
|
Command: "subscribe",
|
|
Data: `{"channel":"AccountChannel","account_id":100}`,
|
|
}
|
|
data, err := json.Marshal(cmd)
|
|
assert.NoError(t, err)
|
|
|
|
var decoded WSCommand
|
|
err = json.Unmarshal(data, &decoded)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "subscribe", decoded.Command)
|
|
}
|
|
|
|
func TestWSCommand_CommandTypes(t *testing.T) {
|
|
commands := []string{"subscribe", "unsubscribe", "ping", "typing_on", "typing_off", "update_presence"}
|
|
for _, cmd := range commands {
|
|
wsCmd := WSCommand{Command: cmd}
|
|
assert.Equal(t, cmd, wsCmd.Command)
|
|
}
|
|
}
|
|
|
|
// === WSClaims struct tests ===
|
|
|
|
func TestWSClaims_UserAuth(t *testing.T) {
|
|
claims := WSClaims{
|
|
UserID: 1,
|
|
AccountID: 100,
|
|
Role: "agent",
|
|
Provider: "email",
|
|
IsContact: false,
|
|
}
|
|
assert.Equal(t, uint(1), claims.UserID)
|
|
assert.Equal(t, uint(100), claims.AccountID)
|
|
assert.Equal(t, "agent", claims.Role)
|
|
assert.False(t, claims.IsContact)
|
|
}
|
|
|
|
func TestWSClaims_ContactAuth(t *testing.T) {
|
|
claims := WSClaims{
|
|
AccountID: 100,
|
|
Role: "contact",
|
|
Provider: "pubsub_token",
|
|
PubsubToken: "abc123",
|
|
IsContact: true,
|
|
ContactID: 50,
|
|
InboxID: 10,
|
|
}
|
|
assert.True(t, claims.IsContact)
|
|
assert.Equal(t, uint(50), claims.ContactID)
|
|
assert.Equal(t, uint(10), claims.InboxID)
|
|
assert.NotEmpty(t, claims.PubsubToken)
|
|
}
|
|
|
|
// === SubscribeData struct tests ===
|
|
|
|
func TestSubscribeData_AccountChannel(t *testing.T) {
|
|
sd := SubscribeData{
|
|
Channel: "AccountChannel",
|
|
AccountID: 100,
|
|
}
|
|
assert.Equal(t, "AccountChannel", sd.Channel)
|
|
assert.Equal(t, uint(100), sd.AccountID)
|
|
}
|
|
|
|
func TestSubscribeData_ConversationChannel(t *testing.T) {
|
|
sd := SubscribeData{
|
|
Channel: "ConversationChannel",
|
|
AccountID: 100,
|
|
ConversationID: 42,
|
|
}
|
|
assert.Equal(t, "ConversationChannel", sd.Channel)
|
|
assert.Equal(t, uint(42), sd.ConversationID)
|
|
}
|
|
|
|
func TestSubscribeData_ContactAuth(t *testing.T) {
|
|
sd := SubscribeData{
|
|
Channel: "ConversationChannel",
|
|
AccountID: 100,
|
|
PubsubToken: "token_abc",
|
|
ConversationID: 42,
|
|
}
|
|
assert.NotEmpty(t, sd.PubsubToken)
|
|
}
|
|
|
|
// === TypingData struct tests ===
|
|
|
|
func TestTypingData(t *testing.T) {
|
|
td := TypingData{
|
|
ConversationID: 42,
|
|
AccountID: 100,
|
|
}
|
|
assert.Equal(t, uint(42), td.ConversationID)
|
|
assert.Equal(t, uint(100), td.AccountID)
|
|
}
|
|
|
|
// === Performer struct tests ===
|
|
|
|
func TestPerformer_UserType(t *testing.T) {
|
|
p := Performer{
|
|
ID: 1,
|
|
Name: "Agent One",
|
|
Type: "user",
|
|
AvatarURL: "https://example.com/avatar1.png",
|
|
}
|
|
assert.Equal(t, "user", p.Type)
|
|
}
|
|
|
|
func TestPerformer_ContactType(t *testing.T) {
|
|
p := Performer{
|
|
ID: 50,
|
|
Name: "Contact Five",
|
|
Type: "contact",
|
|
AvatarURL: "",
|
|
}
|
|
assert.Equal(t, "contact", p.Type)
|
|
} |