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 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  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. "context"
  7. "fmt"
  8. "sort"
  9. "strconv"
  10. "sync"
  11. "testing"
  12. "time"
  13. "code.gitea.io/gitea/models/db"
  14. "code.gitea.io/gitea/models/foreignreference"
  15. issues_model "code.gitea.io/gitea/models/issues"
  16. "code.gitea.io/gitea/models/organization"
  17. repo_model "code.gitea.io/gitea/models/repo"
  18. "code.gitea.io/gitea/models/unittest"
  19. user_model "code.gitea.io/gitea/models/user"
  20. "github.com/stretchr/testify/assert"
  21. "xorm.io/builder"
  22. )
  23. func TestIssue_ReplaceLabels(t *testing.T) {
  24. assert.NoError(t, unittest.PrepareTestDatabase())
  25. testSuccess := func(issueID int64, labelIDs []int64) {
  26. issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: issueID}).(*Issue)
  27. repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository)
  28. doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
  29. labels := make([]*Label, len(labelIDs))
  30. for i, labelID := range labelIDs {
  31. labels[i] = unittest.AssertExistsAndLoadBean(t, &Label{ID: labelID, RepoID: repo.ID}).(*Label)
  32. }
  33. assert.NoError(t, ReplaceIssueLabels(issue, labels, doer))
  34. unittest.AssertCount(t, &IssueLabel{IssueID: issueID}, len(labelIDs))
  35. for _, labelID := range labelIDs {
  36. unittest.AssertExistsAndLoadBean(t, &IssueLabel{IssueID: issueID, LabelID: labelID})
  37. }
  38. }
  39. testSuccess(1, []int64{2})
  40. testSuccess(1, []int64{1, 2})
  41. testSuccess(1, []int64{})
  42. }
  43. func Test_GetIssueIDsByRepoID(t *testing.T) {
  44. assert.NoError(t, unittest.PrepareTestDatabase())
  45. ids, err := GetIssueIDsByRepoID(db.DefaultContext, 1)
  46. assert.NoError(t, err)
  47. assert.Len(t, ids, 5)
  48. }
  49. func TestIssueAPIURL(t *testing.T) {
  50. assert.NoError(t, unittest.PrepareTestDatabase())
  51. issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
  52. err := issue.LoadAttributes()
  53. assert.NoError(t, err)
  54. assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/issues/1", issue.APIURL())
  55. }
  56. func TestGetIssuesByIDs(t *testing.T) {
  57. assert.NoError(t, unittest.PrepareTestDatabase())
  58. testSuccess := func(expectedIssueIDs, nonExistentIssueIDs []int64) {
  59. issues, err := GetIssuesByIDs(db.DefaultContext, append(expectedIssueIDs, nonExistentIssueIDs...))
  60. assert.NoError(t, err)
  61. actualIssueIDs := make([]int64, len(issues))
  62. for i, issue := range issues {
  63. actualIssueIDs[i] = issue.ID
  64. }
  65. assert.Equal(t, expectedIssueIDs, actualIssueIDs)
  66. }
  67. testSuccess([]int64{1, 2, 3}, []int64{})
  68. testSuccess([]int64{1, 2, 3}, []int64{unittest.NonexistentID})
  69. }
  70. func TestGetParticipantIDsByIssue(t *testing.T) {
  71. assert.NoError(t, unittest.PrepareTestDatabase())
  72. checkParticipants := func(issueID int64, userIDs []int) {
  73. issue, err := GetIssueByID(issueID)
  74. assert.NoError(t, err)
  75. participants, err := issue.getParticipantIDsByIssue(db.DefaultContext)
  76. if assert.NoError(t, err) {
  77. participantsIDs := make([]int, len(participants))
  78. for i, uid := range participants {
  79. participantsIDs[i] = int(uid)
  80. }
  81. sort.Ints(participantsIDs)
  82. sort.Ints(userIDs)
  83. assert.Equal(t, userIDs, participantsIDs)
  84. }
  85. }
  86. // User 1 is issue1 poster (see fixtures/issue.yml)
  87. // User 2 only labeled issue1 (see fixtures/comment.yml)
  88. // Users 3 and 5 made actual comments (see fixtures/comment.yml)
  89. // User 3 is inactive, thus not active participant
  90. checkParticipants(1, []int{1, 5})
  91. }
  92. func TestIssue_ClearLabels(t *testing.T) {
  93. tests := []struct {
  94. issueID int64
  95. doerID int64
  96. }{
  97. {1, 2}, // non-pull-request, has labels
  98. {2, 2}, // pull-request, has labels
  99. {3, 2}, // pull-request, has no labels
  100. }
  101. for _, test := range tests {
  102. assert.NoError(t, unittest.PrepareTestDatabase())
  103. issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: test.issueID}).(*Issue)
  104. doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: test.doerID}).(*user_model.User)
  105. assert.NoError(t, ClearIssueLabels(issue, doer))
  106. unittest.AssertNotExistsBean(t, &IssueLabel{IssueID: test.issueID})
  107. }
  108. }
  109. func TestUpdateIssueCols(t *testing.T) {
  110. assert.NoError(t, unittest.PrepareTestDatabase())
  111. issue := unittest.AssertExistsAndLoadBean(t, &Issue{}).(*Issue)
  112. const newTitle = "New Title for unit test"
  113. issue.Title = newTitle
  114. prevContent := issue.Content
  115. issue.Content = "This should have no effect"
  116. now := time.Now().Unix()
  117. assert.NoError(t, UpdateIssueCols(db.DefaultContext, issue, "name"))
  118. then := time.Now().Unix()
  119. updatedIssue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: issue.ID}).(*Issue)
  120. assert.EqualValues(t, newTitle, updatedIssue.Title)
  121. assert.EqualValues(t, prevContent, updatedIssue.Content)
  122. unittest.AssertInt64InRange(t, now, then, int64(updatedIssue.UpdatedUnix))
  123. }
  124. func TestIssues(t *testing.T) {
  125. assert.NoError(t, unittest.PrepareTestDatabase())
  126. for _, test := range []struct {
  127. Opts IssuesOptions
  128. ExpectedIssueIDs []int64
  129. }{
  130. {
  131. IssuesOptions{
  132. AssigneeID: 1,
  133. SortType: "oldest",
  134. },
  135. []int64{1, 6},
  136. },
  137. {
  138. IssuesOptions{
  139. RepoCond: builder.In("repo_id", 1, 3),
  140. SortType: "oldest",
  141. ListOptions: db.ListOptions{
  142. Page: 1,
  143. PageSize: 4,
  144. },
  145. },
  146. []int64{1, 2, 3, 5},
  147. },
  148. {
  149. IssuesOptions{
  150. LabelIDs: []int64{1},
  151. ListOptions: db.ListOptions{
  152. Page: 1,
  153. PageSize: 4,
  154. },
  155. },
  156. []int64{2, 1},
  157. },
  158. {
  159. IssuesOptions{
  160. LabelIDs: []int64{1, 2},
  161. ListOptions: db.ListOptions{
  162. Page: 1,
  163. PageSize: 4,
  164. },
  165. },
  166. []int64{}, // issues with **both** label 1 and 2, none of these issues matches, TODO: add more tests
  167. },
  168. } {
  169. issues, err := Issues(&test.Opts)
  170. assert.NoError(t, err)
  171. if assert.Len(t, issues, len(test.ExpectedIssueIDs)) {
  172. for i, issue := range issues {
  173. assert.EqualValues(t, test.ExpectedIssueIDs[i], issue.ID)
  174. }
  175. }
  176. }
  177. }
  178. func TestGetUserIssueStats(t *testing.T) {
  179. assert.NoError(t, unittest.PrepareTestDatabase())
  180. for _, test := range []struct {
  181. Opts UserIssueStatsOptions
  182. ExpectedIssueStats IssueStats
  183. }{
  184. {
  185. UserIssueStatsOptions{
  186. UserID: 1,
  187. RepoIDs: []int64{1},
  188. FilterMode: FilterModeAll,
  189. },
  190. IssueStats{
  191. YourRepositoriesCount: 1, // 6
  192. AssignCount: 1, // 6
  193. CreateCount: 1, // 6
  194. OpenCount: 1, // 6
  195. ClosedCount: 1, // 1
  196. },
  197. },
  198. {
  199. UserIssueStatsOptions{
  200. UserID: 1,
  201. RepoIDs: []int64{1},
  202. FilterMode: FilterModeAll,
  203. IsClosed: true,
  204. },
  205. IssueStats{
  206. YourRepositoriesCount: 1, // 6
  207. AssignCount: 0,
  208. CreateCount: 0,
  209. OpenCount: 1, // 6
  210. ClosedCount: 1, // 1
  211. },
  212. },
  213. {
  214. UserIssueStatsOptions{
  215. UserID: 1,
  216. FilterMode: FilterModeAssign,
  217. },
  218. IssueStats{
  219. YourRepositoriesCount: 1, // 6
  220. AssignCount: 1, // 6
  221. CreateCount: 1, // 6
  222. OpenCount: 1, // 6
  223. ClosedCount: 0,
  224. },
  225. },
  226. {
  227. UserIssueStatsOptions{
  228. UserID: 1,
  229. FilterMode: FilterModeCreate,
  230. },
  231. IssueStats{
  232. YourRepositoriesCount: 1, // 6
  233. AssignCount: 1, // 6
  234. CreateCount: 1, // 6
  235. OpenCount: 1, // 6
  236. ClosedCount: 0,
  237. },
  238. },
  239. {
  240. UserIssueStatsOptions{
  241. UserID: 1,
  242. FilterMode: FilterModeMention,
  243. },
  244. IssueStats{
  245. YourRepositoriesCount: 1, // 6
  246. AssignCount: 1, // 6
  247. CreateCount: 1, // 6
  248. MentionCount: 0,
  249. OpenCount: 0,
  250. ClosedCount: 0,
  251. },
  252. },
  253. {
  254. UserIssueStatsOptions{
  255. UserID: 1,
  256. FilterMode: FilterModeCreate,
  257. IssueIDs: []int64{1},
  258. },
  259. IssueStats{
  260. YourRepositoriesCount: 1, // 1
  261. AssignCount: 1, // 1
  262. CreateCount: 1, // 1
  263. OpenCount: 1, // 1
  264. ClosedCount: 0,
  265. },
  266. },
  267. {
  268. UserIssueStatsOptions{
  269. UserID: 2,
  270. Org: unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization),
  271. Team: unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 7}).(*organization.Team),
  272. FilterMode: FilterModeAll,
  273. },
  274. IssueStats{
  275. YourRepositoriesCount: 2,
  276. AssignCount: 1,
  277. CreateCount: 1,
  278. OpenCount: 2,
  279. },
  280. },
  281. } {
  282. t.Run(fmt.Sprintf("%#v", test.Opts), func(t *testing.T) {
  283. stats, err := GetUserIssueStats(test.Opts)
  284. if !assert.NoError(t, err) {
  285. return
  286. }
  287. assert.Equal(t, test.ExpectedIssueStats, *stats)
  288. })
  289. }
  290. }
  291. func TestIssue_loadTotalTimes(t *testing.T) {
  292. assert.NoError(t, unittest.PrepareTestDatabase())
  293. ms, err := GetIssueByID(2)
  294. assert.NoError(t, err)
  295. assert.NoError(t, ms.loadTotalTimes(db.DefaultContext))
  296. assert.Equal(t, int64(3682), ms.TotalTrackedTime)
  297. }
  298. func TestIssue_SearchIssueIDsByKeyword(t *testing.T) {
  299. assert.NoError(t, unittest.PrepareTestDatabase())
  300. total, ids, err := SearchIssueIDsByKeyword(context.TODO(), "issue2", []int64{1}, 10, 0)
  301. assert.NoError(t, err)
  302. assert.EqualValues(t, 1, total)
  303. assert.EqualValues(t, []int64{2}, ids)
  304. total, ids, err = SearchIssueIDsByKeyword(context.TODO(), "first", []int64{1}, 10, 0)
  305. assert.NoError(t, err)
  306. assert.EqualValues(t, 1, total)
  307. assert.EqualValues(t, []int64{1}, ids)
  308. total, ids, err = SearchIssueIDsByKeyword(context.TODO(), "for", []int64{1}, 10, 0)
  309. assert.NoError(t, err)
  310. assert.EqualValues(t, 5, total)
  311. assert.ElementsMatch(t, []int64{1, 2, 3, 5, 11}, ids)
  312. // issue1's comment id 2
  313. total, ids, err = SearchIssueIDsByKeyword(context.TODO(), "good", []int64{1}, 10, 0)
  314. assert.NoError(t, err)
  315. assert.EqualValues(t, 1, total)
  316. assert.EqualValues(t, []int64{1}, ids)
  317. }
  318. func TestGetRepoIDsForIssuesOptions(t *testing.T) {
  319. assert.NoError(t, unittest.PrepareTestDatabase())
  320. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
  321. for _, test := range []struct {
  322. Opts IssuesOptions
  323. ExpectedRepoIDs []int64
  324. }{
  325. {
  326. IssuesOptions{
  327. AssigneeID: 2,
  328. },
  329. []int64{3, 32},
  330. },
  331. {
  332. IssuesOptions{
  333. RepoCond: builder.In("repo_id", 1, 2),
  334. },
  335. []int64{1, 2},
  336. },
  337. } {
  338. repoIDs, err := GetRepoIDsForIssuesOptions(&test.Opts, user)
  339. assert.NoError(t, err)
  340. if assert.Len(t, repoIDs, len(test.ExpectedRepoIDs)) {
  341. for i, repoID := range repoIDs {
  342. assert.EqualValues(t, test.ExpectedRepoIDs[i], repoID)
  343. }
  344. }
  345. }
  346. }
  347. func testInsertIssue(t *testing.T, title, content string, expectIndex int64) *Issue {
  348. var newIssue Issue
  349. t.Run(title, func(t *testing.T) {
  350. repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
  351. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
  352. issue := Issue{
  353. RepoID: repo.ID,
  354. PosterID: user.ID,
  355. Poster: user,
  356. Title: title,
  357. Content: content,
  358. }
  359. err := NewIssue(repo, &issue, nil, nil)
  360. assert.NoError(t, err)
  361. has, err := db.GetEngine(db.DefaultContext).ID(issue.ID).Get(&newIssue)
  362. assert.NoError(t, err)
  363. assert.True(t, has)
  364. assert.EqualValues(t, issue.Title, newIssue.Title)
  365. assert.EqualValues(t, issue.Content, newIssue.Content)
  366. if expectIndex > 0 {
  367. assert.EqualValues(t, expectIndex, newIssue.Index)
  368. }
  369. })
  370. return &newIssue
  371. }
  372. func TestIssue_InsertIssue(t *testing.T) {
  373. assert.NoError(t, unittest.PrepareTestDatabase())
  374. // there are 5 issues and max index is 5 on repository 1, so this one should 6
  375. issue := testInsertIssue(t, "my issue1", "special issue's comments?", 6)
  376. _, err := db.GetEngine(db.DefaultContext).ID(issue.ID).Delete(new(Issue))
  377. assert.NoError(t, err)
  378. issue = testInsertIssue(t, `my issue2, this is my son's love \n \r \ `, "special issue's '' comments?", 7)
  379. _, err = db.GetEngine(db.DefaultContext).ID(issue.ID).Delete(new(Issue))
  380. assert.NoError(t, err)
  381. }
  382. func TestIssue_DeleteIssue(t *testing.T) {
  383. assert.NoError(t, unittest.PrepareTestDatabase())
  384. issueIDs, err := GetIssueIDsByRepoID(db.DefaultContext, 1)
  385. assert.NoError(t, err)
  386. assert.EqualValues(t, 5, len(issueIDs))
  387. issue := &Issue{
  388. RepoID: 1,
  389. ID: issueIDs[2],
  390. }
  391. err = DeleteIssue(issue)
  392. assert.NoError(t, err)
  393. issueIDs, err = GetIssueIDsByRepoID(db.DefaultContext, 1)
  394. assert.NoError(t, err)
  395. assert.EqualValues(t, 4, len(issueIDs))
  396. // check attachment removal
  397. attachments, err := repo_model.GetAttachmentsByIssueID(db.DefaultContext, 4)
  398. assert.NoError(t, err)
  399. issue, err = GetIssueByID(4)
  400. assert.NoError(t, err)
  401. err = DeleteIssue(issue)
  402. assert.NoError(t, err)
  403. assert.EqualValues(t, 2, len(attachments))
  404. for i := range attachments {
  405. attachment, err := repo_model.GetAttachmentByUUID(db.DefaultContext, attachments[i].UUID)
  406. assert.Error(t, err)
  407. assert.True(t, repo_model.IsErrAttachmentNotExist(err))
  408. assert.Nil(t, attachment)
  409. }
  410. // check issue dependencies
  411. user, err := user_model.GetUserByID(1)
  412. assert.NoError(t, err)
  413. issue1, err := GetIssueByID(1)
  414. assert.NoError(t, err)
  415. issue2, err := GetIssueByID(2)
  416. assert.NoError(t, err)
  417. err = CreateIssueDependency(user, issue1, issue2)
  418. assert.NoError(t, err)
  419. left, err := IssueNoDependenciesLeft(db.DefaultContext, issue1)
  420. assert.NoError(t, err)
  421. assert.False(t, left)
  422. err = DeleteIssue(&Issue{ID: 2})
  423. assert.NoError(t, err)
  424. left, err = IssueNoDependenciesLeft(db.DefaultContext, issue1)
  425. assert.NoError(t, err)
  426. assert.True(t, left)
  427. }
  428. func TestIssue_ResolveMentions(t *testing.T) {
  429. assert.NoError(t, unittest.PrepareTestDatabase())
  430. testSuccess := func(owner, repo, doer string, mentions []string, expected []int64) {
  431. o := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: owner}).(*user_model.User)
  432. r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: o.ID, LowerName: repo}).(*repo_model.Repository)
  433. issue := &Issue{RepoID: r.ID}
  434. d := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: doer}).(*user_model.User)
  435. resolved, err := ResolveIssueMentionsByVisibility(db.DefaultContext, issue, d, mentions)
  436. assert.NoError(t, err)
  437. ids := make([]int64, len(resolved))
  438. for i, user := range resolved {
  439. ids[i] = user.ID
  440. }
  441. sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] })
  442. assert.EqualValues(t, expected, ids)
  443. }
  444. // Public repo, existing user
  445. testSuccess("user2", "repo1", "user1", []string{"user5"}, []int64{5})
  446. // Public repo, non-existing user
  447. testSuccess("user2", "repo1", "user1", []string{"nonexisting"}, []int64{})
  448. // Public repo, doer
  449. testSuccess("user2", "repo1", "user1", []string{"user1"}, []int64{})
  450. // Private repo, team member
  451. testSuccess("user17", "big_test_private_4", "user20", []string{"user2"}, []int64{2})
  452. // Private repo, not a team member
  453. testSuccess("user17", "big_test_private_4", "user20", []string{"user5"}, []int64{})
  454. // Private repo, whole team
  455. testSuccess("user17", "big_test_private_4", "user15", []string{"user17/owners"}, []int64{18})
  456. }
  457. func TestResourceIndex(t *testing.T) {
  458. assert.NoError(t, unittest.PrepareTestDatabase())
  459. var wg sync.WaitGroup
  460. for i := 0; i < 100; i++ {
  461. wg.Add(1)
  462. go func(i int) {
  463. testInsertIssue(t, fmt.Sprintf("issue %d", i+1), "my issue", 0)
  464. wg.Done()
  465. }(i)
  466. }
  467. wg.Wait()
  468. }
  469. func TestCorrectIssueStats(t *testing.T) {
  470. assert.NoError(t, unittest.PrepareTestDatabase())
  471. // Because the condition is to have chunked database look-ups,
  472. // We have to more issues than `maxQueryParameters`, we will insert.
  473. // maxQueryParameters + 10 issues into the testDatabase.
  474. // Each new issues will have a constant description "Bugs are nasty"
  475. // Which will be used later on.
  476. issueAmount := maxQueryParameters + 10
  477. var wg sync.WaitGroup
  478. for i := 0; i < issueAmount; i++ {
  479. wg.Add(1)
  480. go func(i int) {
  481. testInsertIssue(t, fmt.Sprintf("Issue %d", i+1), "Bugs are nasty", 0)
  482. wg.Done()
  483. }(i)
  484. }
  485. wg.Wait()
  486. // Now we will get all issueID's that match the "Bugs are nasty" query.
  487. total, ids, err := SearchIssueIDsByKeyword(context.TODO(), "Bugs are nasty", []int64{1}, issueAmount, 0)
  488. // Just to be sure.
  489. assert.NoError(t, err)
  490. assert.EqualValues(t, issueAmount, total)
  491. // Now we will call the GetIssueStats with these IDs and if working,
  492. // get the correct stats back.
  493. issueStats, err := GetIssueStats(&IssueStatsOptions{
  494. RepoID: 1,
  495. IssueIDs: ids,
  496. })
  497. // Now check the values.
  498. assert.NoError(t, err)
  499. assert.EqualValues(t, issueStats.OpenCount, issueAmount)
  500. }
  501. func TestIssueForeignReference(t *testing.T) {
  502. assert.NoError(t, unittest.PrepareTestDatabase())
  503. issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 4}).(*Issue)
  504. assert.NotEqualValues(t, issue.Index, issue.ID) // make sure they are different to avoid false positive
  505. // it is fine for an issue to not have a foreign reference
  506. err := issue.LoadAttributes()
  507. assert.NoError(t, err)
  508. assert.Nil(t, issue.ForeignReference)
  509. var foreignIndex int64 = 12345
  510. _, err = GetIssueByForeignIndex(context.Background(), issue.RepoID, foreignIndex)
  511. assert.True(t, foreignreference.IsErrLocalIndexNotExist(err))
  512. _, err = db.GetEngine(db.DefaultContext).Insert(&foreignreference.ForeignReference{
  513. LocalIndex: issue.Index,
  514. ForeignIndex: strconv.FormatInt(foreignIndex, 10),
  515. RepoID: issue.RepoID,
  516. Type: foreignreference.TypeIssue,
  517. })
  518. assert.NoError(t, err)
  519. err = issue.LoadAttributes()
  520. assert.NoError(t, err)
  521. assert.EqualValues(t, issue.ForeignReference.ForeignIndex, strconv.FormatInt(foreignIndex, 10))
  522. found, err := GetIssueByForeignIndex(context.Background(), issue.RepoID, foreignIndex)
  523. assert.NoError(t, err)
  524. assert.EqualValues(t, found.Index, issue.Index)
  525. }
  526. func TestMilestoneList_LoadTotalTrackedTimes(t *testing.T) {
  527. assert.NoError(t, unittest.PrepareTestDatabase())
  528. miles := issues_model.MilestoneList{
  529. unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone),
  530. }
  531. assert.NoError(t, miles.LoadTotalTrackedTimes())
  532. assert.Equal(t, int64(3682), miles[0].TotalTrackedTime)
  533. }
  534. func TestLoadTotalTrackedTime(t *testing.T) {
  535. assert.NoError(t, unittest.PrepareTestDatabase())
  536. milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone)
  537. assert.NoError(t, milestone.LoadTotalTrackedTime())
  538. assert.Equal(t, int64(3682), milestone.TotalTrackedTime)
  539. }
  540. func TestCountIssues(t *testing.T) {
  541. assert.NoError(t, unittest.PrepareTestDatabase())
  542. count, err := CountIssues(&IssuesOptions{})
  543. assert.NoError(t, err)
  544. assert.EqualValues(t, 17, count)
  545. }