2019-07-17 15:02:42 -04:00
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
2019-09-24 13:02:49 +08:00
package mailer
2019-07-17 15:02:42 -04:00
import (
2019-11-07 10:34:28 -03:00
"bytes"
2022-03-22 23:22:54 +08:00
"context"
2022-02-03 23:01:16 +00:00
"fmt"
2019-07-17 15:02:42 -04:00
"html/template"
2022-02-03 23:01:16 +00:00
"strings"
2019-07-17 15:02:42 -04:00
"testing"
2019-11-07 10:34:28 -03:00
texttmpl "text/template"
2019-07-17 15:02:42 -04:00
2019-09-24 13:02:49 +08:00
"code.gitea.io/gitea/models"
2022-04-08 17:11:15 +08:00
"code.gitea.io/gitea/models/db"
2022-06-13 17:37:59 +08:00
issues_model "code.gitea.io/gitea/models/issues"
2021-12-10 09:27:50 +08:00
repo_model "code.gitea.io/gitea/models/repo"
2021-11-12 22:36:47 +08:00
"code.gitea.io/gitea/models/unittest"
2021-11-24 17:49:20 +08:00
user_model "code.gitea.io/gitea/models/user"
2019-07-17 15:02:42 -04:00
"code.gitea.io/gitea/modules/setting"
2022-02-06 07:44:30 -08:00
2019-07-17 15:02:42 -04:00
"github.com/stretchr/testify/assert"
)
2019-11-07 10:34:28 -03:00
const subjectTpl = `
{ { . SubjectPrefix } } [ { { . Repo } } ] @ { { . Doer . Name } } # { { . Issue . Index } } - { { . Issue . Title } }
`
const bodyTpl = `
2019-07-17 15:02:42 -04:00
< ! DOCTYPE html >
< html >
< head >
< meta http - equiv = "Content-Type" content = "text/html; charset=utf-8" / >
< title > { { . Subject } } < / title >
< / head >
< body >
< p > { { . Body } } < / p >
< p >
-- -
< br >
< a href = "{{.Link}}" > View it on Gitea < / a > .
< / p >
< / body >
< / html >
`
2022-06-13 17:37:59 +08:00
func prepareMailerTest ( t * testing . T ) ( doer * user_model . User , repo * repo_model . Repository , issue * issues_model . Issue , comment * issues_model . Comment ) {
2021-11-12 22:36:47 +08:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2022-01-20 18:46:10 +01:00
mailService := setting . Mailer {
2019-09-24 13:02:49 +08:00
From : "test@gitea.com" ,
}
2019-07-17 15:02:42 -04:00
2019-09-24 13:02:49 +08:00
setting . MailService = & mailService
setting . Domain = "localhost"
2019-07-17 15:02:42 -04:00
2021-11-24 17:49:20 +08:00
doer = unittest . AssertExistsAndLoadBean ( t , & user_model . User { ID : 2 } ) . ( * user_model . User )
2021-12-10 09:27:50 +08:00
repo = unittest . AssertExistsAndLoadBean ( t , & repo_model . Repository { ID : 1 , Owner : doer } ) . ( * repo_model . Repository )
2022-06-13 17:37:59 +08:00
issue = unittest . AssertExistsAndLoadBean ( t , & issues_model . Issue { ID : 1 , Repo : repo , Poster : doer } ) . ( * issues_model . Issue )
2022-04-08 17:11:15 +08:00
assert . NoError ( t , issue . LoadRepo ( db . DefaultContext ) )
2022-06-13 17:37:59 +08:00
comment = unittest . AssertExistsAndLoadBean ( t , & issues_model . Comment { ID : 2 , Issue : issue } ) . ( * issues_model . Comment )
2022-06-20 12:02:49 +02:00
return doer , repo , issue , comment
2021-05-22 08:47:16 +02:00
}
func TestComposeIssueCommentMessage ( t * testing . T ) {
doer , _ , issue , comment := prepareMailerTest ( t )
2019-07-17 15:02:42 -04:00
2019-11-07 10:34:28 -03:00
stpl := texttmpl . Must ( texttmpl . New ( "issue/comment" ) . Parse ( subjectTpl ) )
btpl := template . Must ( template . New ( "issue/comment" ) . Parse ( bodyTpl ) )
InitMailRender ( stpl , btpl )
2019-07-17 15:02:42 -04:00
2021-11-24 17:49:20 +08:00
recipients := [ ] * user_model . User { { Name : "Test" , Email : "test@gitea.com" } , { Name : "Test2" , Email : "test2@gitea.com" } }
2022-01-20 18:46:10 +01:00
msgs , err := composeIssueCommentMessages ( & mailCommentContext {
2022-03-22 23:22:54 +08:00
Context : context . TODO ( ) , // TODO: use a correct context
Issue : issue , Doer : doer , ActionType : models . ActionCommentIssue ,
2022-01-20 18:46:10 +01:00
Content : "test body" , Comment : comment ,
} , "en-US" , recipients , false , "issue comment" )
2021-04-20 06:25:08 +08:00
assert . NoError ( t , err )
2019-11-18 05:08:20 -03:00
assert . Len ( t , msgs , 2 )
2020-01-16 17:55:36 +00:00
gomailMsg := msgs [ 0 ] . ToMessage ( )
mailto := gomailMsg . GetHeader ( "To" )
subject := gomailMsg . GetHeader ( "Subject" )
2021-10-01 17:24:43 +02:00
messageID := gomailMsg . GetHeader ( "Message-ID" )
inReplyTo := gomailMsg . GetHeader ( "In-Reply-To" )
2020-01-16 17:55:36 +00:00
references := gomailMsg . GetHeader ( "References" )
2019-07-17 15:02:42 -04:00
2019-11-18 05:08:20 -03:00
assert . Len ( t , mailto , 1 , "exactly one recipient is expected in the To field" )
2019-11-07 10:34:28 -03:00
assert . Equal ( t , "Re: " , subject [ 0 ] [ : 4 ] , "Comment reply subject should contain Re:" )
assert . Equal ( t , "Re: [user2/repo1] @user2 #1 - issue1" , subject [ 0 ] )
2021-10-01 17:24:43 +02:00
assert . Equal ( t , "<user2/repo1/issues/1@localhost>" , inReplyTo [ 0 ] , "In-Reply-To header doesn't match" )
assert . Equal ( t , "<user2/repo1/issues/1@localhost>" , references [ 0 ] , "References header doesn't match" )
assert . Equal ( t , "<user2/repo1/issues/1/comment/2@localhost>" , messageID [ 0 ] , "Message-ID header doesn't match" )
2019-07-17 15:02:42 -04:00
}
func TestComposeIssueMessage ( t * testing . T ) {
2021-05-22 08:47:16 +02:00
doer , _ , issue , _ := prepareMailerTest ( t )
2019-07-17 15:02:42 -04:00
2019-11-07 10:34:28 -03:00
stpl := texttmpl . Must ( texttmpl . New ( "issue/new" ) . Parse ( subjectTpl ) )
btpl := template . Must ( template . New ( "issue/new" ) . Parse ( bodyTpl ) )
InitMailRender ( stpl , btpl )
2019-07-17 15:02:42 -04:00
2021-11-24 17:49:20 +08:00
recipients := [ ] * user_model . User { { Name : "Test" , Email : "test@gitea.com" } , { Name : "Test2" , Email : "test2@gitea.com" } }
2022-01-20 18:46:10 +01:00
msgs , err := composeIssueCommentMessages ( & mailCommentContext {
2022-03-22 23:22:54 +08:00
Context : context . TODO ( ) , // TODO: use a correct context
Issue : issue , Doer : doer , ActionType : models . ActionCreateIssue ,
2022-01-20 18:46:10 +01:00
Content : "test body" ,
} , "en-US" , recipients , false , "issue create" )
2021-04-20 06:25:08 +08:00
assert . NoError ( t , err )
2019-11-18 05:08:20 -03:00
assert . Len ( t , msgs , 2 )
2019-07-17 15:02:42 -04:00
2020-01-16 17:55:36 +00:00
gomailMsg := msgs [ 0 ] . ToMessage ( )
mailto := gomailMsg . GetHeader ( "To" )
subject := gomailMsg . GetHeader ( "Subject" )
messageID := gomailMsg . GetHeader ( "Message-ID" )
2021-10-01 17:24:43 +02:00
inReplyTo := gomailMsg . GetHeader ( "In-Reply-To" )
references := gomailMsg . GetHeader ( "References" )
2019-07-17 15:02:42 -04:00
2019-11-18 05:08:20 -03:00
assert . Len ( t , mailto , 1 , "exactly one recipient is expected in the To field" )
2019-11-07 10:34:28 -03:00
assert . Equal ( t , "[user2/repo1] @user2 #1 - issue1" , subject [ 0 ] )
2021-10-01 17:24:43 +02:00
assert . Equal ( t , "<user2/repo1/issues/1@localhost>" , inReplyTo [ 0 ] , "In-Reply-To header doesn't match" )
assert . Equal ( t , "<user2/repo1/issues/1@localhost>" , references [ 0 ] , "References header doesn't match" )
assert . Equal ( t , "<user2/repo1/issues/1@localhost>" , messageID [ 0 ] , "Message-ID header doesn't match" )
2019-07-17 15:02:42 -04:00
}
2019-11-07 10:34:28 -03:00
func TestTemplateSelection ( t * testing . T ) {
2021-05-22 08:47:16 +02:00
doer , repo , issue , comment := prepareMailerTest ( t )
2021-11-24 17:49:20 +08:00
recipients := [ ] * user_model . User { { Name : "Test" , Email : "test@gitea.com" } }
2019-11-07 10:34:28 -03:00
stpl := texttmpl . Must ( texttmpl . New ( "issue/default" ) . Parse ( "issue/default/subject" ) )
texttmpl . Must ( stpl . New ( "issue/new" ) . Parse ( "issue/new/subject" ) )
texttmpl . Must ( stpl . New ( "pull/comment" ) . Parse ( "pull/comment/subject" ) )
texttmpl . Must ( stpl . New ( "issue/close" ) . Parse ( "" ) ) // Must default to fallback subject
btpl := template . Must ( template . New ( "issue/default" ) . Parse ( "issue/default/body" ) )
template . Must ( btpl . New ( "issue/new" ) . Parse ( "issue/new/body" ) )
template . Must ( btpl . New ( "pull/comment" ) . Parse ( "pull/comment/body" ) )
template . Must ( btpl . New ( "issue/close" ) . Parse ( "issue/close/body" ) )
InitMailRender ( stpl , btpl )
expect := func ( t * testing . T , msg * Message , expSubject , expBody string ) {
2020-01-16 17:55:36 +00:00
subject := msg . ToMessage ( ) . GetHeader ( "Subject" )
2019-11-07 10:34:28 -03:00
msgbuf := new ( bytes . Buffer )
2020-01-16 17:55:36 +00:00
_ , _ = msg . ToMessage ( ) . WriteTo ( msgbuf )
2019-11-07 10:34:28 -03:00
wholemsg := msgbuf . String ( )
assert . Equal ( t , [ ] string { expSubject } , subject )
assert . Contains ( t , wholemsg , expBody )
}
2022-01-20 18:46:10 +01:00
msg := testComposeIssueCommentMessage ( t , & mailCommentContext {
2022-03-22 23:22:54 +08:00
Context : context . TODO ( ) , // TODO: use a correct context
Issue : issue , Doer : doer , ActionType : models . ActionCreateIssue ,
2022-01-20 18:46:10 +01:00
Content : "test body" ,
} , recipients , false , "TestTemplateSelection" )
2019-11-07 10:34:28 -03:00
expect ( t , msg , "issue/new/subject" , "issue/new/body" )
2022-01-20 18:46:10 +01:00
msg = testComposeIssueCommentMessage ( t , & mailCommentContext {
2022-03-22 23:22:54 +08:00
Context : context . TODO ( ) , // TODO: use a correct context
Issue : issue , Doer : doer , ActionType : models . ActionCommentIssue ,
2022-01-20 18:46:10 +01:00
Content : "test body" , Comment : comment ,
} , recipients , false , "TestTemplateSelection" )
2019-11-07 10:34:28 -03:00
expect ( t , msg , "issue/default/subject" , "issue/default/body" )
2022-06-13 17:37:59 +08:00
pull := unittest . AssertExistsAndLoadBean ( t , & issues_model . Issue { ID : 2 , Repo : repo , Poster : doer } ) . ( * issues_model . Issue )
comment = unittest . AssertExistsAndLoadBean ( t , & issues_model . Comment { ID : 4 , Issue : pull } ) . ( * issues_model . Comment )
2022-01-20 18:46:10 +01:00
msg = testComposeIssueCommentMessage ( t , & mailCommentContext {
2022-03-22 23:22:54 +08:00
Context : context . TODO ( ) , // TODO: use a correct context
Issue : pull , Doer : doer , ActionType : models . ActionCommentPull ,
2022-01-20 18:46:10 +01:00
Content : "test body" , Comment : comment ,
} , recipients , false , "TestTemplateSelection" )
2019-11-07 10:34:28 -03:00
expect ( t , msg , "pull/comment/subject" , "pull/comment/body" )
2022-01-20 18:46:10 +01:00
msg = testComposeIssueCommentMessage ( t , & mailCommentContext {
2022-03-22 23:22:54 +08:00
Context : context . TODO ( ) , // TODO: use a correct context
Issue : issue , Doer : doer , ActionType : models . ActionCloseIssue ,
2022-01-20 18:46:10 +01:00
Content : "test body" , Comment : comment ,
} , recipients , false , "TestTemplateSelection" )
2019-11-18 05:08:20 -03:00
expect ( t , msg , "Re: [user2/repo1] issue1 (#1)" , "issue/close/body" )
2019-11-07 10:34:28 -03:00
}
func TestTemplateServices ( t * testing . T ) {
2021-05-22 08:47:16 +02:00
doer , _ , issue , comment := prepareMailerTest ( t )
2022-04-08 17:11:15 +08:00
assert . NoError ( t , issue . LoadRepo ( db . DefaultContext ) )
2019-11-07 10:34:28 -03:00
2022-06-13 17:37:59 +08:00
expect := func ( t * testing . T , issue * issues_model . Issue , comment * issues_model . Comment , doer * user_model . User ,
2022-01-20 18:46:10 +01:00
actionType models . ActionType , fromMention bool , tplSubject , tplBody , expSubject , expBody string ,
) {
2019-11-07 10:34:28 -03:00
stpl := texttmpl . Must ( texttmpl . New ( "issue/default" ) . Parse ( tplSubject ) )
btpl := template . Must ( template . New ( "issue/default" ) . Parse ( tplBody ) )
InitMailRender ( stpl , btpl )
2021-11-24 17:49:20 +08:00
recipients := [ ] * user_model . User { { Name : "Test" , Email : "test@gitea.com" } }
2022-01-20 18:46:10 +01:00
msg := testComposeIssueCommentMessage ( t , & mailCommentContext {
2022-03-22 23:22:54 +08:00
Context : context . TODO ( ) , // TODO: use a correct context
Issue : issue , Doer : doer , ActionType : actionType ,
2022-01-20 18:46:10 +01:00
Content : "test body" , Comment : comment ,
} , recipients , fromMention , "TestTemplateServices" )
2019-11-07 10:34:28 -03:00
2020-01-16 17:55:36 +00:00
subject := msg . ToMessage ( ) . GetHeader ( "Subject" )
2019-11-07 10:34:28 -03:00
msgbuf := new ( bytes . Buffer )
2020-01-16 17:55:36 +00:00
_ , _ = msg . ToMessage ( ) . WriteTo ( msgbuf )
2019-11-07 10:34:28 -03:00
wholemsg := msgbuf . String ( )
assert . Equal ( t , [ ] string { expSubject } , subject )
assert . Contains ( t , wholemsg , "\r\n" + expBody + "\r\n" )
}
expect ( t , issue , comment , doer , models . ActionCommentIssue , false ,
"{{.SubjectPrefix}}[{{.Repo}}]: @{{.Doer.Name}} commented on #{{.Issue.Index}} - {{.Issue.Title}}" ,
"//{{.ActionType}},{{.ActionName}},{{if .IsMention}}norender{{end}}//" ,
"Re: [user2/repo1]: @user2 commented on #1 - issue1" ,
"//issue,comment,//" )
expect ( t , issue , comment , doer , models . ActionCommentIssue , true ,
"{{if .IsMention}}must render{{end}}" ,
"//subject is: {{.Subject}}//" ,
"must render" ,
"//subject is: must render//" )
expect ( t , issue , comment , doer , models . ActionCommentIssue , true ,
"{{.FallbackSubject}}" ,
"//{{.SubjectPrefix}}//" ,
"Re: [user2/repo1] issue1 (#1)" ,
"//Re: //" )
}
2019-11-18 05:08:20 -03:00
2021-11-24 17:49:20 +08:00
func testComposeIssueCommentMessage ( t * testing . T , ctx * mailCommentContext , recipients [ ] * user_model . User , fromMention bool , info string ) * Message {
2021-05-22 08:47:16 +02:00
msgs , err := composeIssueCommentMessages ( ctx , "en-US" , recipients , fromMention , info )
2021-04-20 06:25:08 +08:00
assert . NoError ( t , err )
2019-11-18 05:08:20 -03:00
assert . Len ( t , msgs , 1 )
return msgs [ 0 ]
}
2021-05-22 08:47:16 +02:00
func TestGenerateAdditionalHeaders ( t * testing . T ) {
doer , _ , issue , _ := prepareMailerTest ( t )
2022-03-22 23:22:54 +08:00
ctx := & mailCommentContext { Context : context . TODO ( ) /* TODO: use a correct context */ , Issue : issue , Doer : doer }
2021-11-24 17:49:20 +08:00
recipient := & user_model . User { Name : "Test" , Email : "test@gitea.com" }
2021-05-22 08:47:16 +02:00
headers := generateAdditionalHeaders ( ctx , "dummy-reason" , recipient )
expected := map [ string ] string {
"List-ID" : "user2/repo1 <repo1.user2.localhost>" ,
"List-Archive" : "<https://try.gitea.io/user2/repo1>" ,
2021-12-21 23:53:03 +01:00
"List-Unsubscribe" : "https://try.gitea.io/user2/repo1/issues/1" ,
2021-05-22 08:47:16 +02:00
"X-Gitea-Reason" : "dummy-reason" ,
"X-Gitea-Sender" : "< U<se>r Tw<o > ><" ,
"X-Gitea-Recipient" : "Test" ,
"X-Gitea-Recipient-Address" : "test@gitea.com" ,
"X-Gitea-Repository" : "repo1" ,
"X-Gitea-Repository-Path" : "user2/repo1" ,
"X-Gitea-Repository-Link" : "https://try.gitea.io/user2/repo1" ,
"X-Gitea-Issue-ID" : "1" ,
"X-Gitea-Issue-Link" : "https://try.gitea.io/user2/repo1/issues/1" ,
}
for key , value := range expected {
if assert . Contains ( t , headers , key ) {
assert . Equal ( t , value , headers [ key ] )
}
}
}
2022-02-03 23:01:16 +00:00
func Test_createReference ( t * testing . T ) {
_ , _ , issue , comment := prepareMailerTest ( t )
_ , _ , pullIssue , _ := prepareMailerTest ( t )
pullIssue . IsPull = true
type args struct {
2022-06-13 17:37:59 +08:00
issue * issues_model . Issue
comment * issues_model . Comment
2022-02-03 23:01:16 +00:00
actionType models . ActionType
}
tests := [ ] struct {
name string
args args
prefix string
suffix string
} {
{
name : "Open Issue" ,
args : args {
issue : issue ,
actionType : models . ActionCreateIssue ,
} ,
prefix : fmt . Sprintf ( "%s/issues/%d@%s" , issue . Repo . FullName ( ) , issue . Index , setting . Domain ) ,
} ,
{
name : "Open Pull" ,
args : args {
issue : pullIssue ,
actionType : models . ActionCreatePullRequest ,
} ,
prefix : fmt . Sprintf ( "%s/pulls/%d@%s" , issue . Repo . FullName ( ) , issue . Index , setting . Domain ) ,
} ,
{
name : "Comment Issue" ,
args : args {
issue : issue ,
comment : comment ,
actionType : models . ActionCommentIssue ,
} ,
prefix : fmt . Sprintf ( "%s/issues/%d/comment/%d@%s" , issue . Repo . FullName ( ) , issue . Index , comment . ID , setting . Domain ) ,
} ,
{
name : "Comment Pull" ,
args : args {
issue : pullIssue ,
comment : comment ,
actionType : models . ActionCommentPull ,
} ,
prefix : fmt . Sprintf ( "%s/pulls/%d/comment/%d@%s" , issue . Repo . FullName ( ) , issue . Index , comment . ID , setting . Domain ) ,
} ,
{
name : "Close Issue" ,
args : args {
issue : issue ,
actionType : models . ActionCloseIssue ,
} ,
prefix : fmt . Sprintf ( "%s/issues/%d/close/" , issue . Repo . FullName ( ) , issue . Index ) ,
} ,
{
name : "Close Pull" ,
args : args {
issue : pullIssue ,
actionType : models . ActionClosePullRequest ,
} ,
prefix : fmt . Sprintf ( "%s/pulls/%d/close/" , issue . Repo . FullName ( ) , issue . Index ) ,
} ,
{
name : "Reopen Issue" ,
args : args {
issue : issue ,
actionType : models . ActionReopenIssue ,
} ,
prefix : fmt . Sprintf ( "%s/issues/%d/reopen/" , issue . Repo . FullName ( ) , issue . Index ) ,
} ,
{
name : "Reopen Pull" ,
args : args {
issue : pullIssue ,
actionType : models . ActionReopenPullRequest ,
} ,
prefix : fmt . Sprintf ( "%s/pulls/%d/reopen/" , issue . Repo . FullName ( ) , issue . Index ) ,
} ,
{
name : "Merge Pull" ,
args : args {
issue : pullIssue ,
actionType : models . ActionMergePullRequest ,
} ,
prefix : fmt . Sprintf ( "%s/pulls/%d/merge/" , issue . Repo . FullName ( ) , issue . Index ) ,
} ,
{
name : "Ready Pull" ,
args : args {
issue : pullIssue ,
actionType : models . ActionPullRequestReadyForReview ,
} ,
prefix : fmt . Sprintf ( "%s/pulls/%d/ready/" , issue . Repo . FullName ( ) , issue . Index ) ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
got := createReference ( tt . args . issue , tt . args . comment , tt . args . actionType )
if ! strings . HasPrefix ( got , tt . prefix ) {
t . Errorf ( "createReference() = %v, want %v" , got , tt . prefix )
}
if ! strings . HasSuffix ( got , tt . suffix ) {
t . Errorf ( "createReference() = %v, want %v" , got , tt . prefix )
}
} )
}
}