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