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

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