gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package issues
  4. import (
  5. "testing"
  6. "code.gitea.io/gitea/models/db"
  7. "code.gitea.io/gitea/models/issues"
  8. "code.gitea.io/gitea/models/unittest"
  9. "code.gitea.io/gitea/modules/indexer/issues/internal"
  10. "code.gitea.io/gitea/modules/optional"
  11. "code.gitea.io/gitea/modules/setting"
  12. _ "code.gitea.io/gitea/models"
  13. _ "code.gitea.io/gitea/models/actions"
  14. _ "code.gitea.io/gitea/models/activities"
  15. "github.com/stretchr/testify/assert"
  16. "github.com/stretchr/testify/require"
  17. )
  18. func TestMain(m *testing.M) {
  19. unittest.MainTest(m)
  20. }
  21. func TestDBSearchIssues(t *testing.T) {
  22. require.NoError(t, unittest.PrepareTestDatabase())
  23. setting.Indexer.IssueType = "db"
  24. InitIssueIndexer(true)
  25. t.Run("search issues with keyword", searchIssueWithKeyword)
  26. t.Run("search issues by index", searchIssueByIndex)
  27. t.Run("search issues in repo", searchIssueInRepo)
  28. t.Run("search issues by ID", searchIssueByID)
  29. t.Run("search issues is pr", searchIssueIsPull)
  30. t.Run("search issues is closed", searchIssueIsClosed)
  31. t.Run("search issues is archived", searchIssueIsArchived)
  32. t.Run("search issues by milestone", searchIssueByMilestoneID)
  33. t.Run("search issues by label", searchIssueByLabelID)
  34. t.Run("search issues by time", searchIssueByTime)
  35. t.Run("search issues with order", searchIssueWithOrder)
  36. t.Run("search issues in project", searchIssueInProject)
  37. t.Run("search issues with paginator", searchIssueWithPaginator)
  38. t.Run("search issues with any assignee", searchIssueWithAnyAssignee)
  39. }
  40. func searchIssueWithKeyword(t *testing.T) {
  41. tests := []struct {
  42. opts SearchOptions
  43. expectedIDs []int64
  44. }{
  45. {
  46. SearchOptions{
  47. Keyword: "issue2",
  48. RepoIDs: []int64{1},
  49. },
  50. []int64{2},
  51. },
  52. {
  53. SearchOptions{
  54. Keyword: "first",
  55. RepoIDs: []int64{1},
  56. },
  57. []int64{1},
  58. },
  59. {
  60. SearchOptions{
  61. Keyword: "for",
  62. RepoIDs: []int64{1},
  63. },
  64. []int64{11, 5, 3, 2, 1},
  65. },
  66. {
  67. SearchOptions{
  68. Keyword: "good",
  69. RepoIDs: []int64{1},
  70. },
  71. []int64{1},
  72. },
  73. }
  74. for _, test := range tests {
  75. t.Run(test.opts.Keyword, func(t *testing.T) {
  76. issueIDs, _, err := SearchIssues(t.Context(), &test.opts)
  77. require.NoError(t, err)
  78. assert.Equal(t, test.expectedIDs, issueIDs)
  79. })
  80. }
  81. }
  82. func searchIssueByIndex(t *testing.T) {
  83. tests := []struct {
  84. opts SearchOptions
  85. expectedIDs []int64
  86. }{
  87. {
  88. SearchOptions{
  89. Keyword: "1000",
  90. RepoIDs: []int64{1},
  91. },
  92. []int64{},
  93. },
  94. {
  95. SearchOptions{
  96. Keyword: "2",
  97. RepoIDs: []int64{1, 2, 3, 32},
  98. },
  99. []int64{17, 12, 7, 2},
  100. },
  101. {
  102. SearchOptions{
  103. Keyword: "1",
  104. RepoIDs: []int64{58},
  105. },
  106. []int64{19},
  107. },
  108. }
  109. for _, test := range tests {
  110. issueIDs, _, err := SearchIssues(t.Context(), &test.opts)
  111. require.NoError(t, err)
  112. assert.Equal(t, test.expectedIDs, issueIDs)
  113. }
  114. }
  115. func searchIssueInRepo(t *testing.T) {
  116. tests := []struct {
  117. opts SearchOptions
  118. expectedIDs []int64
  119. }{
  120. {
  121. SearchOptions{
  122. RepoIDs: []int64{1},
  123. },
  124. []int64{11, 5, 3, 2, 1},
  125. },
  126. {
  127. SearchOptions{
  128. RepoIDs: []int64{2},
  129. },
  130. []int64{7, 4},
  131. },
  132. {
  133. SearchOptions{
  134. RepoIDs: []int64{3},
  135. },
  136. []int64{12, 6},
  137. },
  138. {
  139. SearchOptions{
  140. RepoIDs: []int64{4},
  141. },
  142. []int64{},
  143. },
  144. {
  145. SearchOptions{
  146. RepoIDs: []int64{5},
  147. },
  148. []int64{15},
  149. },
  150. }
  151. for _, test := range tests {
  152. issueIDs, _, err := SearchIssues(t.Context(), &test.opts)
  153. require.NoError(t, err)
  154. assert.Equal(t, test.expectedIDs, issueIDs)
  155. }
  156. }
  157. func searchIssueByID(t *testing.T) {
  158. tests := []struct {
  159. opts SearchOptions
  160. expectedIDs []int64
  161. }{
  162. {
  163. opts: SearchOptions{
  164. PosterID: "1",
  165. },
  166. expectedIDs: []int64{11, 6, 3, 2, 1},
  167. },
  168. {
  169. opts: SearchOptions{
  170. AssigneeID: "1",
  171. },
  172. expectedIDs: []int64{6, 1},
  173. },
  174. {
  175. // NOTE: This tests no assignees filtering and also ToSearchOptions() to ensure it handles the filter correctly
  176. opts: *ToSearchOptions("", &issues.IssuesOptions{AssigneeID: "(none)"}),
  177. expectedIDs: []int64{22, 21, 16, 15, 14, 13, 12, 11, 20, 5, 19, 18, 10, 7, 4, 9, 8, 3, 2},
  178. },
  179. {
  180. opts: SearchOptions{
  181. MentionID: optional.Some(int64(4)),
  182. },
  183. expectedIDs: []int64{1},
  184. },
  185. {
  186. opts: SearchOptions{
  187. ReviewedID: optional.Some(int64(1)),
  188. },
  189. expectedIDs: []int64{},
  190. },
  191. {
  192. opts: SearchOptions{
  193. ReviewRequestedID: optional.Some(int64(1)),
  194. },
  195. expectedIDs: []int64{12},
  196. },
  197. {
  198. opts: SearchOptions{
  199. SubscriberID: optional.Some(int64(1)),
  200. },
  201. expectedIDs: []int64{11, 6, 5, 3, 2, 1},
  202. },
  203. {
  204. // issue 20 request user 15 and team 5 which user 15 belongs to
  205. // the review request number of issue 20 should be 1
  206. opts: SearchOptions{
  207. ReviewRequestedID: optional.Some(int64(15)),
  208. },
  209. expectedIDs: []int64{12, 20},
  210. },
  211. {
  212. // user 20 approved the issue 20, so return nothing
  213. opts: SearchOptions{
  214. ReviewRequestedID: optional.Some(int64(20)),
  215. },
  216. expectedIDs: []int64{},
  217. },
  218. }
  219. for _, test := range tests {
  220. issueIDs, _, err := SearchIssues(t.Context(), &test.opts)
  221. require.NoError(t, err)
  222. assert.Equal(t, test.expectedIDs, issueIDs)
  223. }
  224. }
  225. func searchIssueIsPull(t *testing.T) {
  226. tests := []struct {
  227. opts SearchOptions
  228. expectedIDs []int64
  229. }{
  230. {
  231. SearchOptions{
  232. IsPull: optional.Some(false),
  233. },
  234. []int64{17, 16, 15, 14, 13, 6, 5, 18, 10, 7, 4, 1},
  235. },
  236. {
  237. SearchOptions{
  238. IsPull: optional.Some(true),
  239. },
  240. []int64{22, 21, 12, 11, 20, 19, 9, 8, 3, 2},
  241. },
  242. }
  243. for _, test := range tests {
  244. issueIDs, _, err := SearchIssues(t.Context(), &test.opts)
  245. require.NoError(t, err)
  246. assert.Equal(t, test.expectedIDs, issueIDs)
  247. }
  248. }
  249. func searchIssueIsClosed(t *testing.T) {
  250. tests := []struct {
  251. opts SearchOptions
  252. expectedIDs []int64
  253. }{
  254. {
  255. SearchOptions{
  256. IsClosed: optional.Some(false),
  257. },
  258. []int64{22, 21, 17, 16, 15, 14, 13, 12, 11, 20, 6, 19, 18, 10, 7, 9, 8, 3, 2, 1},
  259. },
  260. {
  261. SearchOptions{
  262. IsClosed: optional.Some(true),
  263. },
  264. []int64{5, 4},
  265. },
  266. }
  267. for _, test := range tests {
  268. issueIDs, _, err := SearchIssues(t.Context(), &test.opts)
  269. require.NoError(t, err)
  270. assert.Equal(t, test.expectedIDs, issueIDs)
  271. }
  272. }
  273. func searchIssueIsArchived(t *testing.T) {
  274. tests := []struct {
  275. opts SearchOptions
  276. expectedIDs []int64
  277. }{
  278. {
  279. SearchOptions{
  280. IsArchived: optional.Some(false),
  281. },
  282. []int64{22, 21, 17, 16, 15, 13, 12, 11, 20, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3, 2, 1},
  283. },
  284. {
  285. SearchOptions{
  286. IsArchived: optional.Some(true),
  287. },
  288. []int64{14},
  289. },
  290. }
  291. for _, test := range tests {
  292. issueIDs, _, err := SearchIssues(t.Context(), &test.opts)
  293. require.NoError(t, err)
  294. assert.Equal(t, test.expectedIDs, issueIDs)
  295. }
  296. }
  297. func searchIssueByMilestoneID(t *testing.T) {
  298. tests := []struct {
  299. opts SearchOptions
  300. expectedIDs []int64
  301. }{
  302. {
  303. SearchOptions{
  304. MilestoneIDs: []int64{1},
  305. },
  306. []int64{2},
  307. },
  308. {
  309. SearchOptions{
  310. MilestoneIDs: []int64{3},
  311. },
  312. []int64{3},
  313. },
  314. }
  315. for _, test := range tests {
  316. issueIDs, _, err := SearchIssues(t.Context(), &test.opts)
  317. require.NoError(t, err)
  318. assert.Equal(t, test.expectedIDs, issueIDs)
  319. }
  320. }
  321. func searchIssueByLabelID(t *testing.T) {
  322. tests := []struct {
  323. opts SearchOptions
  324. expectedIDs []int64
  325. }{
  326. {
  327. SearchOptions{
  328. IncludedLabelIDs: []int64{1},
  329. },
  330. []int64{2, 1},
  331. },
  332. {
  333. SearchOptions{
  334. IncludedLabelIDs: []int64{4},
  335. },
  336. []int64{2},
  337. },
  338. {
  339. SearchOptions{
  340. ExcludedLabelIDs: []int64{1},
  341. },
  342. []int64{22, 21, 17, 16, 15, 14, 13, 12, 11, 20, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3},
  343. },
  344. }
  345. for _, test := range tests {
  346. issueIDs, _, err := SearchIssues(t.Context(), &test.opts)
  347. require.NoError(t, err)
  348. assert.Equal(t, test.expectedIDs, issueIDs)
  349. }
  350. }
  351. func searchIssueByTime(t *testing.T) {
  352. tests := []struct {
  353. opts SearchOptions
  354. expectedIDs []int64
  355. }{
  356. {
  357. SearchOptions{
  358. UpdatedAfterUnix: optional.Some(int64(0)),
  359. },
  360. []int64{22, 21, 17, 16, 15, 14, 13, 12, 11, 20, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3, 2, 1},
  361. },
  362. }
  363. for _, test := range tests {
  364. issueIDs, _, err := SearchIssues(t.Context(), &test.opts)
  365. require.NoError(t, err)
  366. assert.Equal(t, test.expectedIDs, issueIDs)
  367. }
  368. }
  369. func searchIssueWithOrder(t *testing.T) {
  370. tests := []struct {
  371. opts SearchOptions
  372. expectedIDs []int64
  373. }{
  374. {
  375. SearchOptions{
  376. SortBy: internal.SortByCreatedAsc,
  377. },
  378. []int64{1, 2, 3, 8, 9, 4, 7, 10, 18, 19, 5, 6, 20, 11, 12, 13, 14, 15, 16, 17, 21, 22},
  379. },
  380. }
  381. for _, test := range tests {
  382. issueIDs, _, err := SearchIssues(t.Context(), &test.opts)
  383. require.NoError(t, err)
  384. assert.Equal(t, test.expectedIDs, issueIDs)
  385. }
  386. }
  387. func searchIssueInProject(t *testing.T) {
  388. tests := []struct {
  389. opts SearchOptions
  390. expectedIDs []int64
  391. }{
  392. {
  393. SearchOptions{
  394. ProjectID: optional.Some(int64(1)),
  395. },
  396. []int64{5, 3, 2, 1},
  397. },
  398. {
  399. SearchOptions{
  400. ProjectColumnID: optional.Some(int64(1)),
  401. },
  402. []int64{1},
  403. },
  404. {
  405. SearchOptions{
  406. ProjectColumnID: optional.Some(int64(0)), // issue with in default column
  407. },
  408. []int64{2},
  409. },
  410. }
  411. for _, test := range tests {
  412. issueIDs, _, err := SearchIssues(t.Context(), &test.opts)
  413. require.NoError(t, err)
  414. assert.Equal(t, test.expectedIDs, issueIDs)
  415. }
  416. }
  417. func searchIssueWithPaginator(t *testing.T) {
  418. tests := []struct {
  419. opts SearchOptions
  420. expectedIDs []int64
  421. expectedTotal int64
  422. }{
  423. {
  424. SearchOptions{
  425. Paginator: &db.ListOptions{
  426. PageSize: 5,
  427. },
  428. },
  429. []int64{22, 21, 17, 16, 15},
  430. 22,
  431. },
  432. }
  433. for _, test := range tests {
  434. issueIDs, total, err := SearchIssues(t.Context(), &test.opts)
  435. require.NoError(t, err)
  436. assert.Equal(t, test.expectedIDs, issueIDs)
  437. assert.Equal(t, test.expectedTotal, total)
  438. }
  439. }
  440. func searchIssueWithAnyAssignee(t *testing.T) {
  441. tests := []struct {
  442. opts SearchOptions
  443. expectedIDs []int64
  444. expectedTotal int64
  445. }{
  446. {
  447. SearchOptions{
  448. AssigneeID: "(any)",
  449. },
  450. []int64{17, 6, 1},
  451. 3,
  452. },
  453. }
  454. for _, test := range tests {
  455. issueIDs, total, err := SearchIssues(t.Context(), &test.opts)
  456. require.NoError(t, err)
  457. assert.Equal(t, test.expectedIDs, issueIDs)
  458. assert.Equal(t, test.expectedTotal, total)
  459. }
  460. }