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_debian_test.go 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. // Copyright 2023 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package integration
  4. import (
  5. "archive/tar"
  6. "bytes"
  7. "compress/gzip"
  8. "fmt"
  9. "io"
  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. "code.gitea.io/gitea/modules/base"
  18. debian_module "code.gitea.io/gitea/modules/packages/debian"
  19. "code.gitea.io/gitea/tests"
  20. "github.com/blakesmith/ar"
  21. "github.com/stretchr/testify/assert"
  22. )
  23. func TestPackageDebian(t *testing.T) {
  24. defer tests.PrepareTestEnv(t)()
  25. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  26. packageName := "gitea"
  27. packageVersion := "1.0.3"
  28. packageDescription := "Package Description"
  29. createArchive := func(name, version, architecture string) io.Reader {
  30. var cbuf bytes.Buffer
  31. zw := gzip.NewWriter(&cbuf)
  32. tw := tar.NewWriter(zw)
  33. tw.WriteHeader(&tar.Header{
  34. Name: "control",
  35. Mode: 0o600,
  36. Size: 50,
  37. })
  38. fmt.Fprintf(tw, "Package: %s\nVersion: %s\nArchitecture: %s\nDescription: %s\n", name, version, architecture, packageDescription)
  39. tw.Close()
  40. zw.Close()
  41. var buf bytes.Buffer
  42. aw := ar.NewWriter(&buf)
  43. aw.WriteGlobalHeader()
  44. hdr := &ar.Header{
  45. Name: "control.tar.gz",
  46. Mode: 0o600,
  47. Size: int64(cbuf.Len()),
  48. }
  49. aw.WriteHeader(hdr)
  50. aw.Write(cbuf.Bytes())
  51. return &buf
  52. }
  53. distributions := []string{"test", "gitea"}
  54. components := []string{"main", "stable"}
  55. architectures := []string{"all", "amd64"}
  56. rootURL := fmt.Sprintf("/api/packages/%s/debian", user.Name)
  57. t.Run("RepositoryKey", func(t *testing.T) {
  58. defer tests.PrintCurrentTest(t)()
  59. req := NewRequest(t, "GET", rootURL+"/repository.key")
  60. resp := MakeRequest(t, req, http.StatusOK)
  61. assert.Equal(t, "application/pgp-keys", resp.Header().Get("Content-Type"))
  62. assert.Contains(t, resp.Body.String(), "-----BEGIN PGP PUBLIC KEY BLOCK-----")
  63. })
  64. for _, distribution := range distributions {
  65. t.Run(fmt.Sprintf("[Distribution:%s]", distribution), func(t *testing.T) {
  66. for _, component := range components {
  67. for _, architecture := range architectures {
  68. t.Run(fmt.Sprintf("[Component:%s,Architecture:%s]", component, architecture), func(t *testing.T) {
  69. t.Run("Upload", func(t *testing.T) {
  70. defer tests.PrintCurrentTest(t)()
  71. uploadURL := fmt.Sprintf("%s/pool/%s/%s/upload", rootURL, distribution, component)
  72. req := NewRequestWithBody(t, "PUT", uploadURL, bytes.NewReader([]byte{}))
  73. MakeRequest(t, req, http.StatusUnauthorized)
  74. req = NewRequestWithBody(t, "PUT", uploadURL, bytes.NewReader([]byte{}))
  75. AddBasicAuthHeader(req, user.Name)
  76. MakeRequest(t, req, http.StatusBadRequest)
  77. req = NewRequestWithBody(t, "PUT", uploadURL, createArchive("", "", ""))
  78. AddBasicAuthHeader(req, user.Name)
  79. MakeRequest(t, req, http.StatusBadRequest)
  80. req = NewRequestWithBody(t, "PUT", uploadURL, createArchive(packageName, packageVersion, architecture))
  81. AddBasicAuthHeader(req, user.Name)
  82. MakeRequest(t, req, http.StatusCreated)
  83. pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeDebian)
  84. assert.NoError(t, err)
  85. assert.Len(t, pvs, 1)
  86. pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
  87. assert.NoError(t, err)
  88. assert.Nil(t, pd.SemVer)
  89. assert.IsType(t, &debian_module.Metadata{}, pd.Metadata)
  90. assert.Equal(t, packageName, pd.Package.Name)
  91. assert.Equal(t, packageVersion, pd.Version.Version)
  92. pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
  93. assert.NoError(t, err)
  94. assert.NotEmpty(t, pfs)
  95. assert.Condition(t, func() bool {
  96. seen := false
  97. expectedFilename := fmt.Sprintf("%s_%s_%s.deb", packageName, packageVersion, architecture)
  98. expectedCompositeKey := fmt.Sprintf("%s|%s", distribution, component)
  99. for _, pf := range pfs {
  100. if pf.Name == expectedFilename && pf.CompositeKey == expectedCompositeKey {
  101. if seen {
  102. return false
  103. }
  104. seen = true
  105. assert.True(t, pf.IsLead)
  106. pfps, err := packages.GetProperties(db.DefaultContext, packages.PropertyTypeFile, pf.ID)
  107. assert.NoError(t, err)
  108. for _, pfp := range pfps {
  109. switch pfp.Name {
  110. case debian_module.PropertyDistribution:
  111. assert.Equal(t, distribution, pfp.Value)
  112. case debian_module.PropertyComponent:
  113. assert.Equal(t, component, pfp.Value)
  114. case debian_module.PropertyArchitecture:
  115. assert.Equal(t, architecture, pfp.Value)
  116. }
  117. }
  118. }
  119. }
  120. return seen
  121. })
  122. req = NewRequestWithBody(t, "PUT", uploadURL, createArchive(packageName, packageVersion, architecture))
  123. AddBasicAuthHeader(req, user.Name)
  124. MakeRequest(t, req, http.StatusBadRequest)
  125. })
  126. t.Run("Download", func(t *testing.T) {
  127. defer tests.PrintCurrentTest(t)()
  128. req := NewRequest(t, "GET", fmt.Sprintf("%s/pool/%s/%s/%s_%s_%s.deb", rootURL, distribution, component, packageName, packageVersion, architecture))
  129. resp := MakeRequest(t, req, http.StatusOK)
  130. assert.Equal(t, "application/vnd.debian.binary-package", resp.Header().Get("Content-Type"))
  131. })
  132. t.Run("Packages", func(t *testing.T) {
  133. defer tests.PrintCurrentTest(t)()
  134. url := fmt.Sprintf("%s/dists/%s/%s/binary-%s/Packages", rootURL, distribution, component, architecture)
  135. req := NewRequest(t, "GET", url)
  136. resp := MakeRequest(t, req, http.StatusOK)
  137. body := resp.Body.String()
  138. assert.Contains(t, body, "Package: "+packageName)
  139. assert.Contains(t, body, "Version: "+packageVersion)
  140. assert.Contains(t, body, "Architecture: "+architecture)
  141. assert.Contains(t, body, fmt.Sprintf("Filename: pool/%s/%s/%s_%s_%s.deb", distribution, component, packageName, packageVersion, architecture))
  142. req = NewRequest(t, "GET", url+".gz")
  143. MakeRequest(t, req, http.StatusOK)
  144. req = NewRequest(t, "GET", url+".xz")
  145. MakeRequest(t, req, http.StatusOK)
  146. url = fmt.Sprintf("%s/dists/%s/%s/%s/by-hash/SHA256/%s", rootURL, distribution, component, architecture, base.EncodeSha256(body))
  147. req = NewRequest(t, "GET", url)
  148. resp = MakeRequest(t, req, http.StatusOK)
  149. assert.Equal(t, body, resp.Body.String())
  150. })
  151. })
  152. }
  153. }
  154. t.Run("Release", func(t *testing.T) {
  155. defer tests.PrintCurrentTest(t)()
  156. req := NewRequest(t, "GET", fmt.Sprintf("%s/dists/%s/Release", rootURL, distribution))
  157. resp := MakeRequest(t, req, http.StatusOK)
  158. body := resp.Body.String()
  159. assert.Contains(t, body, "Components: "+strings.Join(components, " "))
  160. assert.Contains(t, body, "Architectures: "+strings.Join(architectures, " "))
  161. for _, component := range components {
  162. for _, architecture := range architectures {
  163. assert.Contains(t, body, fmt.Sprintf("%s/binary-%s/Packages", component, architecture))
  164. assert.Contains(t, body, fmt.Sprintf("%s/binary-%s/Packages.gz", component, architecture))
  165. assert.Contains(t, body, fmt.Sprintf("%s/binary-%s/Packages.xz", component, architecture))
  166. }
  167. }
  168. req = NewRequest(t, "GET", fmt.Sprintf("%s/dists/%s/by-hash/SHA256/%s", rootURL, distribution, base.EncodeSha256(body)))
  169. resp = MakeRequest(t, req, http.StatusOK)
  170. assert.Equal(t, body, resp.Body.String())
  171. req = NewRequest(t, "GET", fmt.Sprintf("%s/dists/%s/Release.gpg", rootURL, distribution))
  172. resp = MakeRequest(t, req, http.StatusOK)
  173. assert.Contains(t, resp.Body.String(), "-----BEGIN PGP SIGNATURE-----")
  174. req = NewRequest(t, "GET", fmt.Sprintf("%s/dists/%s/InRelease", rootURL, distribution))
  175. resp = MakeRequest(t, req, http.StatusOK)
  176. assert.Contains(t, resp.Body.String(), "-----BEGIN PGP SIGNED MESSAGE-----")
  177. })
  178. })
  179. }
  180. t.Run("Delete", func(t *testing.T) {
  181. defer tests.PrintCurrentTest(t)()
  182. distribution := distributions[0]
  183. architecture := architectures[0]
  184. for _, component := range components {
  185. req := NewRequest(t, "DELETE", fmt.Sprintf("%s/pool/%s/%s/%s/%s/%s", rootURL, distribution, component, packageName, packageVersion, architecture))
  186. MakeRequest(t, req, http.StatusUnauthorized)
  187. req = NewRequest(t, "DELETE", fmt.Sprintf("%s/pool/%s/%s/%s/%s/%s", rootURL, distribution, component, packageName, packageVersion, architecture))
  188. AddBasicAuthHeader(req, user.Name)
  189. MakeRequest(t, req, http.StatusNoContent)
  190. req = NewRequest(t, "GET", fmt.Sprintf("%s/dists/%s/%s/binary-%s/Packages", rootURL, distribution, component, architecture))
  191. MakeRequest(t, req, http.StatusNotFound)
  192. }
  193. req := NewRequest(t, "GET", fmt.Sprintf("%s/dists/%s/Release", rootURL, distribution))
  194. resp := MakeRequest(t, req, http.StatusOK)
  195. body := resp.Body.String()
  196. assert.Contains(t, body, "Components: "+strings.Join(components, " "))
  197. assert.Contains(t, body, "Architectures: "+architectures[1])
  198. })
  199. }