| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934 |
- // Copyright 2021 The Gitea Authors. All rights reserved.
- // SPDX-License-Identifier: MIT
-
- package integration
-
- import (
- "archive/zip"
- "bytes"
- "encoding/base64"
- "encoding/xml"
- "fmt"
- "io"
- "net/http"
- "net/http/httptest"
- neturl "net/url"
- "strconv"
- "strings"
- "testing"
- "time"
-
- auth_model "code.gitea.io/gitea/models/auth"
- "code.gitea.io/gitea/models/packages"
- "code.gitea.io/gitea/models/unittest"
- user_model "code.gitea.io/gitea/models/user"
- nuget_module "code.gitea.io/gitea/modules/packages/nuget"
- "code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/structs"
- "code.gitea.io/gitea/routers/api/packages/nuget"
- packageService "code.gitea.io/gitea/services/packages"
- "code.gitea.io/gitea/tests"
-
- "github.com/stretchr/testify/assert"
- )
-
- func addNuGetAPIKeyHeader(req *RequestWrapper, token string) {
- req.SetHeader("X-NuGet-ApiKey", token)
- }
-
- func decodeXML(t testing.TB, resp *httptest.ResponseRecorder, v any) {
- t.Helper()
-
- assert.NoError(t, xml.NewDecoder(resp.Body).Decode(v))
- }
-
- func TestPackageNuGet(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
-
- type FeedEntryProperties struct {
- Authors string `xml:"Authors"`
- Copyright string `xml:"Copyright,omitempty"`
- Created nuget.TypedValue[time.Time] `xml:"Created"`
- Dependencies string `xml:"Dependencies"`
- Description string `xml:"Description"`
- DevelopmentDependency nuget.TypedValue[bool] `xml:"DevelopmentDependency"`
- DownloadCount nuget.TypedValue[int64] `xml:"DownloadCount"`
- ID string `xml:"Id"`
- IconURL string `xml:"IconUrl,omitempty"`
- Language string `xml:"Language,omitempty"`
- LastUpdated nuget.TypedValue[time.Time] `xml:"LastUpdated"`
- LicenseURL string `xml:"LicenseUrl,omitempty"`
- MinClientVersion string `xml:"MinClientVersion,omitempty"`
- NormalizedVersion string `xml:"NormalizedVersion"`
- Owners string `xml:"Owners,omitempty"`
- PackageSize nuget.TypedValue[int64] `xml:"PackageSize"`
- ProjectURL string `xml:"ProjectUrl,omitempty"`
- Published nuget.TypedValue[time.Time] `xml:"Published"`
- ReleaseNotes string `xml:"ReleaseNotes,omitempty"`
- RequireLicenseAcceptance nuget.TypedValue[bool] `xml:"RequireLicenseAcceptance"`
- Tags string `xml:"Tags,omitempty"`
- Title string `xml:"Title"`
- Version string `xml:"Version"`
- VersionDownloadCount nuget.TypedValue[int64] `xml:"VersionDownloadCount"`
- }
-
- type FeedEntry struct {
- XMLName xml.Name `xml:"entry"`
- Properties *FeedEntryProperties `xml:"properties"`
- Content string `xml:",innerxml"`
- }
-
- type FeedEntryLink struct {
- Rel string `xml:"rel,attr"`
- Href string `xml:"href,attr"`
- }
-
- type FeedResponse struct {
- XMLName xml.Name `xml:"feed"`
- Links []FeedEntryLink `xml:"link"`
- Entries []*FeedEntry `xml:"entry"`
- Count int64 `xml:"count"`
- }
-
- user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
- writeToken := getUserToken(t, user.Name, auth_model.AccessTokenScopeWritePackage)
- readToken := getUserToken(t, user.Name, auth_model.AccessTokenScopeReadPackage)
- badToken := getUserToken(t, user.Name, auth_model.AccessTokenScopeReadNotification)
-
- packageName := "test.package" // id
- packageID := packageName
- packageVersion := "1.0.3"
- packageAuthors := "KN4CK3R"
- packageDescription := "Gitea Test Package"
- isPrerelease := strings.Contains(packageVersion, "-")
-
- symbolFilename := "test.pdb"
- symbolID := "d910bb6948bd4c6cb40155bcf52c3c94"
-
- packageCopyright := "Package Copyright"
- packageIconURL := "https://gitea.io/favicon.png"
- packageLanguage := "Package Language"
- packageLicenseURL := "https://gitea.io/license"
- packageMinClientVersion := "1.0.0.0"
- packageOwners := "Package Owners"
- packageProjectURL := "https://gitea.io"
- packageReleaseNotes := "Package Release Notes"
- summary := "This is a test package."
- packageTags := "tag_1 tag_2 tag_3"
- packageTitle := "Package Title"
- packageDevelopmentDependency := true
- packageRequireLicenseAcceptance := true
-
- dependencyCount := 1
- dependencyTargetFramework := ".NETStandard2.0"
- dependencyID := "Microsoft.CSharp"
- dependencyVersion := "4.5.0"
-
- createNuspec := func(id, version string) string {
- return `<?xml version="1.0" encoding="utf-8"?>
- <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
- <metadata minClientVersion="` + packageMinClientVersion + `">
- <authors>` + packageAuthors + `</authors>
- <copyright>` + packageCopyright + `</copyright>
- <description>` + packageDescription + `</description>
- <developmentDependency>true</developmentDependency>
- <iconUrl>` + packageIconURL + `</iconUrl>
- <id>` + id + `</id>
- <language>` + packageLanguage + `</language>
- <licenseUrl>` + packageLicenseURL + `</licenseUrl>
- <owners>` + packageOwners + `</owners>
- <projectUrl>` + packageProjectURL + `</projectUrl>
- <releaseNotes>` + packageReleaseNotes + `</releaseNotes>
- <requireLicenseAcceptance>true</requireLicenseAcceptance>
- <summary>` + summary + `</summary>
- <tags>` + packageTags + `</tags>
- <title>` + packageTitle + `</title>
- <version>` + version + `</version>
- <dependencies>
- <group targetFramework="` + dependencyTargetFramework + `">
- <dependency id="` + dependencyID + `" version="` + dependencyVersion + `" />
- </group>
- </dependencies>
- </metadata>
- </package>`
- }
-
- createPackage := func(id, version string) *bytes.Buffer {
- var buf bytes.Buffer
- archive := zip.NewWriter(&buf)
- w, _ := archive.Create("package.nuspec")
- w.Write([]byte(createNuspec(id, version)))
- archive.Close()
- return &buf
- }
-
- content := createPackage(packageName, packageVersion).Bytes()
-
- url := fmt.Sprintf("/api/packages/%s/nuget", user.Name)
-
- t.Run("ServiceIndex", func(t *testing.T) {
- t.Run("v2", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- privateUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{Visibility: structs.VisibleTypePrivate})
-
- cases := []struct {
- Owner string
- UseBasicAuth bool
- token string
- expectedStatus int
- }{
- {privateUser.Name, false, "", http.StatusOK},
- {privateUser.Name, true, "", http.StatusOK},
- {privateUser.Name, false, writeToken, http.StatusOK},
- {privateUser.Name, false, readToken, http.StatusOK},
- {privateUser.Name, false, badToken, http.StatusOK},
- {user.Name, false, "", http.StatusOK},
- {user.Name, true, "", http.StatusOK},
- {user.Name, false, writeToken, http.StatusOK},
- {user.Name, false, readToken, http.StatusOK},
- {user.Name, false, badToken, http.StatusOK},
- }
-
- for _, c := range cases {
- t.Run(c.Owner, func(t *testing.T) {
- url := fmt.Sprintf("/api/packages/%s/nuget", c.Owner)
-
- req := NewRequest(t, "GET", url)
- if c.UseBasicAuth {
- req.AddBasicAuth(user.Name)
- } else if c.token != "" {
- addNuGetAPIKeyHeader(req, c.token)
- }
- resp := MakeRequest(t, req, c.expectedStatus)
- if c.expectedStatus != http.StatusOK {
- return
- }
-
- var result nuget.ServiceIndexResponseV2
- decodeXML(t, resp, &result)
-
- assert.Equal(t, setting.AppURL+url[1:], result.Base)
- assert.Equal(t, "Packages", result.Workspace.Collection.Href)
- })
- }
- })
-
- t.Run("v3", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- privateUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{Visibility: structs.VisibleTypePrivate})
-
- cases := []struct {
- Owner string
- UseBasicAuth bool
- token string
- expectedStatus int
- }{
- {privateUser.Name, false, "", http.StatusOK},
- {privateUser.Name, true, "", http.StatusOK},
- {privateUser.Name, false, writeToken, http.StatusOK},
- {privateUser.Name, false, readToken, http.StatusOK},
- {privateUser.Name, false, badToken, http.StatusOK},
- {user.Name, false, "", http.StatusOK},
- {user.Name, true, "", http.StatusOK},
- {user.Name, false, writeToken, http.StatusOK},
- {user.Name, false, readToken, http.StatusOK},
- {user.Name, false, badToken, http.StatusOK},
- }
-
- for _, c := range cases {
- t.Run(c.Owner, func(t *testing.T) {
- url := fmt.Sprintf("/api/packages/%s/nuget", c.Owner)
-
- req := NewRequest(t, "GET", url+"/index.json")
- if c.UseBasicAuth {
- req.AddBasicAuth(user.Name)
- } else if c.token != "" {
- addNuGetAPIKeyHeader(req, c.token)
- }
- resp := MakeRequest(t, req, c.expectedStatus)
-
- if c.expectedStatus != http.StatusOK {
- return
- }
-
- var result nuget.ServiceIndexResponseV3
- DecodeJSON(t, resp, &result)
-
- assert.Equal(t, "3.0.0", result.Version)
- assert.NotEmpty(t, result.Resources)
-
- root := setting.AppURL + url[1:]
- for _, r := range result.Resources {
- switch r.Type {
- case "SearchQueryService":
- fallthrough
- case "SearchQueryService/3.0.0-beta":
- fallthrough
- case "SearchQueryService/3.0.0-rc":
- assert.Equal(t, root+"/query", r.ID)
- case "RegistrationsBaseUrl":
- fallthrough
- case "RegistrationsBaseUrl/3.0.0-beta":
- fallthrough
- case "RegistrationsBaseUrl/3.0.0-rc":
- assert.Equal(t, root+"/registration", r.ID)
- case "PackageBaseAddress/3.0.0":
- assert.Equal(t, root+"/package", r.ID)
- case "PackagePublish/2.0.0":
- assert.Equal(t, root, r.ID)
- }
- }
- })
- }
- })
- })
-
- t.Run("Upload", func(t *testing.T) {
- t.Run("DependencyPackage", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- // create with username/password
- req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content)).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusCreated)
-
- pvs, err := packages.GetVersionsByPackageType(t.Context(), user.ID, packages.TypeNuGet)
- assert.NoError(t, err)
- assert.Len(t, pvs, 1, "Should have one version")
-
- pd, err := packages.GetPackageDescriptor(t.Context(), pvs[0])
- assert.NoError(t, err)
- assert.NotNil(t, pd.SemVer)
- assert.IsType(t, &nuget_module.Metadata{}, pd.Metadata)
- assert.Equal(t, packageName, pd.Package.Name)
- assert.Equal(t, packageVersion, pd.Version.Version)
-
- pfs, err := packages.GetFilesByVersionID(t.Context(), pvs[0].ID)
- assert.NoError(t, err)
- assert.Len(t, pfs, 2, "Should have 2 files: nuget and nuspec")
- for _, pf := range pfs {
- switch pf.Name {
- case fmt.Sprintf("%s.%s.nupkg", packageName, packageVersion):
- assert.True(t, pf.IsLead)
-
- pb, err := packages.GetBlobByID(t.Context(), pf.BlobID)
- assert.NoError(t, err)
- assert.Equal(t, int64(len(content)), pb.Size)
- case packageName + ".nuspec":
- assert.False(t, pf.IsLead)
- default:
- assert.Fail(t, "unexpected filename", "unexpected filename: %v", pf.Name)
- }
- }
-
- req = NewRequestWithBody(t, "PUT", url, bytes.NewReader(content)).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusConflict)
-
- // delete the package
- assert.NoError(t, packageService.DeletePackageVersionAndReferences(t.Context(), pvs[0]))
-
- // create failure with token without write access
- req = NewRequestWithBody(t, "PUT", url, bytes.NewReader(content)).
- AddTokenAuth(readToken)
- MakeRequest(t, req, http.StatusUnauthorized)
-
- // create with token
- req = NewRequestWithBody(t, "PUT", url, bytes.NewReader(content)).
- AddTokenAuth(writeToken)
- MakeRequest(t, req, http.StatusCreated)
-
- pvs, err = packages.GetVersionsByPackageType(t.Context(), user.ID, packages.TypeNuGet)
- assert.NoError(t, err)
- assert.Len(t, pvs, 1, "Should have one version")
-
- pd, err = packages.GetPackageDescriptor(t.Context(), pvs[0])
- assert.NoError(t, err)
- assert.NotNil(t, pd.SemVer)
- assert.IsType(t, &nuget_module.Metadata{}, pd.Metadata)
- assert.Equal(t, packageName, pd.Package.Name)
- assert.Equal(t, packageVersion, pd.Version.Version)
-
- pfs, err = packages.GetFilesByVersionID(t.Context(), pvs[0].ID)
- assert.NoError(t, err)
- assert.Len(t, pfs, 2, "Should have 2 files: nuget and nuspec")
- for _, pf := range pfs {
- switch pf.Name {
- case fmt.Sprintf("%s.%s.nupkg", packageName, packageVersion):
- assert.True(t, pf.IsLead)
-
- pb, err := packages.GetBlobByID(t.Context(), pf.BlobID)
- assert.NoError(t, err)
- assert.Equal(t, int64(len(content)), pb.Size)
- case packageName + ".nuspec":
- assert.False(t, pf.IsLead)
- default:
- assert.Fail(t, "unexpected filename", "unexpected filename: %v", pf.Name)
- }
- }
-
- req = NewRequestWithBody(t, "PUT", url, bytes.NewReader(content)).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusConflict)
- })
-
- t.Run("SymbolPackage", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- createSymbolPackage := func(id, packageType string) io.Reader {
- var buf bytes.Buffer
- archive := zip.NewWriter(&buf)
-
- w, _ := archive.Create("package.nuspec")
- w.Write([]byte(`<?xml version="1.0" encoding="utf-8"?>
- <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
- <metadata>
- <id>` + id + `</id>
- <version>` + packageVersion + `</version>
- <authors>` + packageAuthors + `</authors>
- <description>` + packageDescription + `</description>
- <packageTypes><packageType name="` + packageType + `" /></packageTypes>
- </metadata>
- </package>`))
-
- w, _ = archive.Create(symbolFilename)
- b, _ := base64.StdEncoding.DecodeString(`QlNKQgEAAQAAAAAADAAAAFBEQiB2MS4wAAAAAAAABgB8AAAAWAAAACNQZGIAAAAA1AAAAAgBAAAj
- fgAA3AEAAAQAAAAjU3RyaW5ncwAAAADgAQAABAAAACNVUwDkAQAAMAAAACNHVUlEAAAAFAIAACgB
- AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
- w.Write(b)
-
- archive.Close()
- return &buf
- }
-
- req := NewRequestWithBody(t, "PUT", url+"/symbolpackage", createSymbolPackage("unknown-package", "SymbolsPackage")).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusNotFound)
-
- req = NewRequestWithBody(t, "PUT", url+"/symbolpackage", createSymbolPackage(packageName, "DummyPackage")).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusBadRequest)
-
- req = NewRequestWithBody(t, "PUT", url+"/symbolpackage", createSymbolPackage(packageName, "SymbolsPackage")).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusCreated)
-
- pvs, err := packages.GetVersionsByPackageType(t.Context(), user.ID, packages.TypeNuGet)
- assert.NoError(t, err)
- assert.Len(t, pvs, 1)
-
- pd, err := packages.GetPackageDescriptor(t.Context(), pvs[0])
- assert.NoError(t, err)
- assert.NotNil(t, pd.SemVer)
- assert.IsType(t, &nuget_module.Metadata{}, pd.Metadata)
- assert.Equal(t, packageName, pd.Package.Name)
- assert.Equal(t, packageVersion, pd.Version.Version)
-
- pfs, err := packages.GetFilesByVersionID(t.Context(), pvs[0].ID)
- assert.NoError(t, err)
- assert.Len(t, pfs, 4, "Should have 4 files: nupkg, snupkg, nuspec and pdb")
- for _, pf := range pfs {
- switch pf.Name {
- case fmt.Sprintf("%s.%s.nupkg", packageName, packageVersion):
- assert.True(t, pf.IsLead)
-
- pb, err := packages.GetBlobByID(t.Context(), pf.BlobID)
- assert.NoError(t, err)
- assert.Equal(t, int64(633), pb.Size)
- case fmt.Sprintf("%s.%s.snupkg", packageName, packageVersion):
- assert.False(t, pf.IsLead)
-
- pb, err := packages.GetBlobByID(t.Context(), pf.BlobID)
- assert.NoError(t, err)
- assert.Equal(t, int64(616), pb.Size)
- case packageName + ".nuspec":
- assert.False(t, pf.IsLead)
-
- pb, err := packages.GetBlobByID(t.Context(), pf.BlobID)
- assert.NoError(t, err)
- assert.Equal(t, int64(1043), pb.Size)
- case symbolFilename:
- assert.False(t, pf.IsLead)
-
- pb, err := packages.GetBlobByID(t.Context(), pf.BlobID)
- assert.NoError(t, err)
- assert.Equal(t, int64(160), pb.Size)
-
- pps, err := packages.GetProperties(t.Context(), packages.PropertyTypeFile, pf.ID)
- assert.NoError(t, err)
- assert.Len(t, pps, 1)
- assert.Equal(t, nuget_module.PropertySymbolID, pps[0].Name)
- assert.Equal(t, symbolID, pps[0].Value)
- default:
- assert.FailNow(t, "unexpected file", "unexpected file: %v", pf.Name)
- }
- }
-
- req = NewRequestWithBody(t, "PUT", url+"/symbolpackage", createSymbolPackage(packageName, "SymbolsPackage")).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusConflict)
- })
- })
-
- t.Run("Download", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- checkDownloadCount := func(count int64) {
- pvs, err := packages.GetVersionsByPackageType(t.Context(), user.ID, packages.TypeNuGet)
- assert.NoError(t, err)
- assert.Len(t, pvs, 1)
- assert.Equal(t, count, pvs[0].DownloadCount)
- }
-
- checkDownloadCount(0)
-
- req := NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.%s.nupkg", url, packageName, packageVersion, packageName, packageVersion)).
- AddBasicAuth(user.Name)
- resp := MakeRequest(t, req, http.StatusOK)
-
- assert.Equal(t, content, resp.Body.Bytes())
-
- req = NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.nuspec", url, packageName, packageVersion, packageName)).
- AddBasicAuth(user.Name)
- resp = MakeRequest(t, req, http.StatusOK)
-
- assert.Equal(t, createNuspec(packageName, packageVersion), resp.Body.String())
-
- checkDownloadCount(1)
-
- req = NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.%s.snupkg", url, packageName, packageVersion, packageName, packageVersion)).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusOK)
-
- checkDownloadCount(1)
-
- t.Run("Symbol", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- req := NewRequest(t, "GET", fmt.Sprintf("%s/symbols/%s/%sFFFFFFFF/gitea.pdb", url, symbolFilename, symbolID))
- MakeRequest(t, req, http.StatusBadRequest)
-
- req = NewRequest(t, "GET", fmt.Sprintf("%s/symbols/%s/%sFFFFFFFF/%s", url, symbolFilename, "00000000000000000000000000000000", symbolFilename)).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusNotFound)
-
- req = NewRequest(t, "GET", fmt.Sprintf("%s/symbols/%s/%sFFFFffff/%s", url, symbolFilename, symbolID, symbolFilename)).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusOK)
-
- checkDownloadCount(1)
- })
- })
-
- containsOneNextLink := func(t *testing.T, links []FeedEntryLink) func() bool {
- return func() bool {
- found := 0
- for _, l := range links {
- if l.Rel == "next" {
- found++
- u, err := neturl.Parse(l.Href)
- assert.NoError(t, err)
- q := u.Query()
- assert.Contains(t, q, "$skip")
- assert.Contains(t, q, "$top")
- assert.Equal(t, "1", q.Get("$skip"))
- assert.Equal(t, "1", q.Get("$top"))
- }
- }
- return found == 1
- }
- }
-
- t.Run("SearchService", func(t *testing.T) {
- cases := []struct {
- Query string
- Skip int
- Take int
- ExpectedTotal int64
- ExpectedResults int
- ExpectedExactMatch bool
- }{
- {"", 0, 0, 4, 4, false},
- {"", 0, 10, 4, 4, false},
- {"gitea", 0, 10, 0, 0, false},
- {"test", 0, 10, 1, 1, false},
- {"test", 1, 10, 1, 0, false},
- {"almost.similar", 0, 0, 3, 3, true},
- }
-
- fakePackages := []string{
- packageName,
- "almost.similar.dependency",
- "almost.similar",
- "almost.similar.dependant",
- }
-
- for _, fakePackageName := range fakePackages {
- req := NewRequestWithBody(t, "PUT", url, createPackage(fakePackageName, "1.0.99")).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusCreated)
- }
-
- t.Run("v2", func(t *testing.T) {
- t.Run("Search()", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- for i, c := range cases {
- req := NewRequest(t, "GET", fmt.Sprintf("%s/Search()?searchTerm='%s'&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take)).
- AddBasicAuth(user.Name)
- resp := MakeRequest(t, req, http.StatusOK)
-
- var result FeedResponse
- decodeXML(t, resp, &result)
-
- assert.Equal(t, c.ExpectedTotal, result.Count, "case %d: unexpected total hits", i)
- assert.Len(t, result.Entries, c.ExpectedResults, "case %d: unexpected result count", i)
-
- req = NewRequest(t, "GET", fmt.Sprintf("%s/Search()/$count?searchTerm='%s'&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take)).
- AddBasicAuth(user.Name)
- resp = MakeRequest(t, req, http.StatusOK)
-
- assert.Equal(t, strconv.FormatInt(c.ExpectedTotal, 10), resp.Body.String(), "case %d: unexpected total hits", i)
- }
- })
-
- t.Run("Packages()", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- for i, c := range cases {
- req := NewRequest(t, "GET", fmt.Sprintf("%s/Packages()?$filter=substringof('%s',tolower(Id))&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take)).
- AddBasicAuth(user.Name)
- resp := MakeRequest(t, req, http.StatusOK)
-
- var result FeedResponse
- decodeXML(t, resp, &result)
-
- assert.Equal(t, c.ExpectedTotal, result.Count, "case %d: unexpected total hits", i)
- assert.Len(t, result.Entries, c.ExpectedResults, "case %d: unexpected result count", i)
-
- req = NewRequest(t, "GET", fmt.Sprintf("%s/Packages()/$count?$filter=substringof('%s',tolower(Id))&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take)).
- AddBasicAuth(user.Name)
- resp = MakeRequest(t, req, http.StatusOK)
-
- assert.Equal(t, strconv.FormatInt(c.ExpectedTotal, 10), resp.Body.String(), "case %d: unexpected total hits", i)
- }
- })
-
- t.Run("Packages()", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- t.Run("substringof", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- for i, c := range cases {
- req := NewRequest(t, "GET", fmt.Sprintf("%s/Packages()?$filter=substringof('%s',tolower(Id))&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take)).
- AddBasicAuth(user.Name)
- resp := MakeRequest(t, req, http.StatusOK)
-
- var result FeedResponse
- decodeXML(t, resp, &result)
-
- assert.Equal(t, c.ExpectedTotal, result.Count, "case %d: unexpected total hits", i)
- assert.Len(t, result.Entries, c.ExpectedResults, "case %d: unexpected result count", i)
-
- req = NewRequest(t, "GET", fmt.Sprintf("%s/Packages()/$count?$filter=substringof('%s',tolower(Id))&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take)).
- AddBasicAuth(user.Name)
- resp = MakeRequest(t, req, http.StatusOK)
-
- assert.Equal(t, strconv.FormatInt(c.ExpectedTotal, 10), resp.Body.String(), "case %d: unexpected total hits", i)
- }
- })
-
- t.Run("IdEq", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- for i, c := range cases {
- if c.Query == "" {
- // Ignore the `tolower(Id) eq ''` as it's unlikely to happen
- continue
- }
- req := NewRequest(t, "GET", fmt.Sprintf("%s/Packages()?$filter=(tolower(Id) eq '%s')&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take)).
- AddBasicAuth(user.Name)
- resp := MakeRequest(t, req, http.StatusOK)
-
- var result FeedResponse
- decodeXML(t, resp, &result)
-
- expectedCount := 0
- if c.ExpectedExactMatch {
- expectedCount = 1
- }
-
- assert.Equal(t, int64(expectedCount), result.Count, "case %d: unexpected total hits", i)
- assert.Len(t, result.Entries, expectedCount, "case %d: unexpected result count", i)
-
- req = NewRequest(t, "GET", fmt.Sprintf("%s/Packages()/$count?$filter=(tolower(Id) eq '%s')&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take)).
- AddBasicAuth(user.Name)
- resp = MakeRequest(t, req, http.StatusOK)
-
- assert.Equal(t, strconv.FormatInt(int64(expectedCount), 10), resp.Body.String(), "case %d: unexpected total hits", i)
- }
- })
- })
-
- t.Run("Next", func(t *testing.T) {
- req := NewRequest(t, "GET", url+"/Search()?searchTerm='test'&$skip=0&$top=1").
- AddBasicAuth(user.Name)
- resp := MakeRequest(t, req, http.StatusOK)
-
- var result FeedResponse
- decodeXML(t, resp, &result)
-
- assert.Condition(t, containsOneNextLink(t, result.Links))
- })
- })
-
- t.Run("v3", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- for i, c := range cases {
- req := NewRequest(t, "GET", fmt.Sprintf("%s/query?q=%s&skip=%d&take=%d", url, c.Query, c.Skip, c.Take)).
- AddBasicAuth(user.Name)
- resp := MakeRequest(t, req, http.StatusOK)
-
- var result nuget.SearchResultResponse
- DecodeJSON(t, resp, &result)
-
- assert.Equal(t, c.ExpectedTotal, result.TotalHits, "case %d: unexpected total hits", i)
- assert.Len(t, result.Data, c.ExpectedResults, "case %d: unexpected result count", i)
- }
-
- t.Run("EnforceGrouped", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- req := NewRequestWithBody(t, "PUT", url, createPackage(packageName+".dummy", "1.0.0")).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusCreated)
-
- req = NewRequest(t, "GET", fmt.Sprintf("%s/query?q=%s", url, packageName)).
- AddBasicAuth(user.Name)
- resp := MakeRequest(t, req, http.StatusOK)
-
- var result nuget.SearchResultResponse
- DecodeJSON(t, resp, &result)
-
- assert.EqualValues(t, 2, result.TotalHits)
- assert.Len(t, result.Data, 2)
- for _, sr := range result.Data {
- if sr.ID == packageName {
- assert.Len(t, sr.Versions, 2)
- } else {
- assert.Len(t, sr.Versions, 1)
- }
- }
-
- req = NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, packageName+".dummy", "1.0.0")).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusNoContent)
- })
- })
-
- for _, fakePackageName := range fakePackages {
- req := NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, fakePackageName, "1.0.99")).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusNoContent)
- }
- })
-
- t.Run("RegistrationService", func(t *testing.T) {
- indexURL := fmt.Sprintf("%s%s/registration/%s/index.json", setting.AppURL, url[1:], packageName)
- leafURL := fmt.Sprintf("%s%s/registration/%s/%s.json", setting.AppURL, url[1:], packageName, packageVersion)
- contentURL := fmt.Sprintf("%s%s/package/%s/%s/%s.%s.nupkg", setting.AppURL, url[1:], packageName, packageVersion, packageName, packageVersion)
-
- t.Run("RegistrationIndex", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- req := NewRequest(t, "GET", fmt.Sprintf("%s/registration/%s/index.json", url, packageName)).
- AddBasicAuth(user.Name)
- resp := MakeRequest(t, req, http.StatusOK)
-
- var result nuget.RegistrationIndexResponse
- DecodeJSON(t, resp, &result)
-
- assert.Equal(t, indexURL, result.RegistrationIndexURL)
- assert.Equal(t, 1, result.Count)
- assert.Len(t, result.Pages, 1)
-
- page := result.Pages[0]
- assert.Equal(t, indexURL, page.RegistrationPageURL)
- assert.Equal(t, packageVersion, page.Lower)
- assert.Equal(t, packageVersion, page.Upper)
- assert.Equal(t, 1, page.Count)
- assert.Len(t, page.Items, 1)
-
- item := page.Items[0]
- assert.Equal(t, packageName, item.CatalogEntry.ID)
- assert.Equal(t, packageVersion, item.CatalogEntry.Version)
- assert.Equal(t, packageAuthors, item.CatalogEntry.Authors)
- assert.Equal(t, packageDescription, item.CatalogEntry.Description)
- assert.Equal(t, leafURL, item.CatalogEntry.CatalogLeafURL)
- assert.Equal(t, contentURL, item.CatalogEntry.PackageContentURL)
- assert.Equal(t, packageIconURL, item.CatalogEntry.IconURL)
- assert.Equal(t, packageLanguage, item.CatalogEntry.Language)
- assert.Equal(t, packageLicenseURL, item.CatalogEntry.LicenseURL)
- assert.Equal(t, packageProjectURL, item.CatalogEntry.ProjectURL)
- assert.Equal(t, packageReleaseNotes, item.CatalogEntry.ReleaseNotes)
- assert.Equal(t, packageRequireLicenseAcceptance, item.CatalogEntry.RequireLicenseAcceptance)
- assert.Equal(t, packageTags, item.CatalogEntry.Tags)
- assert.Equal(t, summary, item.CatalogEntry.Summary)
- assert.Equal(t, isPrerelease, item.CatalogEntry.IsPrerelease)
- assert.Len(t, item.CatalogEntry.DependencyGroups, dependencyCount)
-
- dependencyGroup := item.CatalogEntry.DependencyGroups[0]
- assert.Equal(t, dependencyTargetFramework, dependencyGroup.TargetFramework)
- assert.Len(t, dependencyGroup.Dependencies, dependencyCount)
-
- dependency := dependencyGroup.Dependencies[0]
- assert.Equal(t, dependencyID, dependency.ID)
- assert.Equal(t, dependencyVersion, dependency.Range)
- })
-
- t.Run("RegistrationLeaf", func(t *testing.T) {
- t.Run("v2", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- req := NewRequest(t, "GET", fmt.Sprintf("%s/Packages(Id='%s',Version='%s')", url, packageName, packageVersion)).
- AddBasicAuth(user.Name)
- resp := MakeRequest(t, req, http.StatusOK)
-
- var result FeedEntry
- decodeXML(t, resp, &result)
-
- assert.Equal(t, packageAuthors, result.Properties.Authors)
- assert.Equal(t, packageDescription, result.Properties.Description)
- assert.Equal(t, packageID, result.Properties.ID)
- assert.Equal(t, packageVersion, result.Properties.Version)
-
- assert.Equal(t, packageCopyright, result.Properties.Copyright)
- assert.Equal(t, packageDevelopmentDependency, result.Properties.DevelopmentDependency.Value)
- assert.Equal(t, packageIconURL, result.Properties.IconURL)
- assert.Equal(t, packageLanguage, result.Properties.Language)
- assert.Equal(t, packageLicenseURL, result.Properties.LicenseURL)
- assert.Equal(t, packageMinClientVersion, result.Properties.MinClientVersion)
- assert.Equal(t, packageOwners, result.Properties.Owners)
- assert.Equal(t, packageProjectURL, result.Properties.ProjectURL)
- assert.Equal(t, packageReleaseNotes, result.Properties.ReleaseNotes)
- assert.Equal(t, packageRequireLicenseAcceptance, result.Properties.RequireLicenseAcceptance.Value)
- assert.Equal(t, packageTags, result.Properties.Tags)
- assert.Equal(t, packageTitle, result.Properties.Title)
-
- packageVersion := strings.Join([]string{dependencyID, dependencyVersion, dependencyTargetFramework}, ":")
- assert.Equal(t, packageVersion, result.Properties.Dependencies)
- })
-
- t.Run("v3", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- req := NewRequest(t, "GET", fmt.Sprintf("%s/registration/%s/%s.json", url, packageName, packageVersion)).
- AddBasicAuth(user.Name)
- resp := MakeRequest(t, req, http.StatusOK)
-
- var result nuget.RegistrationLeafResponse
- DecodeJSON(t, resp, &result)
-
- assert.Equal(t, leafURL, result.RegistrationLeafURL)
- assert.Equal(t, indexURL, result.RegistrationIndexURL)
- assert.Equal(t, packageAuthors, result.CatalogEntry.Authors)
- assert.Equal(t, packageCopyright, result.CatalogEntry.Copyright)
-
- dependencyGroup := result.CatalogEntry.DependencyGroups[0]
- assert.Equal(t, dependencyTargetFramework, dependencyGroup.TargetFramework)
- assert.Len(t, dependencyGroup.Dependencies, dependencyCount)
-
- dependency := dependencyGroup.Dependencies[0]
- assert.Equal(t, dependencyID, dependency.ID)
- assert.Equal(t, dependencyVersion, dependency.Range)
-
- assert.Equal(t, packageDescription, result.CatalogEntry.Description)
- assert.Equal(t, packageID, result.CatalogEntry.ID)
- assert.Equal(t, packageIconURL, result.CatalogEntry.IconURL)
- assert.Equal(t, isPrerelease, result.CatalogEntry.IsPrerelease)
- assert.Equal(t, packageLanguage, result.CatalogEntry.Language)
- assert.Equal(t, packageLicenseURL, result.CatalogEntry.LicenseURL)
- assert.Equal(t, contentURL, result.PackageContentURL)
- assert.Equal(t, packageProjectURL, result.CatalogEntry.ProjectURL)
- assert.Equal(t, packageRequireLicenseAcceptance, result.CatalogEntry.RequireLicenseAcceptance)
- assert.Equal(t, summary, result.CatalogEntry.Summary)
- assert.Equal(t, packageTags, result.CatalogEntry.Tags)
- assert.Equal(t, packageVersion, result.CatalogEntry.Version)
- })
- })
- })
-
- t.Run("PackageService", func(t *testing.T) {
- t.Run("v2", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- req := NewRequest(t, "GET", fmt.Sprintf("%s/FindPackagesById()?id='%s'&$top=1", url, packageName)).
- AddBasicAuth(user.Name)
- resp := MakeRequest(t, req, http.StatusOK)
-
- var result FeedResponse
- decodeXML(t, resp, &result)
-
- assert.Len(t, result.Entries, 1)
- assert.Equal(t, packageVersion, result.Entries[0].Properties.Version)
- assert.Condition(t, containsOneNextLink(t, result.Links))
-
- req = NewRequest(t, "GET", fmt.Sprintf("%s/FindPackagesById()/$count?id='%s'", url, packageName)).
- AddBasicAuth(user.Name)
- resp = MakeRequest(t, req, http.StatusOK)
-
- assert.Equal(t, "1", resp.Body.String())
- })
-
- t.Run("v3", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- req := NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/index.json", url, packageName)).
- AddBasicAuth(user.Name)
- resp := MakeRequest(t, req, http.StatusOK)
-
- var result nuget.PackageVersionsResponse
- DecodeJSON(t, resp, &result)
-
- assert.Len(t, result.Versions, 1)
- assert.Equal(t, packageVersion, result.Versions[0])
- })
- })
-
- t.Run("Delete", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- req := NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, packageName, packageVersion)).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusNoContent)
-
- pvs, err := packages.GetVersionsByPackageType(t.Context(), user.ID, packages.TypeNuGet)
- assert.NoError(t, err)
- assert.Empty(t, pvs)
- })
-
- t.Run("DownloadNotExists", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- req := NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.%s.nupkg", url, packageName, packageVersion, packageName, packageVersion)).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusNotFound)
-
- req = NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.%s.snupkg", url, packageName, packageVersion, packageName, packageVersion)).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusNotFound)
- })
-
- t.Run("DeleteNotExists", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- req := NewRequest(t, "DELETE", fmt.Sprintf("%s/package/%s/%s", url, packageName, packageVersion)).
- AddBasicAuth(user.Name)
- MakeRequest(t, req, http.StatusNotFound)
- })
- }
|