123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- // Copyright 2023 The Gitea Authors. All rights reserved.
- // SPDX-License-Identifier: MIT
-
- package integration
-
- import (
- "io"
- "net"
- "net/smtp"
- "strings"
- "testing"
- "time"
-
- "code.gitea.io/gitea/models/db"
- issues_model "code.gitea.io/gitea/models/issues"
- "code.gitea.io/gitea/models/unittest"
- user_model "code.gitea.io/gitea/models/user"
- "code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/services/mailer/incoming"
- incoming_payload "code.gitea.io/gitea/services/mailer/incoming/payload"
- token_service "code.gitea.io/gitea/services/mailer/token"
- "code.gitea.io/gitea/tests"
-
- "github.com/stretchr/testify/assert"
- "gopkg.in/gomail.v2"
- )
-
- func TestIncomingEmail(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
-
- user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
- issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
-
- t.Run("Payload", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 1})
-
- _, err := incoming_payload.CreateReferencePayload(user)
- assert.Error(t, err)
-
- issuePayload, err := incoming_payload.CreateReferencePayload(issue)
- assert.NoError(t, err)
- commentPayload, err := incoming_payload.CreateReferencePayload(comment)
- assert.NoError(t, err)
-
- _, err = incoming_payload.GetReferenceFromPayload(db.DefaultContext, []byte{1, 2, 3})
- assert.Error(t, err)
-
- ref, err := incoming_payload.GetReferenceFromPayload(db.DefaultContext, issuePayload)
- assert.NoError(t, err)
- assert.IsType(t, ref, new(issues_model.Issue))
- assert.EqualValues(t, issue.ID, ref.(*issues_model.Issue).ID)
-
- ref, err = incoming_payload.GetReferenceFromPayload(db.DefaultContext, commentPayload)
- assert.NoError(t, err)
- assert.IsType(t, ref, new(issues_model.Comment))
- assert.EqualValues(t, comment.ID, ref.(*issues_model.Comment).ID)
- })
-
- t.Run("Token", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- payload := []byte{1, 2, 3, 4, 5}
-
- token, err := token_service.CreateToken(token_service.ReplyHandlerType, user, payload)
- assert.NoError(t, err)
- assert.NotEmpty(t, token)
-
- ht, u, p, err := token_service.ExtractToken(db.DefaultContext, token)
- assert.NoError(t, err)
- assert.Equal(t, token_service.ReplyHandlerType, ht)
- assert.Equal(t, user.ID, u.ID)
- assert.Equal(t, payload, p)
- })
-
- t.Run("Handler", func(t *testing.T) {
- t.Run("Reply", func(t *testing.T) {
- t.Run("Comment", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- handler := &incoming.ReplyHandler{}
-
- payload, err := incoming_payload.CreateReferencePayload(issue)
- assert.NoError(t, err)
-
- assert.Error(t, handler.Handle(db.DefaultContext, &incoming.MailContent{}, nil, payload))
- assert.NoError(t, handler.Handle(db.DefaultContext, &incoming.MailContent{}, user, payload))
-
- content := &incoming.MailContent{
- Content: "reply by mail",
- Attachments: []*incoming.Attachment{
- {
- Name: "attachment.txt",
- Content: []byte("test"),
- },
- },
- }
-
- assert.NoError(t, handler.Handle(db.DefaultContext, content, user, payload))
-
- comments, err := issues_model.FindComments(db.DefaultContext, &issues_model.FindCommentsOptions{
- IssueID: issue.ID,
- Type: issues_model.CommentTypeComment,
- })
- assert.NoError(t, err)
- assert.NotEmpty(t, comments)
- comment := comments[len(comments)-1]
- assert.Equal(t, user.ID, comment.PosterID)
- assert.Equal(t, content.Content, comment.Content)
- assert.NoError(t, comment.LoadAttachments(db.DefaultContext))
- assert.Len(t, comment.Attachments, 1)
- attachment := comment.Attachments[0]
- assert.Equal(t, content.Attachments[0].Name, attachment.Name)
- assert.EqualValues(t, 4, attachment.Size)
- })
-
- t.Run("CodeComment", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 6})
- issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
-
- handler := &incoming.ReplyHandler{}
- content := &incoming.MailContent{
- Content: "code reply by mail",
- Attachments: []*incoming.Attachment{
- {
- Name: "attachment.txt",
- Content: []byte("test"),
- },
- },
- }
-
- payload, err := incoming_payload.CreateReferencePayload(comment)
- assert.NoError(t, err)
-
- assert.NoError(t, handler.Handle(db.DefaultContext, content, user, payload))
-
- comments, err := issues_model.FindComments(db.DefaultContext, &issues_model.FindCommentsOptions{
- IssueID: issue.ID,
- Type: issues_model.CommentTypeCode,
- })
- assert.NoError(t, err)
- assert.NotEmpty(t, comments)
- comment = comments[len(comments)-1]
- assert.Equal(t, user.ID, comment.PosterID)
- assert.Equal(t, content.Content, comment.Content)
- assert.NoError(t, comment.LoadAttachments(db.DefaultContext))
- assert.Empty(t, comment.Attachments)
- })
- })
-
- t.Run("Unsubscribe", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- watching, err := issues_model.CheckIssueWatch(db.DefaultContext, user, issue)
- assert.NoError(t, err)
- assert.True(t, watching)
-
- handler := &incoming.UnsubscribeHandler{}
-
- content := &incoming.MailContent{
- Content: "unsub me",
- }
-
- payload, err := incoming_payload.CreateReferencePayload(issue)
- assert.NoError(t, err)
-
- assert.NoError(t, handler.Handle(db.DefaultContext, content, user, payload))
-
- watching, err = issues_model.CheckIssueWatch(db.DefaultContext, user, issue)
- assert.NoError(t, err)
- assert.False(t, watching)
- })
- })
-
- if setting.IncomingEmail.Enabled {
- // This test connects to the configured email server and is currently only enabled for MySql integration tests.
- // It sends a reply to create a comment. If the comment is not detected after 10 seconds the test fails.
- t.Run("IMAP", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- payload, err := incoming_payload.CreateReferencePayload(issue)
- assert.NoError(t, err)
- token, err := token_service.CreateToken(token_service.ReplyHandlerType, user, payload)
- assert.NoError(t, err)
-
- msg := gomail.NewMessage()
- msg.SetHeader("To", strings.Replace(setting.IncomingEmail.ReplyToAddress, setting.IncomingEmail.TokenPlaceholder, token, 1))
- msg.SetHeader("From", user.Email)
- msg.SetBody("text/plain", token)
- err = gomail.Send(&smtpTestSender{}, msg)
- assert.NoError(t, err)
-
- assert.Eventually(t, func() bool {
- comments, err := issues_model.FindComments(db.DefaultContext, &issues_model.FindCommentsOptions{
- IssueID: issue.ID,
- Type: issues_model.CommentTypeComment,
- })
- assert.NoError(t, err)
- assert.NotEmpty(t, comments)
-
- comment := comments[len(comments)-1]
-
- return comment.PosterID == user.ID && comment.Content == token
- }, 10*time.Second, 1*time.Second)
- })
- }
- }
-
- // A simple SMTP mail sender used for integration tests.
- type smtpTestSender struct{}
-
- func (s *smtpTestSender) Send(from string, to []string, msg io.WriterTo) error {
- conn, err := net.Dial("tcp", net.JoinHostPort(setting.IncomingEmail.Host, "25"))
- if err != nil {
- return err
- }
- defer conn.Close()
-
- client, err := smtp.NewClient(conn, setting.IncomingEmail.Host)
- if err != nil {
- return err
- }
-
- if err = client.Mail(from); err != nil {
- return err
- }
-
- for _, rec := range to {
- if err = client.Rcpt(rec); err != nil {
- return err
- }
- }
-
- w, err := client.Data()
- if err != nil {
- return err
- }
- if _, err := msg.WriteTo(w); err != nil {
- return err
- }
- if err := w.Close(); err != nil {
- return err
- }
-
- return client.Quit()
- }
|