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.

repo_list_test.go 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package repo_test
  4. import (
  5. "strings"
  6. "testing"
  7. "code.gitea.io/gitea/models/db"
  8. repo_model "code.gitea.io/gitea/models/repo"
  9. "code.gitea.io/gitea/models/unittest"
  10. "code.gitea.io/gitea/modules/util"
  11. "github.com/stretchr/testify/assert"
  12. )
  13. func getTestCases() []struct {
  14. name string
  15. opts *repo_model.SearchRepoOptions
  16. count int
  17. } {
  18. testCases := []struct {
  19. name string
  20. opts *repo_model.SearchRepoOptions
  21. count int
  22. }{
  23. {
  24. name: "PublicRepositoriesByName",
  25. opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, Collaborate: util.OptionalBoolFalse},
  26. count: 7,
  27. },
  28. {
  29. name: "PublicAndPrivateRepositoriesByName",
  30. opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, Collaborate: util.OptionalBoolFalse},
  31. count: 14,
  32. },
  33. {
  34. name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFirstPage",
  35. opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse},
  36. count: 14,
  37. },
  38. {
  39. name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitSecondPage",
  40. opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 2, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse},
  41. count: 14,
  42. },
  43. {
  44. name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitThirdPage",
  45. opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse},
  46. count: 14,
  47. },
  48. {
  49. name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFourthPage",
  50. opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse},
  51. count: 14,
  52. },
  53. {
  54. name: "PublicRepositoriesOfUser",
  55. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Collaborate: util.OptionalBoolFalse},
  56. count: 2,
  57. },
  58. {
  59. name: "PublicRepositoriesOfUser2",
  60. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Collaborate: util.OptionalBoolFalse},
  61. count: 0,
  62. },
  63. {
  64. name: "PublicRepositoriesOfOrg3",
  65. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Collaborate: util.OptionalBoolFalse},
  66. count: 2,
  67. },
  68. {
  69. name: "PublicAndPrivateRepositoriesOfUser",
  70. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, Collaborate: util.OptionalBoolFalse},
  71. count: 4,
  72. },
  73. {
  74. name: "PublicAndPrivateRepositoriesOfUser2",
  75. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, Collaborate: util.OptionalBoolFalse},
  76. count: 0,
  77. },
  78. {
  79. name: "PublicAndPrivateRepositoriesOfOrg3",
  80. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true, Collaborate: util.OptionalBoolFalse},
  81. count: 4,
  82. },
  83. {
  84. name: "PublicRepositoriesOfUserIncludingCollaborative",
  85. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15},
  86. count: 5,
  87. },
  88. {
  89. name: "PublicRepositoriesOfUser2IncludingCollaborative",
  90. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18},
  91. count: 1,
  92. },
  93. {
  94. name: "PublicRepositoriesOfOrg3IncludingCollaborative",
  95. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20},
  96. count: 3,
  97. },
  98. {
  99. name: "PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
  100. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true},
  101. count: 9,
  102. },
  103. {
  104. name: "PublicAndPrivateRepositoriesOfUser2IncludingCollaborative",
  105. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true},
  106. count: 4,
  107. },
  108. {
  109. name: "PublicAndPrivateRepositoriesOfOrg3IncludingCollaborative",
  110. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true},
  111. count: 7,
  112. },
  113. {
  114. name: "PublicRepositoriesOfOrganization",
  115. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Collaborate: util.OptionalBoolFalse},
  116. count: 1,
  117. },
  118. {
  119. name: "PublicAndPrivateRepositoriesOfOrganization",
  120. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Private: true, Collaborate: util.OptionalBoolFalse},
  121. count: 2,
  122. },
  123. {
  124. name: "AllPublic/PublicRepositoriesByName",
  125. opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, AllPublic: true, Collaborate: util.OptionalBoolFalse},
  126. count: 7,
  127. },
  128. {
  129. name: "AllPublic/PublicAndPrivateRepositoriesByName",
  130. opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, AllPublic: true, Collaborate: util.OptionalBoolFalse},
  131. count: 14,
  132. },
  133. {
  134. name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative",
  135. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: util.OptionalBoolFalse},
  136. count: 31,
  137. },
  138. {
  139. name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
  140. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: util.OptionalBoolFalse},
  141. count: 36,
  142. },
  143. {
  144. name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
  145. opts: &repo_model.SearchRepoOptions{Keyword: "test", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true},
  146. count: 15,
  147. },
  148. {
  149. name: "AllPublic/PublicAndPrivateRepositoriesOfUser2IncludingCollaborativeByName",
  150. opts: &repo_model.SearchRepoOptions{Keyword: "test", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, AllPublic: true},
  151. count: 13,
  152. },
  153. {
  154. name: "AllPublic/PublicRepositoriesOfOrganization",
  155. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse, Template: util.OptionalBoolFalse},
  156. count: 31,
  157. },
  158. {
  159. name: "AllTemplates",
  160. opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Template: util.OptionalBoolTrue},
  161. count: 2,
  162. },
  163. {
  164. name: "OwnerSlashRepoSearch",
  165. opts: &repo_model.SearchRepoOptions{Keyword: "user/repo2", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, OwnerID: 0},
  166. count: 2,
  167. },
  168. {
  169. name: "OwnerSlashSearch",
  170. opts: &repo_model.SearchRepoOptions{Keyword: "user20/", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, OwnerID: 0},
  171. count: 4,
  172. },
  173. }
  174. return testCases
  175. }
  176. func TestSearchRepository(t *testing.T) {
  177. assert.NoError(t, unittest.PrepareTestDatabase())
  178. // test search public repository on explore page
  179. repos, count, err := repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{
  180. ListOptions: db.ListOptions{
  181. Page: 1,
  182. PageSize: 10,
  183. },
  184. Keyword: "repo_12",
  185. Collaborate: util.OptionalBoolFalse,
  186. })
  187. assert.NoError(t, err)
  188. if assert.Len(t, repos, 1) {
  189. assert.Equal(t, "test_repo_12", repos[0].Name)
  190. }
  191. assert.Equal(t, int64(1), count)
  192. repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{
  193. ListOptions: db.ListOptions{
  194. Page: 1,
  195. PageSize: 10,
  196. },
  197. Keyword: "test_repo",
  198. Collaborate: util.OptionalBoolFalse,
  199. })
  200. assert.NoError(t, err)
  201. assert.Equal(t, int64(2), count)
  202. assert.Len(t, repos, 2)
  203. // test search private repository on explore page
  204. repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{
  205. ListOptions: db.ListOptions{
  206. Page: 1,
  207. PageSize: 10,
  208. },
  209. Keyword: "repo_13",
  210. Private: true,
  211. Collaborate: util.OptionalBoolFalse,
  212. })
  213. assert.NoError(t, err)
  214. if assert.Len(t, repos, 1) {
  215. assert.Equal(t, "test_repo_13", repos[0].Name)
  216. }
  217. assert.Equal(t, int64(1), count)
  218. repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{
  219. ListOptions: db.ListOptions{
  220. Page: 1,
  221. PageSize: 10,
  222. },
  223. Keyword: "test_repo",
  224. Private: true,
  225. Collaborate: util.OptionalBoolFalse,
  226. })
  227. assert.NoError(t, err)
  228. assert.Equal(t, int64(3), count)
  229. assert.Len(t, repos, 3)
  230. // Test non existing owner
  231. repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{OwnerID: unittest.NonexistentID})
  232. assert.NoError(t, err)
  233. assert.Empty(t, repos)
  234. assert.Equal(t, int64(0), count)
  235. // Test search within description
  236. repos, count, err = repo_model.SearchRepository(db.DefaultContext, &repo_model.SearchRepoOptions{
  237. ListOptions: db.ListOptions{
  238. Page: 1,
  239. PageSize: 10,
  240. },
  241. Keyword: "description_14",
  242. Collaborate: util.OptionalBoolFalse,
  243. IncludeDescription: true,
  244. })
  245. assert.NoError(t, err)
  246. if assert.Len(t, repos, 1) {
  247. assert.Equal(t, "test_repo_14", repos[0].Name)
  248. }
  249. assert.Equal(t, int64(1), count)
  250. // Test NOT search within description
  251. repos, count, err = repo_model.SearchRepository(db.DefaultContext, &repo_model.SearchRepoOptions{
  252. ListOptions: db.ListOptions{
  253. Page: 1,
  254. PageSize: 10,
  255. },
  256. Keyword: "description_14",
  257. Collaborate: util.OptionalBoolFalse,
  258. IncludeDescription: false,
  259. })
  260. assert.NoError(t, err)
  261. assert.Empty(t, repos)
  262. assert.Equal(t, int64(0), count)
  263. testCases := getTestCases()
  264. for _, testCase := range testCases {
  265. t.Run(testCase.name, func(t *testing.T) {
  266. repos, count, err := repo_model.SearchRepositoryByName(db.DefaultContext, testCase.opts)
  267. assert.NoError(t, err)
  268. assert.Equal(t, int64(testCase.count), count)
  269. page := testCase.opts.Page
  270. if page <= 0 {
  271. page = 1
  272. }
  273. expectedLen := testCase.opts.PageSize
  274. if testCase.opts.PageSize*page > testCase.count+testCase.opts.PageSize {
  275. expectedLen = 0
  276. } else if testCase.opts.PageSize*page > testCase.count {
  277. expectedLen = testCase.count % testCase.opts.PageSize
  278. }
  279. if assert.Len(t, repos, expectedLen) {
  280. for _, repo := range repos {
  281. assert.NotEmpty(t, repo.Name)
  282. if len(testCase.opts.Keyword) > 0 {
  283. // Keyword match condition is different for search terms of form "owner/repo"
  284. if strings.Count(testCase.opts.Keyword, "/") == 1 {
  285. // May still match as a whole...
  286. wholeMatch := strings.Contains(repo.Name, testCase.opts.Keyword)
  287. pieces := strings.Split(testCase.opts.Keyword, "/")
  288. ownerName := pieces[0]
  289. repoName := pieces[1]
  290. // ... or match in parts
  291. splitMatch := strings.Contains(repo.OwnerName, ownerName) && strings.Contains(repo.Name, repoName)
  292. assert.True(t, wholeMatch || splitMatch, "Keyword '%s' does not match repo '%s/%s'", testCase.opts.Keyword, repo.Owner.Name, repo.Name)
  293. } else {
  294. assert.Contains(t, repo.Name, testCase.opts.Keyword)
  295. }
  296. }
  297. if !testCase.opts.Private {
  298. assert.False(t, repo.IsPrivate)
  299. }
  300. if testCase.opts.Fork == util.OptionalBoolTrue && testCase.opts.Mirror == util.OptionalBoolTrue {
  301. assert.True(t, repo.IsFork || repo.IsMirror)
  302. } else {
  303. switch testCase.opts.Fork {
  304. case util.OptionalBoolFalse:
  305. assert.False(t, repo.IsFork)
  306. case util.OptionalBoolTrue:
  307. assert.True(t, repo.IsFork)
  308. }
  309. switch testCase.opts.Mirror {
  310. case util.OptionalBoolFalse:
  311. assert.False(t, repo.IsMirror)
  312. case util.OptionalBoolTrue:
  313. assert.True(t, repo.IsMirror)
  314. }
  315. }
  316. if testCase.opts.OwnerID > 0 && !testCase.opts.AllPublic {
  317. switch testCase.opts.Collaborate {
  318. case util.OptionalBoolFalse:
  319. assert.Equal(t, testCase.opts.OwnerID, repo.Owner.ID)
  320. case util.OptionalBoolTrue:
  321. assert.NotEqual(t, testCase.opts.OwnerID, repo.Owner.ID)
  322. }
  323. }
  324. }
  325. }
  326. })
  327. }
  328. }
  329. func TestCountRepository(t *testing.T) {
  330. assert.NoError(t, unittest.PrepareTestDatabase())
  331. testCases := getTestCases()
  332. for _, testCase := range testCases {
  333. t.Run(testCase.name, func(t *testing.T) {
  334. count, err := repo_model.CountRepository(db.DefaultContext, testCase.opts)
  335. assert.NoError(t, err)
  336. assert.Equal(t, int64(testCase.count), count)
  337. })
  338. }
  339. }
  340. func TestSearchRepositoryByTopicName(t *testing.T) {
  341. assert.NoError(t, unittest.PrepareTestDatabase())
  342. testCases := []struct {
  343. name string
  344. opts *repo_model.SearchRepoOptions
  345. count int
  346. }{
  347. {
  348. name: "AllPublic/SearchPublicRepositoriesFromTopicAndName",
  349. opts: &repo_model.SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql"},
  350. count: 2,
  351. },
  352. {
  353. name: "AllPublic/OnlySearchPublicRepositoriesFromTopic",
  354. opts: &repo_model.SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql", TopicOnly: true},
  355. count: 1,
  356. },
  357. {
  358. name: "AllPublic/OnlySearchMultipleKeywordPublicRepositoriesFromTopic",
  359. opts: &repo_model.SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql,golang", TopicOnly: true},
  360. count: 2,
  361. },
  362. }
  363. for _, testCase := range testCases {
  364. t.Run(testCase.name, func(t *testing.T) {
  365. _, count, err := repo_model.SearchRepositoryByName(db.DefaultContext, testCase.opts)
  366. assert.NoError(t, err)
  367. assert.Equal(t, int64(testCase.count), count)
  368. })
  369. }
  370. }