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_swift_test.go 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. // Copyright 2023 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package integration
  4. import (
  5. "archive/zip"
  6. "bytes"
  7. "fmt"
  8. "io"
  9. "mime/multipart"
  10. "net/http"
  11. "strings"
  12. "testing"
  13. "code.gitea.io/gitea/models/db"
  14. "code.gitea.io/gitea/models/packages"
  15. "code.gitea.io/gitea/models/unittest"
  16. user_model "code.gitea.io/gitea/models/user"
  17. swift_module "code.gitea.io/gitea/modules/packages/swift"
  18. "code.gitea.io/gitea/modules/setting"
  19. swift_router "code.gitea.io/gitea/routers/api/packages/swift"
  20. "code.gitea.io/gitea/tests"
  21. "github.com/stretchr/testify/assert"
  22. )
  23. func TestPackageSwift(t *testing.T) {
  24. defer tests.PrepareTestEnv(t)()
  25. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  26. packageScope := "test-scope"
  27. packageName := "test_package"
  28. packageID := packageScope + "." + packageName
  29. packageVersion := "1.0.3"
  30. packageAuthor := "KN4CK3R"
  31. packageDescription := "Gitea Test Package"
  32. packageRepositoryURL := "https://gitea.io/gitea/gitea"
  33. contentManifest1 := "// swift-tools-version:5.7\n//\n// Package.swift"
  34. contentManifest2 := "// swift-tools-version:5.6\n//\n// Package@swift-5.6.swift"
  35. url := fmt.Sprintf("/api/packages/%s/swift", user.Name)
  36. t.Run("CheckAcceptMediaType", func(t *testing.T) {
  37. defer tests.PrintCurrentTest(t)()
  38. for _, sub := range []string{
  39. "/scope/package",
  40. "/scope/package.json",
  41. "/scope/package/1.0.0",
  42. "/scope/package/1.0.0.json",
  43. "/scope/package/1.0.0.zip",
  44. "/scope/package/1.0.0/Package.swift",
  45. "/identifiers",
  46. } {
  47. req := NewRequest(t, "GET", url+sub)
  48. req.Header.Add("Accept", "application/unknown")
  49. resp := MakeRequest(t, req, http.StatusBadRequest)
  50. assert.Equal(t, "1", resp.Header().Get("Content-Version"))
  51. assert.Equal(t, "application/problem+json", resp.Header().Get("Content-Type"))
  52. }
  53. req := NewRequestWithBody(t, "PUT", url+"/scope/package/1.0.0", strings.NewReader("")).
  54. AddBasicAuth(user.Name).
  55. SetHeader("Accept", "application/unknown")
  56. resp := MakeRequest(t, req, http.StatusBadRequest)
  57. assert.Equal(t, "1", resp.Header().Get("Content-Version"))
  58. assert.Equal(t, "application/problem+json", resp.Header().Get("Content-Type"))
  59. })
  60. t.Run("Upload", func(t *testing.T) {
  61. defer tests.PrintCurrentTest(t)()
  62. uploadPackage := func(t *testing.T, url string, expectedStatus int, sr io.Reader, metadata string) {
  63. var body bytes.Buffer
  64. mpw := multipart.NewWriter(&body)
  65. part, _ := mpw.CreateFormFile("source-archive", "source-archive.zip")
  66. io.Copy(part, sr)
  67. if metadata != "" {
  68. mpw.WriteField("metadata", metadata)
  69. }
  70. mpw.Close()
  71. req := NewRequestWithBody(t, "PUT", url, &body).
  72. SetHeader("Content-Type", mpw.FormDataContentType()).
  73. SetHeader("Accept", swift_router.AcceptJSON).
  74. AddBasicAuth(user.Name)
  75. MakeRequest(t, req, expectedStatus)
  76. }
  77. createArchive := func(files map[string]string) *bytes.Buffer {
  78. var buf bytes.Buffer
  79. zw := zip.NewWriter(&buf)
  80. for filename, content := range files {
  81. w, _ := zw.Create(filename)
  82. w.Write([]byte(content))
  83. }
  84. zw.Close()
  85. return &buf
  86. }
  87. for _, triple := range []string{"/sc_ope/package/1.0.0", "/scope/pack~age/1.0.0", "/scope/package/1_0.0"} {
  88. req := NewRequestWithBody(t, "PUT", url+triple, bytes.NewReader([]byte{})).
  89. AddBasicAuth(user.Name)
  90. resp := MakeRequest(t, req, http.StatusBadRequest)
  91. assert.Equal(t, "1", resp.Header().Get("Content-Version"))
  92. assert.Equal(t, "application/problem+json", resp.Header().Get("Content-Type"))
  93. }
  94. uploadURL := fmt.Sprintf("%s/%s/%s/%s", url, packageScope, packageName, packageVersion)
  95. req := NewRequestWithBody(t, "PUT", uploadURL, bytes.NewReader([]byte{}))
  96. MakeRequest(t, req, http.StatusUnauthorized)
  97. uploadPackage(
  98. t,
  99. uploadURL,
  100. http.StatusCreated,
  101. createArchive(map[string]string{
  102. "Package.swift": contentManifest1,
  103. "Package@swift-5.6.swift": contentManifest2,
  104. }),
  105. `{"name":"`+packageName+`","version":"`+packageVersion+`","description":"`+packageDescription+`","codeRepository":"`+packageRepositoryURL+`","author":{"givenName":"`+packageAuthor+`"},"repositoryURLs":["`+packageRepositoryURL+`"]}`,
  106. )
  107. pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeSwift)
  108. assert.NoError(t, err)
  109. assert.Len(t, pvs, 1)
  110. pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
  111. assert.NoError(t, err)
  112. assert.NotNil(t, pd.SemVer)
  113. assert.Equal(t, packageID, pd.Package.Name)
  114. assert.Equal(t, packageVersion, pd.Version.Version)
  115. assert.IsType(t, &swift_module.Metadata{}, pd.Metadata)
  116. metadata := pd.Metadata.(*swift_module.Metadata)
  117. assert.Equal(t, packageDescription, metadata.Description)
  118. assert.Len(t, metadata.Manifests, 2)
  119. assert.Equal(t, contentManifest1, metadata.Manifests[""].Content)
  120. assert.Equal(t, contentManifest2, metadata.Manifests["5.6"].Content)
  121. assert.Len(t, pd.VersionProperties, 1)
  122. assert.Equal(t, packageRepositoryURL, pd.VersionProperties.GetByName(swift_module.PropertyRepositoryURL))
  123. pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
  124. assert.NoError(t, err)
  125. assert.Len(t, pfs, 1)
  126. assert.Equal(t, fmt.Sprintf("%s-%s.zip", packageName, packageVersion), pfs[0].Name)
  127. assert.True(t, pfs[0].IsLead)
  128. uploadPackage(
  129. t,
  130. uploadURL,
  131. http.StatusConflict,
  132. createArchive(map[string]string{
  133. "Package.swift": contentManifest1,
  134. }),
  135. "",
  136. )
  137. })
  138. t.Run("Download", func(t *testing.T) {
  139. defer tests.PrintCurrentTest(t)()
  140. req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s/%s.zip", url, packageScope, packageName, packageVersion)).
  141. AddBasicAuth(user.Name).
  142. SetHeader("Accept", swift_router.AcceptZip)
  143. resp := MakeRequest(t, req, http.StatusOK)
  144. assert.Equal(t, "1", resp.Header().Get("Content-Version"))
  145. assert.Equal(t, "application/zip", resp.Header().Get("Content-Type"))
  146. pv, err := packages.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages.TypeSwift, packageID, packageVersion)
  147. assert.NotNil(t, pv)
  148. assert.NoError(t, err)
  149. pd, err := packages.GetPackageDescriptor(db.DefaultContext, pv)
  150. assert.NoError(t, err)
  151. assert.Equal(t, "sha256="+pd.Files[0].Blob.HashSHA256, resp.Header().Get("Digest"))
  152. })
  153. t.Run("EnumeratePackageVersions", func(t *testing.T) {
  154. defer tests.PrintCurrentTest(t)()
  155. req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s", url, packageScope, packageName)).
  156. AddBasicAuth(user.Name).
  157. SetHeader("Accept", swift_router.AcceptJSON)
  158. resp := MakeRequest(t, req, http.StatusOK)
  159. versionURL := setting.AppURL + url[1:] + fmt.Sprintf("/%s/%s/%s", packageScope, packageName, packageVersion)
  160. assert.Equal(t, "1", resp.Header().Get("Content-Version"))
  161. assert.Equal(t, fmt.Sprintf(`<%s>; rel="latest-version"`, versionURL), resp.Header().Get("Link"))
  162. body := resp.Body.String()
  163. var result *swift_router.EnumeratePackageVersionsResponse
  164. DecodeJSON(t, resp, &result)
  165. assert.Len(t, result.Releases, 1)
  166. assert.Contains(t, result.Releases, packageVersion)
  167. assert.Equal(t, versionURL, result.Releases[packageVersion].URL)
  168. req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s.json", url, packageScope, packageName)).
  169. AddBasicAuth(user.Name)
  170. resp = MakeRequest(t, req, http.StatusOK)
  171. assert.Equal(t, body, resp.Body.String())
  172. })
  173. t.Run("PackageVersionMetadata", func(t *testing.T) {
  174. defer tests.PrintCurrentTest(t)()
  175. req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s/%s", url, packageScope, packageName, packageVersion)).
  176. AddBasicAuth(user.Name).
  177. SetHeader("Accept", swift_router.AcceptJSON)
  178. resp := MakeRequest(t, req, http.StatusOK)
  179. assert.Equal(t, "1", resp.Header().Get("Content-Version"))
  180. body := resp.Body.String()
  181. var result *swift_router.PackageVersionMetadataResponse
  182. DecodeJSON(t, resp, &result)
  183. pv, err := packages.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages.TypeSwift, packageID, packageVersion)
  184. assert.NotNil(t, pv)
  185. assert.NoError(t, err)
  186. pd, err := packages.GetPackageDescriptor(db.DefaultContext, pv)
  187. assert.NoError(t, err)
  188. assert.Equal(t, packageID, result.ID)
  189. assert.Equal(t, packageVersion, result.Version)
  190. assert.Len(t, result.Resources, 1)
  191. assert.Equal(t, "source-archive", result.Resources[0].Name)
  192. assert.Equal(t, "application/zip", result.Resources[0].Type)
  193. assert.Equal(t, pd.Files[0].Blob.HashSHA256, result.Resources[0].Checksum)
  194. assert.Equal(t, "SoftwareSourceCode", result.Metadata.Type)
  195. assert.Equal(t, packageName, result.Metadata.Name)
  196. assert.Equal(t, packageVersion, result.Metadata.Version)
  197. assert.Equal(t, packageDescription, result.Metadata.Description)
  198. assert.Equal(t, "Swift", result.Metadata.ProgrammingLanguage.Name)
  199. assert.Equal(t, packageAuthor, result.Metadata.Author.GivenName)
  200. req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s/%s.json", url, packageScope, packageName, packageVersion)).
  201. AddBasicAuth(user.Name)
  202. resp = MakeRequest(t, req, http.StatusOK)
  203. assert.Equal(t, body, resp.Body.String())
  204. })
  205. t.Run("DownloadManifest", func(t *testing.T) {
  206. manifestURL := fmt.Sprintf("%s/%s/%s/%s/Package.swift", url, packageScope, packageName, packageVersion)
  207. t.Run("Default", func(t *testing.T) {
  208. defer tests.PrintCurrentTest(t)()
  209. req := NewRequest(t, "GET", manifestURL).
  210. AddBasicAuth(user.Name).
  211. SetHeader("Accept", swift_router.AcceptSwift)
  212. resp := MakeRequest(t, req, http.StatusOK)
  213. assert.Equal(t, "1", resp.Header().Get("Content-Version"))
  214. assert.Equal(t, "text/x-swift", resp.Header().Get("Content-Type"))
  215. assert.Equal(t, contentManifest1, resp.Body.String())
  216. })
  217. t.Run("DifferentVersion", func(t *testing.T) {
  218. defer tests.PrintCurrentTest(t)()
  219. req := NewRequest(t, "GET", manifestURL+"?swift-version=5.6").
  220. AddBasicAuth(user.Name)
  221. resp := MakeRequest(t, req, http.StatusOK)
  222. assert.Equal(t, "1", resp.Header().Get("Content-Version"))
  223. assert.Equal(t, "text/x-swift", resp.Header().Get("Content-Type"))
  224. assert.Equal(t, contentManifest2, resp.Body.String())
  225. req = NewRequest(t, "GET", manifestURL+"?swift-version=5.6.0").
  226. AddBasicAuth(user.Name)
  227. MakeRequest(t, req, http.StatusOK)
  228. })
  229. t.Run("Redirect", func(t *testing.T) {
  230. defer tests.PrintCurrentTest(t)()
  231. req := NewRequest(t, "GET", manifestURL+"?swift-version=1.0").
  232. AddBasicAuth(user.Name)
  233. resp := MakeRequest(t, req, http.StatusSeeOther)
  234. assert.Equal(t, "1", resp.Header().Get("Content-Version"))
  235. assert.Equal(t, setting.AppURL+url[1:]+fmt.Sprintf("/%s/%s/%s/Package.swift", packageScope, packageName, packageVersion), resp.Header().Get("Location"))
  236. })
  237. })
  238. t.Run("LookupPackageIdentifiers", func(t *testing.T) {
  239. defer tests.PrintCurrentTest(t)()
  240. req := NewRequest(t, "GET", url+"/identifiers").
  241. SetHeader("Accept", swift_router.AcceptJSON)
  242. resp := MakeRequest(t, req, http.StatusBadRequest)
  243. assert.Equal(t, "1", resp.Header().Get("Content-Version"))
  244. assert.Equal(t, "application/problem+json", resp.Header().Get("Content-Type"))
  245. req = NewRequest(t, "GET", url+"/identifiers?url=https://unknown.host/")
  246. MakeRequest(t, req, http.StatusNotFound)
  247. req = NewRequest(t, "GET", url+"/identifiers?url="+packageRepositoryURL).
  248. SetHeader("Accept", swift_router.AcceptJSON)
  249. resp = MakeRequest(t, req, http.StatusOK)
  250. var result *swift_router.LookupPackageIdentifiersResponse
  251. DecodeJSON(t, resp, &result)
  252. assert.Len(t, result.Identifiers, 1)
  253. assert.Equal(t, packageID, result.Identifiers[0])
  254. })
  255. }