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.

api_packages_conan_test.go 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. // Copyright 2022 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package integration
  4. import (
  5. "fmt"
  6. "net/http"
  7. stdurl "net/url"
  8. "strings"
  9. "testing"
  10. "time"
  11. "code.gitea.io/gitea/models/db"
  12. "code.gitea.io/gitea/models/packages"
  13. conan_model "code.gitea.io/gitea/models/packages/conan"
  14. "code.gitea.io/gitea/models/unittest"
  15. user_model "code.gitea.io/gitea/models/user"
  16. conan_module "code.gitea.io/gitea/modules/packages/conan"
  17. "code.gitea.io/gitea/modules/setting"
  18. conan_router "code.gitea.io/gitea/routers/api/packages/conan"
  19. "code.gitea.io/gitea/tests"
  20. "github.com/stretchr/testify/assert"
  21. )
  22. const (
  23. conanfileName = "conanfile.py"
  24. conaninfoName = "conaninfo.txt"
  25. conanLicense = "MIT"
  26. conanAuthor = "Gitea <info@gitea.io>"
  27. conanHomepage = "https://gitea.io/"
  28. conanURL = "https://gitea.com/"
  29. conanDescription = "Description of ConanPackage"
  30. conanTopic = "gitea"
  31. conanPackageReference = "dummyreference"
  32. contentConaninfo = `[settings]
  33. arch=x84_64
  34. [requires]
  35. fmt/7.1.3
  36. [options]
  37. shared=False
  38. [full_settings]
  39. arch=x84_64
  40. [full_requires]
  41. fmt/7.1.3
  42. [full_options]
  43. shared=False
  44. [recipe_hash]
  45. 74714915a51073acb548ca1ce29afbac
  46. [env]
  47. CC=gcc-10`
  48. )
  49. func buildConanfileContent(name, version string) string {
  50. return `from conans import ConanFile, CMake, tools
  51. class ConanPackageConan(ConanFile):
  52. name = "` + name + `"
  53. version = "` + version + `"
  54. license = "` + conanLicense + `"
  55. author = "` + conanAuthor + `"
  56. homepage = "` + conanHomepage + `"
  57. url = "` + conanURL + `"
  58. description = "` + conanDescription + `"
  59. topics = ("` + conanTopic + `")
  60. settings = "os", "compiler", "build_type", "arch"
  61. options = {"shared": [True, False], "fPIC": [True, False]}
  62. default_options = {"shared": False, "fPIC": True}
  63. generators = "cmake"`
  64. }
  65. func uploadConanPackageV1(t *testing.T, baseURL, token, name, version, user, channel string) {
  66. contentConanfile := buildConanfileContent(name, version)
  67. recipeURL := fmt.Sprintf("%s/v1/conans/%s/%s/%s/%s", baseURL, name, version, user, channel)
  68. req := NewRequest(t, "GET", recipeURL).
  69. AddTokenAuth(token)
  70. MakeRequest(t, req, http.StatusNotFound)
  71. req = NewRequest(t, "GET", fmt.Sprintf("%s/digest", recipeURL)).
  72. AddTokenAuth(token)
  73. MakeRequest(t, req, http.StatusNotFound)
  74. req = NewRequest(t, "GET", fmt.Sprintf("%s/download_urls", recipeURL)).
  75. AddTokenAuth(token)
  76. MakeRequest(t, req, http.StatusNotFound)
  77. req = NewRequest(t, "POST", fmt.Sprintf("%s/upload_urls", recipeURL))
  78. MakeRequest(t, req, http.StatusUnauthorized)
  79. req = NewRequestWithJSON(t, "POST", fmt.Sprintf("%s/upload_urls", recipeURL), map[string]int64{
  80. conanfileName: int64(len(contentConanfile)),
  81. "removed.txt": 0,
  82. }).AddTokenAuth(token)
  83. resp := MakeRequest(t, req, http.StatusOK)
  84. uploadURLs := make(map[string]string)
  85. DecodeJSON(t, resp, &uploadURLs)
  86. assert.Contains(t, uploadURLs, conanfileName)
  87. assert.NotContains(t, uploadURLs, "removed.txt")
  88. uploadURL := uploadURLs[conanfileName]
  89. assert.NotEmpty(t, uploadURL)
  90. req = NewRequestWithBody(t, "PUT", uploadURL, strings.NewReader(contentConanfile)).
  91. AddTokenAuth(token)
  92. MakeRequest(t, req, http.StatusCreated)
  93. packageURL := fmt.Sprintf("%s/packages/%s", recipeURL, conanPackageReference)
  94. req = NewRequest(t, "GET", packageURL).
  95. AddTokenAuth(token)
  96. MakeRequest(t, req, http.StatusNotFound)
  97. req = NewRequest(t, "GET", fmt.Sprintf("%s/digest", packageURL)).
  98. AddTokenAuth(token)
  99. MakeRequest(t, req, http.StatusNotFound)
  100. req = NewRequest(t, "GET", fmt.Sprintf("%s/download_urls", packageURL)).
  101. AddTokenAuth(token)
  102. MakeRequest(t, req, http.StatusNotFound)
  103. req = NewRequest(t, "POST", fmt.Sprintf("%s/upload_urls", packageURL))
  104. MakeRequest(t, req, http.StatusUnauthorized)
  105. req = NewRequestWithJSON(t, "POST", fmt.Sprintf("%s/upload_urls", packageURL), map[string]int64{
  106. conaninfoName: int64(len(contentConaninfo)),
  107. "removed.txt": 0,
  108. }).AddTokenAuth(token)
  109. resp = MakeRequest(t, req, http.StatusOK)
  110. uploadURLs = make(map[string]string)
  111. DecodeJSON(t, resp, &uploadURLs)
  112. assert.Contains(t, uploadURLs, conaninfoName)
  113. assert.NotContains(t, uploadURLs, "removed.txt")
  114. uploadURL = uploadURLs[conaninfoName]
  115. assert.NotEmpty(t, uploadURL)
  116. req = NewRequestWithBody(t, "PUT", uploadURL, strings.NewReader(contentConaninfo)).
  117. AddTokenAuth(token)
  118. MakeRequest(t, req, http.StatusCreated)
  119. }
  120. func uploadConanPackageV2(t *testing.T, baseURL, token, name, version, user, channel, recipeRevision, packageRevision string) {
  121. contentConanfile := buildConanfileContent(name, version)
  122. recipeURL := fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s", baseURL, name, version, user, channel, recipeRevision)
  123. req := NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/files/%s", recipeURL, conanfileName), strings.NewReader(contentConanfile)).
  124. AddTokenAuth(token)
  125. MakeRequest(t, req, http.StatusCreated)
  126. req = NewRequest(t, "GET", fmt.Sprintf("%s/files", recipeURL)).
  127. AddTokenAuth(token)
  128. resp := MakeRequest(t, req, http.StatusOK)
  129. var list *struct {
  130. Files map[string]any `json:"files"`
  131. }
  132. DecodeJSON(t, resp, &list)
  133. assert.Len(t, list.Files, 1)
  134. assert.Contains(t, list.Files, conanfileName)
  135. packageURL := fmt.Sprintf("%s/packages/%s/revisions/%s", recipeURL, conanPackageReference, packageRevision)
  136. req = NewRequest(t, "GET", fmt.Sprintf("%s/files", packageURL)).
  137. AddTokenAuth(token)
  138. MakeRequest(t, req, http.StatusNotFound)
  139. req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/files/%s", packageURL, conaninfoName), strings.NewReader(contentConaninfo)).
  140. AddTokenAuth(token)
  141. MakeRequest(t, req, http.StatusCreated)
  142. req = NewRequest(t, "GET", fmt.Sprintf("%s/files", packageURL)).
  143. AddTokenAuth(token)
  144. resp = MakeRequest(t, req, http.StatusOK)
  145. list = nil
  146. DecodeJSON(t, resp, &list)
  147. assert.Len(t, list.Files, 1)
  148. assert.Contains(t, list.Files, conaninfoName)
  149. }
  150. func TestPackageConan(t *testing.T) {
  151. defer tests.PrepareTestEnv(t)()
  152. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  153. name := "ConanPackage"
  154. version1 := "1.2"
  155. version2 := "1.3"
  156. user1 := "dummy"
  157. user2 := "gitea"
  158. channel1 := "test"
  159. channel2 := "final"
  160. revision1 := "rev1"
  161. revision2 := "rev2"
  162. url := fmt.Sprintf("%sapi/packages/%s/conan", setting.AppURL, user.Name)
  163. t.Run("v1", func(t *testing.T) {
  164. t.Run("Ping", func(t *testing.T) {
  165. defer tests.PrintCurrentTest(t)()
  166. req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/ping", url))
  167. resp := MakeRequest(t, req, http.StatusOK)
  168. assert.Equal(t, "revisions", resp.Header().Get("X-Conan-Server-Capabilities"))
  169. })
  170. token := ""
  171. t.Run("Authenticate", func(t *testing.T) {
  172. defer tests.PrintCurrentTest(t)()
  173. req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/users/authenticate", url)).
  174. AddBasicAuth(user.Name)
  175. resp := MakeRequest(t, req, http.StatusOK)
  176. token = resp.Body.String()
  177. assert.NotEmpty(t, token)
  178. })
  179. t.Run("CheckCredentials", func(t *testing.T) {
  180. defer tests.PrintCurrentTest(t)()
  181. req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/users/check_credentials", url)).
  182. AddTokenAuth(token)
  183. MakeRequest(t, req, http.StatusOK)
  184. })
  185. t.Run("Upload", func(t *testing.T) {
  186. defer tests.PrintCurrentTest(t)()
  187. uploadConanPackageV1(t, url, token, name, version1, user1, channel1)
  188. t.Run("Validate", func(t *testing.T) {
  189. defer tests.PrintCurrentTest(t)()
  190. pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeConan)
  191. assert.NoError(t, err)
  192. assert.Len(t, pvs, 1)
  193. pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
  194. assert.NoError(t, err)
  195. assert.Nil(t, pd.SemVer)
  196. assert.Equal(t, name, pd.Package.Name)
  197. assert.Equal(t, version1, pd.Version.Version)
  198. assert.IsType(t, &conan_module.Metadata{}, pd.Metadata)
  199. metadata := pd.Metadata.(*conan_module.Metadata)
  200. assert.Equal(t, conanLicense, metadata.License)
  201. assert.Equal(t, conanAuthor, metadata.Author)
  202. assert.Equal(t, conanHomepage, metadata.ProjectURL)
  203. assert.Equal(t, conanURL, metadata.RepositoryURL)
  204. assert.Equal(t, conanDescription, metadata.Description)
  205. assert.Equal(t, []string{conanTopic}, metadata.Keywords)
  206. pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
  207. assert.NoError(t, err)
  208. assert.Len(t, pfs, 2)
  209. for _, pf := range pfs {
  210. pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID)
  211. assert.NoError(t, err)
  212. if pf.Name == conanfileName {
  213. assert.True(t, pf.IsLead)
  214. assert.Equal(t, int64(len(buildConanfileContent(name, version1))), pb.Size)
  215. } else if pf.Name == conaninfoName {
  216. assert.False(t, pf.IsLead)
  217. assert.Equal(t, int64(len(contentConaninfo)), pb.Size)
  218. } else {
  219. assert.FailNow(t, "unknown file: %s", pf.Name)
  220. }
  221. }
  222. })
  223. })
  224. t.Run("Download", func(t *testing.T) {
  225. defer tests.PrintCurrentTest(t)()
  226. recipeURL := fmt.Sprintf("%s/v1/conans/%s/%s/%s/%s", url, name, version1, user1, channel1)
  227. req := NewRequest(t, "GET", recipeURL)
  228. resp := MakeRequest(t, req, http.StatusOK)
  229. fileHashes := make(map[string]string)
  230. DecodeJSON(t, resp, &fileHashes)
  231. assert.Len(t, fileHashes, 1)
  232. assert.Contains(t, fileHashes, conanfileName)
  233. assert.Equal(t, "7abc52241c22090782c54731371847a8", fileHashes[conanfileName])
  234. req = NewRequest(t, "GET", fmt.Sprintf("%s/digest", recipeURL))
  235. resp = MakeRequest(t, req, http.StatusOK)
  236. downloadURLs := make(map[string]string)
  237. DecodeJSON(t, resp, &downloadURLs)
  238. assert.Contains(t, downloadURLs, conanfileName)
  239. req = NewRequest(t, "GET", fmt.Sprintf("%s/download_urls", recipeURL))
  240. resp = MakeRequest(t, req, http.StatusOK)
  241. DecodeJSON(t, resp, &downloadURLs)
  242. assert.Contains(t, downloadURLs, conanfileName)
  243. req = NewRequest(t, "GET", downloadURLs[conanfileName])
  244. resp = MakeRequest(t, req, http.StatusOK)
  245. assert.Equal(t, buildConanfileContent(name, version1), resp.Body.String())
  246. packageURL := fmt.Sprintf("%s/packages/%s", recipeURL, conanPackageReference)
  247. req = NewRequest(t, "GET", packageURL)
  248. resp = MakeRequest(t, req, http.StatusOK)
  249. fileHashes = make(map[string]string)
  250. DecodeJSON(t, resp, &fileHashes)
  251. assert.Len(t, fileHashes, 1)
  252. assert.Contains(t, fileHashes, conaninfoName)
  253. assert.Equal(t, "7628bfcc5b17f1470c468621a78df394", fileHashes[conaninfoName])
  254. req = NewRequest(t, "GET", fmt.Sprintf("%s/digest", packageURL))
  255. resp = MakeRequest(t, req, http.StatusOK)
  256. downloadURLs = make(map[string]string)
  257. DecodeJSON(t, resp, &downloadURLs)
  258. assert.Contains(t, downloadURLs, conaninfoName)
  259. req = NewRequest(t, "GET", fmt.Sprintf("%s/download_urls", packageURL))
  260. resp = MakeRequest(t, req, http.StatusOK)
  261. DecodeJSON(t, resp, &downloadURLs)
  262. assert.Contains(t, downloadURLs, conaninfoName)
  263. req = NewRequest(t, "GET", downloadURLs[conaninfoName])
  264. resp = MakeRequest(t, req, http.StatusOK)
  265. assert.Equal(t, contentConaninfo, resp.Body.String())
  266. })
  267. t.Run("Search", func(t *testing.T) {
  268. uploadConanPackageV1(t, url, token, name, version2, user1, channel1)
  269. uploadConanPackageV1(t, url, token, name, version1, user1, channel2)
  270. uploadConanPackageV1(t, url, token, name, version1, user2, channel1)
  271. uploadConanPackageV1(t, url, token, name, version1, user2, channel2)
  272. t.Run("Recipe", func(t *testing.T) {
  273. defer tests.PrintCurrentTest(t)()
  274. cases := []struct {
  275. Query string
  276. Expected []string
  277. }{
  278. {"ConanPackage", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  279. {"ConanPackage/1.2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  280. {"ConanPackage/1.1", []string{}},
  281. {"Conan*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  282. {"ConanPackage/", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  283. {"ConanPackage/*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  284. {"ConanPackage/1*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  285. {"ConanPackage/*2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  286. {"ConanPackage/1*2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  287. {"ConanPackage/1.2@", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  288. {"ConanPackage/1.2@du*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final"}},
  289. {"ConanPackage/1.2@du*/", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@dummy/final"}},
  290. {"ConanPackage/1.2@du*/*test", []string{"ConanPackage/1.2@dummy/test"}},
  291. {"ConanPackage/1.2@du*/*st", []string{"ConanPackage/1.2@dummy/test"}},
  292. {"ConanPackage/1.2@gitea/*", []string{"ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  293. {"*/*@dummy", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@dummy/final"}},
  294. {"*/*@*/final", []string{"ConanPackage/1.2@dummy/final", "ConanPackage/1.2@gitea/final"}},
  295. }
  296. for i, c := range cases {
  297. req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/conans/search?q=%s", url, stdurl.QueryEscape(c.Query)))
  298. resp := MakeRequest(t, req, http.StatusOK)
  299. var result *conan_router.SearchResult
  300. DecodeJSON(t, resp, &result)
  301. assert.ElementsMatch(t, c.Expected, result.Results, "case %d: unexpected result", i)
  302. }
  303. })
  304. t.Run("Package", func(t *testing.T) {
  305. defer tests.PrintCurrentTest(t)()
  306. req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/conans/%s/%s/%s/%s/search", url, name, version1, user1, channel2))
  307. resp := MakeRequest(t, req, http.StatusOK)
  308. var result map[string]*conan_module.Conaninfo
  309. DecodeJSON(t, resp, &result)
  310. assert.Contains(t, result, conanPackageReference)
  311. info := result[conanPackageReference]
  312. assert.NotEmpty(t, info.Settings)
  313. })
  314. })
  315. t.Run("Delete", func(t *testing.T) {
  316. t.Run("Package", func(t *testing.T) {
  317. defer tests.PrintCurrentTest(t)()
  318. cases := []struct {
  319. Channel string
  320. References []string
  321. }{
  322. {channel1, []string{conanPackageReference}},
  323. {channel2, []string{}},
  324. }
  325. for i, c := range cases {
  326. rref, _ := conan_module.NewRecipeReference(name, version1, user1, c.Channel, conan_module.DefaultRevision)
  327. references, err := conan_model.GetPackageReferences(db.DefaultContext, user.ID, rref)
  328. assert.NoError(t, err)
  329. assert.NotEmpty(t, references)
  330. req := NewRequestWithJSON(t, "POST", fmt.Sprintf("%s/v1/conans/%s/%s/%s/%s/packages/delete", url, name, version1, user1, c.Channel), map[string][]string{
  331. "package_ids": c.References,
  332. }).AddTokenAuth(token)
  333. MakeRequest(t, req, http.StatusOK)
  334. references, err = conan_model.GetPackageReferences(db.DefaultContext, user.ID, rref)
  335. assert.NoError(t, err)
  336. assert.Empty(t, references, "case %d: should be empty", i)
  337. }
  338. })
  339. t.Run("Recipe", func(t *testing.T) {
  340. defer tests.PrintCurrentTest(t)()
  341. cases := []struct {
  342. Channel string
  343. }{
  344. {channel1},
  345. {channel2},
  346. }
  347. for i, c := range cases {
  348. rref, _ := conan_module.NewRecipeReference(name, version1, user1, c.Channel, conan_module.DefaultRevision)
  349. revisions, err := conan_model.GetRecipeRevisions(db.DefaultContext, user.ID, rref)
  350. assert.NoError(t, err)
  351. assert.NotEmpty(t, revisions)
  352. req := NewRequest(t, "DELETE", fmt.Sprintf("%s/v1/conans/%s/%s/%s/%s", url, name, version1, user1, c.Channel)).
  353. AddTokenAuth(token)
  354. MakeRequest(t, req, http.StatusOK)
  355. revisions, err = conan_model.GetRecipeRevisions(db.DefaultContext, user.ID, rref)
  356. assert.NoError(t, err)
  357. assert.Empty(t, revisions, "case %d: should be empty", i)
  358. }
  359. })
  360. })
  361. })
  362. t.Run("v2", func(t *testing.T) {
  363. t.Run("Ping", func(t *testing.T) {
  364. defer tests.PrintCurrentTest(t)()
  365. req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/ping", url))
  366. resp := MakeRequest(t, req, http.StatusOK)
  367. assert.Equal(t, "revisions", resp.Header().Get("X-Conan-Server-Capabilities"))
  368. })
  369. token := ""
  370. t.Run("Authenticate", func(t *testing.T) {
  371. defer tests.PrintCurrentTest(t)()
  372. req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/users/authenticate", url)).
  373. AddBasicAuth(user.Name)
  374. resp := MakeRequest(t, req, http.StatusOK)
  375. body := resp.Body.String()
  376. assert.NotEmpty(t, body)
  377. token = fmt.Sprintf("Bearer %s", body)
  378. })
  379. t.Run("CheckCredentials", func(t *testing.T) {
  380. defer tests.PrintCurrentTest(t)()
  381. req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/users/check_credentials", url)).
  382. AddTokenAuth(token)
  383. MakeRequest(t, req, http.StatusOK)
  384. })
  385. t.Run("Upload", func(t *testing.T) {
  386. defer tests.PrintCurrentTest(t)()
  387. uploadConanPackageV2(t, url, token, name, version1, user1, channel1, revision1, revision1)
  388. t.Run("Validate", func(t *testing.T) {
  389. defer tests.PrintCurrentTest(t)()
  390. pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeConan)
  391. assert.NoError(t, err)
  392. assert.Len(t, pvs, 2)
  393. })
  394. })
  395. t.Run("Latest", func(t *testing.T) {
  396. defer tests.PrintCurrentTest(t)()
  397. recipeURL := fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s", url, name, version1, user1, channel1)
  398. req := NewRequest(t, "GET", fmt.Sprintf("%s/latest", recipeURL))
  399. resp := MakeRequest(t, req, http.StatusOK)
  400. obj := make(map[string]string)
  401. DecodeJSON(t, resp, &obj)
  402. assert.Contains(t, obj, "revision")
  403. assert.Equal(t, revision1, obj["revision"])
  404. req = NewRequest(t, "GET", fmt.Sprintf("%s/revisions/%s/packages/%s/latest", recipeURL, revision1, conanPackageReference))
  405. resp = MakeRequest(t, req, http.StatusOK)
  406. obj = make(map[string]string)
  407. DecodeJSON(t, resp, &obj)
  408. assert.Contains(t, obj, "revision")
  409. assert.Equal(t, revision1, obj["revision"])
  410. })
  411. t.Run("ListRevisions", func(t *testing.T) {
  412. defer tests.PrintCurrentTest(t)()
  413. uploadConanPackageV2(t, url, token, name, version1, user1, channel1, revision1, revision2)
  414. uploadConanPackageV2(t, url, token, name, version1, user1, channel1, revision2, revision1)
  415. uploadConanPackageV2(t, url, token, name, version1, user1, channel1, revision2, revision2)
  416. recipeURL := fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions", url, name, version1, user1, channel1)
  417. req := NewRequest(t, "GET", recipeURL)
  418. resp := MakeRequest(t, req, http.StatusOK)
  419. type RevisionInfo struct {
  420. Revision string `json:"revision"`
  421. Time time.Time `json:"time"`
  422. }
  423. type RevisionList struct {
  424. Revisions []*RevisionInfo `json:"revisions"`
  425. }
  426. var list *RevisionList
  427. DecodeJSON(t, resp, &list)
  428. assert.Len(t, list.Revisions, 2)
  429. revs := make([]string, 0, len(list.Revisions))
  430. for _, rev := range list.Revisions {
  431. revs = append(revs, rev.Revision)
  432. }
  433. assert.ElementsMatch(t, []string{revision1, revision2}, revs)
  434. req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/packages/%s/revisions", recipeURL, revision1, conanPackageReference))
  435. resp = MakeRequest(t, req, http.StatusOK)
  436. DecodeJSON(t, resp, &list)
  437. assert.Len(t, list.Revisions, 2)
  438. revs = make([]string, 0, len(list.Revisions))
  439. for _, rev := range list.Revisions {
  440. revs = append(revs, rev.Revision)
  441. }
  442. assert.ElementsMatch(t, []string{revision1, revision2}, revs)
  443. })
  444. t.Run("Search", func(t *testing.T) {
  445. t.Run("Recipe", func(t *testing.T) {
  446. defer tests.PrintCurrentTest(t)()
  447. cases := []struct {
  448. Query string
  449. Expected []string
  450. }{
  451. {"ConanPackage", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  452. {"ConanPackage/1.2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  453. {"ConanPackage/1.1", []string{}},
  454. {"Conan*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  455. {"ConanPackage/", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  456. {"ConanPackage/*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  457. {"ConanPackage/1*", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  458. {"ConanPackage/*2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  459. {"ConanPackage/1*2", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  460. {"ConanPackage/1.2@", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  461. {"ConanPackage/1.2@du*", []string{"ConanPackage/1.2@dummy/test"}},
  462. {"ConanPackage/1.2@du*/", []string{"ConanPackage/1.2@dummy/test"}},
  463. {"ConanPackage/1.2@du*/*test", []string{"ConanPackage/1.2@dummy/test"}},
  464. {"ConanPackage/1.2@du*/*st", []string{"ConanPackage/1.2@dummy/test"}},
  465. {"ConanPackage/1.2@gitea/*", []string{"ConanPackage/1.2@gitea/test", "ConanPackage/1.2@gitea/final"}},
  466. {"*/*@dummy", []string{"ConanPackage/1.2@dummy/test", "ConanPackage/1.3@dummy/test"}},
  467. {"*/*@*/final", []string{"ConanPackage/1.2@gitea/final"}},
  468. }
  469. for i, c := range cases {
  470. req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/conans/search?q=%s", url, stdurl.QueryEscape(c.Query)))
  471. resp := MakeRequest(t, req, http.StatusOK)
  472. var result *conan_router.SearchResult
  473. DecodeJSON(t, resp, &result)
  474. assert.ElementsMatch(t, c.Expected, result.Results, "case %d: unexpected result", i)
  475. }
  476. })
  477. t.Run("Package", func(t *testing.T) {
  478. defer tests.PrintCurrentTest(t)()
  479. req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/search", url, name, version1, user1, channel1))
  480. resp := MakeRequest(t, req, http.StatusOK)
  481. var result map[string]*conan_module.Conaninfo
  482. DecodeJSON(t, resp, &result)
  483. assert.Contains(t, result, conanPackageReference)
  484. info := result[conanPackageReference]
  485. assert.NotEmpty(t, info.Settings)
  486. req = NewRequest(t, "GET", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s/search", url, name, version1, user1, channel1, revision1))
  487. resp = MakeRequest(t, req, http.StatusOK)
  488. result = make(map[string]*conan_module.Conaninfo)
  489. DecodeJSON(t, resp, &result)
  490. assert.Contains(t, result, conanPackageReference)
  491. info = result[conanPackageReference]
  492. assert.NotEmpty(t, info.Settings)
  493. })
  494. })
  495. t.Run("Delete", func(t *testing.T) {
  496. t.Run("Package", func(t *testing.T) {
  497. defer tests.PrintCurrentTest(t)()
  498. rref, _ := conan_module.NewRecipeReference(name, version1, user1, channel1, revision1)
  499. pref, _ := conan_module.NewPackageReference(rref, conanPackageReference, conan_module.DefaultRevision)
  500. checkPackageRevisionCount := func(count int) {
  501. revisions, err := conan_model.GetPackageRevisions(db.DefaultContext, user.ID, pref)
  502. assert.NoError(t, err)
  503. assert.Len(t, revisions, count)
  504. }
  505. checkPackageReferenceCount := func(count int) {
  506. references, err := conan_model.GetPackageReferences(db.DefaultContext, user.ID, rref)
  507. assert.NoError(t, err)
  508. assert.Len(t, references, count)
  509. }
  510. checkPackageRevisionCount(2)
  511. req := NewRequest(t, "DELETE", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s/packages/%s/revisions/%s", url, name, version1, user1, channel1, revision1, conanPackageReference, revision1)).
  512. AddTokenAuth(token)
  513. MakeRequest(t, req, http.StatusOK)
  514. checkPackageRevisionCount(1)
  515. req = NewRequest(t, "DELETE", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s/packages/%s", url, name, version1, user1, channel1, revision1, conanPackageReference)).
  516. AddTokenAuth(token)
  517. MakeRequest(t, req, http.StatusOK)
  518. checkPackageRevisionCount(0)
  519. rref = rref.WithRevision(revision2)
  520. checkPackageReferenceCount(1)
  521. req = NewRequest(t, "DELETE", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s/packages", url, name, version1, user1, channel1, revision2)).
  522. AddTokenAuth(token)
  523. MakeRequest(t, req, http.StatusOK)
  524. checkPackageReferenceCount(0)
  525. })
  526. t.Run("Recipe", func(t *testing.T) {
  527. defer tests.PrintCurrentTest(t)()
  528. rref, _ := conan_module.NewRecipeReference(name, version1, user1, channel1, conan_module.DefaultRevision)
  529. checkRecipeRevisionCount := func(count int) {
  530. revisions, err := conan_model.GetRecipeRevisions(db.DefaultContext, user.ID, rref)
  531. assert.NoError(t, err)
  532. assert.Len(t, revisions, count)
  533. }
  534. checkRecipeRevisionCount(2)
  535. req := NewRequest(t, "DELETE", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s/revisions/%s", url, name, version1, user1, channel1, revision1)).
  536. AddTokenAuth(token)
  537. MakeRequest(t, req, http.StatusOK)
  538. checkRecipeRevisionCount(1)
  539. req = NewRequest(t, "DELETE", fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s", url, name, version1, user1, channel1)).
  540. AddTokenAuth(token)
  541. MakeRequest(t, req, http.StatusOK)
  542. checkRecipeRevisionCount(0)
  543. })
  544. })
  545. })
  546. }