gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. // Copyright 2023 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. // This package contains tests for issues indexer modules.
  4. // All the code in this package is only used for testing.
  5. // Do not put any production code in this package to avoid it being included in the final binary.
  6. package tests
  7. import (
  8. "fmt"
  9. "slices"
  10. "testing"
  11. "time"
  12. "code.gitea.io/gitea/models/db"
  13. "code.gitea.io/gitea/modules/indexer/issues/internal"
  14. "code.gitea.io/gitea/modules/optional"
  15. "code.gitea.io/gitea/modules/timeutil"
  16. "github.com/stretchr/testify/assert"
  17. "github.com/stretchr/testify/require"
  18. )
  19. func TestIndexer(t *testing.T, indexer internal.Indexer) {
  20. _, err := indexer.Init(t.Context())
  21. require.NoError(t, err)
  22. require.NoError(t, indexer.Ping(t.Context()))
  23. var (
  24. ids []int64
  25. data = map[int64]*internal.IndexerData{}
  26. )
  27. {
  28. d := generateDefaultIndexerData()
  29. for _, v := range d {
  30. ids = append(ids, v.ID)
  31. data[v.ID] = v
  32. }
  33. require.NoError(t, indexer.Index(t.Context(), d...))
  34. waitData(t, indexer, int64(len(data)))
  35. }
  36. defer func() {
  37. require.NoError(t, indexer.Delete(t.Context(), ids...))
  38. }()
  39. for _, c := range cases {
  40. t.Run(c.Name, func(t *testing.T) {
  41. if len(c.ExtraData) > 0 {
  42. require.NoError(t, indexer.Index(t.Context(), c.ExtraData...))
  43. for _, v := range c.ExtraData {
  44. data[v.ID] = v
  45. }
  46. waitData(t, indexer, int64(len(data)))
  47. defer func() {
  48. for _, v := range c.ExtraData {
  49. require.NoError(t, indexer.Delete(t.Context(), v.ID))
  50. delete(data, v.ID)
  51. }
  52. waitData(t, indexer, int64(len(data)))
  53. }()
  54. }
  55. result, err := indexer.Search(t.Context(), c.SearchOptions)
  56. require.NoError(t, err)
  57. if c.Expected != nil {
  58. c.Expected(t, data, result)
  59. } else {
  60. ids := make([]int64, 0, len(result.Hits))
  61. for _, hit := range result.Hits {
  62. ids = append(ids, hit.ID)
  63. }
  64. assert.Equal(t, c.ExpectedIDs, ids)
  65. assert.Equal(t, c.ExpectedTotal, result.Total)
  66. }
  67. // test counting
  68. c.SearchOptions.Paginator = &db.ListOptions{PageSize: 0}
  69. countResult, err := indexer.Search(t.Context(), c.SearchOptions)
  70. require.NoError(t, err)
  71. assert.Empty(t, countResult.Hits)
  72. assert.Equal(t, result.Total, countResult.Total)
  73. })
  74. }
  75. }
  76. var cases = []*testIndexerCase{
  77. {
  78. Name: "default",
  79. SearchOptions: &internal.SearchOptions{},
  80. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  81. assert.Len(t, result.Hits, len(data))
  82. assert.Equal(t, len(data), int(result.Total))
  83. },
  84. },
  85. {
  86. Name: "empty",
  87. SearchOptions: &internal.SearchOptions{
  88. Keyword: "f1dfac73-fda6-4a6b-b8a4-2408fcb8ef69",
  89. },
  90. ExpectedIDs: []int64{},
  91. ExpectedTotal: 0,
  92. },
  93. {
  94. Name: "with limit",
  95. SearchOptions: &internal.SearchOptions{
  96. Paginator: &db.ListOptions{
  97. PageSize: 5,
  98. },
  99. },
  100. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  101. assert.Len(t, result.Hits, 5)
  102. assert.Equal(t, len(data), int(result.Total))
  103. },
  104. },
  105. {
  106. Name: "Keyword",
  107. ExtraData: []*internal.IndexerData{
  108. {ID: 1000, Title: "hi hello world"},
  109. {ID: 1001, Content: "hi hello world"},
  110. {ID: 1002, Comments: []string{"hi", "hello world"}},
  111. },
  112. SearchOptions: &internal.SearchOptions{
  113. Keyword: "hello",
  114. },
  115. ExpectedIDs: []int64{1002, 1001, 1000},
  116. ExpectedTotal: 3,
  117. },
  118. {
  119. Name: "RepoIDs",
  120. ExtraData: []*internal.IndexerData{
  121. {ID: 1001, Title: "hello world", RepoID: 1, IsPublic: false},
  122. {ID: 1002, Title: "hello world", RepoID: 1, IsPublic: false},
  123. {ID: 1003, Title: "hello world", RepoID: 2, IsPublic: true},
  124. {ID: 1004, Title: "hello world", RepoID: 2, IsPublic: true},
  125. {ID: 1005, Title: "hello world", RepoID: 3, IsPublic: true},
  126. {ID: 1006, Title: "hello world", RepoID: 4, IsPublic: false},
  127. {ID: 1007, Title: "hello world", RepoID: 5, IsPublic: false},
  128. },
  129. SearchOptions: &internal.SearchOptions{
  130. Keyword: "hello",
  131. RepoIDs: []int64{1, 4},
  132. },
  133. ExpectedIDs: []int64{1006, 1002, 1001},
  134. ExpectedTotal: 3,
  135. },
  136. {
  137. Name: "RepoIDs and AllPublic",
  138. ExtraData: []*internal.IndexerData{
  139. {ID: 1001, Title: "hello world", RepoID: 1, IsPublic: false},
  140. {ID: 1002, Title: "hello world", RepoID: 1, IsPublic: false},
  141. {ID: 1003, Title: "hello world", RepoID: 2, IsPublic: true},
  142. {ID: 1004, Title: "hello world", RepoID: 2, IsPublic: true},
  143. {ID: 1005, Title: "hello world", RepoID: 3, IsPublic: true},
  144. {ID: 1006, Title: "hello world", RepoID: 4, IsPublic: false},
  145. {ID: 1007, Title: "hello world", RepoID: 5, IsPublic: false},
  146. },
  147. SearchOptions: &internal.SearchOptions{
  148. Keyword: "hello",
  149. RepoIDs: []int64{1, 4},
  150. AllPublic: true,
  151. },
  152. ExpectedIDs: []int64{1006, 1005, 1004, 1003, 1002, 1001},
  153. ExpectedTotal: 6,
  154. },
  155. {
  156. Name: "issue only",
  157. SearchOptions: &internal.SearchOptions{
  158. Paginator: &db.ListOptions{
  159. PageSize: 5,
  160. },
  161. IsPull: optional.Some(false),
  162. },
  163. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  164. assert.Len(t, result.Hits, 5)
  165. for _, v := range result.Hits {
  166. assert.False(t, data[v.ID].IsPull)
  167. }
  168. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool { return !v.IsPull }), result.Total)
  169. },
  170. },
  171. {
  172. Name: "pull only",
  173. SearchOptions: &internal.SearchOptions{
  174. Paginator: &db.ListOptions{
  175. PageSize: 5,
  176. },
  177. IsPull: optional.Some(true),
  178. },
  179. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  180. assert.Len(t, result.Hits, 5)
  181. for _, v := range result.Hits {
  182. assert.True(t, data[v.ID].IsPull)
  183. }
  184. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool { return v.IsPull }), result.Total)
  185. },
  186. },
  187. {
  188. Name: "opened only",
  189. SearchOptions: &internal.SearchOptions{
  190. Paginator: &db.ListOptions{
  191. PageSize: 5,
  192. },
  193. IsClosed: optional.Some(false),
  194. },
  195. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  196. assert.Len(t, result.Hits, 5)
  197. for _, v := range result.Hits {
  198. assert.False(t, data[v.ID].IsClosed)
  199. }
  200. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool { return !v.IsClosed }), result.Total)
  201. },
  202. },
  203. {
  204. Name: "closed only",
  205. SearchOptions: &internal.SearchOptions{
  206. Paginator: &db.ListOptions{
  207. PageSize: 5,
  208. },
  209. IsClosed: optional.Some(true),
  210. },
  211. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  212. assert.Len(t, result.Hits, 5)
  213. for _, v := range result.Hits {
  214. assert.True(t, data[v.ID].IsClosed)
  215. }
  216. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool { return v.IsClosed }), result.Total)
  217. },
  218. },
  219. {
  220. Name: "labels",
  221. ExtraData: []*internal.IndexerData{
  222. {ID: 1000, Title: "hello a", LabelIDs: []int64{2000, 2001, 2002}},
  223. {ID: 1001, Title: "hello b", LabelIDs: []int64{2000, 2001}},
  224. {ID: 1002, Title: "hello c", LabelIDs: []int64{2000, 2001, 2003}},
  225. {ID: 1003, Title: "hello d", LabelIDs: []int64{2000}},
  226. {ID: 1004, Title: "hello e", LabelIDs: []int64{}},
  227. },
  228. SearchOptions: &internal.SearchOptions{
  229. Keyword: "hello",
  230. IncludedLabelIDs: []int64{2000, 2001},
  231. ExcludedLabelIDs: []int64{2003},
  232. },
  233. ExpectedIDs: []int64{1001, 1000},
  234. ExpectedTotal: 2,
  235. },
  236. {
  237. Name: "include any labels",
  238. ExtraData: []*internal.IndexerData{
  239. {ID: 1000, Title: "hello a", LabelIDs: []int64{2000, 2001, 2002}},
  240. {ID: 1001, Title: "hello b", LabelIDs: []int64{2001}},
  241. {ID: 1002, Title: "hello c", LabelIDs: []int64{2000, 2001, 2003}},
  242. {ID: 1003, Title: "hello d", LabelIDs: []int64{2002}},
  243. {ID: 1004, Title: "hello e", LabelIDs: []int64{}},
  244. },
  245. SearchOptions: &internal.SearchOptions{
  246. Keyword: "hello",
  247. IncludedAnyLabelIDs: []int64{2001, 2002},
  248. ExcludedLabelIDs: []int64{2003},
  249. },
  250. ExpectedIDs: []int64{1003, 1001, 1000},
  251. ExpectedTotal: 3,
  252. },
  253. {
  254. Name: "MilestoneIDs",
  255. SearchOptions: &internal.SearchOptions{
  256. Paginator: &db.ListOptions{
  257. PageSize: 5,
  258. },
  259. MilestoneIDs: []int64{1, 2, 6},
  260. },
  261. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  262. assert.Len(t, result.Hits, 5)
  263. for _, v := range result.Hits {
  264. assert.Contains(t, []int64{1, 2, 6}, data[v.ID].MilestoneID)
  265. }
  266. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool {
  267. return v.MilestoneID == 1 || v.MilestoneID == 2 || v.MilestoneID == 6
  268. }), result.Total)
  269. },
  270. },
  271. {
  272. Name: "no MilestoneIDs",
  273. SearchOptions: &internal.SearchOptions{
  274. Paginator: &db.ListOptions{
  275. PageSize: 5,
  276. },
  277. MilestoneIDs: []int64{0},
  278. },
  279. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  280. assert.Len(t, result.Hits, 5)
  281. for _, v := range result.Hits {
  282. assert.Equal(t, int64(0), data[v.ID].MilestoneID)
  283. }
  284. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool {
  285. return v.MilestoneID == 0
  286. }), result.Total)
  287. },
  288. },
  289. {
  290. Name: "ProjectID",
  291. SearchOptions: &internal.SearchOptions{
  292. Paginator: &db.ListOptions{
  293. PageSize: 5,
  294. },
  295. ProjectID: optional.Some(int64(1)),
  296. },
  297. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  298. assert.Len(t, result.Hits, 5)
  299. for _, v := range result.Hits {
  300. assert.Equal(t, int64(1), data[v.ID].ProjectID)
  301. }
  302. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool {
  303. return v.ProjectID == 1
  304. }), result.Total)
  305. },
  306. },
  307. {
  308. Name: "no ProjectID",
  309. SearchOptions: &internal.SearchOptions{
  310. Paginator: &db.ListOptions{
  311. PageSize: 5,
  312. },
  313. ProjectID: optional.Some(int64(0)),
  314. },
  315. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  316. assert.Len(t, result.Hits, 5)
  317. for _, v := range result.Hits {
  318. assert.Equal(t, int64(0), data[v.ID].ProjectID)
  319. }
  320. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool {
  321. return v.ProjectID == 0
  322. }), result.Total)
  323. },
  324. },
  325. {
  326. Name: "ProjectColumnID",
  327. SearchOptions: &internal.SearchOptions{
  328. Paginator: &db.ListOptions{
  329. PageSize: 5,
  330. },
  331. ProjectColumnID: optional.Some(int64(1)),
  332. },
  333. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  334. assert.Len(t, result.Hits, 5)
  335. for _, v := range result.Hits {
  336. assert.Equal(t, int64(1), data[v.ID].ProjectColumnID)
  337. }
  338. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool {
  339. return v.ProjectColumnID == 1
  340. }), result.Total)
  341. },
  342. },
  343. {
  344. Name: "no ProjectColumnID",
  345. SearchOptions: &internal.SearchOptions{
  346. Paginator: &db.ListOptions{
  347. PageSize: 5,
  348. },
  349. ProjectColumnID: optional.Some(int64(0)),
  350. },
  351. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  352. assert.Len(t, result.Hits, 5)
  353. for _, v := range result.Hits {
  354. assert.Equal(t, int64(0), data[v.ID].ProjectColumnID)
  355. }
  356. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool {
  357. return v.ProjectColumnID == 0
  358. }), result.Total)
  359. },
  360. },
  361. {
  362. Name: "PosterID",
  363. SearchOptions: &internal.SearchOptions{
  364. Paginator: &db.ListOptions{
  365. PageSize: 5,
  366. },
  367. PosterID: "1",
  368. },
  369. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  370. assert.Len(t, result.Hits, 5)
  371. for _, v := range result.Hits {
  372. assert.Equal(t, int64(1), data[v.ID].PosterID)
  373. }
  374. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool {
  375. return v.PosterID == 1
  376. }), result.Total)
  377. },
  378. },
  379. {
  380. Name: "AssigneeID",
  381. SearchOptions: &internal.SearchOptions{
  382. Paginator: &db.ListOptions{
  383. PageSize: 5,
  384. },
  385. AssigneeID: "1",
  386. },
  387. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  388. assert.Len(t, result.Hits, 5)
  389. for _, v := range result.Hits {
  390. assert.Equal(t, int64(1), data[v.ID].AssigneeID)
  391. }
  392. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool {
  393. return v.AssigneeID == 1
  394. }), result.Total)
  395. },
  396. },
  397. {
  398. Name: "no AssigneeID",
  399. SearchOptions: &internal.SearchOptions{
  400. Paginator: &db.ListOptions{
  401. PageSize: 5,
  402. },
  403. AssigneeID: "(none)",
  404. },
  405. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  406. assert.Len(t, result.Hits, 5)
  407. for _, v := range result.Hits {
  408. assert.Equal(t, int64(0), data[v.ID].AssigneeID)
  409. }
  410. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool {
  411. return v.AssigneeID == 0
  412. }), result.Total)
  413. },
  414. },
  415. {
  416. Name: "MentionID",
  417. SearchOptions: &internal.SearchOptions{
  418. Paginator: &db.ListOptions{
  419. PageSize: 5,
  420. },
  421. MentionID: optional.Some(int64(1)),
  422. },
  423. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  424. assert.Len(t, result.Hits, 5)
  425. for _, v := range result.Hits {
  426. assert.Contains(t, data[v.ID].MentionIDs, int64(1))
  427. }
  428. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool {
  429. return slices.Contains(v.MentionIDs, 1)
  430. }), result.Total)
  431. },
  432. },
  433. {
  434. Name: "ReviewedID",
  435. SearchOptions: &internal.SearchOptions{
  436. Paginator: &db.ListOptions{
  437. PageSize: 5,
  438. },
  439. ReviewedID: optional.Some(int64(1)),
  440. },
  441. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  442. assert.Len(t, result.Hits, 5)
  443. for _, v := range result.Hits {
  444. assert.Contains(t, data[v.ID].ReviewedIDs, int64(1))
  445. }
  446. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool {
  447. return slices.Contains(v.ReviewedIDs, 1)
  448. }), result.Total)
  449. },
  450. },
  451. {
  452. Name: "ReviewRequestedID",
  453. SearchOptions: &internal.SearchOptions{
  454. Paginator: &db.ListOptions{
  455. PageSize: 5,
  456. },
  457. ReviewRequestedID: optional.Some(int64(1)),
  458. },
  459. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  460. assert.Len(t, result.Hits, 5)
  461. for _, v := range result.Hits {
  462. assert.Contains(t, data[v.ID].ReviewRequestedIDs, int64(1))
  463. }
  464. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool {
  465. return slices.Contains(v.ReviewRequestedIDs, 1)
  466. }), result.Total)
  467. },
  468. },
  469. {
  470. Name: "SubscriberID",
  471. SearchOptions: &internal.SearchOptions{
  472. Paginator: &db.ListOptions{
  473. PageSize: 5,
  474. },
  475. SubscriberID: optional.Some(int64(1)),
  476. },
  477. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  478. assert.Len(t, result.Hits, 5)
  479. for _, v := range result.Hits {
  480. assert.Contains(t, data[v.ID].SubscriberIDs, int64(1))
  481. }
  482. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool {
  483. return slices.Contains(v.SubscriberIDs, 1)
  484. }), result.Total)
  485. },
  486. },
  487. {
  488. Name: "updated",
  489. SearchOptions: &internal.SearchOptions{
  490. Paginator: &db.ListOptions{
  491. PageSize: 5,
  492. },
  493. UpdatedAfterUnix: optional.Some(int64(20)),
  494. UpdatedBeforeUnix: optional.Some(int64(30)),
  495. },
  496. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  497. assert.Len(t, result.Hits, 5)
  498. for _, v := range result.Hits {
  499. assert.GreaterOrEqual(t, data[v.ID].UpdatedUnix, int64(20))
  500. assert.LessOrEqual(t, data[v.ID].UpdatedUnix, int64(30))
  501. }
  502. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool {
  503. return data[v.ID].UpdatedUnix >= 20 && data[v.ID].UpdatedUnix <= 30
  504. }), result.Total)
  505. },
  506. },
  507. {
  508. Name: "SortByCreatedDesc",
  509. SearchOptions: &internal.SearchOptions{
  510. Paginator: &db.ListOptionsAll,
  511. SortBy: internal.SortByCreatedDesc,
  512. },
  513. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  514. assert.Len(t, result.Hits, len(data))
  515. assert.Equal(t, len(data), int(result.Total))
  516. for i, v := range result.Hits {
  517. if i < len(result.Hits)-1 {
  518. assert.GreaterOrEqual(t, data[v.ID].CreatedUnix, data[result.Hits[i+1].ID].CreatedUnix)
  519. }
  520. }
  521. },
  522. },
  523. {
  524. Name: "SortByUpdatedDesc",
  525. SearchOptions: &internal.SearchOptions{
  526. Paginator: &db.ListOptionsAll,
  527. SortBy: internal.SortByUpdatedDesc,
  528. },
  529. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  530. assert.Len(t, result.Hits, len(data))
  531. assert.Equal(t, len(data), int(result.Total))
  532. for i, v := range result.Hits {
  533. if i < len(result.Hits)-1 {
  534. assert.GreaterOrEqual(t, data[v.ID].UpdatedUnix, data[result.Hits[i+1].ID].UpdatedUnix)
  535. }
  536. }
  537. },
  538. },
  539. {
  540. Name: "SortByCommentsDesc",
  541. SearchOptions: &internal.SearchOptions{
  542. Paginator: &db.ListOptionsAll,
  543. SortBy: internal.SortByCommentsDesc,
  544. },
  545. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  546. assert.Len(t, result.Hits, len(data))
  547. assert.Equal(t, len(data), int(result.Total))
  548. for i, v := range result.Hits {
  549. if i < len(result.Hits)-1 {
  550. assert.GreaterOrEqual(t, data[v.ID].CommentCount, data[result.Hits[i+1].ID].CommentCount)
  551. }
  552. }
  553. },
  554. },
  555. {
  556. Name: "SortByDeadlineDesc",
  557. SearchOptions: &internal.SearchOptions{
  558. Paginator: &db.ListOptionsAll,
  559. SortBy: internal.SortByDeadlineDesc,
  560. },
  561. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  562. assert.Len(t, result.Hits, len(data))
  563. assert.Equal(t, len(data), int(result.Total))
  564. for i, v := range result.Hits {
  565. if i < len(result.Hits)-1 {
  566. assert.GreaterOrEqual(t, data[v.ID].DeadlineUnix, data[result.Hits[i+1].ID].DeadlineUnix)
  567. }
  568. }
  569. },
  570. },
  571. {
  572. Name: "SortByCreatedAsc",
  573. SearchOptions: &internal.SearchOptions{
  574. Paginator: &db.ListOptionsAll,
  575. SortBy: internal.SortByCreatedAsc,
  576. },
  577. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  578. assert.Len(t, result.Hits, len(data))
  579. assert.Equal(t, len(data), int(result.Total))
  580. for i, v := range result.Hits {
  581. if i < len(result.Hits)-1 {
  582. assert.LessOrEqual(t, data[v.ID].CreatedUnix, data[result.Hits[i+1].ID].CreatedUnix)
  583. }
  584. }
  585. },
  586. },
  587. {
  588. Name: "SortByUpdatedAsc",
  589. SearchOptions: &internal.SearchOptions{
  590. Paginator: &db.ListOptionsAll,
  591. SortBy: internal.SortByUpdatedAsc,
  592. },
  593. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  594. assert.Len(t, result.Hits, len(data))
  595. assert.Equal(t, len(data), int(result.Total))
  596. for i, v := range result.Hits {
  597. if i < len(result.Hits)-1 {
  598. assert.LessOrEqual(t, data[v.ID].UpdatedUnix, data[result.Hits[i+1].ID].UpdatedUnix)
  599. }
  600. }
  601. },
  602. },
  603. {
  604. Name: "SortByCommentsAsc",
  605. SearchOptions: &internal.SearchOptions{
  606. Paginator: &db.ListOptionsAll,
  607. SortBy: internal.SortByCommentsAsc,
  608. },
  609. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  610. assert.Len(t, result.Hits, len(data))
  611. assert.Equal(t, len(data), int(result.Total))
  612. for i, v := range result.Hits {
  613. if i < len(result.Hits)-1 {
  614. assert.LessOrEqual(t, data[v.ID].CommentCount, data[result.Hits[i+1].ID].CommentCount)
  615. }
  616. }
  617. },
  618. },
  619. {
  620. Name: "SortByDeadlineAsc",
  621. SearchOptions: &internal.SearchOptions{
  622. Paginator: &db.ListOptionsAll,
  623. SortBy: internal.SortByDeadlineAsc,
  624. },
  625. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  626. assert.Len(t, result.Hits, len(data))
  627. assert.Equal(t, len(data), int(result.Total))
  628. for i, v := range result.Hits {
  629. if i < len(result.Hits)-1 {
  630. assert.LessOrEqual(t, data[v.ID].DeadlineUnix, data[result.Hits[i+1].ID].DeadlineUnix)
  631. }
  632. }
  633. },
  634. },
  635. {
  636. Name: "SearchAnyAssignee",
  637. SearchOptions: &internal.SearchOptions{
  638. AssigneeID: "(any)",
  639. },
  640. Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
  641. assert.Len(t, result.Hits, 180)
  642. for _, v := range result.Hits {
  643. assert.GreaterOrEqual(t, data[v.ID].AssigneeID, int64(1))
  644. }
  645. assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool {
  646. return v.AssigneeID >= 1
  647. }), result.Total)
  648. },
  649. },
  650. }
  651. type testIndexerCase struct {
  652. Name string
  653. ExtraData []*internal.IndexerData
  654. SearchOptions *internal.SearchOptions
  655. Expected func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) // if nil, use ExpectedIDs, ExpectedTotal
  656. ExpectedIDs []int64
  657. ExpectedTotal int64
  658. }
  659. func generateDefaultIndexerData() []*internal.IndexerData {
  660. var id int64
  661. var data []*internal.IndexerData
  662. for repoID := int64(1); repoID <= 10; repoID++ {
  663. for issueIndex := int64(1); issueIndex <= 20; issueIndex++ {
  664. id++
  665. comments := make([]string, id%4)
  666. for i := range comments {
  667. comments[i] = fmt.Sprintf("comment%d", i)
  668. }
  669. labelIDs := make([]int64, id%5)
  670. for i := range labelIDs {
  671. labelIDs[i] = int64(i) + 1 // LabelID should not be 0
  672. }
  673. mentionIDs := make([]int64, id%6)
  674. for i := range mentionIDs {
  675. mentionIDs[i] = int64(i) + 1 // MentionID should not be 0
  676. }
  677. reviewedIDs := make([]int64, id%7)
  678. for i := range reviewedIDs {
  679. reviewedIDs[i] = int64(i) + 1 // ReviewID should not be 0
  680. }
  681. reviewRequestedIDs := make([]int64, id%8)
  682. for i := range reviewRequestedIDs {
  683. reviewRequestedIDs[i] = int64(i) + 1 // ReviewRequestedID should not be 0
  684. }
  685. subscriberIDs := make([]int64, id%9)
  686. for i := range subscriberIDs {
  687. subscriberIDs[i] = int64(i) + 1 // SubscriberID should not be 0
  688. }
  689. data = append(data, &internal.IndexerData{
  690. ID: id,
  691. RepoID: repoID,
  692. IsPublic: repoID%2 == 0,
  693. Title: fmt.Sprintf("issue%d of repo%d", issueIndex, repoID),
  694. Content: fmt.Sprintf("content%d", issueIndex),
  695. Comments: comments,
  696. IsPull: issueIndex%2 == 0,
  697. IsClosed: issueIndex%3 == 0,
  698. LabelIDs: labelIDs,
  699. NoLabel: len(labelIDs) == 0,
  700. MilestoneID: issueIndex % 4,
  701. ProjectID: issueIndex % 5,
  702. ProjectColumnID: issueIndex % 6,
  703. PosterID: id%10 + 1, // PosterID should not be 0
  704. AssigneeID: issueIndex % 10,
  705. MentionIDs: mentionIDs,
  706. ReviewedIDs: reviewedIDs,
  707. ReviewRequestedIDs: reviewRequestedIDs,
  708. SubscriberIDs: subscriberIDs,
  709. UpdatedUnix: timeutil.TimeStamp(id + issueIndex),
  710. CreatedUnix: timeutil.TimeStamp(id),
  711. DeadlineUnix: timeutil.TimeStamp(id + issueIndex + repoID),
  712. CommentCount: int64(len(comments)),
  713. })
  714. }
  715. }
  716. return data
  717. }
  718. func countIndexerData(data map[int64]*internal.IndexerData, f func(v *internal.IndexerData) bool) int64 {
  719. var count int64
  720. for _, v := range data {
  721. if f(v) {
  722. count++
  723. }
  724. }
  725. return count
  726. }
  727. // waitData waits for the indexer to index all data.
  728. // Some engines like Elasticsearch index data asynchronously, so we need to wait for a while.
  729. func waitData(t *testing.T, indexer internal.Indexer, total int64) {
  730. assert.Eventually(t, func() bool {
  731. result, err := indexer.Search(t.Context(), &internal.SearchOptions{Paginator: &db.ListOptions{}})
  732. require.NoError(t, err)
  733. return result.Total == total
  734. }, 10*time.Second, 100*time.Millisecond, "expected total=%d", total)
  735. }