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_nuget_test.go 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package integration
  4. import (
  5. "archive/zip"
  6. "bytes"
  7. "encoding/base64"
  8. "encoding/xml"
  9. "fmt"
  10. "io"
  11. "net/http"
  12. "net/http/httptest"
  13. neturl "net/url"
  14. "strconv"
  15. "testing"
  16. "time"
  17. auth_model "code.gitea.io/gitea/models/auth"
  18. "code.gitea.io/gitea/models/db"
  19. "code.gitea.io/gitea/models/packages"
  20. "code.gitea.io/gitea/models/unittest"
  21. user_model "code.gitea.io/gitea/models/user"
  22. nuget_module "code.gitea.io/gitea/modules/packages/nuget"
  23. "code.gitea.io/gitea/modules/setting"
  24. "code.gitea.io/gitea/modules/structs"
  25. "code.gitea.io/gitea/routers/api/packages/nuget"
  26. "code.gitea.io/gitea/tests"
  27. "github.com/stretchr/testify/assert"
  28. )
  29. func addNuGetAPIKeyHeader(request *http.Request, token string) *http.Request {
  30. request.Header.Set("X-NuGet-ApiKey", token)
  31. return request
  32. }
  33. func decodeXML(t testing.TB, resp *httptest.ResponseRecorder, v any) {
  34. t.Helper()
  35. assert.NoError(t, xml.NewDecoder(resp.Body).Decode(v))
  36. }
  37. func TestPackageNuGet(t *testing.T) {
  38. defer tests.PrepareTestEnv(t)()
  39. type FeedEntryProperties struct {
  40. Version string `xml:"Version"`
  41. NormalizedVersion string `xml:"NormalizedVersion"`
  42. Authors string `xml:"Authors"`
  43. Dependencies string `xml:"Dependencies"`
  44. Description string `xml:"Description"`
  45. VersionDownloadCount nuget.TypedValue[int64] `xml:"VersionDownloadCount"`
  46. DownloadCount nuget.TypedValue[int64] `xml:"DownloadCount"`
  47. PackageSize nuget.TypedValue[int64] `xml:"PackageSize"`
  48. Created nuget.TypedValue[time.Time] `xml:"Created"`
  49. LastUpdated nuget.TypedValue[time.Time] `xml:"LastUpdated"`
  50. Published nuget.TypedValue[time.Time] `xml:"Published"`
  51. ProjectURL string `xml:"ProjectUrl,omitempty"`
  52. ReleaseNotes string `xml:"ReleaseNotes,omitempty"`
  53. RequireLicenseAcceptance nuget.TypedValue[bool] `xml:"RequireLicenseAcceptance"`
  54. Title string `xml:"Title"`
  55. }
  56. type FeedEntry struct {
  57. XMLName xml.Name `xml:"entry"`
  58. Properties *FeedEntryProperties `xml:"properties"`
  59. Content string `xml:",innerxml"`
  60. }
  61. type FeedEntryLink struct {
  62. Rel string `xml:"rel,attr"`
  63. Href string `xml:"href,attr"`
  64. }
  65. type FeedResponse struct {
  66. XMLName xml.Name `xml:"feed"`
  67. Links []FeedEntryLink `xml:"link"`
  68. Entries []*FeedEntry `xml:"entry"`
  69. Count int64 `xml:"count"`
  70. }
  71. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  72. token := getUserToken(t, user.Name, auth_model.AccessTokenScopeWritePackage)
  73. packageName := "test.package"
  74. packageVersion := "1.0.3"
  75. packageAuthors := "KN4CK3R"
  76. packageDescription := "Gitea Test Package"
  77. symbolFilename := "test.pdb"
  78. symbolID := "d910bb6948bd4c6cb40155bcf52c3c94"
  79. createPackage := func(id, version string) io.Reader {
  80. var buf bytes.Buffer
  81. archive := zip.NewWriter(&buf)
  82. w, _ := archive.Create("package.nuspec")
  83. w.Write([]byte(`<?xml version="1.0" encoding="utf-8"?>
  84. <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
  85. <metadata>
  86. <id>` + id + `</id>
  87. <version>` + version + `</version>
  88. <authors>` + packageAuthors + `</authors>
  89. <description>` + packageDescription + `</description>
  90. <dependencies>
  91. <group targetFramework=".NETStandard2.0">
  92. <dependency id="Microsoft.CSharp" version="4.5.0" />
  93. </group>
  94. </dependencies>
  95. </metadata>
  96. </package>`))
  97. archive.Close()
  98. return &buf
  99. }
  100. content, _ := io.ReadAll(createPackage(packageName, packageVersion))
  101. url := fmt.Sprintf("/api/packages/%s/nuget", user.Name)
  102. t.Run("ServiceIndex", func(t *testing.T) {
  103. t.Run("v2", func(t *testing.T) {
  104. defer tests.PrintCurrentTest(t)()
  105. privateUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{Visibility: structs.VisibleTypePrivate})
  106. cases := []struct {
  107. Owner string
  108. UseBasicAuth bool
  109. UseTokenAuth bool
  110. }{
  111. {privateUser.Name, false, false},
  112. {privateUser.Name, true, false},
  113. {privateUser.Name, false, true},
  114. {user.Name, false, false},
  115. {user.Name, true, false},
  116. {user.Name, false, true},
  117. }
  118. for _, c := range cases {
  119. url := fmt.Sprintf("/api/packages/%s/nuget", c.Owner)
  120. req := NewRequest(t, "GET", url)
  121. if c.UseBasicAuth {
  122. req = AddBasicAuthHeader(req, user.Name)
  123. } else if c.UseTokenAuth {
  124. req = addNuGetAPIKeyHeader(req, token)
  125. }
  126. resp := MakeRequest(t, req, http.StatusOK)
  127. var result nuget.ServiceIndexResponseV2
  128. decodeXML(t, resp, &result)
  129. assert.Equal(t, setting.AppURL+url[1:], result.Base)
  130. assert.Equal(t, "Packages", result.Workspace.Collection.Href)
  131. }
  132. })
  133. t.Run("v3", func(t *testing.T) {
  134. defer tests.PrintCurrentTest(t)()
  135. privateUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{Visibility: structs.VisibleTypePrivate})
  136. cases := []struct {
  137. Owner string
  138. UseBasicAuth bool
  139. UseTokenAuth bool
  140. }{
  141. {privateUser.Name, false, false},
  142. {privateUser.Name, true, false},
  143. {privateUser.Name, false, true},
  144. {user.Name, false, false},
  145. {user.Name, true, false},
  146. {user.Name, false, true},
  147. }
  148. for _, c := range cases {
  149. url := fmt.Sprintf("/api/packages/%s/nuget", c.Owner)
  150. req := NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
  151. if c.UseBasicAuth {
  152. req = AddBasicAuthHeader(req, user.Name)
  153. } else if c.UseTokenAuth {
  154. req = addNuGetAPIKeyHeader(req, token)
  155. }
  156. resp := MakeRequest(t, req, http.StatusOK)
  157. var result nuget.ServiceIndexResponseV3
  158. DecodeJSON(t, resp, &result)
  159. assert.Equal(t, "3.0.0", result.Version)
  160. assert.NotEmpty(t, result.Resources)
  161. root := setting.AppURL + url[1:]
  162. for _, r := range result.Resources {
  163. switch r.Type {
  164. case "SearchQueryService":
  165. fallthrough
  166. case "SearchQueryService/3.0.0-beta":
  167. fallthrough
  168. case "SearchQueryService/3.0.0-rc":
  169. assert.Equal(t, root+"/query", r.ID)
  170. case "RegistrationsBaseUrl":
  171. fallthrough
  172. case "RegistrationsBaseUrl/3.0.0-beta":
  173. fallthrough
  174. case "RegistrationsBaseUrl/3.0.0-rc":
  175. assert.Equal(t, root+"/registration", r.ID)
  176. case "PackageBaseAddress/3.0.0":
  177. assert.Equal(t, root+"/package", r.ID)
  178. case "PackagePublish/2.0.0":
  179. assert.Equal(t, root, r.ID)
  180. }
  181. }
  182. }
  183. })
  184. })
  185. t.Run("Upload", func(t *testing.T) {
  186. t.Run("DependencyPackage", func(t *testing.T) {
  187. defer tests.PrintCurrentTest(t)()
  188. req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content))
  189. req = AddBasicAuthHeader(req, user.Name)
  190. MakeRequest(t, req, http.StatusCreated)
  191. pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNuGet)
  192. assert.NoError(t, err)
  193. assert.Len(t, pvs, 1)
  194. pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
  195. assert.NoError(t, err)
  196. assert.NotNil(t, pd.SemVer)
  197. assert.IsType(t, &nuget_module.Metadata{}, pd.Metadata)
  198. assert.Equal(t, packageName, pd.Package.Name)
  199. assert.Equal(t, packageVersion, pd.Version.Version)
  200. pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
  201. assert.NoError(t, err)
  202. assert.Len(t, pfs, 1)
  203. assert.Equal(t, fmt.Sprintf("%s.%s.nupkg", packageName, packageVersion), pfs[0].Name)
  204. assert.True(t, pfs[0].IsLead)
  205. pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
  206. assert.NoError(t, err)
  207. assert.Equal(t, int64(len(content)), pb.Size)
  208. req = NewRequestWithBody(t, "PUT", url, bytes.NewReader(content))
  209. req = AddBasicAuthHeader(req, user.Name)
  210. MakeRequest(t, req, http.StatusConflict)
  211. })
  212. t.Run("SymbolPackage", func(t *testing.T) {
  213. defer tests.PrintCurrentTest(t)()
  214. createSymbolPackage := func(id, packageType string) io.Reader {
  215. var buf bytes.Buffer
  216. archive := zip.NewWriter(&buf)
  217. w, _ := archive.Create("package.nuspec")
  218. w.Write([]byte(`<?xml version="1.0" encoding="utf-8"?>
  219. <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
  220. <metadata>
  221. <id>` + id + `</id>
  222. <version>` + packageVersion + `</version>
  223. <authors>` + packageAuthors + `</authors>
  224. <description>` + packageDescription + `</description>
  225. <packageTypes><packageType name="` + packageType + `" /></packageTypes>
  226. </metadata>
  227. </package>`))
  228. w, _ = archive.Create(symbolFilename)
  229. b, _ := base64.StdEncoding.DecodeString(`QlNKQgEAAQAAAAAADAAAAFBEQiB2MS4wAAAAAAAABgB8AAAAWAAAACNQZGIAAAAA1AAAAAgBAAAj
  230. fgAA3AEAAAQAAAAjU3RyaW5ncwAAAADgAQAABAAAACNVUwDkAQAAMAAAACNHVUlEAAAAFAIAACgB
  231. AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
  232. w.Write(b)
  233. archive.Close()
  234. return &buf
  235. }
  236. req := NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createSymbolPackage("unknown-package", "SymbolsPackage"))
  237. req = AddBasicAuthHeader(req, user.Name)
  238. MakeRequest(t, req, http.StatusNotFound)
  239. req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createSymbolPackage(packageName, "DummyPackage"))
  240. req = AddBasicAuthHeader(req, user.Name)
  241. MakeRequest(t, req, http.StatusBadRequest)
  242. req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createSymbolPackage(packageName, "SymbolsPackage"))
  243. req = AddBasicAuthHeader(req, user.Name)
  244. MakeRequest(t, req, http.StatusCreated)
  245. pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNuGet)
  246. assert.NoError(t, err)
  247. assert.Len(t, pvs, 1)
  248. pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
  249. assert.NoError(t, err)
  250. assert.NotNil(t, pd.SemVer)
  251. assert.IsType(t, &nuget_module.Metadata{}, pd.Metadata)
  252. assert.Equal(t, packageName, pd.Package.Name)
  253. assert.Equal(t, packageVersion, pd.Version.Version)
  254. pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
  255. assert.NoError(t, err)
  256. assert.Len(t, pfs, 3)
  257. for _, pf := range pfs {
  258. switch pf.Name {
  259. case fmt.Sprintf("%s.%s.nupkg", packageName, packageVersion):
  260. case fmt.Sprintf("%s.%s.snupkg", packageName, packageVersion):
  261. assert.False(t, pf.IsLead)
  262. pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID)
  263. assert.NoError(t, err)
  264. assert.Equal(t, int64(616), pb.Size)
  265. case symbolFilename:
  266. assert.False(t, pf.IsLead)
  267. pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID)
  268. assert.NoError(t, err)
  269. assert.Equal(t, int64(160), pb.Size)
  270. pps, err := packages.GetProperties(db.DefaultContext, packages.PropertyTypeFile, pf.ID)
  271. assert.NoError(t, err)
  272. assert.Len(t, pps, 1)
  273. assert.Equal(t, nuget_module.PropertySymbolID, pps[0].Name)
  274. assert.Equal(t, symbolID, pps[0].Value)
  275. default:
  276. assert.Fail(t, "unexpected file: %v", pf.Name)
  277. }
  278. }
  279. req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createSymbolPackage(packageName, "SymbolsPackage"))
  280. req = AddBasicAuthHeader(req, user.Name)
  281. MakeRequest(t, req, http.StatusConflict)
  282. })
  283. })
  284. t.Run("Download", func(t *testing.T) {
  285. defer tests.PrintCurrentTest(t)()
  286. checkDownloadCount := func(count int64) {
  287. pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNuGet)
  288. assert.NoError(t, err)
  289. assert.Len(t, pvs, 1)
  290. assert.Equal(t, count, pvs[0].DownloadCount)
  291. }
  292. checkDownloadCount(0)
  293. req := NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.%s.nupkg", url, packageName, packageVersion, packageName, packageVersion))
  294. req = AddBasicAuthHeader(req, user.Name)
  295. resp := MakeRequest(t, req, http.StatusOK)
  296. assert.Equal(t, content, resp.Body.Bytes())
  297. checkDownloadCount(1)
  298. req = NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.%s.snupkg", url, packageName, packageVersion, packageName, packageVersion))
  299. req = AddBasicAuthHeader(req, user.Name)
  300. MakeRequest(t, req, http.StatusOK)
  301. checkDownloadCount(1)
  302. t.Run("Symbol", func(t *testing.T) {
  303. defer tests.PrintCurrentTest(t)()
  304. req := NewRequest(t, "GET", fmt.Sprintf("%s/symbols/%s/%sFFFFFFFF/gitea.pdb", url, symbolFilename, symbolID))
  305. MakeRequest(t, req, http.StatusBadRequest)
  306. req = NewRequest(t, "GET", fmt.Sprintf("%s/symbols/%s/%sFFFFFFFF/%s", url, symbolFilename, "00000000000000000000000000000000", symbolFilename))
  307. req = AddBasicAuthHeader(req, user.Name)
  308. MakeRequest(t, req, http.StatusNotFound)
  309. req = NewRequest(t, "GET", fmt.Sprintf("%s/symbols/%s/%sFFFFffff/%s", url, symbolFilename, symbolID, symbolFilename))
  310. req = AddBasicAuthHeader(req, user.Name)
  311. MakeRequest(t, req, http.StatusOK)
  312. checkDownloadCount(1)
  313. })
  314. })
  315. containsOneNextLink := func(t *testing.T, links []FeedEntryLink) func() bool {
  316. return func() bool {
  317. found := 0
  318. for _, l := range links {
  319. if l.Rel == "next" {
  320. found++
  321. u, err := neturl.Parse(l.Href)
  322. assert.NoError(t, err)
  323. q := u.Query()
  324. assert.Contains(t, q, "$skip")
  325. assert.Contains(t, q, "$top")
  326. assert.Equal(t, "1", q.Get("$skip"))
  327. assert.Equal(t, "1", q.Get("$top"))
  328. }
  329. }
  330. return found == 1
  331. }
  332. }
  333. t.Run("SearchService", func(t *testing.T) {
  334. cases := []struct {
  335. Query string
  336. Skip int
  337. Take int
  338. ExpectedTotal int64
  339. ExpectedResults int
  340. }{
  341. {"", 0, 0, 1, 1},
  342. {"", 0, 10, 1, 1},
  343. {"gitea", 0, 10, 0, 0},
  344. {"test", 0, 10, 1, 1},
  345. {"test", 1, 10, 1, 0},
  346. }
  347. t.Run("v2", func(t *testing.T) {
  348. t.Run("Search()", func(t *testing.T) {
  349. defer tests.PrintCurrentTest(t)()
  350. for i, c := range cases {
  351. req := NewRequest(t, "GET", fmt.Sprintf("%s/Search()?searchTerm='%s'&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take))
  352. req = AddBasicAuthHeader(req, user.Name)
  353. resp := MakeRequest(t, req, http.StatusOK)
  354. var result FeedResponse
  355. decodeXML(t, resp, &result)
  356. assert.Equal(t, c.ExpectedTotal, result.Count, "case %d: unexpected total hits", i)
  357. assert.Len(t, result.Entries, c.ExpectedResults, "case %d: unexpected result count", i)
  358. req = NewRequest(t, "GET", fmt.Sprintf("%s/Search()/$count?searchTerm='%s'&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take))
  359. req = AddBasicAuthHeader(req, user.Name)
  360. resp = MakeRequest(t, req, http.StatusOK)
  361. assert.Equal(t, strconv.FormatInt(c.ExpectedTotal, 10), resp.Body.String(), "case %d: unexpected total hits", i)
  362. }
  363. })
  364. t.Run("Packages()", func(t *testing.T) {
  365. defer tests.PrintCurrentTest(t)()
  366. for i, c := range cases {
  367. req := NewRequest(t, "GET", fmt.Sprintf("%s/Packages()?$filter=substringof('%s',tolower(Id))&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take))
  368. req = AddBasicAuthHeader(req, user.Name)
  369. resp := MakeRequest(t, req, http.StatusOK)
  370. var result FeedResponse
  371. decodeXML(t, resp, &result)
  372. assert.Equal(t, c.ExpectedTotal, result.Count, "case %d: unexpected total hits", i)
  373. assert.Len(t, result.Entries, c.ExpectedResults, "case %d: unexpected result count", i)
  374. 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))
  375. req = AddBasicAuthHeader(req, user.Name)
  376. resp = MakeRequest(t, req, http.StatusOK)
  377. assert.Equal(t, strconv.FormatInt(c.ExpectedTotal, 10), resp.Body.String(), "case %d: unexpected total hits", i)
  378. }
  379. })
  380. t.Run("Next", func(t *testing.T) {
  381. req := NewRequest(t, "GET", fmt.Sprintf("%s/Search()?searchTerm='test'&$skip=0&$top=1", url))
  382. req = AddBasicAuthHeader(req, user.Name)
  383. resp := MakeRequest(t, req, http.StatusOK)
  384. var result FeedResponse
  385. decodeXML(t, resp, &result)
  386. assert.Condition(t, containsOneNextLink(t, result.Links))
  387. })
  388. })
  389. t.Run("v3", func(t *testing.T) {
  390. defer tests.PrintCurrentTest(t)()
  391. for i, c := range cases {
  392. req := NewRequest(t, "GET", fmt.Sprintf("%s/query?q=%s&skip=%d&take=%d", url, c.Query, c.Skip, c.Take))
  393. req = AddBasicAuthHeader(req, user.Name)
  394. resp := MakeRequest(t, req, http.StatusOK)
  395. var result nuget.SearchResultResponse
  396. DecodeJSON(t, resp, &result)
  397. assert.Equal(t, c.ExpectedTotal, result.TotalHits, "case %d: unexpected total hits", i)
  398. assert.Len(t, result.Data, c.ExpectedResults, "case %d: unexpected result count", i)
  399. }
  400. t.Run("EnforceGrouped", func(t *testing.T) {
  401. defer tests.PrintCurrentTest(t)()
  402. req := NewRequestWithBody(t, "PUT", url, createPackage(packageName+".dummy", "1.0.0"))
  403. req = AddBasicAuthHeader(req, user.Name)
  404. MakeRequest(t, req, http.StatusCreated)
  405. req = NewRequestWithBody(t, "PUT", url, createPackage(packageName, "1.0.99"))
  406. req = AddBasicAuthHeader(req, user.Name)
  407. MakeRequest(t, req, http.StatusCreated)
  408. req = NewRequest(t, "GET", fmt.Sprintf("%s/query?q=%s", url, packageName))
  409. req = AddBasicAuthHeader(req, user.Name)
  410. resp := MakeRequest(t, req, http.StatusOK)
  411. var result nuget.SearchResultResponse
  412. DecodeJSON(t, resp, &result)
  413. assert.EqualValues(t, 3, result.TotalHits)
  414. assert.Len(t, result.Data, 2)
  415. for _, sr := range result.Data {
  416. if sr.ID == packageName {
  417. assert.Len(t, sr.Versions, 2)
  418. } else {
  419. assert.Len(t, sr.Versions, 1)
  420. }
  421. }
  422. req = NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, packageName+".dummy", "1.0.0"))
  423. req = AddBasicAuthHeader(req, user.Name)
  424. MakeRequest(t, req, http.StatusNoContent)
  425. req = NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, packageName, "1.0.99"))
  426. req = AddBasicAuthHeader(req, user.Name)
  427. MakeRequest(t, req, http.StatusNoContent)
  428. })
  429. })
  430. })
  431. t.Run("RegistrationService", func(t *testing.T) {
  432. indexURL := fmt.Sprintf("%s%s/registration/%s/index.json", setting.AppURL, url[1:], packageName)
  433. leafURL := fmt.Sprintf("%s%s/registration/%s/%s.json", setting.AppURL, url[1:], packageName, packageVersion)
  434. contentURL := fmt.Sprintf("%s%s/package/%s/%s/%s.%s.nupkg", setting.AppURL, url[1:], packageName, packageVersion, packageName, packageVersion)
  435. t.Run("RegistrationIndex", func(t *testing.T) {
  436. defer tests.PrintCurrentTest(t)()
  437. req := NewRequest(t, "GET", fmt.Sprintf("%s/registration/%s/index.json", url, packageName))
  438. req = AddBasicAuthHeader(req, user.Name)
  439. resp := MakeRequest(t, req, http.StatusOK)
  440. var result nuget.RegistrationIndexResponse
  441. DecodeJSON(t, resp, &result)
  442. assert.Equal(t, indexURL, result.RegistrationIndexURL)
  443. assert.Equal(t, 1, result.Count)
  444. assert.Len(t, result.Pages, 1)
  445. assert.Equal(t, indexURL, result.Pages[0].RegistrationPageURL)
  446. assert.Equal(t, packageVersion, result.Pages[0].Lower)
  447. assert.Equal(t, packageVersion, result.Pages[0].Upper)
  448. assert.Equal(t, 1, result.Pages[0].Count)
  449. assert.Len(t, result.Pages[0].Items, 1)
  450. assert.Equal(t, packageName, result.Pages[0].Items[0].CatalogEntry.ID)
  451. assert.Equal(t, packageVersion, result.Pages[0].Items[0].CatalogEntry.Version)
  452. assert.Equal(t, packageAuthors, result.Pages[0].Items[0].CatalogEntry.Authors)
  453. assert.Equal(t, packageDescription, result.Pages[0].Items[0].CatalogEntry.Description)
  454. assert.Equal(t, leafURL, result.Pages[0].Items[0].CatalogEntry.CatalogLeafURL)
  455. assert.Equal(t, contentURL, result.Pages[0].Items[0].CatalogEntry.PackageContentURL)
  456. })
  457. t.Run("RegistrationLeaf", func(t *testing.T) {
  458. t.Run("v2", func(t *testing.T) {
  459. defer tests.PrintCurrentTest(t)()
  460. req := NewRequest(t, "GET", fmt.Sprintf("%s/Packages(Id='%s',Version='%s')", url, packageName, packageVersion))
  461. req = AddBasicAuthHeader(req, user.Name)
  462. resp := MakeRequest(t, req, http.StatusOK)
  463. var result FeedEntry
  464. decodeXML(t, resp, &result)
  465. assert.Equal(t, packageName, result.Properties.Title)
  466. assert.Equal(t, packageVersion, result.Properties.Version)
  467. assert.Equal(t, packageAuthors, result.Properties.Authors)
  468. assert.Equal(t, packageDescription, result.Properties.Description)
  469. assert.Equal(t, "Microsoft.CSharp:4.5.0:.NETStandard2.0", result.Properties.Dependencies)
  470. })
  471. t.Run("v3", func(t *testing.T) {
  472. defer tests.PrintCurrentTest(t)()
  473. req := NewRequest(t, "GET", fmt.Sprintf("%s/registration/%s/%s.json", url, packageName, packageVersion))
  474. req = AddBasicAuthHeader(req, user.Name)
  475. resp := MakeRequest(t, req, http.StatusOK)
  476. var result nuget.RegistrationLeafResponse
  477. DecodeJSON(t, resp, &result)
  478. assert.Equal(t, leafURL, result.RegistrationLeafURL)
  479. assert.Equal(t, contentURL, result.PackageContentURL)
  480. assert.Equal(t, indexURL, result.RegistrationIndexURL)
  481. })
  482. })
  483. })
  484. t.Run("PackageService", func(t *testing.T) {
  485. t.Run("v2", func(t *testing.T) {
  486. defer tests.PrintCurrentTest(t)()
  487. req := NewRequest(t, "GET", fmt.Sprintf("%s/FindPackagesById()?id='%s'&$top=1", url, packageName))
  488. req = AddBasicAuthHeader(req, user.Name)
  489. resp := MakeRequest(t, req, http.StatusOK)
  490. var result FeedResponse
  491. decodeXML(t, resp, &result)
  492. assert.Len(t, result.Entries, 1)
  493. assert.Equal(t, packageVersion, result.Entries[0].Properties.Version)
  494. assert.Condition(t, containsOneNextLink(t, result.Links))
  495. req = NewRequest(t, "GET", fmt.Sprintf("%s/FindPackagesById()/$count?id='%s'", url, packageName))
  496. req = AddBasicAuthHeader(req, user.Name)
  497. resp = MakeRequest(t, req, http.StatusOK)
  498. assert.Equal(t, "1", resp.Body.String())
  499. })
  500. t.Run("v3", func(t *testing.T) {
  501. defer tests.PrintCurrentTest(t)()
  502. req := NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/index.json", url, packageName))
  503. req = AddBasicAuthHeader(req, user.Name)
  504. resp := MakeRequest(t, req, http.StatusOK)
  505. var result nuget.PackageVersionsResponse
  506. DecodeJSON(t, resp, &result)
  507. assert.Len(t, result.Versions, 1)
  508. assert.Equal(t, packageVersion, result.Versions[0])
  509. })
  510. })
  511. t.Run("Delete", func(t *testing.T) {
  512. defer tests.PrintCurrentTest(t)()
  513. req := NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, packageName, packageVersion))
  514. req = AddBasicAuthHeader(req, user.Name)
  515. MakeRequest(t, req, http.StatusNoContent)
  516. pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNuGet)
  517. assert.NoError(t, err)
  518. assert.Empty(t, pvs)
  519. })
  520. t.Run("DownloadNotExists", func(t *testing.T) {
  521. defer tests.PrintCurrentTest(t)()
  522. req := NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.%s.nupkg", url, packageName, packageVersion, packageName, packageVersion))
  523. req = AddBasicAuthHeader(req, user.Name)
  524. MakeRequest(t, req, http.StatusNotFound)
  525. req = NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s.%s.snupkg", url, packageName, packageVersion, packageName, packageVersion))
  526. req = AddBasicAuthHeader(req, user.Name)
  527. MakeRequest(t, req, http.StatusNotFound)
  528. })
  529. t.Run("DeleteNotExists", func(t *testing.T) {
  530. defer tests.PrintCurrentTest(t)()
  531. req := NewRequest(t, "DELETE", fmt.Sprintf("%s/package/%s/%s", url, packageName, packageVersion))
  532. req = AddBasicAuthHeader(req, user.Name)
  533. MakeRequest(t, req, http.StatusNotFound)
  534. })
  535. }