Files

531 lines
18 KiB
Go

package provider
import (
"context"
"encoding/json"
"testing"
"github.com/gochat/gochat/internal/channel"
"github.com/gochat/gochat/internal/model"
channelmodel "github.com/gochat/gochat/internal/model/channel"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// ===========================
// EmailProvider tests
// ===========================
func TestEmailProvider_Type_Cov5(t *testing.T) {
p := NewEmailProvider()
assert.Equal(t, channel.ChannelEmail, p.Type())
}
func TestEmailProvider_ConfigSchema_Cov5(t *testing.T) {
p := NewEmailProvider()
schema := p.ConfigSchema()
require.NotNil(t, schema)
assert.Contains(t, schema.Required, "email")
assert.NotEmpty(t, schema.Properties)
}
func TestEmailProvider_ValidateConfig_MissingEmail_Cov5(t *testing.T) {
p := NewEmailProvider()
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{})
require.Error(t, err)
assert.Contains(t, err.Error(), "email is required")
}
func TestEmailProvider_ValidateConfig_BadEmail_Cov5(t *testing.T) {
p := NewEmailProvider()
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{
"email": "not-an-email",
})
require.Error(t, err)
assert.Contains(t, err.Error(), "email format is invalid")
}
func TestEmailProvider_ValidateConfig_IMAPMissingAddress_Cov5(t *testing.T) {
p := NewEmailProvider()
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{
"email": "test@example.com",
"imap_enabled": true,
})
require.Error(t, err)
assert.Contains(t, err.Error(), "imap_address is required")
}
func TestEmailProvider_ValidateConfig_IMAPMissingLogin_Cov5(t *testing.T) {
p := NewEmailProvider()
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{
"email": "test@example.com",
"imap_enabled": true,
"imap_address": "imap.example.com",
})
require.Error(t, err)
assert.Contains(t, err.Error(), "imap_login is required")
}
func TestEmailProvider_ValidateConfig_IMAPMissingPassword_Cov5(t *testing.T) {
p := NewEmailProvider()
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{
"email": "test@example.com",
"imap_enabled": true,
"imap_address": "imap.example.com",
"imap_login": "user",
"imap_password": "",
})
require.Error(t, err)
assert.Contains(t, err.Error(), "imap_password is required")
}
func TestEmailProvider_ValidateConfig_IMAPBadPort_Cov5(t *testing.T) {
p := NewEmailProvider()
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{
"email": "test@example.com",
"imap_enabled": true,
"imap_address": "imap.example.com",
"imap_login": "user",
"imap_password": "pass",
"imap_port": float64(99999),
})
require.Error(t, err)
assert.Contains(t, err.Error(), "imap_port")
}
func TestEmailProvider_ValidateConfig_SMTPMissingAddress_Cov5(t *testing.T) {
p := NewEmailProvider()
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{
"email": "test@example.com",
"smtp_enabled": true,
"imap_enabled": false,
})
require.Error(t, err)
assert.Contains(t, err.Error(), "smtp_address is required")
}
func TestEmailProvider_ValidateConfig_SMTPMissingLogin_Cov5(t *testing.T) {
p := NewEmailProvider()
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{
"email": "test@example.com",
"smtp_enabled": true,
"imap_enabled": false,
"smtp_address": "smtp.example.com",
})
require.Error(t, err)
assert.Contains(t, err.Error(), "smtp_login is required")
}
func TestEmailProvider_ValidateConfig_SMTPMissingPassword_Cov5(t *testing.T) {
p := NewEmailProvider()
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{
"email": "test@example.com",
"smtp_enabled": true,
"imap_enabled": false,
"smtp_address": "smtp.example.com",
"smtp_login": "user",
"smtp_password": "",
})
require.Error(t, err)
assert.Contains(t, err.Error(), "smtp_password is required")
}
func TestEmailProvider_ValidateConfig_SMTPBadPort_Cov5(t *testing.T) {
p := NewEmailProvider()
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{
"email": "test@example.com",
"smtp_enabled": true,
"imap_enabled": false,
"smtp_address": "smtp.example.com",
"smtp_login": "user",
"smtp_password": "pass",
"smtp_port": float64(99999),
})
require.Error(t, err)
assert.Contains(t, err.Error(), "smtp_port")
}
func TestEmailProvider_ValidateConfig_Success_Cov5(t *testing.T) {
p := NewEmailProvider()
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{
"email": "test@example.com",
"imap_enabled": false,
"smtp_enabled": false,
})
assert.NoError(t, err)
}
func TestEmailProvider_DefaultConfig_Cov5(t *testing.T) {
p := NewEmailProvider()
cfg := p.DefaultConfig()
assert.Equal(t, "Support", cfg["mailbox_name"])
assert.Equal(t, true, cfg["imap_enabled"])
assert.Equal(t, 993, cfg["imap_port"])
assert.Equal(t, 587, cfg["smtp_port"])
assert.Equal(t, "ssl", cfg["imap_ssl_mode"])
assert.Equal(t, "starttls", cfg["smtp_ssl_mode"])
}
func TestEmailProvider_Capabilities_Cov5(t *testing.T) {
p := NewEmailProvider()
caps := p.Capabilities()
assert.True(t, caps.SupportsAttachments)
assert.True(t, caps.SupportsReplies)
assert.True(t, caps.SupportsEmailHeaders)
assert.False(t, caps.SupportsLocation)
}
func TestEmailProvider_PollInterval_Cov5(t *testing.T) {
p := NewEmailProvider()
assert.Equal(t, 5*60*1000000000, int(p.PollInterval()))
}
func TestEmailProvider_SetService_Cov5(t *testing.T) {
p := NewEmailProvider()
p.SetService(&mockEmailService_Cov5{})
assert.NotNil(t, p.emailService)
}
func TestEmailProvider_OnCreate_Success_Cov5(t *testing.T) {
p := NewEmailProvider()
cfg, err := p.OnCreate(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, channel.ChannelConfig{
"email": "test@example.com",
})
require.NoError(t, err)
assert.Equal(t, "test@example.com", cfg["email"])
assert.NotEmpty(t, cfg["forward_to_address"])
assert.Equal(t, "example.com", cfg["domain"])
}
func TestEmailProvider_OnCreate_MissingEmail_Cov5(t *testing.T) {
p := NewEmailProvider()
_, err := p.OnCreate(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, channel.ChannelConfig{})
require.Error(t, err)
}
func TestEmailProvider_OnCreate_WithForwardTo_Cov5(t *testing.T) {
p := NewEmailProvider()
cfg, err := p.OnCreate(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, channel.ChannelConfig{
"email": "test@example.com",
"forward_to_address": "custom@fwd.com",
})
require.NoError(t, err)
assert.Equal(t, "custom@fwd.com", cfg["forward_to_address"])
}
func TestEmailProvider_OnDestroy_Cov5(t *testing.T) {
p := NewEmailProvider()
err := p.OnDestroy(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, channel.ChannelConfig{
"email": "test@example.com",
})
assert.NoError(t, err)
}
func TestEmailProvider_ValidateWebhookRequest_Cov5(t *testing.T) {
p := NewEmailProvider()
err := p.ValidateWebhookRequest(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, &channel.WebhookRequest{})
assert.NoError(t, err)
}
func TestEmailProvider_GetContactProfile_Cov5(t *testing.T) {
p := NewEmailProvider()
profile, err := p.GetContactProfile(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, "user@example.com")
require.NoError(t, err)
assert.Equal(t, "user@example.com", profile.Name)
assert.Equal(t, "user@example.com", profile.Extra["email"])
}
func TestEmailProvider_ProcessIncoming_BadJSON_Cov5(t *testing.T) {
p := NewEmailProvider()
_, err := p.ProcessIncoming(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, []byte("bad json"))
require.Error(t, err)
}
func TestEmailProvider_ProcessIncoming_TextEmail_Cov5(t *testing.T) {
p := NewEmailProvider()
emailJSON, _ := json.Marshal(EmailMessage{
MessageID: "msg123",
From: "sender@example.com",
FromName: "Sender",
To: "rcpt@example.com",
TextContent: "Hello world",
Subject: "Test",
})
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"use_reply_to":"false"}`}
msg, err := p.ProcessIncoming(context.Background(), inbox, emailJSON)
require.NoError(t, err)
assert.Equal(t, "Hello world", msg.Content)
assert.Equal(t, "msg123", msg.SourceID)
}
func TestEmailProvider_ProcessIncoming_HTMLEmail_Cov5(t *testing.T) {
p := NewEmailProvider()
emailJSON, _ := json.Marshal(EmailMessage{
MessageID: "msg456",
From: "sender@example.com",
FromName: "Sender",
HTMLContent: "<p>Hello <b>world</b></p>",
Subject: "HTML Test",
})
inbox := &model.Inbox{Base: model.Base{ID: 1}}
msg, err := p.ProcessIncoming(context.Background(), inbox, emailJSON)
require.NoError(t, err)
assert.Contains(t, msg.Content, "Hello")
}
func TestEmailProvider_ProcessIncoming_WithAttachments_Cov5(t *testing.T) {
p := NewEmailProvider()
emailJSON, _ := json.Marshal(EmailMessage{
MessageID: "msg789",
From: "sender@example.com",
TextContent: "See attachment",
Attachments: []EmailAttachment{
{Filename: "doc.pdf", ContentType: "application/pdf", FileSize: 1024},
},
})
inbox := &model.Inbox{Base: model.Base{ID: 1}}
msg, err := p.ProcessIncoming(context.Background(), inbox, emailJSON)
require.NoError(t, err)
assert.Len(t, msg.Attachments, 1)
assert.Equal(t, "doc.pdf", msg.Attachments[0].Filename)
}
func TestEmailProvider_ProcessIncoming_WithReplyTo_Cov5(t *testing.T) {
p := NewEmailProvider()
emailJSON, _ := json.Marshal(EmailMessage{
MessageID: "msg_re",
From: "from@example.com",
ReplyTo: "replyto@example.com",
TextContent: "Reply test",
InReplyTo: "orig_msg_id",
})
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"use_reply_to":"true"}`}
msg, err := p.ProcessIncoming(context.Background(), inbox, emailJSON)
require.NoError(t, err)
assert.Equal(t, "replyto@example.com", msg.SenderID)
assert.Equal(t, "orig_msg_id", msg.ReplyToID)
}
func TestEmailProvider_SendMessage_NoService_Cov5(t *testing.T) {
p := NewEmailProvider()
_, err := p.SendMessage(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, &model.Message{}, &model.Contact{})
require.Error(t, err)
assert.Contains(t, err.Error(), "not initialized")
}
func TestEmailProvider_SendMessage_SMTPDisabled_Cov5(t *testing.T) {
p := NewEmailProvider()
p.SetService(&mockEmailService_Cov5{})
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"smtp_enabled":false}`}
_, err := p.SendMessage(context.Background(), inbox, &model.Message{}, &model.Contact{})
require.Error(t, err)
assert.Contains(t, err.Error(), "SMTP is not enabled")
}
func TestEmailProvider_SendMessage_NoSMTPAddress_Cov5(t *testing.T) {
p := NewEmailProvider()
p.SetService(&mockEmailService_Cov5{})
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"smtp_enabled":true}`}
_, err := p.SendMessage(context.Background(), inbox, &model.Message{}, &model.Contact{})
require.Error(t, err)
assert.Contains(t, err.Error(), "smtp_address")
}
func TestEmailProvider_SendMessage_NoContactEmail_Cov5(t *testing.T) {
p := NewEmailProvider()
p.SetService(&mockEmailService_Cov5{})
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"smtp_enabled":true,"smtp_address":"smtp.test.com","email":"from@test.com"}`}
_, err := p.SendMessage(context.Background(), inbox, &model.Message{}, &model.Contact{Identifier: ""})
require.Error(t, err)
assert.Contains(t, err.Error(), "no email address")
}
func TestEmailProvider_SendMessage_Success_Cov5(t *testing.T) {
p := NewEmailProvider()
p.SetService(&mockEmailService_Cov5{})
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"smtp_enabled":true,"smtp_address":"smtp.test.com","email":"from@test.com"}`}
result, err := p.SendMessage(context.Background(), inbox, &model.Message{Content: "test msg"}, &model.Contact{Identifier: "rcpt@test.com"})
require.NoError(t, err)
assert.Equal(t, "mock_msg_id", result.ExternalID)
}
func TestEmailProvider_PollMessages_NoService_Cov5(t *testing.T) {
p := NewEmailProvider()
msgs, err := p.PollMessages(context.Background(), &model.Inbox{Base: model.Base{ID: 1}})
require.NoError(t, err)
assert.Nil(t, msgs)
}
func TestEmailProvider_PollMessages_IMAPDisabled_Cov5(t *testing.T) {
p := NewEmailProvider()
p.SetService(&mockEmailService_Cov5{})
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"imap_enabled":false}`}
msgs, err := p.PollMessages(context.Background(), inbox)
require.NoError(t, err)
assert.Nil(t, msgs)
}
func TestEmailProvider_PollMessages_IncompleteConfig_Cov5(t *testing.T) {
p := NewEmailProvider()
p.SetService(&mockEmailService_Cov5{})
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"imap_enabled":true}`}
msgs, err := p.PollMessages(context.Background(), inbox)
require.NoError(t, err)
assert.Nil(t, msgs)
}
func TestEmailProvider_PollMessages_Success_Cov5(t *testing.T) {
p := NewEmailProvider()
p.SetService(&mockEmailService_Cov5{})
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"imap_enabled":true,"imap_address":"imap.test.com","imap_login":"user","imap_password":"pass"}`}
msgs, err := p.PollMessages(context.Background(), inbox)
require.NoError(t, err)
assert.Len(t, msgs, 1)
}
func TestEmailProvider_PollMessages_BadConfig_Cov5(t *testing.T) {
p := NewEmailProvider()
p.SetService(&mockEmailService_Cov5{})
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: "bad json"}
msgs, err := p.PollMessages(context.Background(), inbox)
require.NoError(t, err)
assert.Nil(t, msgs)
}
func TestStripHTMLTags_Cov5(t *testing.T) {
result := stripHTMLTags("<p>Hello <b>world</b></p>")
assert.Contains(t, result, "Hello")
assert.Contains(t, result, "world")
assert.NotContains(t, result, "<")
}
func TestStripHTMLTags_Entities_Cov5(t *testing.T) {
result := stripHTMLTags("&nbsp; &amp; &lt; &gt; &#39; &quot;")
assert.Contains(t, result, " ")
assert.Contains(t, result, "&")
}
func TestBuildEmailSubject_Cov5(t *testing.T) {
result := buildEmailSubject(nil, &model.Message{Content: "short msg"}, channel.ChannelConfig{
"mailbox_name": "Support",
})
assert.Contains(t, result, "[Support]")
assert.Contains(t, result, "short msg")
}
func TestBuildEmailSubject_LongContent_Cov5(t *testing.T) {
longContent := "This is a very long message that exceeds the fifty character limit for sure"
result := buildEmailSubject(nil, &model.Message{Content: longContent}, channel.ChannelConfig{})
assert.Contains(t, result, "...")
}
func TestBuildEmailSubject_DefaultMailbox_Cov5(t *testing.T) {
result := buildEmailSubject(nil, &model.Message{Content: "msg"}, channel.ChannelConfig{})
assert.Contains(t, result, "[Support]")
}
func TestInboxConfigMap_Empty_Cov5(t *testing.T) {
cfg, err := inboxConfigMap(&model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: ""})
require.NoError(t, err)
assert.Empty(t, cfg)
}
func TestInboxConfigMap_BadJSON_Cov5(t *testing.T) {
_, err := inboxConfigMap(&model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: "bad json"})
require.Error(t, err)
}
func TestInboxConfigMap_Success_Cov5(t *testing.T) {
cfg, err := inboxConfigMap(&model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"key":"value","num":42.0}`})
require.NoError(t, err)
assert.Equal(t, "value", cfg["key"])
}
func TestInboxConfigValue_Cov5(t *testing.T) {
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"str":"hello","b":true,"n":42.0}`}
assert.Equal(t, "hello", inboxConfigValue(inbox, "str"))
assert.Equal(t, "true", inboxConfigValue(inbox, "b"))
assert.Equal(t, "42", inboxConfigValue(inbox, "n"))
assert.Equal(t, "", inboxConfigValue(inbox, "missing"))
}
func TestInboxConfigValue_BadJSON_Cov5(t *testing.T) {
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: "bad"}
assert.Equal(t, "", inboxConfigValue(inbox, "key"))
}
// ===========================
// ChannelRegistry tests
// ===========================
func TestChannelRegistry_Cov5(t *testing.T) {
r := NewChannelRegistry()
assert.NotNil(t, r)
assert.Empty(t, r.List())
}
func TestChannelRegistry_RegisterGet_Cov5(t *testing.T) {
r := NewChannelRegistry()
r.Register(&mockChannelProvider_Cov5{name: "test"})
p := r.Get("test")
require.NotNil(t, p)
assert.Equal(t, "test", p.Name())
}
func TestChannelRegistry_GetNotFound_Cov5(t *testing.T) {
r := NewChannelRegistry()
assert.Nil(t, r.Get("nonexistent"))
}
func TestChannelRegistry_List_Cov5(t *testing.T) {
r := NewChannelRegistry()
r.Register(&mockChannelProvider_Cov5{name: "a"})
r.Register(&mockChannelProvider_Cov5{name: "b"})
names := r.List()
assert.Len(t, names, 2)
}
// ===========================
// Mocks
// ===========================
type mockEmailService_Cov5 struct{}
func (m *mockEmailService_Cov5) ValidateIMAPConnection(config channel.ChannelConfig) error {
return nil
}
func (m *mockEmailService_Cov5) ValidateSMTPConnection(config channel.ChannelConfig) error {
return nil
}
func (m *mockEmailService_Cov5) FetchIMAPMessages(ctx context.Context, inbox *model.Inbox, config channel.ChannelConfig) ([]*channel.IncomingMessage, error) {
return []*channel.IncomingMessage{{SourceID: "test"}}, nil
}
func (m *mockEmailService_Cov5) SendViaSMTP(config channel.ChannelConfig, from, to, subject, body string) (string, error) {
return "mock_msg_id", nil
}
type mockChannelProvider_Cov5 struct {
name string
}
func (m *mockChannelProvider_Cov5) Name() string { return m.name }
func (m *mockChannelProvider_Cov5) CreateChannel(ctx context.Context, accountID uint, params map[string]interface{}) (channelmodel.Channelable, error) {
return nil, nil
}
func (m *mockChannelProvider_Cov5) UpdateChannel(ctx context.Context, channelID uint, params map[string]interface{}) (channelmodel.Channelable, error) {
return nil, nil
}
func (m *mockChannelProvider_Cov5) DeleteChannel(ctx context.Context, channelID uint) error {
return nil
}
func (m *mockChannelProvider_Cov5) HandleWebhook(ctx context.Context, payload map[string]interface{}) error {
return nil
}
func (m *mockChannelProvider_Cov5) ProcessIncomingMessage(ctx context.Context, inboxID uint, contactID uint, payload map[string]interface{}) (*IncomingMessageResult, error) {
return &IncomingMessageResult{}, nil
}
func (m *mockChannelProvider_Cov5) ProcessOutgoingMessage(ctx context.Context, conversationID uint, messageID uint, content string) error {
return nil
}
func (m *mockChannelProvider_Cov5) ValidateConfig(params map[string]interface{}) error { return nil }