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_conda_test.go 9.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. // Copyright 2022 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package integration
  4. import (
  5. "archive/tar"
  6. "archive/zip"
  7. "bytes"
  8. "fmt"
  9. "io"
  10. "net/http"
  11. "testing"
  12. "code.gitea.io/gitea/models/db"
  13. "code.gitea.io/gitea/models/packages"
  14. "code.gitea.io/gitea/models/unittest"
  15. user_model "code.gitea.io/gitea/models/user"
  16. conda_module "code.gitea.io/gitea/modules/packages/conda"
  17. "code.gitea.io/gitea/tests"
  18. "github.com/dsnet/compress/bzip2"
  19. "github.com/klauspost/compress/zstd"
  20. "github.com/stretchr/testify/assert"
  21. )
  22. func TestPackageConda(t *testing.T) {
  23. defer tests.PrepareTestEnv(t)()
  24. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  25. packageName := "test_package"
  26. packageVersion := "1.0.1"
  27. channel := "test-channel"
  28. root := fmt.Sprintf("/api/packages/%s/conda", user.Name)
  29. t.Run("Upload", func(t *testing.T) {
  30. tarContent := func() []byte {
  31. var buf bytes.Buffer
  32. tw := tar.NewWriter(&buf)
  33. content := []byte(`{"name":"` + packageName + `","version":"` + packageVersion + `","subdir":"noarch","build":"xxx"}`)
  34. hdr := &tar.Header{
  35. Name: "info/index.json",
  36. Mode: 0o600,
  37. Size: int64(len(content)),
  38. }
  39. tw.WriteHeader(hdr)
  40. tw.Write(content)
  41. tw.Close()
  42. return buf.Bytes()
  43. }()
  44. t.Run(".tar.bz2", func(t *testing.T) {
  45. defer tests.PrintCurrentTest(t)()
  46. var buf bytes.Buffer
  47. bw, _ := bzip2.NewWriter(&buf, nil)
  48. io.Copy(bw, bytes.NewReader(tarContent))
  49. bw.Close()
  50. filename := fmt.Sprintf("%s-%s.tar.bz2", packageName, packageVersion)
  51. req := NewRequestWithBody(t, "PUT", root+"/"+filename, bytes.NewReader(buf.Bytes()))
  52. MakeRequest(t, req, http.StatusUnauthorized)
  53. req = NewRequestWithBody(t, "PUT", root+"/"+filename, bytes.NewReader(buf.Bytes()))
  54. AddBasicAuthHeader(req, user.Name)
  55. MakeRequest(t, req, http.StatusCreated)
  56. req = NewRequestWithBody(t, "PUT", root+"/"+filename, bytes.NewReader(buf.Bytes()))
  57. AddBasicAuthHeader(req, user.Name)
  58. MakeRequest(t, req, http.StatusConflict)
  59. pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeConda)
  60. assert.NoError(t, err)
  61. assert.Len(t, pvs, 1)
  62. pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
  63. assert.NoError(t, err)
  64. assert.Nil(t, pd.SemVer)
  65. assert.IsType(t, &conda_module.VersionMetadata{}, pd.Metadata)
  66. assert.Equal(t, packageName, pd.Package.Name)
  67. assert.Equal(t, packageVersion, pd.Version.Version)
  68. assert.Empty(t, pd.PackageProperties.GetByName(conda_module.PropertyChannel))
  69. })
  70. t.Run(".conda", func(t *testing.T) {
  71. defer tests.PrintCurrentTest(t)()
  72. var infoBuf bytes.Buffer
  73. zsw, _ := zstd.NewWriter(&infoBuf)
  74. io.Copy(zsw, bytes.NewReader(tarContent))
  75. zsw.Close()
  76. var buf bytes.Buffer
  77. zpw := zip.NewWriter(&buf)
  78. w, _ := zpw.Create("info-x.tar.zst")
  79. w.Write(infoBuf.Bytes())
  80. zpw.Close()
  81. fullName := channel + "/" + packageName
  82. filename := fmt.Sprintf("%s-%s.conda", packageName, packageVersion)
  83. req := NewRequestWithBody(t, "PUT", root+"/"+channel+"/"+filename, bytes.NewReader(buf.Bytes()))
  84. MakeRequest(t, req, http.StatusUnauthorized)
  85. req = NewRequestWithBody(t, "PUT", root+"/"+channel+"/"+filename, bytes.NewReader(buf.Bytes()))
  86. AddBasicAuthHeader(req, user.Name)
  87. MakeRequest(t, req, http.StatusCreated)
  88. req = NewRequestWithBody(t, "PUT", root+"/"+channel+"/"+filename, bytes.NewReader(buf.Bytes()))
  89. AddBasicAuthHeader(req, user.Name)
  90. MakeRequest(t, req, http.StatusConflict)
  91. pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeConda)
  92. assert.NoError(t, err)
  93. assert.Len(t, pvs, 2)
  94. pds, err := packages.GetPackageDescriptors(db.DefaultContext, pvs)
  95. assert.NoError(t, err)
  96. assert.Condition(t, func() bool {
  97. for _, pd := range pds {
  98. if pd.Package.Name == fullName {
  99. return true
  100. }
  101. }
  102. return false
  103. })
  104. for _, pd := range pds {
  105. if pd.Package.Name == fullName {
  106. assert.Nil(t, pd.SemVer)
  107. assert.IsType(t, &conda_module.VersionMetadata{}, pd.Metadata)
  108. assert.Equal(t, fullName, pd.Package.Name)
  109. assert.Equal(t, packageVersion, pd.Version.Version)
  110. assert.Equal(t, channel, pd.PackageProperties.GetByName(conda_module.PropertyChannel))
  111. }
  112. }
  113. })
  114. })
  115. t.Run("Download", func(t *testing.T) {
  116. t.Run(".tar.bz2", func(t *testing.T) {
  117. defer tests.PrintCurrentTest(t)()
  118. req := NewRequest(t, "GET", fmt.Sprintf("%s/noarch/%s-%s-xxx.tar.bz2", root, packageName, packageVersion))
  119. MakeRequest(t, req, http.StatusOK)
  120. req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/noarch/%s-%s-xxx.tar.bz2", root, channel, packageName, packageVersion))
  121. MakeRequest(t, req, http.StatusNotFound)
  122. })
  123. t.Run(".conda", func(t *testing.T) {
  124. defer tests.PrintCurrentTest(t)()
  125. req := NewRequest(t, "GET", fmt.Sprintf("%s/noarch/%s-%s-xxx.conda", root, packageName, packageVersion))
  126. MakeRequest(t, req, http.StatusNotFound)
  127. req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/noarch/%s-%s-xxx.conda", root, channel, packageName, packageVersion))
  128. MakeRequest(t, req, http.StatusOK)
  129. })
  130. })
  131. t.Run("EnumeratePackages", func(t *testing.T) {
  132. type Info struct {
  133. Subdir string `json:"subdir"`
  134. }
  135. type PackageInfo struct {
  136. Name string `json:"name"`
  137. Version string `json:"version"`
  138. NoArch string `json:"noarch"`
  139. Subdir string `json:"subdir"`
  140. Timestamp int64 `json:"timestamp"`
  141. Build string `json:"build"`
  142. BuildNumber int64 `json:"build_number"`
  143. Dependencies []string `json:"depends"`
  144. License string `json:"license"`
  145. LicenseFamily string `json:"license_family"`
  146. HashMD5 string `json:"md5"`
  147. HashSHA256 string `json:"sha256"`
  148. Size int64 `json:"size"`
  149. }
  150. type RepoData struct {
  151. Info Info `json:"info"`
  152. Packages map[string]*PackageInfo `json:"packages"`
  153. PackagesConda map[string]*PackageInfo `json:"packages.conda"`
  154. Removed map[string]*PackageInfo `json:"removed"`
  155. }
  156. req := NewRequest(t, "GET", fmt.Sprintf("%s/noarch/repodata.json", root))
  157. resp := MakeRequest(t, req, http.StatusOK)
  158. assert.Equal(t, "application/json", resp.Header().Get("Content-Type"))
  159. req = NewRequest(t, "GET", fmt.Sprintf("%s/noarch/repodata.json.bz2", root))
  160. resp = MakeRequest(t, req, http.StatusOK)
  161. assert.Equal(t, "application/x-bzip2", resp.Header().Get("Content-Type"))
  162. req = NewRequest(t, "GET", fmt.Sprintf("%s/noarch/current_repodata.json", root))
  163. resp = MakeRequest(t, req, http.StatusOK)
  164. assert.Equal(t, "application/json", resp.Header().Get("Content-Type"))
  165. req = NewRequest(t, "GET", fmt.Sprintf("%s/noarch/current_repodata.json.bz2", root))
  166. resp = MakeRequest(t, req, http.StatusOK)
  167. assert.Equal(t, "application/x-bzip2", resp.Header().Get("Content-Type"))
  168. t.Run(".tar.bz2", func(t *testing.T) {
  169. defer tests.PrintCurrentTest(t)()
  170. pv, err := packages.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages.TypeConda, packageName, packageVersion)
  171. assert.NoError(t, err)
  172. pd, err := packages.GetPackageDescriptor(db.DefaultContext, pv)
  173. assert.NoError(t, err)
  174. req := NewRequest(t, "GET", fmt.Sprintf("%s/noarch/repodata.json", root))
  175. resp := MakeRequest(t, req, http.StatusOK)
  176. var result RepoData
  177. DecodeJSON(t, resp, &result)
  178. assert.Equal(t, "noarch", result.Info.Subdir)
  179. assert.Empty(t, result.PackagesConda)
  180. assert.Empty(t, result.Removed)
  181. filename := fmt.Sprintf("%s-%s-xxx.tar.bz2", packageName, packageVersion)
  182. assert.Contains(t, result.Packages, filename)
  183. packageInfo := result.Packages[filename]
  184. assert.Equal(t, packageName, packageInfo.Name)
  185. assert.Equal(t, packageVersion, packageInfo.Version)
  186. assert.Equal(t, "noarch", packageInfo.Subdir)
  187. assert.Equal(t, "xxx", packageInfo.Build)
  188. assert.Equal(t, pd.Files[0].Blob.HashMD5, packageInfo.HashMD5)
  189. assert.Equal(t, pd.Files[0].Blob.HashSHA256, packageInfo.HashSHA256)
  190. assert.Equal(t, pd.Files[0].Blob.Size, packageInfo.Size)
  191. })
  192. t.Run(".conda", func(t *testing.T) {
  193. defer tests.PrintCurrentTest(t)()
  194. pv, err := packages.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages.TypeConda, channel+"/"+packageName, packageVersion)
  195. assert.NoError(t, err)
  196. pd, err := packages.GetPackageDescriptor(db.DefaultContext, pv)
  197. assert.NoError(t, err)
  198. req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/noarch/repodata.json", root, channel))
  199. resp := MakeRequest(t, req, http.StatusOK)
  200. var result RepoData
  201. DecodeJSON(t, resp, &result)
  202. assert.Equal(t, "noarch", result.Info.Subdir)
  203. assert.Empty(t, result.Packages)
  204. assert.Empty(t, result.Removed)
  205. filename := fmt.Sprintf("%s-%s-xxx.conda", packageName, packageVersion)
  206. assert.Contains(t, result.PackagesConda, filename)
  207. packageInfo := result.PackagesConda[filename]
  208. assert.Equal(t, packageName, packageInfo.Name)
  209. assert.Equal(t, packageVersion, packageInfo.Version)
  210. assert.Equal(t, "noarch", packageInfo.Subdir)
  211. assert.Equal(t, "xxx", packageInfo.Build)
  212. assert.Equal(t, pd.Files[0].Blob.HashMD5, packageInfo.HashMD5)
  213. assert.Equal(t, pd.Files[0].Blob.HashSHA256, packageInfo.HashSHA256)
  214. assert.Equal(t, pd.Files[0].Blob.Size, packageInfo.Size)
  215. })
  216. })
  217. }