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_milestone_test.go 12KB

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