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  }