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.

api_issue_test.go 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package integration
  4. import (
  5. "fmt"
  6. "net/http"
  7. "net/url"
  8. "testing"
  9. "time"
  10. "code.gitea.io/gitea/models/db"
  11. issues_model "code.gitea.io/gitea/models/issues"
  12. repo_model "code.gitea.io/gitea/models/repo"
  13. "code.gitea.io/gitea/models/unittest"
  14. user_model "code.gitea.io/gitea/models/user"
  15. "code.gitea.io/gitea/modules/setting"
  16. api "code.gitea.io/gitea/modules/structs"
  17. "code.gitea.io/gitea/tests"
  18. "github.com/stretchr/testify/assert"
  19. )
  20. func TestAPIListIssues(t *testing.T) {
  21. defer tests.PrepareTestEnv(t)()
  22. repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
  23. owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
  24. session := loginUser(t, owner.Name)
  25. token := getTokenForLoggedInUser(t, session)
  26. link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/issues", owner.Name, repo.Name))
  27. link.RawQuery = url.Values{"token": {token}, "state": {"all"}}.Encode()
  28. resp := session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
  29. var apiIssues []*api.Issue
  30. DecodeJSON(t, resp, &apiIssues)
  31. assert.Len(t, apiIssues, unittest.GetCount(t, &issues_model.Issue{RepoID: repo.ID}))
  32. for _, apiIssue := range apiIssues {
  33. unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: apiIssue.ID, RepoID: repo.ID})
  34. }
  35. // test milestone filter
  36. link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "type": {"all"}, "milestones": {"ignore,milestone1,3,4"}}.Encode()
  37. resp = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
  38. DecodeJSON(t, resp, &apiIssues)
  39. if assert.Len(t, apiIssues, 2) {
  40. assert.EqualValues(t, 3, apiIssues[0].Milestone.ID)
  41. assert.EqualValues(t, 1, apiIssues[1].Milestone.ID)
  42. }
  43. link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "created_by": {"user2"}}.Encode()
  44. resp = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
  45. DecodeJSON(t, resp, &apiIssues)
  46. if assert.Len(t, apiIssues, 1) {
  47. assert.EqualValues(t, 5, apiIssues[0].ID)
  48. }
  49. link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "assigned_by": {"user1"}}.Encode()
  50. resp = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
  51. DecodeJSON(t, resp, &apiIssues)
  52. if assert.Len(t, apiIssues, 1) {
  53. assert.EqualValues(t, 1, apiIssues[0].ID)
  54. }
  55. link.RawQuery = url.Values{"token": {token}, "state": {"all"}, "mentioned_by": {"user4"}}.Encode()
  56. resp = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
  57. DecodeJSON(t, resp, &apiIssues)
  58. if assert.Len(t, apiIssues, 1) {
  59. assert.EqualValues(t, 1, apiIssues[0].ID)
  60. }
  61. }
  62. func TestAPICreateIssue(t *testing.T) {
  63. defer tests.PrepareTestEnv(t)()
  64. const body, title = "apiTestBody", "apiTestTitle"
  65. repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
  66. owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID})
  67. session := loginUser(t, owner.Name)
  68. token := getTokenForLoggedInUser(t, session)
  69. urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues?state=all&token=%s", owner.Name, repoBefore.Name, token)
  70. req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateIssueOption{
  71. Body: body,
  72. Title: title,
  73. Assignee: owner.Name,
  74. })
  75. resp := session.MakeRequest(t, req, http.StatusCreated)
  76. var apiIssue api.Issue
  77. DecodeJSON(t, resp, &apiIssue)
  78. assert.Equal(t, body, apiIssue.Body)
  79. assert.Equal(t, title, apiIssue.Title)
  80. unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{
  81. RepoID: repoBefore.ID,
  82. AssigneeID: owner.ID,
  83. Content: body,
  84. Title: title,
  85. })
  86. repoAfter := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
  87. assert.Equal(t, repoBefore.NumIssues+1, repoAfter.NumIssues)
  88. assert.Equal(t, repoBefore.NumClosedIssues, repoAfter.NumClosedIssues)
  89. }
  90. func TestAPIEditIssue(t *testing.T) {
  91. defer tests.PrepareTestEnv(t)()
  92. issueBefore := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10})
  93. repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID})
  94. owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID})
  95. assert.NoError(t, issueBefore.LoadAttributes(db.DefaultContext))
  96. assert.Equal(t, int64(1019307200), int64(issueBefore.DeadlineUnix))
  97. assert.Equal(t, api.StateOpen, issueBefore.State())
  98. session := loginUser(t, owner.Name)
  99. token := getTokenForLoggedInUser(t, session)
  100. // update values of issue
  101. issueState := "closed"
  102. removeDeadline := true
  103. milestone := int64(4)
  104. body := "new content!"
  105. title := "new title from api set"
  106. urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d?token=%s", owner.Name, repoBefore.Name, issueBefore.Index, token)
  107. req := NewRequestWithJSON(t, "PATCH", urlStr, api.EditIssueOption{
  108. State: &issueState,
  109. RemoveDeadline: &removeDeadline,
  110. Milestone: &milestone,
  111. Body: &body,
  112. Title: title,
  113. // ToDo change more
  114. })
  115. resp := session.MakeRequest(t, req, http.StatusCreated)
  116. var apiIssue api.Issue
  117. DecodeJSON(t, resp, &apiIssue)
  118. issueAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10})
  119. repoAfter := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID})
  120. // check deleted user
  121. assert.Equal(t, int64(500), issueAfter.PosterID)
  122. assert.NoError(t, issueAfter.LoadAttributes(db.DefaultContext))
  123. assert.Equal(t, int64(-1), issueAfter.PosterID)
  124. assert.Equal(t, int64(-1), issueBefore.PosterID)
  125. assert.Equal(t, int64(-1), apiIssue.Poster.ID)
  126. // check repo change
  127. assert.Equal(t, repoBefore.NumClosedIssues+1, repoAfter.NumClosedIssues)
  128. // API response
  129. assert.Equal(t, api.StateClosed, apiIssue.State)
  130. assert.Equal(t, milestone, apiIssue.Milestone.ID)
  131. assert.Equal(t, body, apiIssue.Body)
  132. assert.True(t, apiIssue.Deadline == nil)
  133. assert.Equal(t, title, apiIssue.Title)
  134. // in database
  135. assert.Equal(t, api.StateClosed, issueAfter.State())
  136. assert.Equal(t, milestone, issueAfter.MilestoneID)
  137. assert.Equal(t, int64(0), int64(issueAfter.DeadlineUnix))
  138. assert.Equal(t, body, issueAfter.Content)
  139. assert.Equal(t, title, issueAfter.Title)
  140. }
  141. func TestAPISearchIssues(t *testing.T) {
  142. defer tests.PrepareTestEnv(t)()
  143. token := getUserToken(t, "user2")
  144. // as this API was used in the frontend, it uses UI page size
  145. expectedIssueCount := 15 // from the fixtures
  146. if expectedIssueCount > setting.UI.IssuePagingNum {
  147. expectedIssueCount = setting.UI.IssuePagingNum
  148. }
  149. link, _ := url.Parse("/api/v1/repos/issues/search")
  150. query := url.Values{"token": {getUserToken(t, "user1")}}
  151. var apiIssues []*api.Issue
  152. link.RawQuery = query.Encode()
  153. req := NewRequest(t, "GET", link.String())
  154. resp := MakeRequest(t, req, http.StatusOK)
  155. DecodeJSON(t, resp, &apiIssues)
  156. assert.Len(t, apiIssues, expectedIssueCount)
  157. since := "2000-01-01T00%3A50%3A01%2B00%3A00" // 946687801
  158. before := time.Unix(999307200, 0).Format(time.RFC3339)
  159. query.Add("since", since)
  160. query.Add("before", before)
  161. query.Add("token", token)
  162. link.RawQuery = query.Encode()
  163. req = NewRequest(t, "GET", link.String())
  164. resp = MakeRequest(t, req, http.StatusOK)
  165. DecodeJSON(t, resp, &apiIssues)
  166. assert.Len(t, apiIssues, 8)
  167. query.Del("since")
  168. query.Del("before")
  169. query.Add("state", "closed")
  170. link.RawQuery = query.Encode()
  171. req = NewRequest(t, "GET", link.String())
  172. resp = MakeRequest(t, req, http.StatusOK)
  173. DecodeJSON(t, resp, &apiIssues)
  174. assert.Len(t, apiIssues, 2)
  175. query.Set("state", "all")
  176. link.RawQuery = query.Encode()
  177. req = NewRequest(t, "GET", link.String())
  178. resp = MakeRequest(t, req, http.StatusOK)
  179. DecodeJSON(t, resp, &apiIssues)
  180. assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count"))
  181. assert.Len(t, apiIssues, 17)
  182. query.Add("limit", "10")
  183. link.RawQuery = query.Encode()
  184. req = NewRequest(t, "GET", link.String())
  185. resp = MakeRequest(t, req, http.StatusOK)
  186. DecodeJSON(t, resp, &apiIssues)
  187. assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count"))
  188. assert.Len(t, apiIssues, 10)
  189. query = url.Values{"assigned": {"true"}, "state": {"all"}, "token": {token}}
  190. link.RawQuery = query.Encode()
  191. req = NewRequest(t, "GET", link.String())
  192. resp = MakeRequest(t, req, http.StatusOK)
  193. DecodeJSON(t, resp, &apiIssues)
  194. assert.Len(t, apiIssues, 2)
  195. query = url.Values{"milestones": {"milestone1"}, "state": {"all"}, "token": {token}}
  196. link.RawQuery = query.Encode()
  197. req = NewRequest(t, "GET", link.String())
  198. resp = MakeRequest(t, req, http.StatusOK)
  199. DecodeJSON(t, resp, &apiIssues)
  200. assert.Len(t, apiIssues, 1)
  201. query = url.Values{"milestones": {"milestone1,milestone3"}, "state": {"all"}, "token": {token}}
  202. link.RawQuery = query.Encode()
  203. req = NewRequest(t, "GET", link.String())
  204. resp = MakeRequest(t, req, http.StatusOK)
  205. DecodeJSON(t, resp, &apiIssues)
  206. assert.Len(t, apiIssues, 2)
  207. query = url.Values{"owner": {"user2"}, "token": {token}} // user
  208. link.RawQuery = query.Encode()
  209. req = NewRequest(t, "GET", link.String())
  210. resp = MakeRequest(t, req, http.StatusOK)
  211. DecodeJSON(t, resp, &apiIssues)
  212. assert.Len(t, apiIssues, 6)
  213. query = url.Values{"owner": {"user3"}, "token": {token}} // organization
  214. link.RawQuery = query.Encode()
  215. req = NewRequest(t, "GET", link.String())
  216. resp = MakeRequest(t, req, http.StatusOK)
  217. DecodeJSON(t, resp, &apiIssues)
  218. assert.Len(t, apiIssues, 5)
  219. query = url.Values{"owner": {"user3"}, "team": {"team1"}, "token": {token}} // organization + team
  220. link.RawQuery = query.Encode()
  221. req = NewRequest(t, "GET", link.String())
  222. resp = MakeRequest(t, req, http.StatusOK)
  223. DecodeJSON(t, resp, &apiIssues)
  224. assert.Len(t, apiIssues, 2)
  225. }
  226. func TestAPISearchIssuesWithLabels(t *testing.T) {
  227. defer tests.PrepareTestEnv(t)()
  228. // as this API was used in the frontend, it uses UI page size
  229. expectedIssueCount := 15 // from the fixtures
  230. if expectedIssueCount > setting.UI.IssuePagingNum {
  231. expectedIssueCount = setting.UI.IssuePagingNum
  232. }
  233. link, _ := url.Parse("/api/v1/repos/issues/search")
  234. query := url.Values{"token": {getUserToken(t, "user1")}}
  235. var apiIssues []*api.Issue
  236. link.RawQuery = query.Encode()
  237. req := NewRequest(t, "GET", link.String())
  238. resp := MakeRequest(t, req, http.StatusOK)
  239. DecodeJSON(t, resp, &apiIssues)
  240. assert.Len(t, apiIssues, expectedIssueCount)
  241. query.Add("labels", "label1")
  242. link.RawQuery = query.Encode()
  243. req = NewRequest(t, "GET", link.String())
  244. resp = MakeRequest(t, req, http.StatusOK)
  245. DecodeJSON(t, resp, &apiIssues)
  246. assert.Len(t, apiIssues, 2)
  247. // multiple labels
  248. query.Set("labels", "label1,label2")
  249. link.RawQuery = query.Encode()
  250. req = NewRequest(t, "GET", link.String())
  251. resp = MakeRequest(t, req, http.StatusOK)
  252. DecodeJSON(t, resp, &apiIssues)
  253. assert.Len(t, apiIssues, 2)
  254. // an org label
  255. query.Set("labels", "orglabel4")
  256. link.RawQuery = query.Encode()
  257. req = NewRequest(t, "GET", link.String())
  258. resp = MakeRequest(t, req, http.StatusOK)
  259. DecodeJSON(t, resp, &apiIssues)
  260. assert.Len(t, apiIssues, 1)
  261. // org and repo label
  262. query.Set("labels", "label2,orglabel4")
  263. query.Add("state", "all")
  264. link.RawQuery = query.Encode()
  265. req = NewRequest(t, "GET", link.String())
  266. resp = MakeRequest(t, req, http.StatusOK)
  267. DecodeJSON(t, resp, &apiIssues)
  268. assert.Len(t, apiIssues, 2)
  269. // org and repo label which share the same issue
  270. query.Set("labels", "label1,orglabel4")
  271. link.RawQuery = query.Encode()
  272. req = NewRequest(t, "GET", link.String())
  273. resp = MakeRequest(t, req, http.StatusOK)
  274. DecodeJSON(t, resp, &apiIssues)
  275. assert.Len(t, apiIssues, 2)
  276. }