You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

issue_test.go 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package integrations
  5. import (
  6. "fmt"
  7. "net/http"
  8. "net/url"
  9. "path"
  10. "strconv"
  11. "strings"
  12. "testing"
  13. "time"
  14. "code.gitea.io/gitea/models/db"
  15. issues_model "code.gitea.io/gitea/models/issues"
  16. repo_model "code.gitea.io/gitea/models/repo"
  17. "code.gitea.io/gitea/models/unittest"
  18. user_model "code.gitea.io/gitea/models/user"
  19. "code.gitea.io/gitea/modules/indexer/issues"
  20. "code.gitea.io/gitea/modules/references"
  21. "code.gitea.io/gitea/modules/setting"
  22. api "code.gitea.io/gitea/modules/structs"
  23. "code.gitea.io/gitea/modules/test"
  24. "github.com/PuerkitoBio/goquery"
  25. "github.com/stretchr/testify/assert"
  26. )
  27. func getIssuesSelection(t testing.TB, htmlDoc *HTMLDoc) *goquery.Selection {
  28. issueList := htmlDoc.doc.Find(".issue.list")
  29. assert.EqualValues(t, 1, issueList.Length())
  30. return issueList.Find("li").Find(".title")
  31. }
  32. func getIssue(t *testing.T, repoID int64, issueSelection *goquery.Selection) *issues_model.Issue {
  33. href, exists := issueSelection.Attr("href")
  34. assert.True(t, exists)
  35. indexStr := href[strings.LastIndexByte(href, '/')+1:]
  36. index, err := strconv.Atoi(indexStr)
  37. assert.NoError(t, err, "Invalid issue href: %s", href)
  38. return unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repoID, Index: int64(index)}).(*issues_model.Issue)
  39. }
  40. func assertMatch(t testing.TB, issue *issues_model.Issue, keyword string) {
  41. matches := strings.Contains(strings.ToLower(issue.Title), keyword) ||
  42. strings.Contains(strings.ToLower(issue.Content), keyword)
  43. for _, comment := range issue.Comments {
  44. matches = matches || strings.Contains(
  45. strings.ToLower(comment.Content),
  46. keyword,
  47. )
  48. }
  49. assert.True(t, matches)
  50. }
  51. func TestNoLoginViewIssues(t *testing.T) {
  52. defer prepareTestEnv(t)()
  53. req := NewRequest(t, "GET", "/user2/repo1/issues")
  54. MakeRequest(t, req, http.StatusOK)
  55. }
  56. func TestViewIssuesSortByType(t *testing.T) {
  57. defer prepareTestEnv(t)()
  58. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
  59. repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
  60. session := loginUser(t, user.Name)
  61. req := NewRequest(t, "GET", repo.Link()+"/issues?type=created_by")
  62. resp := session.MakeRequest(t, req, http.StatusOK)
  63. htmlDoc := NewHTMLParser(t, resp.Body)
  64. issuesSelection := getIssuesSelection(t, htmlDoc)
  65. expectedNumIssues := unittest.GetCount(t,
  66. &issues_model.Issue{RepoID: repo.ID, PosterID: user.ID},
  67. unittest.Cond("is_closed=?", false),
  68. unittest.Cond("is_pull=?", false),
  69. )
  70. if expectedNumIssues > setting.UI.IssuePagingNum {
  71. expectedNumIssues = setting.UI.IssuePagingNum
  72. }
  73. assert.EqualValues(t, expectedNumIssues, issuesSelection.Length())
  74. issuesSelection.Each(func(_ int, selection *goquery.Selection) {
  75. issue := getIssue(t, repo.ID, selection)
  76. assert.EqualValues(t, user.ID, issue.PosterID)
  77. })
  78. }
  79. func TestViewIssuesKeyword(t *testing.T) {
  80. defer prepareTestEnv(t)()
  81. repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
  82. issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{
  83. RepoID: repo.ID,
  84. Index: 1,
  85. }).(*issues_model.Issue)
  86. issues.UpdateIssueIndexer(issue)
  87. time.Sleep(time.Second * 1)
  88. const keyword = "first"
  89. req := NewRequestf(t, "GET", "%s/issues?q=%s", repo.Link(), keyword)
  90. resp := MakeRequest(t, req, http.StatusOK)
  91. htmlDoc := NewHTMLParser(t, resp.Body)
  92. issuesSelection := getIssuesSelection(t, htmlDoc)
  93. assert.EqualValues(t, 1, issuesSelection.Length())
  94. issuesSelection.Each(func(_ int, selection *goquery.Selection) {
  95. issue := getIssue(t, repo.ID, selection)
  96. assert.False(t, issue.IsClosed)
  97. assert.False(t, issue.IsPull)
  98. assertMatch(t, issue, keyword)
  99. })
  100. }
  101. func TestNoLoginViewIssue(t *testing.T) {
  102. defer prepareTestEnv(t)()
  103. req := NewRequest(t, "GET", "/user2/repo1/issues/1")
  104. MakeRequest(t, req, http.StatusOK)
  105. }
  106. func testNewIssue(t *testing.T, session *TestSession, user, repo, title, content string) string {
  107. req := NewRequest(t, "GET", path.Join(user, repo, "issues", "new"))
  108. resp := session.MakeRequest(t, req, http.StatusOK)
  109. htmlDoc := NewHTMLParser(t, resp.Body)
  110. link, exists := htmlDoc.doc.Find("form.ui.form").Attr("action")
  111. assert.True(t, exists, "The template has changed")
  112. req = NewRequestWithValues(t, "POST", link, map[string]string{
  113. "_csrf": htmlDoc.GetCSRF(),
  114. "title": title,
  115. "content": content,
  116. })
  117. resp = session.MakeRequest(t, req, http.StatusSeeOther)
  118. issueURL := test.RedirectURL(resp)
  119. req = NewRequest(t, "GET", issueURL)
  120. resp = session.MakeRequest(t, req, http.StatusOK)
  121. htmlDoc = NewHTMLParser(t, resp.Body)
  122. val := htmlDoc.doc.Find("#issue-title").Text()
  123. assert.Equal(t, title, val)
  124. val = htmlDoc.doc.Find(".comment .render-content p").First().Text()
  125. assert.Equal(t, content, val)
  126. return issueURL
  127. }
  128. func testIssueAddComment(t *testing.T, session *TestSession, issueURL, content, status string) int64 {
  129. req := NewRequest(t, "GET", issueURL)
  130. resp := session.MakeRequest(t, req, http.StatusOK)
  131. htmlDoc := NewHTMLParser(t, resp.Body)
  132. link, exists := htmlDoc.doc.Find("#comment-form").Attr("action")
  133. assert.True(t, exists, "The template has changed")
  134. commentCount := htmlDoc.doc.Find(".comment-list .comment .render-content").Length()
  135. req = NewRequestWithValues(t, "POST", link, map[string]string{
  136. "_csrf": htmlDoc.GetCSRF(),
  137. "content": content,
  138. "status": status,
  139. })
  140. resp = session.MakeRequest(t, req, http.StatusSeeOther)
  141. req = NewRequest(t, "GET", test.RedirectURL(resp))
  142. resp = session.MakeRequest(t, req, http.StatusOK)
  143. htmlDoc = NewHTMLParser(t, resp.Body)
  144. val := htmlDoc.doc.Find(".comment-list .comment .render-content p").Eq(commentCount).Text()
  145. assert.Equal(t, content, val)
  146. idAttr, has := htmlDoc.doc.Find(".comment-list .comment").Eq(commentCount).Attr("id")
  147. idStr := idAttr[strings.LastIndexByte(idAttr, '-')+1:]
  148. assert.True(t, has)
  149. id, err := strconv.Atoi(idStr)
  150. assert.NoError(t, err)
  151. return int64(id)
  152. }
  153. func TestNewIssue(t *testing.T) {
  154. defer prepareTestEnv(t)()
  155. session := loginUser(t, "user2")
  156. testNewIssue(t, session, "user2", "repo1", "Title", "Description")
  157. }
  158. func TestIssueCommentClose(t *testing.T) {
  159. defer prepareTestEnv(t)()
  160. session := loginUser(t, "user2")
  161. issueURL := testNewIssue(t, session, "user2", "repo1", "Title", "Description")
  162. testIssueAddComment(t, session, issueURL, "Test comment 1", "")
  163. testIssueAddComment(t, session, issueURL, "Test comment 2", "")
  164. testIssueAddComment(t, session, issueURL, "Test comment 3", "close")
  165. // Validate that issue content has not been updated
  166. req := NewRequest(t, "GET", issueURL)
  167. resp := session.MakeRequest(t, req, http.StatusOK)
  168. htmlDoc := NewHTMLParser(t, resp.Body)
  169. val := htmlDoc.doc.Find(".comment-list .comment .render-content p").First().Text()
  170. assert.Equal(t, "Description", val)
  171. }
  172. func TestIssueReaction(t *testing.T) {
  173. defer prepareTestEnv(t)()
  174. session := loginUser(t, "user2")
  175. issueURL := testNewIssue(t, session, "user2", "repo1", "Title", "Description")
  176. req := NewRequest(t, "GET", issueURL)
  177. resp := session.MakeRequest(t, req, http.StatusOK)
  178. htmlDoc := NewHTMLParser(t, resp.Body)
  179. req = NewRequestWithValues(t, "POST", path.Join(issueURL, "/reactions/react"), map[string]string{
  180. "_csrf": htmlDoc.GetCSRF(),
  181. "content": "8ball",
  182. })
  183. session.MakeRequest(t, req, http.StatusInternalServerError)
  184. req = NewRequestWithValues(t, "POST", path.Join(issueURL, "/reactions/react"), map[string]string{
  185. "_csrf": htmlDoc.GetCSRF(),
  186. "content": "eyes",
  187. })
  188. session.MakeRequest(t, req, http.StatusOK)
  189. req = NewRequestWithValues(t, "POST", path.Join(issueURL, "/reactions/unreact"), map[string]string{
  190. "_csrf": htmlDoc.GetCSRF(),
  191. "content": "eyes",
  192. })
  193. session.MakeRequest(t, req, http.StatusOK)
  194. }
  195. func TestIssueCrossReference(t *testing.T) {
  196. defer prepareTestEnv(t)()
  197. // Issue that will be referenced
  198. _, issueBase := testIssueWithBean(t, "user2", 1, "Title", "Description")
  199. // Ref from issue title
  200. issueRefURL, issueRef := testIssueWithBean(t, "user2", 1, fmt.Sprintf("Title ref #%d", issueBase.Index), "Description")
  201. unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{
  202. IssueID: issueBase.ID,
  203. RefRepoID: 1,
  204. RefIssueID: issueRef.ID,
  205. RefCommentID: 0,
  206. RefIsPull: false,
  207. RefAction: references.XRefActionNone,
  208. })
  209. // Edit title, neuter ref
  210. testIssueChangeInfo(t, "user2", issueRefURL, "title", "Title no ref")
  211. unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{
  212. IssueID: issueBase.ID,
  213. RefRepoID: 1,
  214. RefIssueID: issueRef.ID,
  215. RefCommentID: 0,
  216. RefIsPull: false,
  217. RefAction: references.XRefActionNeutered,
  218. })
  219. // Ref from issue content
  220. issueRefURL, issueRef = testIssueWithBean(t, "user2", 1, "TitleXRef", fmt.Sprintf("Description ref #%d", issueBase.Index))
  221. unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{
  222. IssueID: issueBase.ID,
  223. RefRepoID: 1,
  224. RefIssueID: issueRef.ID,
  225. RefCommentID: 0,
  226. RefIsPull: false,
  227. RefAction: references.XRefActionNone,
  228. })
  229. // Edit content, neuter ref
  230. testIssueChangeInfo(t, "user2", issueRefURL, "content", "Description no ref")
  231. unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{
  232. IssueID: issueBase.ID,
  233. RefRepoID: 1,
  234. RefIssueID: issueRef.ID,
  235. RefCommentID: 0,
  236. RefIsPull: false,
  237. RefAction: references.XRefActionNeutered,
  238. })
  239. // Ref from a comment
  240. session := loginUser(t, "user2")
  241. commentID := testIssueAddComment(t, session, issueRefURL, fmt.Sprintf("Adding ref from comment #%d", issueBase.Index), "")
  242. comment := &issues_model.Comment{
  243. IssueID: issueBase.ID,
  244. RefRepoID: 1,
  245. RefIssueID: issueRef.ID,
  246. RefCommentID: commentID,
  247. RefIsPull: false,
  248. RefAction: references.XRefActionNone,
  249. }
  250. unittest.AssertExistsAndLoadBean(t, comment)
  251. // Ref from a different repository
  252. _, issueRef = testIssueWithBean(t, "user12", 10, "TitleXRef", fmt.Sprintf("Description ref user2/repo1#%d", issueBase.Index))
  253. unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{
  254. IssueID: issueBase.ID,
  255. RefRepoID: 10,
  256. RefIssueID: issueRef.ID,
  257. RefCommentID: 0,
  258. RefIsPull: false,
  259. RefAction: references.XRefActionNone,
  260. })
  261. }
  262. func testIssueWithBean(t *testing.T, user string, repoID int64, title, content string) (string, *issues_model.Issue) {
  263. session := loginUser(t, user)
  264. issueURL := testNewIssue(t, session, user, fmt.Sprintf("repo%d", repoID), title, content)
  265. indexStr := issueURL[strings.LastIndexByte(issueURL, '/')+1:]
  266. index, err := strconv.Atoi(indexStr)
  267. assert.NoError(t, err, "Invalid issue href: %s", issueURL)
  268. issue := &issues_model.Issue{RepoID: repoID, Index: int64(index)}
  269. unittest.AssertExistsAndLoadBean(t, issue)
  270. return issueURL, issue
  271. }
  272. func testIssueChangeInfo(t *testing.T, user, issueURL, info, value string) {
  273. session := loginUser(t, user)
  274. req := NewRequest(t, "GET", issueURL)
  275. resp := session.MakeRequest(t, req, http.StatusOK)
  276. htmlDoc := NewHTMLParser(t, resp.Body)
  277. req = NewRequestWithValues(t, "POST", path.Join(issueURL, info), map[string]string{
  278. "_csrf": htmlDoc.GetCSRF(),
  279. info: value,
  280. })
  281. _ = session.MakeRequest(t, req, http.StatusOK)
  282. }
  283. func TestIssueRedirect(t *testing.T) {
  284. defer prepareTestEnv(t)()
  285. session := loginUser(t, "user2")
  286. // Test external tracker where style not set (shall default numeric)
  287. req := NewRequest(t, "GET", path.Join("org26", "repo_external_tracker", "issues", "1"))
  288. resp := session.MakeRequest(t, req, http.StatusSeeOther)
  289. assert.Equal(t, "https://tracker.com/org26/repo_external_tracker/issues/1", test.RedirectURL(resp))
  290. // Test external tracker with numeric style
  291. req = NewRequest(t, "GET", path.Join("org26", "repo_external_tracker_numeric", "issues", "1"))
  292. resp = session.MakeRequest(t, req, http.StatusSeeOther)
  293. assert.Equal(t, "https://tracker.com/org26/repo_external_tracker_numeric/issues/1", test.RedirectURL(resp))
  294. // Test external tracker with alphanumeric style (for a pull request)
  295. req = NewRequest(t, "GET", path.Join("org26", "repo_external_tracker_alpha", "issues", "1"))
  296. resp = session.MakeRequest(t, req, http.StatusSeeOther)
  297. assert.Equal(t, "/"+path.Join("org26", "repo_external_tracker_alpha", "pulls", "1"), test.RedirectURL(resp))
  298. }
  299. func TestSearchIssues(t *testing.T) {
  300. defer prepareTestEnv(t)()
  301. session := loginUser(t, "user2")
  302. link, _ := url.Parse("/issues/search")
  303. req := NewRequest(t, "GET", link.String())
  304. resp := session.MakeRequest(t, req, http.StatusOK)
  305. var apiIssues []*api.Issue
  306. DecodeJSON(t, resp, &apiIssues)
  307. assert.Len(t, apiIssues, 10)
  308. req = NewRequest(t, "GET", link.String())
  309. resp = session.MakeRequest(t, req, http.StatusOK)
  310. DecodeJSON(t, resp, &apiIssues)
  311. assert.Len(t, apiIssues, 10)
  312. since := "2000-01-01T00%3A50%3A01%2B00%3A00" // 946687801
  313. before := time.Unix(999307200, 0).Format(time.RFC3339)
  314. query := url.Values{}
  315. query.Add("since", since)
  316. query.Add("before", before)
  317. link.RawQuery = query.Encode()
  318. req = NewRequest(t, "GET", link.String())
  319. resp = session.MakeRequest(t, req, http.StatusOK)
  320. DecodeJSON(t, resp, &apiIssues)
  321. assert.Len(t, apiIssues, 8)
  322. query.Del("since")
  323. query.Del("before")
  324. query.Add("state", "closed")
  325. link.RawQuery = query.Encode()
  326. req = NewRequest(t, "GET", link.String())
  327. resp = session.MakeRequest(t, req, http.StatusOK)
  328. DecodeJSON(t, resp, &apiIssues)
  329. assert.Len(t, apiIssues, 2)
  330. query.Set("state", "all")
  331. link.RawQuery = query.Encode()
  332. req = NewRequest(t, "GET", link.String())
  333. resp = session.MakeRequest(t, req, http.StatusOK)
  334. DecodeJSON(t, resp, &apiIssues)
  335. assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count"))
  336. assert.Len(t, apiIssues, 10) // there are more but 10 is page item limit
  337. query.Add("limit", "20")
  338. link.RawQuery = query.Encode()
  339. req = NewRequest(t, "GET", link.String())
  340. resp = session.MakeRequest(t, req, http.StatusOK)
  341. DecodeJSON(t, resp, &apiIssues)
  342. assert.Len(t, apiIssues, 17)
  343. query = url.Values{"assigned": {"true"}, "state": {"all"}}
  344. link.RawQuery = query.Encode()
  345. req = NewRequest(t, "GET", link.String())
  346. resp = session.MakeRequest(t, req, http.StatusOK)
  347. DecodeJSON(t, resp, &apiIssues)
  348. assert.Len(t, apiIssues, 2)
  349. query = url.Values{"milestones": {"milestone1"}, "state": {"all"}}
  350. link.RawQuery = query.Encode()
  351. req = NewRequest(t, "GET", link.String())
  352. resp = session.MakeRequest(t, req, http.StatusOK)
  353. DecodeJSON(t, resp, &apiIssues)
  354. assert.Len(t, apiIssues, 1)
  355. query = url.Values{"milestones": {"milestone1,milestone3"}, "state": {"all"}}
  356. link.RawQuery = query.Encode()
  357. req = NewRequest(t, "GET", link.String())
  358. resp = session.MakeRequest(t, req, http.StatusOK)
  359. DecodeJSON(t, resp, &apiIssues)
  360. assert.Len(t, apiIssues, 2)
  361. query = url.Values{"owner": {"user2"}} // user
  362. link.RawQuery = query.Encode()
  363. req = NewRequest(t, "GET", link.String())
  364. resp = session.MakeRequest(t, req, http.StatusOK)
  365. DecodeJSON(t, resp, &apiIssues)
  366. assert.Len(t, apiIssues, 6)
  367. query = url.Values{"owner": {"user3"}} // organization
  368. link.RawQuery = query.Encode()
  369. req = NewRequest(t, "GET", link.String())
  370. resp = session.MakeRequest(t, req, http.StatusOK)
  371. DecodeJSON(t, resp, &apiIssues)
  372. assert.Len(t, apiIssues, 5)
  373. query = url.Values{"owner": {"user3"}, "team": {"team1"}} // organization + team
  374. link.RawQuery = query.Encode()
  375. req = NewRequest(t, "GET", link.String())
  376. resp = session.MakeRequest(t, req, http.StatusOK)
  377. DecodeJSON(t, resp, &apiIssues)
  378. assert.Len(t, apiIssues, 2)
  379. }
  380. func TestSearchIssuesWithLabels(t *testing.T) {
  381. defer prepareTestEnv(t)()
  382. token := getUserToken(t, "user1")
  383. link, _ := url.Parse("/api/v1/repos/issues/search?token=" + token)
  384. req := NewRequest(t, "GET", link.String())
  385. resp := MakeRequest(t, req, http.StatusOK)
  386. var apiIssues []*api.Issue
  387. DecodeJSON(t, resp, &apiIssues)
  388. assert.Len(t, apiIssues, 10)
  389. query := url.Values{
  390. "token": []string{token},
  391. }
  392. link.RawQuery = query.Encode()
  393. req = NewRequest(t, "GET", link.String())
  394. resp = MakeRequest(t, req, http.StatusOK)
  395. DecodeJSON(t, resp, &apiIssues)
  396. assert.Len(t, apiIssues, 10)
  397. query.Add("labels", "label1")
  398. link.RawQuery = query.Encode()
  399. req = NewRequest(t, "GET", link.String())
  400. resp = MakeRequest(t, req, http.StatusOK)
  401. DecodeJSON(t, resp, &apiIssues)
  402. assert.Len(t, apiIssues, 2)
  403. // multiple labels
  404. query.Set("labels", "label1,label2")
  405. link.RawQuery = query.Encode()
  406. req = NewRequest(t, "GET", link.String())
  407. resp = MakeRequest(t, req, http.StatusOK)
  408. DecodeJSON(t, resp, &apiIssues)
  409. assert.Len(t, apiIssues, 2)
  410. // an org label
  411. query.Set("labels", "orglabel4")
  412. link.RawQuery = query.Encode()
  413. req = NewRequest(t, "GET", link.String())
  414. resp = MakeRequest(t, req, http.StatusOK)
  415. DecodeJSON(t, resp, &apiIssues)
  416. assert.Len(t, apiIssues, 1)
  417. // org and repo label
  418. query.Set("labels", "label2,orglabel4")
  419. query.Add("state", "all")
  420. link.RawQuery = query.Encode()
  421. req = NewRequest(t, "GET", link.String())
  422. resp = MakeRequest(t, req, http.StatusOK)
  423. DecodeJSON(t, resp, &apiIssues)
  424. assert.Len(t, apiIssues, 2)
  425. // org and repo label which share the same issue
  426. query.Set("labels", "label1,orglabel4")
  427. link.RawQuery = query.Encode()
  428. req = NewRequest(t, "GET", link.String())
  429. resp = MakeRequest(t, req, http.StatusOK)
  430. DecodeJSON(t, resp, &apiIssues)
  431. assert.Len(t, apiIssues, 2)
  432. }
  433. func TestGetIssueInfo(t *testing.T) {
  434. defer prepareTestEnv(t)()
  435. issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}).(*issues_model.Issue)
  436. repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
  437. owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
  438. assert.NoError(t, issue.LoadAttributes(db.DefaultContext))
  439. assert.Equal(t, int64(1019307200), int64(issue.DeadlineUnix))
  440. assert.Equal(t, api.StateOpen, issue.State())
  441. session := loginUser(t, owner.Name)
  442. urlStr := fmt.Sprintf("/%s/%s/issues/%d/info", owner.Name, repo.Name, issue.Index)
  443. req := NewRequest(t, "GET", urlStr)
  444. resp := session.MakeRequest(t, req, http.StatusOK)
  445. var apiIssue api.Issue
  446. DecodeJSON(t, resp, &apiIssue)
  447. assert.EqualValues(t, issue.ID, apiIssue.ID)
  448. }
  449. func TestUpdateIssueDeadline(t *testing.T) {
  450. defer prepareTestEnv(t)()
  451. issueBefore := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}).(*issues_model.Issue)
  452. repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}).(*repo_model.Repository)
  453. owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}).(*user_model.User)
  454. assert.NoError(t, issueBefore.LoadAttributes(db.DefaultContext))
  455. assert.Equal(t, int64(1019307200), int64(issueBefore.DeadlineUnix))
  456. assert.Equal(t, api.StateOpen, issueBefore.State())
  457. session := loginUser(t, owner.Name)
  458. issueURL := fmt.Sprintf("%s/%s/issues/%d", owner.Name, repoBefore.Name, issueBefore.Index)
  459. req := NewRequest(t, "GET", issueURL)
  460. resp := session.MakeRequest(t, req, http.StatusOK)
  461. htmlDoc := NewHTMLParser(t, resp.Body)
  462. urlStr := issueURL + "/deadline?_csrf=" + htmlDoc.GetCSRF()
  463. req = NewRequestWithJSON(t, "POST", urlStr, map[string]string{
  464. "due_date": "2022-04-06T00:00:00.000Z",
  465. })
  466. resp = session.MakeRequest(t, req, http.StatusCreated)
  467. var apiIssue api.IssueDeadline
  468. DecodeJSON(t, resp, &apiIssue)
  469. assert.EqualValues(t, "2022-04-06", apiIssue.Deadline.Format("2006-01-02"))
  470. }