gitea源码

api_packages_cargo_test.go 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package integration
  4. import (
  5. "bytes"
  6. "encoding/binary"
  7. "fmt"
  8. "io"
  9. "net/http"
  10. neturl "net/url"
  11. "testing"
  12. "code.gitea.io/gitea/models/packages"
  13. repo_model "code.gitea.io/gitea/models/repo"
  14. "code.gitea.io/gitea/models/unittest"
  15. user_model "code.gitea.io/gitea/models/user"
  16. "code.gitea.io/gitea/modules/gitrepo"
  17. "code.gitea.io/gitea/modules/json"
  18. cargo_module "code.gitea.io/gitea/modules/packages/cargo"
  19. "code.gitea.io/gitea/modules/setting"
  20. cargo_router "code.gitea.io/gitea/routers/api/packages/cargo"
  21. cargo_service "code.gitea.io/gitea/services/packages/cargo"
  22. "code.gitea.io/gitea/tests"
  23. "github.com/stretchr/testify/assert"
  24. )
  25. func TestPackageCargo(t *testing.T) {
  26. onGiteaRun(t, testPackageCargo)
  27. }
  28. func testPackageCargo(t *testing.T, _ *neturl.URL) {
  29. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  30. packageName := "cargo-package"
  31. packageVersion := "1.0.3"
  32. packageDescription := "Package Description"
  33. packageAuthor := "KN4CK3R"
  34. packageHomepage := "https://gitea.io/"
  35. packageLicense := "MIT"
  36. createPackage := func(name, version string) io.Reader {
  37. metadata := `{
  38. "name":"` + name + `",
  39. "vers":"` + version + `",
  40. "description":"` + packageDescription + `",
  41. "authors": ["` + packageAuthor + `"],
  42. "deps":[
  43. {
  44. "name":"dep",
  45. "version_req":"1.0",
  46. "registry": "https://gitea.io/user/_cargo-index",
  47. "kind": "normal",
  48. "default_features": true
  49. }
  50. ],
  51. "homepage":"` + packageHomepage + `",
  52. "license":"` + packageLicense + `"
  53. }`
  54. var buf bytes.Buffer
  55. binary.Write(&buf, binary.LittleEndian, uint32(len(metadata)))
  56. buf.WriteString(metadata)
  57. binary.Write(&buf, binary.LittleEndian, uint32(4))
  58. buf.WriteString("test")
  59. return &buf
  60. }
  61. err := cargo_service.InitializeIndexRepository(t.Context(), user, user)
  62. assert.NoError(t, err)
  63. repo, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), user.Name, cargo_service.IndexRepositoryName)
  64. assert.NotNil(t, repo)
  65. assert.NoError(t, err)
  66. readGitContent := func(t *testing.T, path string) string {
  67. gitRepo, err := gitrepo.OpenRepository(t.Context(), repo)
  68. assert.NoError(t, err)
  69. defer gitRepo.Close()
  70. commit, err := gitRepo.GetBranchCommit(repo.DefaultBranch)
  71. assert.NoError(t, err)
  72. blob, err := commit.GetBlobByPath(path)
  73. assert.NoError(t, err)
  74. content, err := blob.GetBlobContent(1024)
  75. assert.NoError(t, err)
  76. return content
  77. }
  78. root := fmt.Sprintf("%sapi/packages/%s/cargo", setting.AppURL, user.Name)
  79. url := root + "/api/v1/crates"
  80. t.Run("Index", func(t *testing.T) {
  81. t.Run("Git/Config", func(t *testing.T) {
  82. defer tests.PrintCurrentTest(t)()
  83. content := readGitContent(t, cargo_service.ConfigFileName)
  84. var config cargo_service.Config
  85. err := json.Unmarshal([]byte(content), &config)
  86. assert.NoError(t, err)
  87. assert.Equal(t, url, config.DownloadURL)
  88. assert.Equal(t, root, config.APIURL)
  89. })
  90. t.Run("HTTP/Config", func(t *testing.T) {
  91. defer tests.PrintCurrentTest(t)()
  92. req := NewRequest(t, "GET", root+"/"+cargo_service.ConfigFileName)
  93. resp := MakeRequest(t, req, http.StatusOK)
  94. var config cargo_service.Config
  95. err := json.Unmarshal(resp.Body.Bytes(), &config)
  96. assert.NoError(t, err)
  97. assert.Equal(t, url, config.DownloadURL)
  98. assert.Equal(t, root, config.APIURL)
  99. })
  100. })
  101. t.Run("Upload", func(t *testing.T) {
  102. t.Run("InvalidNameOrVersion", func(t *testing.T) {
  103. defer tests.PrintCurrentTest(t)()
  104. content := createPackage("0test", "1.0.0")
  105. req := NewRequestWithBody(t, "PUT", url+"/new", content).
  106. AddBasicAuth(user.Name)
  107. resp := MakeRequest(t, req, http.StatusBadRequest)
  108. var status cargo_router.StatusResponse
  109. DecodeJSON(t, resp, &status)
  110. assert.False(t, status.OK)
  111. content = createPackage("test", "-1.0.0")
  112. req = NewRequestWithBody(t, "PUT", url+"/new", content).
  113. AddBasicAuth(user.Name)
  114. resp = MakeRequest(t, req, http.StatusBadRequest)
  115. DecodeJSON(t, resp, &status)
  116. assert.False(t, status.OK)
  117. })
  118. t.Run("InvalidContent", func(t *testing.T) {
  119. defer tests.PrintCurrentTest(t)()
  120. metadata := `{"name":"test","vers":"1.0.0"}`
  121. var buf bytes.Buffer
  122. binary.Write(&buf, binary.LittleEndian, uint32(len(metadata)))
  123. buf.WriteString(metadata)
  124. binary.Write(&buf, binary.LittleEndian, uint32(4))
  125. buf.WriteString("te")
  126. req := NewRequestWithBody(t, "PUT", url+"/new", &buf).
  127. AddBasicAuth(user.Name)
  128. MakeRequest(t, req, http.StatusBadRequest)
  129. })
  130. t.Run("Valid", func(t *testing.T) {
  131. defer tests.PrintCurrentTest(t)()
  132. req := NewRequestWithBody(t, "PUT", url+"/new", createPackage(packageName, packageVersion))
  133. MakeRequest(t, req, http.StatusUnauthorized)
  134. req = NewRequestWithBody(t, "PUT", url+"/new", createPackage(packageName, packageVersion)).
  135. AddBasicAuth(user.Name)
  136. resp := MakeRequest(t, req, http.StatusOK)
  137. var status cargo_router.StatusResponse
  138. DecodeJSON(t, resp, &status)
  139. assert.True(t, status.OK)
  140. pvs, err := packages.GetVersionsByPackageType(t.Context(), user.ID, packages.TypeCargo)
  141. assert.NoError(t, err)
  142. assert.Len(t, pvs, 1)
  143. pd, err := packages.GetPackageDescriptor(t.Context(), pvs[0])
  144. assert.NoError(t, err)
  145. assert.NotNil(t, pd.SemVer)
  146. assert.IsType(t, &cargo_module.Metadata{}, pd.Metadata)
  147. assert.Equal(t, packageName, pd.Package.Name)
  148. assert.Equal(t, packageVersion, pd.Version.Version)
  149. pfs, err := packages.GetFilesByVersionID(t.Context(), pvs[0].ID)
  150. assert.NoError(t, err)
  151. assert.Len(t, pfs, 1)
  152. assert.Equal(t, fmt.Sprintf("%s-%s.crate", packageName, packageVersion), pfs[0].Name)
  153. assert.True(t, pfs[0].IsLead)
  154. pb, err := packages.GetBlobByID(t.Context(), pfs[0].BlobID)
  155. assert.NoError(t, err)
  156. assert.EqualValues(t, 4, pb.Size)
  157. req = NewRequestWithBody(t, "PUT", url+"/new", createPackage(packageName, packageVersion)).
  158. AddBasicAuth(user.Name)
  159. MakeRequest(t, req, http.StatusConflict)
  160. t.Run("Index", func(t *testing.T) {
  161. t.Run("Git", func(t *testing.T) {
  162. t.Run("Entry", func(t *testing.T) {
  163. defer tests.PrintCurrentTest(t)()
  164. content := readGitContent(t, cargo_service.BuildPackagePath(packageName))
  165. var entry cargo_service.IndexVersionEntry
  166. err := json.Unmarshal([]byte(content), &entry)
  167. assert.NoError(t, err)
  168. assert.Equal(t, packageName, entry.Name)
  169. assert.Equal(t, packageVersion, entry.Version)
  170. assert.Equal(t, pb.HashSHA256, entry.FileChecksum)
  171. assert.False(t, entry.Yanked)
  172. assert.Len(t, entry.Dependencies, 1)
  173. dep := entry.Dependencies[0]
  174. assert.Equal(t, "dep", dep.Name)
  175. assert.Equal(t, "1.0", dep.Req)
  176. assert.Equal(t, "normal", dep.Kind)
  177. assert.True(t, dep.DefaultFeatures)
  178. assert.Empty(t, dep.Features)
  179. assert.False(t, dep.Optional)
  180. assert.Nil(t, dep.Target)
  181. assert.NotNil(t, dep.Registry)
  182. assert.Equal(t, "https://gitea.io/user/_cargo-index", *dep.Registry)
  183. assert.Nil(t, dep.Package)
  184. })
  185. t.Run("Rebuild", func(t *testing.T) {
  186. defer tests.PrintCurrentTest(t)()
  187. err := cargo_service.RebuildIndex(t.Context(), user, user)
  188. assert.NoError(t, err)
  189. _ = readGitContent(t, cargo_service.BuildPackagePath(packageName))
  190. })
  191. })
  192. t.Run("HTTP", func(t *testing.T) {
  193. t.Run("Entry", func(t *testing.T) {
  194. defer tests.PrintCurrentTest(t)()
  195. req := NewRequest(t, "GET", root+"/"+cargo_service.BuildPackagePath(packageName))
  196. resp := MakeRequest(t, req, http.StatusOK)
  197. var entry cargo_service.IndexVersionEntry
  198. err := json.Unmarshal(resp.Body.Bytes(), &entry)
  199. assert.NoError(t, err)
  200. assert.Equal(t, packageName, entry.Name)
  201. assert.Equal(t, packageVersion, entry.Version)
  202. assert.Equal(t, pb.HashSHA256, entry.FileChecksum)
  203. assert.False(t, entry.Yanked)
  204. assert.Len(t, entry.Dependencies, 1)
  205. dep := entry.Dependencies[0]
  206. assert.Equal(t, "dep", dep.Name)
  207. assert.Equal(t, "1.0", dep.Req)
  208. assert.Equal(t, "normal", dep.Kind)
  209. assert.True(t, dep.DefaultFeatures)
  210. assert.Empty(t, dep.Features)
  211. assert.False(t, dep.Optional)
  212. assert.Nil(t, dep.Target)
  213. assert.NotNil(t, dep.Registry)
  214. assert.Equal(t, "https://gitea.io/user/_cargo-index", *dep.Registry)
  215. assert.Nil(t, dep.Package)
  216. })
  217. })
  218. })
  219. })
  220. })
  221. t.Run("Download", func(t *testing.T) {
  222. defer tests.PrintCurrentTest(t)()
  223. pv, err := packages.GetVersionByNameAndVersion(t.Context(), user.ID, packages.TypeCargo, packageName, packageVersion)
  224. assert.NoError(t, err)
  225. assert.EqualValues(t, 0, pv.DownloadCount)
  226. pfs, err := packages.GetFilesByVersionID(t.Context(), pv.ID)
  227. assert.NoError(t, err)
  228. assert.Len(t, pfs, 1)
  229. req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s/download", url, neturl.PathEscape(packageName), neturl.PathEscape(pv.Version))).
  230. AddBasicAuth(user.Name)
  231. resp := MakeRequest(t, req, http.StatusOK)
  232. assert.Equal(t, "test", resp.Body.String())
  233. pv, err = packages.GetVersionByNameAndVersion(t.Context(), user.ID, packages.TypeCargo, packageName, packageVersion)
  234. assert.NoError(t, err)
  235. assert.EqualValues(t, 1, pv.DownloadCount)
  236. })
  237. t.Run("Search", func(t *testing.T) {
  238. defer tests.PrintCurrentTest(t)()
  239. cases := []struct {
  240. Query string
  241. Page int
  242. PerPage int
  243. ExpectedTotal int64
  244. ExpectedResults int
  245. }{
  246. {"", 0, 0, 1, 1},
  247. {"", 1, 10, 1, 1},
  248. {"cargo", 1, 0, 1, 1},
  249. {"cargo", 1, 10, 1, 1},
  250. {"cargo", 2, 10, 1, 0},
  251. {"test", 0, 10, 0, 0},
  252. }
  253. for i, c := range cases {
  254. req := NewRequest(t, "GET", fmt.Sprintf("%s?q=%s&page=%d&per_page=%d", url, c.Query, c.Page, c.PerPage)).
  255. AddBasicAuth(user.Name)
  256. resp := MakeRequest(t, req, http.StatusOK)
  257. var result cargo_router.SearchResult
  258. DecodeJSON(t, resp, &result)
  259. assert.Equal(t, c.ExpectedTotal, result.Meta.Total, "case %d: unexpected total hits", i)
  260. assert.Len(t, result.Crates, c.ExpectedResults, "case %d: unexpected result count", i)
  261. }
  262. })
  263. t.Run("Yank", func(t *testing.T) {
  264. defer tests.PrintCurrentTest(t)()
  265. req := NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s/yank", url, neturl.PathEscape(packageName), neturl.PathEscape(packageVersion))).
  266. AddBasicAuth(user.Name)
  267. resp := MakeRequest(t, req, http.StatusOK)
  268. var status cargo_router.StatusResponse
  269. DecodeJSON(t, resp, &status)
  270. assert.True(t, status.OK)
  271. content := readGitContent(t, cargo_service.BuildPackagePath(packageName))
  272. var entry cargo_service.IndexVersionEntry
  273. err := json.Unmarshal([]byte(content), &entry)
  274. assert.NoError(t, err)
  275. assert.True(t, entry.Yanked)
  276. })
  277. t.Run("Unyank", func(t *testing.T) {
  278. defer tests.PrintCurrentTest(t)()
  279. req := NewRequest(t, "PUT", fmt.Sprintf("%s/%s/%s/unyank", url, neturl.PathEscape(packageName), neturl.PathEscape(packageVersion))).
  280. AddBasicAuth(user.Name)
  281. resp := MakeRequest(t, req, http.StatusOK)
  282. var status cargo_router.StatusResponse
  283. DecodeJSON(t, resp, &status)
  284. assert.True(t, status.OK)
  285. content := readGitContent(t, cargo_service.BuildPackagePath(packageName))
  286. var entry cargo_service.IndexVersionEntry
  287. err := json.Unmarshal([]byte(content), &entry)
  288. assert.NoError(t, err)
  289. assert.False(t, entry.Yanked)
  290. })
  291. t.Run("ListOwners", func(t *testing.T) {
  292. defer tests.PrintCurrentTest(t)()
  293. req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/owners", url, neturl.PathEscape(packageName)))
  294. resp := MakeRequest(t, req, http.StatusOK)
  295. var owners cargo_router.Owners
  296. DecodeJSON(t, resp, &owners)
  297. assert.Len(t, owners.Users, 1)
  298. assert.Equal(t, user.ID, owners.Users[0].ID)
  299. assert.Equal(t, user.Name, owners.Users[0].Login)
  300. assert.Equal(t, user.DisplayName(), owners.Users[0].Name)
  301. })
  302. }