gitea源码

api_packages_maven_test.go 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package integration
  4. import (
  5. "fmt"
  6. "net/http"
  7. "net/url"
  8. "strconv"
  9. "strings"
  10. "sync"
  11. "testing"
  12. "code.gitea.io/gitea/models/packages"
  13. "code.gitea.io/gitea/models/unittest"
  14. user_model "code.gitea.io/gitea/models/user"
  15. "code.gitea.io/gitea/modules/packages/maven"
  16. "code.gitea.io/gitea/modules/test"
  17. "code.gitea.io/gitea/tests"
  18. "github.com/stretchr/testify/assert"
  19. "github.com/stretchr/testify/require"
  20. )
  21. func TestPackageMaven(t *testing.T) {
  22. defer tests.PrepareTestEnv(t)()
  23. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  24. groupID := "com.gitea"
  25. artifactID := "test-project"
  26. packageVersion := "1.0.1"
  27. packageDescription := "Test Description"
  28. root := "/api/packages/user2/maven/com/gitea/test-project"
  29. filename := "any-name.jar"
  30. putFile := func(t *testing.T, path, content string, expectedStatus int) {
  31. req := NewRequestWithBody(t, "PUT", root+path, strings.NewReader(content)).AddBasicAuth(user.Name)
  32. MakeRequest(t, req, expectedStatus)
  33. }
  34. checkHeaders := func(t *testing.T, h http.Header, contentType string, contentLength int64) {
  35. assert.Equal(t, contentType, h.Get("Content-Type"))
  36. assert.Equal(t, strconv.FormatInt(contentLength, 10), h.Get("Content-Length"))
  37. assert.NotEmpty(t, h.Get("Last-Modified"))
  38. }
  39. t.Run("Upload", func(t *testing.T) {
  40. defer tests.PrintCurrentTest(t)()
  41. putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusCreated)
  42. putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusConflict)
  43. putFile(t, "/maven-metadata.xml", "test", http.StatusOK)
  44. pvs, err := packages.GetVersionsByPackageType(t.Context(), user.ID, packages.TypeMaven)
  45. require.NoError(t, err)
  46. assert.Len(t, pvs, 1)
  47. pd, err := packages.GetPackageDescriptor(t.Context(), pvs[0])
  48. require.NoError(t, err)
  49. assert.Nil(t, pd.SemVer)
  50. assert.Nil(t, pd.Metadata)
  51. assert.Equal(t, groupID+":"+artifactID, pd.Package.Name)
  52. assert.Equal(t, packageVersion, pd.Version.Version)
  53. pfs, err := packages.GetFilesByVersionID(t.Context(), pvs[0].ID)
  54. require.NoError(t, err)
  55. assert.Len(t, pfs, 1)
  56. assert.Equal(t, filename, pfs[0].Name)
  57. assert.False(t, pfs[0].IsLead)
  58. pb, err := packages.GetBlobByID(t.Context(), pfs[0].BlobID)
  59. require.NoError(t, err)
  60. assert.Equal(t, int64(4), pb.Size)
  61. })
  62. t.Run("UploadLegacy", func(t *testing.T) {
  63. defer tests.PrintCurrentTest(t)()
  64. // try to upload a package with legacy package name (will be saved as "GroupID-ArtifactID")
  65. legacyRootLink := "/api/packages/user2/maven/com/gitea/legacy-project"
  66. req := NewRequestWithBody(t, "PUT", legacyRootLink+"/1.0.2/any-file-name?use_legacy_package_name=1", strings.NewReader("test-content")).AddBasicAuth(user.Name)
  67. MakeRequest(t, req, http.StatusCreated)
  68. p, err := packages.GetPackageByName(t.Context(), user.ID, packages.TypeMaven, "com.gitea-legacy-project")
  69. require.NoError(t, err)
  70. assert.Equal(t, "com.gitea-legacy-project", p.Name)
  71. req = NewRequest(t, "HEAD", legacyRootLink+"/1.0.2/any-file-name").AddBasicAuth(user.Name)
  72. MakeRequest(t, req, http.StatusOK)
  73. req = NewRequest(t, "GET", "/user2/-/packages/maven/com.gitea-legacy-project/1.0.2")
  74. MakeRequest(t, req, http.StatusOK)
  75. req = NewRequest(t, "GET", "/user2/-/packages/maven/com.gitea:legacy-project/1.0.2")
  76. MakeRequest(t, req, http.StatusNotFound)
  77. req = NewRequest(t, "GET", "/user2/-/packages/maven/com.gitea%3Alegacy-project/1.0.2")
  78. MakeRequest(t, req, http.StatusNotFound)
  79. // legacy package names should also be able to be listed
  80. req = NewRequest(t, "GET", legacyRootLink+"/maven-metadata.xml").AddBasicAuth(user.Name)
  81. resp := MakeRequest(t, req, http.StatusOK)
  82. respBody := resp.Body.String()
  83. assert.Contains(t, respBody, "<version>1.0.2</version>")
  84. // then upload a package with correct package name (will be saved as "GroupID:ArtifactID")
  85. req = NewRequestWithBody(t, "PUT", legacyRootLink+"/1.0.3/any-file-name", strings.NewReader("test-content")).AddBasicAuth(user.Name)
  86. MakeRequest(t, req, http.StatusCreated)
  87. _, err = packages.GetPackageByName(t.Context(), user.ID, packages.TypeMaven, "com.gitea-legacy-project")
  88. require.ErrorIs(t, err, packages.ErrPackageNotExist)
  89. p, err = packages.GetPackageByName(t.Context(), user.ID, packages.TypeMaven, "com.gitea:legacy-project")
  90. require.NoError(t, err)
  91. assert.Equal(t, "com.gitea:legacy-project", p.Name)
  92. req = NewRequest(t, "HEAD", legacyRootLink+"/1.0.2/any-file-name").AddBasicAuth(user.Name)
  93. MakeRequest(t, req, http.StatusOK)
  94. req = NewRequest(t, "GET", "/user2/-/packages/maven/com.gitea-legacy-project/1.0.2")
  95. MakeRequest(t, req, http.StatusNotFound)
  96. req = NewRequest(t, "GET", "/user2/-/packages/maven/com.gitea:legacy-project/1.0.2")
  97. MakeRequest(t, req, http.StatusOK)
  98. req = NewRequest(t, "GET", "/user2/-/packages/maven/com.gitea%3Alegacy-project/1.0.2")
  99. MakeRequest(t, req, http.StatusOK)
  100. // now 2 packages should be listed
  101. req = NewRequest(t, "GET", legacyRootLink+"/maven-metadata.xml").AddBasicAuth(user.Name)
  102. resp = MakeRequest(t, req, http.StatusOK)
  103. respBody = resp.Body.String()
  104. assert.Contains(t, respBody, "<version>1.0.2</version>")
  105. assert.Contains(t, respBody, "<version>1.0.3</version>")
  106. require.NoError(t, packages.DeletePackageByID(t.Context(), p.ID))
  107. })
  108. t.Run("UploadExists", func(t *testing.T) {
  109. defer tests.PrintCurrentTest(t)()
  110. putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusConflict)
  111. })
  112. t.Run("Download", func(t *testing.T) {
  113. defer tests.PrintCurrentTest(t)()
  114. req := NewRequest(t, "HEAD", fmt.Sprintf("%s/%s/%s", root, packageVersion, filename)).AddBasicAuth(user.Name)
  115. resp := MakeRequest(t, req, http.StatusOK)
  116. checkHeaders(t, resp.Header(), "application/java-archive", 4)
  117. req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s", root, packageVersion, filename)).AddBasicAuth(user.Name)
  118. resp = MakeRequest(t, req, http.StatusOK)
  119. checkHeaders(t, resp.Header(), "application/java-archive", 4)
  120. assert.Equal(t, []byte("test"), resp.Body.Bytes())
  121. pvs, err := packages.GetVersionsByPackageType(t.Context(), user.ID, packages.TypeMaven)
  122. require.NoError(t, err)
  123. assert.Len(t, pvs, 1)
  124. assert.Equal(t, int64(0), pvs[0].DownloadCount)
  125. })
  126. t.Run("UploadVerifySHA1", func(t *testing.T) {
  127. defer tests.PrintCurrentTest(t)()
  128. t.Run("Missmatch", func(t *testing.T) {
  129. defer tests.PrintCurrentTest(t)()
  130. putFile(t, fmt.Sprintf("/%s/%s.sha1", packageVersion, filename), "test", http.StatusBadRequest)
  131. })
  132. t.Run("Valid", func(t *testing.T) {
  133. defer tests.PrintCurrentTest(t)()
  134. putFile(t, fmt.Sprintf("/%s/%s.sha1", packageVersion, filename), "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", http.StatusOK)
  135. })
  136. })
  137. pomContent := `<?xml version="1.0"?>
  138. <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  139. <groupId>` + groupID + `</groupId>
  140. <artifactId>` + artifactID + `</artifactId>
  141. <version>` + packageVersion + `</version>
  142. <description>` + packageDescription + `</description>
  143. </project>`
  144. t.Run("UploadPOM", func(t *testing.T) {
  145. defer tests.PrintCurrentTest(t)()
  146. pvs, err := packages.GetVersionsByPackageType(t.Context(), user.ID, packages.TypeMaven)
  147. require.NoError(t, err)
  148. assert.Len(t, pvs, 1)
  149. pd, err := packages.GetPackageDescriptor(t.Context(), pvs[0])
  150. require.NoError(t, err)
  151. assert.Nil(t, pd.Metadata)
  152. putFile(t, fmt.Sprintf("/%s/%s.pom", packageVersion, filename), pomContent, http.StatusCreated)
  153. pvs, err = packages.GetVersionsByPackageType(t.Context(), user.ID, packages.TypeMaven)
  154. require.NoError(t, err)
  155. assert.Len(t, pvs, 1)
  156. pd, err = packages.GetPackageDescriptor(t.Context(), pvs[0])
  157. require.NoError(t, err)
  158. assert.IsType(t, &maven.Metadata{}, pd.Metadata)
  159. assert.Equal(t, packageDescription, pd.Metadata.(*maven.Metadata).Description)
  160. pfs, err := packages.GetFilesByVersionID(t.Context(), pvs[0].ID)
  161. require.NoError(t, err)
  162. assert.Len(t, pfs, 2)
  163. for _, pf := range pfs {
  164. if strings.HasSuffix(pf.Name, ".pom") {
  165. assert.Equal(t, filename+".pom", pf.Name)
  166. assert.True(t, pf.IsLead)
  167. } else {
  168. assert.False(t, pf.IsLead)
  169. }
  170. }
  171. })
  172. t.Run("DownloadPOM", func(t *testing.T) {
  173. defer tests.PrintCurrentTest(t)()
  174. req := NewRequest(t, "HEAD", fmt.Sprintf("%s/%s/%s.pom", root, packageVersion, filename)).AddBasicAuth(user.Name)
  175. resp := MakeRequest(t, req, http.StatusOK)
  176. checkHeaders(t, resp.Header(), "text/xml", int64(len(pomContent)))
  177. req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s.pom", root, packageVersion, filename)).AddBasicAuth(user.Name)
  178. resp = MakeRequest(t, req, http.StatusOK)
  179. checkHeaders(t, resp.Header(), "text/xml", int64(len(pomContent)))
  180. assert.Equal(t, []byte(pomContent), resp.Body.Bytes())
  181. pvs, err := packages.GetVersionsByPackageType(t.Context(), user.ID, packages.TypeMaven)
  182. require.NoError(t, err)
  183. assert.Len(t, pvs, 1)
  184. assert.Equal(t, int64(1), pvs[0].DownloadCount)
  185. })
  186. t.Run("DownloadChecksums", func(t *testing.T) {
  187. defer tests.PrintCurrentTest(t)()
  188. req := NewRequest(t, "GET", fmt.Sprintf("%s/1.2.3/%s", root, filename)).AddBasicAuth(user.Name)
  189. MakeRequest(t, req, http.StatusNotFound)
  190. for key, checksum := range map[string]string{
  191. "md5": "098f6bcd4621d373cade4e832627b4f6",
  192. "sha1": "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
  193. "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
  194. "sha512": "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff",
  195. } {
  196. req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s.%s", root, packageVersion, filename, key)).AddBasicAuth(user.Name)
  197. resp := MakeRequest(t, req, http.StatusOK)
  198. assert.Equal(t, checksum, resp.Body.String())
  199. }
  200. })
  201. t.Run("DownloadMetadata", func(t *testing.T) {
  202. defer tests.PrintCurrentTest(t)()
  203. req := NewRequest(t, "GET", root+"/maven-metadata.xml").AddBasicAuth(user.Name)
  204. resp := MakeRequest(t, req, http.StatusOK)
  205. expectedMetadata := `<?xml version="1.0" encoding="UTF-8"?>` + "\n<metadata><groupId>com.gitea</groupId><artifactId>test-project</artifactId><versioning><release>1.0.1</release><latest>1.0.1</latest><versions><version>1.0.1</version></versions></versioning></metadata>"
  206. checkHeaders(t, resp.Header(), "text/xml", int64(len(expectedMetadata)))
  207. assert.Equal(t, expectedMetadata, resp.Body.String())
  208. for key, checksum := range map[string]string{
  209. "md5": "6bee0cebaaa686d658adf3e7e16371a0",
  210. "sha1": "8696abce499fe84d9ea93e5492abe7147e195b6c",
  211. "sha256": "3f48322f81c4b2c3bb8649ae1e5c9801476162b520e1c2734ac06b2c06143208",
  212. "sha512": "cb075aa2e2ef1a83cdc14dd1e08c505b72d633399b39e73a21f00f0deecb39a3e2c79f157c1163f8a3854828750706e0dec3a0f5e4778e91f8ec2cf351a855f2",
  213. } {
  214. req := NewRequest(t, "GET", fmt.Sprintf("%s/maven-metadata.xml.%s", root, key)).AddBasicAuth(user.Name)
  215. resp := MakeRequest(t, req, http.StatusOK)
  216. assert.Equal(t, checksum, resp.Body.String())
  217. }
  218. })
  219. t.Run("UploadSnapshot", func(t *testing.T) {
  220. snapshotVersion := packageVersion + "-SNAPSHOT"
  221. putFile(t, fmt.Sprintf("/%s/%s", snapshotVersion, filename), "test", http.StatusCreated)
  222. putFile(t, "/maven-metadata.xml", "test", http.StatusOK)
  223. putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test", http.StatusCreated)
  224. putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test-overwrite", http.StatusCreated)
  225. })
  226. t.Run("InvalidFile", func(t *testing.T) {
  227. invalidVersion := packageVersion + "-invalid"
  228. putFile(t, fmt.Sprintf("/%s/%s", invalidVersion, filename), "any invalid content", http.StatusCreated)
  229. req := NewRequestf(t, "GET", "/%s/-/packages/maven/%s/%s", user.Name, url.QueryEscape(groupID+":"+artifactID), invalidVersion)
  230. resp := MakeRequest(t, req, http.StatusOK)
  231. assert.Contains(t, resp.Body.String(), "No metadata.")
  232. assert.True(t, test.IsNormalPageCompleted(resp.Body.String()))
  233. })
  234. }
  235. func TestPackageMavenConcurrent(t *testing.T) {
  236. defer tests.PrepareTestEnv(t)()
  237. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  238. groupID := "com.gitea"
  239. artifactID := "test-project"
  240. packageVersion := "1.0.1"
  241. root := fmt.Sprintf("/api/packages/%s/maven/%s/%s", user.Name, strings.ReplaceAll(groupID, ".", "/"), artifactID)
  242. putFile := func(t *testing.T, path, content string, expectedStatus int) {
  243. req := NewRequestWithBody(t, "PUT", root+path, strings.NewReader(content)).AddBasicAuth(user.Name)
  244. MakeRequest(t, req, expectedStatus)
  245. }
  246. t.Run("Concurrent Upload", func(t *testing.T) {
  247. defer tests.PrintCurrentTest(t)()
  248. var wg sync.WaitGroup
  249. for i := range 10 {
  250. wg.Add(1)
  251. go func(i int) {
  252. putFile(t, fmt.Sprintf("/%s/%s.jar", packageVersion, strconv.Itoa(i)), "test", http.StatusCreated)
  253. wg.Done()
  254. }(i)
  255. }
  256. wg.Wait()
  257. })
  258. }