code.gitea.io/gitea@v1.22.3/tests/integration/api_packages_maven_test.go (about)

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