package email import ( "context" "encoding/json" "net/http" "net/http/httptest" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" channelpkg "github.com/gochat/gochat/internal/channel" "github.com/gochat/gochat/internal/model" ) func TestNewWebhookHandler_Cov4(t *testing.T) { h := NewWebhookHandler() assert.NotNil(t, h) } func TestWebhookHandler_HandleWebhookRequest_EmptyBody_Cov4(t *testing.T) { h := NewWebhookHandler() w := httptest.NewRecorder() r := httptest.NewRequest("POST", "/webhook", nil) h.HandleWebhookRequest(w, r) assert.Equal(t, http.StatusBadRequest, w.Code) } func TestWebhookHandler_HandleWebhookRequest_ReadError_Cov4(t *testing.T) { h := NewWebhookHandler() w := httptest.NewRecorder() r := httptest.NewRequest("POST", "/webhook", &errReaderCov4{}) h.HandleWebhookRequest(w, r) assert.Equal(t, http.StatusInternalServerError, w.Code) } func TestWebhookHandler_HandleWebhookRequest_ValidMailgun_Cov4(t *testing.T) { h := NewWebhookHandler() w := httptest.NewRecorder() body := `{"from":"sender@example.com","subject":"Test","body-plain":"Hello","to":"recipient@example.com","Message-Id":"msg-1"}` r := httptest.NewRequest("POST", "/webhook", strings.NewReader(body)) r.Header.Set("X-Mailgun-Sid", "12345") r.Header.Set("Content-Type", "application/json") h.HandleWebhookRequest(w, r) assert.Equal(t, http.StatusOK, w.Code) assert.Contains(t, w.Body.String(), "accepted") } func TestWebhookHandler_HandleWebhookRequest_ValidSendGrid_Cov4(t *testing.T) { h := NewWebhookHandler() w := httptest.NewRecorder() body := `{"envelope":{"from":"sender@example.com","to":["recipient@example.com"]},"subject":"Test","text":"Hello","html":"
Hello
","messageId":"msg-2"}` r := httptest.NewRequest("POST", "/webhook", strings.NewReader(body)) r.Header.Set("X-Sg-Envelope-Id", "env-123") r.Header.Set("Content-Type", "application/json") h.HandleWebhookRequest(w, r) assert.Equal(t, http.StatusOK, w.Code) } func TestWebhookHandler_HandleWebhookRequest_GenericJSON_Cov4(t *testing.T) { h := NewWebhookHandler() w := httptest.NewRecorder() body := `{"from":"sender@example.com","subject":"Test","text":"Hello","to":"recipient@example.com","message_id":"msg-3"}` r := httptest.NewRequest("POST", "/webhook", strings.NewReader(body)) r.Header.Set("Content-Type", "application/json") h.HandleWebhookRequest(w, r) assert.Equal(t, http.StatusOK, w.Code) } func TestWebhookHandler_HandleWebhookRequest_RawEmail_Cov4(t *testing.T) { h := NewWebhookHandler() w := httptest.NewRecorder() body := "From: sender@example.com\r\nSubject: Test\r\n\r\nHello world" r := httptest.NewRequest("POST", "/webhook", strings.NewReader(body)) h.HandleWebhookRequest(w, r) assert.Equal(t, http.StatusOK, w.Code) } func TestWebhookHandler_HandleWebhookRequest_InvalidMailgun_Cov4(t *testing.T) { h := NewWebhookHandler() w := httptest.NewRecorder() body := "invalid json" r := httptest.NewRequest("POST", "/webhook", strings.NewReader(body)) r.Header.Set("X-Mailgun-Sid", "12345") h.HandleWebhookRequest(w, r) // Should still return 200 to prevent retries assert.Equal(t, http.StatusOK, w.Code) } func TestWebhookHandler_ParseWebhookBody_Cov4(t *testing.T) { h := NewWebhookHandler() t.Run("mailgun", func(t *testing.T) { body := `{"from":"sender@example.com","subject":"Test","body-plain":"Hello","to":"recipient@example.com","Message-Id":"msg-1"}` headers := http.Header{} headers.Set("X-Mailgun-Sid", "12345") msg, err := h.ParseWebhookBody([]byte(body), headers) require.NoError(t, err) assert.Equal(t, "sender@example.com", msg.FromAddress) assert.Equal(t, "Test", msg.Subject) }) t.Run("sendgrid", func(t *testing.T) { body := `{"envelope":{"from":"sender@example.com","to":["recipient@example.com"]},"subject":"Test","text":"Hello"}` headers := http.Header{} headers.Set("X-Sg-Envelope-Id", "env-123") msg, err := h.ParseWebhookBody([]byte(body), headers) require.NoError(t, err) assert.Equal(t, "sender@example.com", msg.FromAddress) assert.Equal(t, "Test", msg.Subject) }) t.Run("generic json", func(t *testing.T) { body := `{"from":"sender@example.com","subject":"Test","text":"Hello","to":"recipient@example.com"}` headers := http.Header{} headers.Set("Content-Type", "application/json") msg, err := h.ParseWebhookBody([]byte(body), headers) require.NoError(t, err) assert.Equal(t, "sender@example.com", msg.FromAddress) }) t.Run("raw email", func(t *testing.T) { body := "From: sender@example.com\r\nSubject: Test\r\n\r\nHello" msg, err := h.ParseWebhookBody([]byte(body), http.Header{}) require.NoError(t, err) assert.NotEmpty(t, msg.TextContent) }) } func TestIsMailgunPayload_Cov4(t *testing.T) { headers := http.Header{} assert.False(t, isMailgunPayload(headers)) headers.Set("X-Mailgun-Sid", "12345") assert.True(t, isMailgunPayload(headers)) } func TestIsSendGridPayload_Cov4(t *testing.T) { headers := http.Header{} assert.False(t, isSendGridPayload(headers)) headers.Set("X-Sg-Envelope-Id", "env-123") assert.True(t, isSendGridPayload(headers)) } func TestParseMailgunPayload_Cov4(t *testing.T) { t.Run("valid", func(t *testing.T) { body := `{"from":"sender@example.com","subject":"Test","body-plain":"Hello","to":"recipient@example.com","Message-Id":"msg-1","In-Reply-To":"parent","References":"Hello
"}` msg, err := parseMailgunPayload([]byte(body)) require.NoError(t, err) assert.Equal(t, "sender@example.com", msg.FromAddress) assert.Equal(t, "Test", msg.Subject) assert.Equal(t, "Hello", msg.TextContent) assert.Equal(t, "Hello
", msg.HTMLContent) assert.Equal(t, "msg-1", msg.MessageID) }) t.Run("invalid json", func(t *testing.T) { _, err := parseMailgunPayload([]byte("invalid")) assert.Error(t, err) }) } func TestParseSendGridPayload_Cov4(t *testing.T) { t.Run("valid", func(t *testing.T) { body := `{"envelope":{"from":"sender@example.com","to":["recipient@example.com"]},"subject":"Test","text":"Hello","html":"Hello
","messageId":"msg-2","in_reply_to":"parent","date":"2024-01-01"}` msg, err := parseSendGridPayload([]byte(body)) require.NoError(t, err) assert.Equal(t, "sender@example.com", msg.FromAddress) assert.Equal(t, "Test", msg.Subject) assert.Equal(t, "Hello", msg.TextContent) assert.Equal(t, "Hello
", msg.HTMLContent) assert.Equal(t, "msg-2", msg.MessageID) assert.Equal(t, "parent", msg.InReplyTo) }) t.Run("invalid json", func(t *testing.T) { _, err := parseSendGridPayload([]byte("invalid")) assert.Error(t, err) }) } func TestParseGenericJSONPayload_Cov4(t *testing.T) { t.Run("valid", func(t *testing.T) { data := map[string]interface{}{ "from": "sender@example.com", "subject": "Test", "text": "Hello", "html": "Hello
", "message_id": "msg-3", "in_reply_to": "parent", "date": "2024-01-01", "to": "recipient@example.com", } msg, err := parseGenericJSONPayload(data) require.NoError(t, err) assert.Equal(t, "sender@example.com", msg.FromAddress) assert.Equal(t, "Test", msg.Subject) assert.Equal(t, "Hello", msg.TextContent) assert.Equal(t, "Hello
", msg.HTMLContent) assert.Equal(t, "msg-3", msg.MessageID) assert.Equal(t, "parent", msg.InReplyTo) assert.Equal(t, []string{"recipient@example.com"}, msg.ToAddresses) }) } func TestParseRawEmail_Cov4(t *testing.T) { body := "From: sender@example.com\r\nSubject: Test\r\n\r\nHello world" msg, err := parseRawEmail([]byte(body)) require.NoError(t, err) assert.NotEmpty(t, msg.TextContent) assert.Contains(t, msg.TextContent, "Hello world") } func TestEmailProvider_SendMessage_WithSMTPConfig_Cov4(t *testing.T) { provider := NewEmailProvider(NewService(), &Repository{}, NewIncomingProcessor(nil)) ctx := context.Background() inbox := &model.Inbox{ Base: model.Base{ID: 1}, AccountID: 1, ChannelConfig: `{"smtp_email":"support@example.com","smtp_address":"smtp.example.com","smtp_port":587,"smtp_password":"pass","imap_address":"imap.example.com","imap_port":993,"imap_email":"support@example.com","imap_password":"pass"}`, } contact := &model.Contact{SourceID: "recipient@example.com"} msg := &model.Message{Content: "test"} // This will try to connect to smtp.example.com — should fail with network error _, err := provider.SendMessage(ctx, inbox, msg, contact) assert.Error(t, err) } func TestEmailProvider_PollInterval_Cov4(t *testing.T) { provider := NewEmailProvider(NewService(), &Repository{}, NewIncomingProcessor(nil)) interval := provider.PollInterval() assert.NotZero(t, interval) } func TestEmailProvider_PollMessages_Cov4(t *testing.T) { provider := NewEmailProvider(NewService(), &Repository{}, NewIncomingProcessor(nil)) inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 1} // With empty config, should fail _, err := provider.PollMessages(context.Background(), inbox) assert.Error(t, err) } func TestEmailMessage_JSON_Cov4(t *testing.T) { msg := EmailMessage{ MessageID: "msg-1", FromAddress: "sender@example.com", Subject: "Test", TextContent: "Hello", } data, err := json.Marshal(msg) require.NoError(t, err) assert.Contains(t, string(data), "msg-1") var decoded EmailMessage err = json.Unmarshal(data, &decoded) require.NoError(t, err) assert.Equal(t, msg.MessageID, decoded.MessageID) } func TestEmailAttachment_JSON_Cov4(t *testing.T) { att := EmailAttachment{ Filename: "doc.pdf", ContentType: "application/pdf", FileSize: 1024, } data, err := json.Marshal(att) require.NoError(t, err) assert.Contains(t, string(data), "doc.pdf") var decoded EmailAttachment err = json.Unmarshal(data, &decoded) require.NoError(t, err) assert.Equal(t, att.Filename, decoded.Filename) } // errReaderCov4 is a reader that always returns an error type errReaderCov4 struct{} func (e *errReaderCov4) Read(p []byte) (n int, err error) { return 0, assertErrorCov4("read error") } type errStringCov4 string func (e errStringCov4) Error() string { return string(e) } func assertErrorCov4(msg string) error { return errStringCov4(msg) } func jsonMarshal(v interface{}) ([]byte, error) { return json.Marshal(v) } func TestChannelpkgConstant_Cov4(t *testing.T) { // Ensure channelpkg import is used assert.Equal(t, "email", string(channelpkg.ChannelEmail)) }