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