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.

tests.go 23KB

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