gitea源码

milestone_test.go 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package issues_test
  4. import (
  5. "sort"
  6. "testing"
  7. "code.gitea.io/gitea/models/db"
  8. issues_model "code.gitea.io/gitea/models/issues"
  9. repo_model "code.gitea.io/gitea/models/repo"
  10. "code.gitea.io/gitea/models/unittest"
  11. "code.gitea.io/gitea/modules/optional"
  12. "code.gitea.io/gitea/modules/setting"
  13. api "code.gitea.io/gitea/modules/structs"
  14. "code.gitea.io/gitea/modules/timeutil"
  15. "github.com/stretchr/testify/assert"
  16. )
  17. func TestMilestone_State(t *testing.T) {
  18. assert.Equal(t, api.StateOpen, (&issues_model.Milestone{IsClosed: false}).State())
  19. assert.Equal(t, api.StateClosed, (&issues_model.Milestone{IsClosed: true}).State())
  20. }
  21. func TestGetMilestoneByRepoID(t *testing.T) {
  22. assert.NoError(t, unittest.PrepareTestDatabase())
  23. milestone, err := issues_model.GetMilestoneByRepoID(t.Context(), 1, 1)
  24. assert.NoError(t, err)
  25. assert.EqualValues(t, 1, milestone.ID)
  26. assert.EqualValues(t, 1, milestone.RepoID)
  27. _, err = issues_model.GetMilestoneByRepoID(t.Context(), unittest.NonexistentID, unittest.NonexistentID)
  28. assert.True(t, issues_model.IsErrMilestoneNotExist(err))
  29. }
  30. func TestGetMilestonesByRepoID(t *testing.T) {
  31. assert.NoError(t, unittest.PrepareTestDatabase())
  32. test := func(repoID int64, state api.StateType) {
  33. var isClosed optional.Option[bool]
  34. switch state {
  35. case api.StateClosed, api.StateOpen:
  36. isClosed = optional.Some(state == api.StateClosed)
  37. }
  38. repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})
  39. milestones, err := db.Find[issues_model.Milestone](t.Context(), issues_model.FindMilestoneOptions{
  40. RepoID: repo.ID,
  41. IsClosed: isClosed,
  42. })
  43. assert.NoError(t, err)
  44. var n int
  45. switch state {
  46. case api.StateClosed:
  47. n = repo.NumClosedMilestones
  48. case api.StateAll:
  49. n = repo.NumMilestones
  50. case api.StateOpen:
  51. fallthrough
  52. default:
  53. n = repo.NumOpenMilestones
  54. }
  55. assert.Len(t, milestones, n)
  56. for _, milestone := range milestones {
  57. assert.Equal(t, repoID, milestone.RepoID)
  58. }
  59. }
  60. test(1, api.StateOpen)
  61. test(1, api.StateAll)
  62. test(1, api.StateClosed)
  63. test(2, api.StateOpen)
  64. test(2, api.StateAll)
  65. test(2, api.StateClosed)
  66. test(3, api.StateOpen)
  67. test(3, api.StateClosed)
  68. test(3, api.StateAll)
  69. milestones, err := db.Find[issues_model.Milestone](t.Context(), issues_model.FindMilestoneOptions{
  70. RepoID: unittest.NonexistentID,
  71. IsClosed: optional.Some(false),
  72. })
  73. assert.NoError(t, err)
  74. assert.Empty(t, milestones)
  75. }
  76. func TestGetMilestones(t *testing.T) {
  77. assert.NoError(t, unittest.PrepareTestDatabase())
  78. repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
  79. test := func(sortType string, sortCond func(*issues_model.Milestone) int) {
  80. for _, page := range []int{0, 1} {
  81. milestones, err := db.Find[issues_model.Milestone](t.Context(), issues_model.FindMilestoneOptions{
  82. ListOptions: db.ListOptions{
  83. Page: page,
  84. PageSize: setting.UI.IssuePagingNum,
  85. },
  86. RepoID: repo.ID,
  87. IsClosed: optional.Some(false),
  88. SortType: sortType,
  89. })
  90. assert.NoError(t, err)
  91. assert.Len(t, milestones, repo.NumMilestones-repo.NumClosedMilestones)
  92. values := make([]int, len(milestones))
  93. for i, milestone := range milestones {
  94. values[i] = sortCond(milestone)
  95. }
  96. assert.True(t, sort.IntsAreSorted(values))
  97. milestones, err = db.Find[issues_model.Milestone](t.Context(), issues_model.FindMilestoneOptions{
  98. ListOptions: db.ListOptions{
  99. Page: page,
  100. PageSize: setting.UI.IssuePagingNum,
  101. },
  102. RepoID: repo.ID,
  103. IsClosed: optional.Some(true),
  104. Name: "",
  105. SortType: sortType,
  106. })
  107. assert.NoError(t, err)
  108. assert.Len(t, milestones, repo.NumClosedMilestones)
  109. values = make([]int, len(milestones))
  110. for i, milestone := range milestones {
  111. values[i] = sortCond(milestone)
  112. }
  113. assert.True(t, sort.IntsAreSorted(values))
  114. }
  115. }
  116. test("furthestduedate", func(milestone *issues_model.Milestone) int {
  117. return -int(milestone.DeadlineUnix)
  118. })
  119. test("leastcomplete", func(milestone *issues_model.Milestone) int {
  120. return milestone.Completeness
  121. })
  122. test("mostcomplete", func(milestone *issues_model.Milestone) int {
  123. return -milestone.Completeness
  124. })
  125. test("leastissues", func(milestone *issues_model.Milestone) int {
  126. return milestone.NumIssues
  127. })
  128. test("mostissues", func(milestone *issues_model.Milestone) int {
  129. return -milestone.NumIssues
  130. })
  131. test("soonestduedate", func(milestone *issues_model.Milestone) int {
  132. return int(milestone.DeadlineUnix)
  133. })
  134. }
  135. func TestCountRepoMilestones(t *testing.T) {
  136. assert.NoError(t, unittest.PrepareTestDatabase())
  137. test := func(repoID int64) {
  138. repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})
  139. count, err := db.Count[issues_model.Milestone](t.Context(), issues_model.FindMilestoneOptions{
  140. RepoID: repoID,
  141. })
  142. assert.NoError(t, err)
  143. assert.EqualValues(t, repo.NumMilestones, count)
  144. }
  145. test(1)
  146. test(2)
  147. test(3)
  148. count, err := db.Count[issues_model.Milestone](t.Context(), issues_model.FindMilestoneOptions{
  149. RepoID: unittest.NonexistentID,
  150. })
  151. assert.NoError(t, err)
  152. assert.EqualValues(t, 0, count)
  153. }
  154. func TestCountRepoClosedMilestones(t *testing.T) {
  155. assert.NoError(t, unittest.PrepareTestDatabase())
  156. test := func(repoID int64) {
  157. repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})
  158. count, err := db.Count[issues_model.Milestone](t.Context(), issues_model.FindMilestoneOptions{
  159. RepoID: repoID,
  160. IsClosed: optional.Some(true),
  161. })
  162. assert.NoError(t, err)
  163. assert.EqualValues(t, repo.NumClosedMilestones, count)
  164. }
  165. test(1)
  166. test(2)
  167. test(3)
  168. count, err := db.Count[issues_model.Milestone](t.Context(), issues_model.FindMilestoneOptions{
  169. RepoID: unittest.NonexistentID,
  170. IsClosed: optional.Some(true),
  171. })
  172. assert.NoError(t, err)
  173. assert.EqualValues(t, 0, count)
  174. }
  175. func TestCountMilestonesByRepoIDs(t *testing.T) {
  176. assert.NoError(t, unittest.PrepareTestDatabase())
  177. milestonesCount := func(repoID int64) (int, int) {
  178. repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})
  179. return repo.NumOpenMilestones, repo.NumClosedMilestones
  180. }
  181. repo1OpenCount, repo1ClosedCount := milestonesCount(1)
  182. repo2OpenCount, repo2ClosedCount := milestonesCount(2)
  183. openCounts, err := issues_model.CountMilestonesMap(t.Context(), issues_model.FindMilestoneOptions{
  184. RepoIDs: []int64{1, 2},
  185. IsClosed: optional.Some(false),
  186. })
  187. assert.NoError(t, err)
  188. assert.EqualValues(t, repo1OpenCount, openCounts[1])
  189. assert.EqualValues(t, repo2OpenCount, openCounts[2])
  190. closedCounts, err := issues_model.CountMilestonesMap(t.Context(),
  191. issues_model.FindMilestoneOptions{
  192. RepoIDs: []int64{1, 2},
  193. IsClosed: optional.Some(true),
  194. })
  195. assert.NoError(t, err)
  196. assert.EqualValues(t, repo1ClosedCount, closedCounts[1])
  197. assert.EqualValues(t, repo2ClosedCount, closedCounts[2])
  198. }
  199. func TestGetMilestonesByRepoIDs(t *testing.T) {
  200. assert.NoError(t, unittest.PrepareTestDatabase())
  201. repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
  202. repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
  203. test := func(sortType string, sortCond func(*issues_model.Milestone) int) {
  204. for _, page := range []int{0, 1} {
  205. openMilestones, err := db.Find[issues_model.Milestone](t.Context(), issues_model.FindMilestoneOptions{
  206. ListOptions: db.ListOptions{
  207. Page: page,
  208. PageSize: setting.UI.IssuePagingNum,
  209. },
  210. RepoIDs: []int64{repo1.ID, repo2.ID},
  211. IsClosed: optional.Some(false),
  212. SortType: sortType,
  213. })
  214. assert.NoError(t, err)
  215. assert.Len(t, openMilestones, repo1.NumOpenMilestones+repo2.NumOpenMilestones)
  216. values := make([]int, len(openMilestones))
  217. for i, milestone := range openMilestones {
  218. values[i] = sortCond(milestone)
  219. }
  220. assert.True(t, sort.IntsAreSorted(values))
  221. closedMilestones, err := db.Find[issues_model.Milestone](t.Context(),
  222. issues_model.FindMilestoneOptions{
  223. ListOptions: db.ListOptions{
  224. Page: page,
  225. PageSize: setting.UI.IssuePagingNum,
  226. },
  227. RepoIDs: []int64{repo1.ID, repo2.ID},
  228. IsClosed: optional.Some(true),
  229. SortType: sortType,
  230. })
  231. assert.NoError(t, err)
  232. assert.Len(t, closedMilestones, repo1.NumClosedMilestones+repo2.NumClosedMilestones)
  233. values = make([]int, len(closedMilestones))
  234. for i, milestone := range closedMilestones {
  235. values[i] = sortCond(milestone)
  236. }
  237. assert.True(t, sort.IntsAreSorted(values))
  238. }
  239. }
  240. test("furthestduedate", func(milestone *issues_model.Milestone) int {
  241. return -int(milestone.DeadlineUnix)
  242. })
  243. test("leastcomplete", func(milestone *issues_model.Milestone) int {
  244. return milestone.Completeness
  245. })
  246. test("mostcomplete", func(milestone *issues_model.Milestone) int {
  247. return -milestone.Completeness
  248. })
  249. test("leastissues", func(milestone *issues_model.Milestone) int {
  250. return milestone.NumIssues
  251. })
  252. test("mostissues", func(milestone *issues_model.Milestone) int {
  253. return -milestone.NumIssues
  254. })
  255. test("soonestduedate", func(milestone *issues_model.Milestone) int {
  256. return int(milestone.DeadlineUnix)
  257. })
  258. }
  259. func TestNewMilestone(t *testing.T) {
  260. assert.NoError(t, unittest.PrepareTestDatabase())
  261. milestone := &issues_model.Milestone{
  262. RepoID: 1,
  263. Name: "milestoneName",
  264. Content: "milestoneContent",
  265. }
  266. assert.NoError(t, issues_model.NewMilestone(t.Context(), milestone))
  267. unittest.AssertExistsAndLoadBean(t, milestone)
  268. unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &issues_model.Milestone{})
  269. }
  270. func TestChangeMilestoneStatus(t *testing.T) {
  271. assert.NoError(t, unittest.PrepareTestDatabase())
  272. milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1})
  273. assert.NoError(t, issues_model.ChangeMilestoneStatus(t.Context(), milestone, true))
  274. unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}, "is_closed=1")
  275. unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &issues_model.Milestone{})
  276. assert.NoError(t, issues_model.ChangeMilestoneStatus(t.Context(), milestone, false))
  277. unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}, "is_closed=0")
  278. unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &issues_model.Milestone{})
  279. }
  280. func TestDeleteMilestoneByRepoID(t *testing.T) {
  281. assert.NoError(t, unittest.PrepareTestDatabase())
  282. assert.NoError(t, issues_model.DeleteMilestoneByRepoID(t.Context(), 1, 1))
  283. unittest.AssertNotExistsBean(t, &issues_model.Milestone{ID: 1})
  284. unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: 1})
  285. assert.NoError(t, issues_model.DeleteMilestoneByRepoID(t.Context(), unittest.NonexistentID, unittest.NonexistentID))
  286. }
  287. func TestUpdateMilestone(t *testing.T) {
  288. assert.NoError(t, unittest.PrepareTestDatabase())
  289. milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1})
  290. milestone.Name = " newMilestoneName "
  291. milestone.Content = "newMilestoneContent"
  292. assert.NoError(t, issues_model.UpdateMilestone(t.Context(), milestone, milestone.IsClosed))
  293. milestone = unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1})
  294. assert.Equal(t, "newMilestoneName", milestone.Name)
  295. unittest.CheckConsistencyFor(t, &issues_model.Milestone{})
  296. }
  297. func TestUpdateMilestoneCounters(t *testing.T) {
  298. assert.NoError(t, unittest.PrepareTestDatabase())
  299. issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{MilestoneID: 1},
  300. "is_closed=0")
  301. issue.IsClosed = true
  302. issue.ClosedUnix = timeutil.TimeStampNow()
  303. _, err := db.GetEngine(t.Context()).ID(issue.ID).Cols("is_closed", "closed_unix").Update(issue)
  304. assert.NoError(t, err)
  305. assert.NoError(t, issues_model.UpdateMilestoneCounters(t.Context(), issue.MilestoneID))
  306. unittest.CheckConsistencyFor(t, &issues_model.Milestone{})
  307. issue.IsClosed = false
  308. issue.ClosedUnix = 0
  309. _, err = db.GetEngine(t.Context()).ID(issue.ID).Cols("is_closed", "closed_unix").Update(issue)
  310. assert.NoError(t, err)
  311. assert.NoError(t, issues_model.UpdateMilestoneCounters(t.Context(), issue.MilestoneID))
  312. unittest.CheckConsistencyFor(t, &issues_model.Milestone{})
  313. }
  314. func TestMigrate_InsertMilestones(t *testing.T) {
  315. assert.NoError(t, unittest.PrepareTestDatabase())
  316. reponame := "repo1"
  317. repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame})
  318. name := "milestonetest1"
  319. ms := &issues_model.Milestone{
  320. RepoID: repo.ID,
  321. Name: name,
  322. }
  323. err := issues_model.InsertMilestones(t.Context(), ms)
  324. assert.NoError(t, err)
  325. unittest.AssertExistsAndLoadBean(t, ms)
  326. repoModified := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID})
  327. assert.Equal(t, repo.NumMilestones+1, repoModified.NumMilestones)
  328. unittest.CheckConsistencyFor(t, &issues_model.Milestone{})
  329. }