2017-04-29 08:52:25 +03:00
// Copyright 2017 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.
package integrations
import (
2019-09-20 08:45:38 +03:00
"fmt"
2017-04-29 08:52:25 +03:00
"net/http"
2017-06-18 16:25:58 +03:00
"path"
2017-06-15 06:09:03 +03:00
"strconv"
"strings"
2017-04-29 08:52:25 +03:00
"testing"
2020-01-07 14:23:09 +03:00
"time"
2017-04-29 08:52:25 +03:00
2017-06-15 06:09:03 +03:00
"code.gitea.io/gitea/models"
2021-12-10 04:27:50 +03:00
repo_model "code.gitea.io/gitea/models/repo"
2021-11-16 11:53:21 +03:00
"code.gitea.io/gitea/models/unittest"
2021-11-24 12:49:20 +03:00
user_model "code.gitea.io/gitea/models/user"
2020-01-07 14:23:09 +03:00
"code.gitea.io/gitea/modules/indexer/issues"
2019-10-14 01:29:10 +03:00
"code.gitea.io/gitea/modules/references"
2017-06-15 06:09:03 +03:00
"code.gitea.io/gitea/modules/setting"
2017-12-16 00:11:02 +03:00
"code.gitea.io/gitea/modules/test"
2017-06-15 06:09:03 +03:00
"github.com/PuerkitoBio/goquery"
2017-04-29 08:52:25 +03:00
"github.com/stretchr/testify/assert"
)
2017-09-16 23:16:21 +03:00
func getIssuesSelection ( t testing . TB , htmlDoc * HTMLDoc ) * goquery . Selection {
issueList := htmlDoc . doc . Find ( ".issue.list" )
assert . EqualValues ( t , 1 , issueList . Length ( ) )
return issueList . Find ( "li" ) . Find ( ".title" )
2017-06-15 06:09:03 +03:00
}
func getIssue ( t * testing . T , repoID int64 , issueSelection * goquery . Selection ) * models . Issue {
href , exists := issueSelection . Attr ( "href" )
assert . True ( t , exists )
indexStr := href [ strings . LastIndexByte ( href , '/' ) + 1 : ]
index , err := strconv . Atoi ( indexStr )
assert . NoError ( t , err , "Invalid issue href: %s" , href )
2021-11-16 11:53:21 +03:00
return unittest . AssertExistsAndLoadBean ( t , & models . Issue { RepoID : repoID , Index : int64 ( index ) } ) . ( * models . Issue )
2017-06-15 06:09:03 +03:00
}
2017-09-16 23:16:21 +03:00
func assertMatch ( t testing . TB , issue * models . Issue , keyword string ) {
matches := strings . Contains ( strings . ToLower ( issue . Title ) , keyword ) ||
strings . Contains ( strings . ToLower ( issue . Content ) , keyword )
for _ , comment := range issue . Comments {
matches = matches || strings . Contains (
strings . ToLower ( comment . Content ) ,
keyword ,
)
}
assert . True ( t , matches )
}
2017-05-27 06:34:11 +03:00
func TestNoLoginViewIssues ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer prepareTestEnv ( t ) ( )
2017-05-27 06:34:11 +03:00
2017-06-10 03:41:36 +03:00
req := NewRequest ( t , "GET" , "/user2/repo1/issues" )
2017-07-07 22:36:47 +03:00
MakeRequest ( t , req , http . StatusOK )
2017-05-27 06:34:11 +03:00
}
2017-09-16 23:16:21 +03:00
func TestViewIssuesSortByType ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer prepareTestEnv ( t ) ( )
2017-06-15 06:09:03 +03:00
2021-11-24 12:49:20 +03:00
user := unittest . AssertExistsAndLoadBean ( t , & user_model . User { ID : 1 } ) . ( * user_model . User )
2021-12-10 04:27:50 +03:00
repo := unittest . AssertExistsAndLoadBean ( t , & repo_model . Repository { ID : 1 } ) . ( * repo_model . Repository )
2017-06-15 06:09:03 +03:00
2017-06-17 07:49:45 +03:00
session := loginUser ( t , user . Name )
2021-11-16 21:18:25 +03:00
req := NewRequest ( t , "GET" , repo . Link ( ) + "/issues?type=created_by" )
2017-07-07 22:36:47 +03:00
resp := session . MakeRequest ( t , req , http . StatusOK )
2017-06-15 06:09:03 +03:00
2017-06-17 19:29:59 +03:00
htmlDoc := NewHTMLParser ( t , resp . Body )
2017-09-16 23:16:21 +03:00
issuesSelection := getIssuesSelection ( t , htmlDoc )
2021-11-16 11:53:21 +03:00
expectedNumIssues := unittest . GetCount ( t ,
2017-06-15 06:09:03 +03:00
& models . Issue { RepoID : repo . ID , PosterID : user . ID } ,
2021-11-16 11:53:21 +03:00
unittest . Cond ( "is_closed=?" , false ) ,
unittest . Cond ( "is_pull=?" , false ) ,
2017-06-15 06:09:03 +03:00
)
if expectedNumIssues > setting . UI . IssuePagingNum {
expectedNumIssues = setting . UI . IssuePagingNum
}
assert . EqualValues ( t , expectedNumIssues , issuesSelection . Length ( ) )
issuesSelection . Each ( func ( _ int , selection * goquery . Selection ) {
issue := getIssue ( t , repo . ID , selection )
assert . EqualValues ( t , user . ID , issue . PosterID )
} )
}
2017-09-16 23:16:21 +03:00
func TestViewIssuesKeyword ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer prepareTestEnv ( t ) ( )
2017-09-16 23:16:21 +03:00
2021-12-10 04:27:50 +03:00
repo := unittest . AssertExistsAndLoadBean ( t , & repo_model . Repository { ID : 1 } ) . ( * repo_model . Repository )
2021-11-16 11:53:21 +03:00
issue := unittest . AssertExistsAndLoadBean ( t , & models . Issue {
2020-01-07 14:23:09 +03:00
RepoID : repo . ID ,
Index : 1 ,
} ) . ( * models . Issue )
issues . UpdateIssueIndexer ( issue )
time . Sleep ( time . Second * 1 )
2017-09-16 23:16:21 +03:00
const keyword = "first"
2021-11-16 21:18:25 +03:00
req := NewRequestf ( t , "GET" , "%s/issues?q=%s" , repo . Link ( ) , keyword )
2017-09-16 23:16:21 +03:00
resp := MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
issuesSelection := getIssuesSelection ( t , htmlDoc )
assert . EqualValues ( t , 1 , issuesSelection . Length ( ) )
issuesSelection . Each ( func ( _ int , selection * goquery . Selection ) {
issue := getIssue ( t , repo . ID , selection )
assert . False ( t , issue . IsClosed )
assert . False ( t , issue . IsPull )
assertMatch ( t , issue , keyword )
} )
}
2017-04-29 08:52:25 +03:00
func TestNoLoginViewIssue ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer prepareTestEnv ( t ) ( )
2017-04-29 08:52:25 +03:00
2017-06-10 03:41:36 +03:00
req := NewRequest ( t , "GET" , "/user2/repo1/issues/1" )
2017-07-07 22:36:47 +03:00
MakeRequest ( t , req , http . StatusOK )
2017-04-29 08:52:25 +03:00
}
2017-06-18 16:25:58 +03:00
2017-11-03 12:23:17 +03:00
func testNewIssue ( t * testing . T , session * TestSession , user , repo , title , content string ) string {
2017-06-18 16:25:58 +03:00
req := NewRequest ( t , "GET" , path . Join ( user , repo , "issues" , "new" ) )
2017-07-07 22:36:47 +03:00
resp := session . MakeRequest ( t , req , http . StatusOK )
2017-06-18 16:25:58 +03:00
htmlDoc := NewHTMLParser ( t , resp . Body )
link , exists := htmlDoc . doc . Find ( "form.ui.form" ) . Attr ( "action" )
assert . True ( t , exists , "The template has changed" )
req = NewRequestWithValues ( t , "POST" , link , map [ string ] string {
2017-11-03 12:23:17 +03:00
"_csrf" : htmlDoc . GetCSRF ( ) ,
"title" : title ,
"content" : content ,
} )
resp = session . MakeRequest ( t , req , http . StatusFound )
2017-12-16 00:11:02 +03:00
issueURL := test . RedirectURL ( resp )
2017-11-03 12:23:17 +03:00
req = NewRequest ( t , "GET" , issueURL )
resp = session . MakeRequest ( t , req , http . StatusOK )
htmlDoc = NewHTMLParser ( t , resp . Body )
val := htmlDoc . doc . Find ( "#issue-title" ) . Text ( )
assert . Equal ( t , title , val )
2020-04-11 01:01:41 +03:00
val = htmlDoc . doc . Find ( ".comment .render-content p" ) . First ( ) . Text ( )
2017-11-03 12:23:17 +03:00
assert . Equal ( t , content , val )
return issueURL
}
2019-09-20 08:45:38 +03:00
func testIssueAddComment ( t * testing . T , session * TestSession , issueURL , content , status string ) int64 {
2017-11-03 12:23:17 +03:00
req := NewRequest ( t , "GET" , issueURL )
resp := session . MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
link , exists := htmlDoc . doc . Find ( "#comment-form" ) . Attr ( "action" )
assert . True ( t , exists , "The template has changed" )
2020-04-11 01:01:41 +03:00
commentCount := htmlDoc . doc . Find ( ".comment-list .comment .render-content" ) . Length ( )
2017-11-03 12:23:17 +03:00
req = NewRequestWithValues ( t , "POST" , link , map [ string ] string {
"_csrf" : htmlDoc . GetCSRF ( ) ,
"content" : content ,
"status" : status ,
2017-06-18 16:25:58 +03:00
} )
2017-07-07 22:36:47 +03:00
resp = session . MakeRequest ( t , req , http . StatusFound )
2017-12-16 00:11:02 +03:00
req = NewRequest ( t , "GET" , test . RedirectURL ( resp ) )
2017-07-07 22:36:47 +03:00
resp = session . MakeRequest ( t , req , http . StatusOK )
2017-11-03 12:23:17 +03:00
htmlDoc = NewHTMLParser ( t , resp . Body )
2020-04-11 01:01:41 +03:00
val := htmlDoc . doc . Find ( ".comment-list .comment .render-content p" ) . Eq ( commentCount ) . Text ( )
2017-11-03 12:23:17 +03:00
assert . Equal ( t , content , val )
2019-09-20 08:45:38 +03:00
2020-04-11 01:01:41 +03:00
idAttr , has := htmlDoc . doc . Find ( ".comment-list .comment" ) . Eq ( commentCount ) . Attr ( "id" )
2019-09-20 08:45:38 +03:00
idStr := idAttr [ strings . LastIndexByte ( idAttr , '-' ) + 1 : ]
assert . True ( t , has )
id , err := strconv . Atoi ( idStr )
assert . NoError ( t , err )
return int64 ( id )
2017-06-18 16:25:58 +03:00
}
func TestNewIssue ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer prepareTestEnv ( t ) ( )
2017-06-18 16:25:58 +03:00
session := loginUser ( t , "user2" )
2017-11-03 12:23:17 +03:00
testNewIssue ( t , session , "user2" , "repo1" , "Title" , "Description" )
}
func TestIssueCommentClose ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer prepareTestEnv ( t ) ( )
2017-11-03 12:23:17 +03:00
session := loginUser ( t , "user2" )
issueURL := testNewIssue ( t , session , "user2" , "repo1" , "Title" , "Description" )
testIssueAddComment ( t , session , issueURL , "Test comment 1" , "" )
testIssueAddComment ( t , session , issueURL , "Test comment 2" , "" )
testIssueAddComment ( t , session , issueURL , "Test comment 3" , "close" )
// Validate that issue content has not been updated
req := NewRequest ( t , "GET" , issueURL )
resp := session . MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
2020-04-11 01:01:41 +03:00
val := htmlDoc . doc . Find ( ".comment-list .comment .render-content p" ) . First ( ) . Text ( )
2017-11-03 12:23:17 +03:00
assert . Equal ( t , "Description" , val )
2017-06-18 16:25:58 +03:00
}
2019-09-20 08:45:38 +03:00
2019-12-02 01:57:24 +03:00
func TestIssueReaction ( t * testing . T ) {
defer prepareTestEnv ( t ) ( )
session := loginUser ( t , "user2" )
issueURL := testNewIssue ( t , session , "user2" , "repo1" , "Title" , "Description" )
req := NewRequest ( t , "GET" , issueURL )
resp := session . MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
req = NewRequestWithValues ( t , "POST" , path . Join ( issueURL , "/reactions/react" ) , map [ string ] string {
"_csrf" : htmlDoc . GetCSRF ( ) ,
"content" : "8ball" ,
} )
session . MakeRequest ( t , req , http . StatusInternalServerError )
req = NewRequestWithValues ( t , "POST" , path . Join ( issueURL , "/reactions/react" ) , map [ string ] string {
"_csrf" : htmlDoc . GetCSRF ( ) ,
"content" : "eyes" ,
} )
session . MakeRequest ( t , req , http . StatusOK )
req = NewRequestWithValues ( t , "POST" , path . Join ( issueURL , "/reactions/unreact" ) , map [ string ] string {
"_csrf" : htmlDoc . GetCSRF ( ) ,
"content" : "eyes" ,
} )
session . MakeRequest ( t , req , http . StatusOK )
}
2019-09-20 08:45:38 +03:00
func TestIssueCrossReference ( t * testing . T ) {
2019-11-26 02:21:37 +03:00
defer prepareTestEnv ( t ) ( )
2019-09-20 08:45:38 +03:00
// Issue that will be referenced
_ , issueBase := testIssueWithBean ( t , "user2" , 1 , "Title" , "Description" )
// Ref from issue title
issueRefURL , issueRef := testIssueWithBean ( t , "user2" , 1 , fmt . Sprintf ( "Title ref #%d" , issueBase . Index ) , "Description" )
2021-11-16 11:53:21 +03:00
unittest . AssertExistsAndLoadBean ( t , & models . Comment {
2019-09-20 08:45:38 +03:00
IssueID : issueBase . ID ,
RefRepoID : 1 ,
RefIssueID : issueRef . ID ,
RefCommentID : 0 ,
RefIsPull : false ,
2019-10-14 01:29:10 +03:00
RefAction : references . XRefActionNone } )
2019-09-20 08:45:38 +03:00
// Edit title, neuter ref
testIssueChangeInfo ( t , "user2" , issueRefURL , "title" , "Title no ref" )
2021-11-16 11:53:21 +03:00
unittest . AssertExistsAndLoadBean ( t , & models . Comment {
2019-09-20 08:45:38 +03:00
IssueID : issueBase . ID ,
RefRepoID : 1 ,
RefIssueID : issueRef . ID ,
RefCommentID : 0 ,
RefIsPull : false ,
2019-10-14 01:29:10 +03:00
RefAction : references . XRefActionNeutered } )
2019-09-20 08:45:38 +03:00
// Ref from issue content
issueRefURL , issueRef = testIssueWithBean ( t , "user2" , 1 , "TitleXRef" , fmt . Sprintf ( "Description ref #%d" , issueBase . Index ) )
2021-11-16 11:53:21 +03:00
unittest . AssertExistsAndLoadBean ( t , & models . Comment {
2019-09-20 08:45:38 +03:00
IssueID : issueBase . ID ,
RefRepoID : 1 ,
RefIssueID : issueRef . ID ,
RefCommentID : 0 ,
RefIsPull : false ,
2019-10-14 01:29:10 +03:00
RefAction : references . XRefActionNone } )
2019-09-20 08:45:38 +03:00
// Edit content, neuter ref
testIssueChangeInfo ( t , "user2" , issueRefURL , "content" , "Description no ref" )
2021-11-16 11:53:21 +03:00
unittest . AssertExistsAndLoadBean ( t , & models . Comment {
2019-09-20 08:45:38 +03:00
IssueID : issueBase . ID ,
RefRepoID : 1 ,
RefIssueID : issueRef . ID ,
RefCommentID : 0 ,
RefIsPull : false ,
2019-10-14 01:29:10 +03:00
RefAction : references . XRefActionNeutered } )
2019-09-20 08:45:38 +03:00
// Ref from a comment
session := loginUser ( t , "user2" )
commentID := testIssueAddComment ( t , session , issueRefURL , fmt . Sprintf ( "Adding ref from comment #%d" , issueBase . Index ) , "" )
comment := & models . Comment {
IssueID : issueBase . ID ,
RefRepoID : 1 ,
RefIssueID : issueRef . ID ,
RefCommentID : commentID ,
RefIsPull : false ,
2019-10-14 01:29:10 +03:00
RefAction : references . XRefActionNone }
2021-11-16 11:53:21 +03:00
unittest . AssertExistsAndLoadBean ( t , comment )
2019-09-20 08:45:38 +03:00
// Ref from a different repository
2021-11-18 04:33:06 +03:00
_ , issueRef = testIssueWithBean ( t , "user12" , 10 , "TitleXRef" , fmt . Sprintf ( "Description ref user2/repo1#%d" , issueBase . Index ) )
2021-11-16 11:53:21 +03:00
unittest . AssertExistsAndLoadBean ( t , & models . Comment {
2019-09-20 08:45:38 +03:00
IssueID : issueBase . ID ,
RefRepoID : 10 ,
RefIssueID : issueRef . ID ,
RefCommentID : 0 ,
RefIsPull : false ,
2019-10-14 01:29:10 +03:00
RefAction : references . XRefActionNone } )
2019-09-20 08:45:38 +03:00
}
func testIssueWithBean ( t * testing . T , user string , repoID int64 , title , content string ) ( string , * models . Issue ) {
session := loginUser ( t , user )
issueURL := testNewIssue ( t , session , user , fmt . Sprintf ( "repo%d" , repoID ) , title , content )
indexStr := issueURL [ strings . LastIndexByte ( issueURL , '/' ) + 1 : ]
index , err := strconv . Atoi ( indexStr )
assert . NoError ( t , err , "Invalid issue href: %s" , issueURL )
issue := & models . Issue { RepoID : repoID , Index : int64 ( index ) }
2021-11-16 11:53:21 +03:00
unittest . AssertExistsAndLoadBean ( t , issue )
2019-09-20 08:45:38 +03:00
return issueURL , issue
}
2021-12-20 07:41:31 +03:00
func testIssueChangeInfo ( t * testing . T , user , issueURL , info , value string ) {
2019-09-20 08:45:38 +03:00
session := loginUser ( t , user )
req := NewRequest ( t , "GET" , issueURL )
resp := session . MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
req = NewRequestWithValues ( t , "POST" , path . Join ( issueURL , info ) , map [ string ] string {
"_csrf" : htmlDoc . GetCSRF ( ) ,
info : value ,
} )
_ = session . MakeRequest ( t , req , http . StatusOK )
}
2019-12-07 07:21:18 +03:00
func TestIssueRedirect ( t * testing . T ) {
defer prepareTestEnv ( t ) ( )
session := loginUser ( t , "user2" )
// Test external tracker where style not set (shall default numeric)
req := NewRequest ( t , "GET" , path . Join ( "org26" , "repo_external_tracker" , "issues" , "1" ) )
resp := session . MakeRequest ( t , req , http . StatusFound )
assert . Equal ( t , "https://tracker.com/org26/repo_external_tracker/issues/1" , test . RedirectURL ( resp ) )
// Test external tracker with numeric style
req = NewRequest ( t , "GET" , path . Join ( "org26" , "repo_external_tracker_numeric" , "issues" , "1" ) )
resp = session . MakeRequest ( t , req , http . StatusFound )
assert . Equal ( t , "https://tracker.com/org26/repo_external_tracker_numeric/issues/1" , test . RedirectURL ( resp ) )
// Test external tracker with alphanumeric style (for a pull request)
req = NewRequest ( t , "GET" , path . Join ( "org26" , "repo_external_tracker_alpha" , "issues" , "1" ) )
resp = session . MakeRequest ( t , req , http . StatusFound )
assert . Equal ( t , "/" + path . Join ( "org26" , "repo_external_tracker_alpha" , "pulls" , "1" ) , test . RedirectURL ( resp ) )
}