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