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