From bed592c075b25fcf7e8af44830059272cfd0a231 Mon Sep 17 00:00:00 2001 From: Diana Str Date: Fri, 19 Sep 2025 16:30:45 +0200 Subject: [PATCH] Added test for maven cleanup --- models/fixtures/package.yml | 6 + models/fixtures/package_blob.yml | 88 +++++++++ models/fixtures/package_file.yml | 99 ++++++++++ models/fixtures/package_version.yml | 8 + services/packages/maven/cleanup.go | 15 +- services/packages/maven/cleanup_test.go | 250 ++++++++++++++++++++++++ 6 files changed, 460 insertions(+), 6 deletions(-) create mode 100644 models/fixtures/package.yml create mode 100644 models/fixtures/package_blob.yml create mode 100644 models/fixtures/package_file.yml create mode 100644 models/fixtures/package_version.yml create mode 100644 services/packages/maven/cleanup_test.go diff --git a/models/fixtures/package.yml b/models/fixtures/package.yml new file mode 100644 index 0000000000..45ff9dac82 --- /dev/null +++ b/models/fixtures/package.yml @@ -0,0 +1,6 @@ +- + id: 1 + owner_id: 2 + type: maven + name: com.gitea:test-project + lower_name: com.gitea:test-project diff --git a/models/fixtures/package_blob.yml b/models/fixtures/package_blob.yml new file mode 100644 index 0000000000..225d848002 --- /dev/null +++ b/models/fixtures/package_blob.yml @@ -0,0 +1,88 @@ +- + id: 1 + size: 14 + hash_md5: 27224a672372115e5a1d125ed7b2a0b1 + hash_sha1: 9854582a2958b2d31541ce4a6a1a36201b80c01 + hash_sha256: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a01 + hash_sha512: ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a801 + created_unix: 1672531200 +- + id: 2 + size: 14 + hash_md5: 27224a672372115e5a1d125ed7b2a0b2 + hash_sha1: 9854582a2958b2d31541ce4a6a1a36201b80c02 + hash_sha256: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a02 + hash_sha512: ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a802 + created_unix: 1672531200 +- + id: 3 + size: 14 + hash_md5: 27224a672372115e5a1d125ed7b2a0b3 + hash_sha1: 9854582a2958b2d31541ce4a6a1a36201b80c03 + hash_sha256: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a03 + hash_sha512: ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a803 + created_unix: 1672531200 +- + id: 4 + size: 14 + hash_md5: 27224a672372115e5a1d125ed7b2a0b4 + hash_sha1: 9854582a2958b2d31541ce4a6a1a36201b80c04 + hash_sha256: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a04 + hash_sha512: ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a804 + created_unix: 1672531200 +- + id: 5 + size: 14 + hash_md5: 27224a672372115e5a1d125ed7b2a0b5 + hash_sha1: 9854582a2958b2d31541ce4a6a1a36201b80c05 + hash_sha256: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a05 + hash_sha512: ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a805 + created_unix: 1672531200 +- + id: 6 + size: 14 + hash_md5: 27224a672372115e5a1d125ed7b2a0b6 + hash_sha1: 9854582a2958b2d31541ce4a6a1a36201b80c06 + hash_sha256: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a06 + hash_sha512: ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a806 + created_unix: 1672531200 +- + id: 7 + size: 14 + hash_md5: 27224a672372115e5a1d125ed7b2a0b7 + hash_sha1: 9854582a2958b2d31541ce4a6a1a36201b80c07 + hash_sha256: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a07 + hash_sha512: ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a807 + created_unix: 1672531200 +- + id: 8 + size: 14 + hash_md5: 27224a672372115e5a1d125ed7b2a0b8 + hash_sha1: 9854582a2958b2d31541ce4a6a1a36201b80c08 + hash_sha256: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 + hash_sha512: ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a808 + created_unix: 1672531200 +- + id: 9 + size: 14 + hash_md5: 27224a672372115e5a1d125ed7b2a0b9 + hash_sha1: 9854582a2958b2d31541ce4a6a1a36201b80c09 + hash_sha256: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a09 + hash_sha512: ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a809 + created_unix: 1672531200 +- + id: 10 + size: 14 + hash_md5: 27224a672372115e5a1d125ed7b2a0ba + hash_sha1: 9854582a2958b2d31541ce4a6a1a36201b80c10 + hash_sha256: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a10 + hash_sha512: ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a810 + created_unix: 1672531200 +- + id: 11 + size: 14 + hash_md5: 27224a672372115e5a1d125ed7b2a0bb + hash_sha1: 9854582a2958b2d31541ce4a6a1a36201b80c11 + hash_sha256: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a11 + hash_sha512: ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a811 + created_unix: 1672531200 diff --git a/models/fixtures/package_file.yml b/models/fixtures/package_file.yml new file mode 100644 index 0000000000..c4e50c59c5 --- /dev/null +++ b/models/fixtures/package_file.yml @@ -0,0 +1,99 @@ +- + id: 1 + version_id: 1 + blob_id: 1 + name: gitea-test-1.0-20230101.000000-1.jar + lower_name: gitea-test-1.0-20230101.000000-1.jar + composite_key: "" + is_lead: false + created_unix: 1672531200 +- + id: 2 + version_id: 1 + blob_id: 2 + name: gitea-test-1.0-20230101.000000-2.jar + lower_name: gitea-test-1.0-20230101.000000-2.jar + composite_key: "" + is_lead: false + created_unix: 1672531200 +- + id: 3 + version_id: 1 + blob_id: 3 + name: gitea-test-1.0-20230101.000000-3.jar + lower_name: gitea-test-1.0-20230101.000000-3.jar + composite_key: "" + is_lead: false + created_unix: 1672531200 +- + id: 4 + version_id: 1 + blob_id: 4 + name: gitea-test-1.0-20230101.000000-4.jar + lower_name: gitea-test-1.0-20230101.000000-4.jar + composite_key: "" + is_lead: false + created_unix: 1672531200 +- + id: 5 + version_id: 1 + blob_id: 5 + name: gitea-test-1.0-20230101.000000-5.jar + lower_name: gitea-test-1.0-20230101.000000-5.jar + composite_key: "" + is_lead: false + created_unix: 1672531200 +- + id: 6 + version_id: 1 + blob_id: 6 + name: gitea-test-1.0-20230101.000000-3-sources.jar + lower_name: gitea-test-1.0-20230101.000000-3-sources.jar + composite_key: "" + is_lead: false + created_unix: 1672531200 +- + id: 7 + version_id: 1 + blob_id: 7 + name: gitea-test-1.0-20230101.000000-3-javadoc.jar + lower_name: gitea-test-1.0-20230101.000000-3-javadoc.jar + composite_key: "" + is_lead: false + created_unix: 1672531200 +- + id: 8 + version_id: 1 + blob_id: 8 + name: gitea-test-1.0-20230101.000000-4-sources.jar + lower_name: gitea-test-1.0-20230101.000000-4-sources.jar + composite_key: "" + is_lead: false + created_unix: 1672531200 +- + id: 9 + version_id: 1 + blob_id: 9 + name: gitea-test-1.0-20230101.000000-4-javadoc.jar + lower_name: gitea-test-1.0-20230101.000000-4-javadoc.jar + composite_key: "" + is_lead: false + created_unix: 1672531200 +- + id: 10 + version_id: 1 + blob_id: 10 + name: gitea-test-1.0-20230101.000000-5-sources.jar + lower_name: gitea-test-1.0-20230101.000000-5-sources.jar + composite_key: "" + is_lead: false + created_unix: 1672531200 +- + id: 11 + version_id: 1 + blob_id: 11 + name: gitea-test-1.0-20230101.000000-5-javadoc.jar + lower_name: gitea-test-1.0-20230101.000000-5-javadoc.jar + composite_key: "" + is_lead: false + created_unix: 1672531200 diff --git a/models/fixtures/package_version.yml b/models/fixtures/package_version.yml new file mode 100644 index 0000000000..fdcc6babf0 --- /dev/null +++ b/models/fixtures/package_version.yml @@ -0,0 +1,8 @@ +- + id: 1 + package_id: 1 + creator_id: 2 + version: 1.0-SNAPSHOT + lower_version: 1.0-snapshot + metadata_json: '{"artifact_id":"test-project","group_id":"com.gitea"}' + created_unix: 1672531200 diff --git a/services/packages/maven/cleanup.go b/services/packages/maven/cleanup.go index d4ee9028d7..bf8ed22469 100644 --- a/services/packages/maven/cleanup.go +++ b/services/packages/maven/cleanup.go @@ -1,3 +1,6 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + package maven import ( @@ -38,21 +41,21 @@ func CleanupSnapshotVersions(ctx context.Context) error { continue } - var artifactId, groupId string + var artifactID, groupID string if version.MetadataJSON != "" { - var metadata map[string]interface{} + var metadata map[string]any if err := json.Unmarshal([]byte(version.MetadataJSON), &metadata); err != nil { log.Warn("Maven Cleanup: error during cleanup: failed to unmarshal metadataJSON for package version ID: %d: %w", version.ID, err) } else { - artifactId, _ = metadata["artifact_id"].(string) - groupId, _ = metadata["group_id"].(string) - log.Debug("Maven Cleanup: processing package version with ID: %s, Group ID: %s, Artifact ID: %s, Version: %s", version.ID, groupId, artifactId, version.Version) + artifactID, _ = metadata["artifact_id"].(string) + groupID, _ = metadata["group_id"].(string) + log.Debug("Maven Cleanup: processing package version with ID: %s, Group ID: %s, Artifact ID: %s, Version: %s", version.ID, groupID, artifactID, version.Version) } } if err := cleanSnapshotFiles(ctx, version.ID, retainBuilds, debugSession); err != nil { formattedErr := fmt.Errorf("version '%s' (ID: %d, Group ID: %s, Artifact ID: %s): %w", - version.Version, version.ID, groupId, artifactId, err) + version.Version, version.ID, groupID, artifactID, err) if errors.Is(err, packages.ErrMetadataFile) { metadataErrors = append(metadataErrors, formattedErr) diff --git a/services/packages/maven/cleanup_test.go b/services/packages/maven/cleanup_test.go new file mode 100644 index 0000000000..596154eb91 --- /dev/null +++ b/services/packages/maven/cleanup_test.go @@ -0,0 +1,250 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package maven + +import ( + "bytes" + "testing" + + "code.gitea.io/gitea/models/packages" + "code.gitea.io/gitea/models/unittest" + packages_module "code.gitea.io/gitea/modules/packages" + "code.gitea.io/gitea/modules/setting" + packages_service "code.gitea.io/gitea/services/packages" + + "github.com/stretchr/testify/assert" +) + +func TestMain(m *testing.M) { + unittest.MainTest(m) +} + +func addMavenMetadataToPackageVersion(t *testing.T, pv *packages.PackageVersion) { + // Create maven-metadata.xml content with build number 5 (matching the fixtures) + // Maven metadata structure explanation: + // - : Contains the latest snapshot timestamp and build number + // - : Lists all available files for each build number + // - : File extension (jar, pom, etc.) + // - : Optional classifier (sources, javadoc, tests, etc.) + // - : The actual version string with timestamp and build number + // - : Timestamp when the artifact was deployed + metadataXML := ` + + com.gitea + test-project + 1.0-SNAPSHOT + + + 20230101.000000 + 5 + + 20230101000000 + + + jar + 1.0-20230101.000000-1 + 20230101000000 + + + jar + 1.0-20230101.000000-2 + 20230101000000 + + + jar + 1.0-20230101.000000-3 + 20230101000000 + + + sources + jar + 1.0-20230101.000000-3 + 20230101000000 + + + javadoc + jar + 1.0-20230101.000000-3 + 20230101000000 + + + jar + 1.0-20230101.000000-4 + 20230101000000 + + + sources + jar + 1.0-20230101.000000-4 + 20230101000000 + + + javadoc + jar + 1.0-20230101.000000-4 + 20230101000000 + + + jar + 1.0-20230101.000000-5 + 20230101000000 + + + sources + jar + 1.0-20230101.000000-5 + 20230101000000 + + + javadoc + jar + 1.0-20230101.000000-5 + 20230101000000 + + + +` + + // Add metadata file to the existing package version using service method + metadataReader := bytes.NewReader([]byte(metadataXML)) + hsr, err := packages_module.CreateHashedBufferFromReader(metadataReader) + assert.NoError(t, err) + + pfci := &packages_service.PackageFileCreationInfo{ + PackageFileInfo: packages_service.PackageFileInfo{ + Filename: "maven-metadata.xml", + }, + Data: hsr, + } + + _, err = packages_service.AddFileToPackageVersionInternal(t.Context(), pv, pfci) + assert.NoError(t, err) +} + +func TestCleanupSnapshotVersions(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + t.Run("Should skip when retainBuilds is negative", func(t *testing.T) { + setting.Packages.RetainMavenSnapshotBuilds = -1 + setting.Packages.DebugMavenCleanup = false + t.Logf("Test settings: retainBuilds=%d, debug=%t", setting.Packages.RetainMavenSnapshotBuilds, setting.Packages.DebugMavenCleanup) + err := CleanupSnapshotVersions(t.Context()) + assert.NoError(t, err) + }) + + t.Run("Should skip when retainBuilds is zero", func(t *testing.T) { + setting.Packages.RetainMavenSnapshotBuilds = 0 + setting.Packages.DebugMavenCleanup = false + t.Logf("Test settings: retainBuilds=%d, debug=%t", setting.Packages.RetainMavenSnapshotBuilds, setting.Packages.DebugMavenCleanup) + err := CleanupSnapshotVersions(t.Context()) + assert.NoError(t, err) + }) + + t.Run("Should handle missing metadata file gracefully", func(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + setting.Packages.RetainMavenSnapshotBuilds = 2 + setting.Packages.DebugMavenCleanup = false + + // Get the existing package version from fixtures (ID 1) + pv, err := packages.GetVersionByID(t.Context(), 1) + assert.NoError(t, err) + + // Verify all 11 files exist before cleanup (5 base jars + 6 classifier jars) + filesBefore, err := packages.GetFilesByVersionID(t.Context(), pv.ID) + assert.NoError(t, err) + assert.Len(t, filesBefore, 11) // 5 base jars + 6 classifier jars (sources + javadoc for builds 3,4,5) + + // No metadata file exists in fixtures - should handle gracefully + err = CleanupSnapshotVersions(t.Context()) + assert.NoError(t, err) + + // Verify all 11 files still exist after cleanup (no cleanup should occur without metadata) + filesAfter, err := packages.GetFilesByVersionID(t.Context(), pv.ID) + assert.NoError(t, err) + assert.Len(t, filesAfter, 11, "All files should remain when metadata is missing") + }) + + t.Run("Should work with debug mode", func(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + setting.Packages.RetainMavenSnapshotBuilds = 2 + setting.Packages.DebugMavenCleanup = true + + pv, err := packages.GetVersionByID(t.Context(), 1) + assert.NoError(t, err) + + addMavenMetadataToPackageVersion(t, pv) + + filesBefore, err := packages.GetFilesByVersionID(t.Context(), pv.ID) + assert.NoError(t, err) + assert.Len(t, filesBefore, 12) // 11 jar files + 1 metadata file + + err = CleanupSnapshotVersions(t.Context()) + assert.NoError(t, err) + + // Verify all files still exist after cleanup (debug mode should not delete anything) + filesAfter, err := packages.GetFilesByVersionID(t.Context(), pv.ID) + assert.NoError(t, err) + assert.Len(t, filesAfter, 12, "All files should remain in debug mode") + }) + + t.Run("Should test actual cleanup with metadata", func(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + setting.Packages.DebugMavenCleanup = false + setting.Packages.RetainMavenSnapshotBuilds = 2 + t.Logf("Test settings: retainBuilds=%d, debug=%t", setting.Packages.RetainMavenSnapshotBuilds, setting.Packages.DebugMavenCleanup) + + // Get the existing package version from fixtures (ID 1) + pv, err := packages.GetVersionByID(t.Context(), 1) + assert.NoError(t, err) + assert.Equal(t, "1.0-SNAPSHOT", pv.Version) + + addMavenMetadataToPackageVersion(t, pv) + + filesBefore, err := packages.GetFilesByVersionID(t.Context(), pv.ID) + assert.NoError(t, err) + assert.Len(t, filesBefore, 12) // 11 jar files + 1 metadata file + + // Test cleanup with retainBuilds = 2 (should keep builds 4 and 5, remove 1, 2, 3) + // Build 4: base jar + sources + javadoc = 3 files + // Build 5: base jar + sources + javadoc = 3 files + // Total retained: 6 files + 1 metadata = 7 files + err = CleanupSnapshotVersions(t.Context()) + assert.NoError(t, err) + + filesAfter, err := packages.GetFilesByVersionID(t.Context(), pv.ID) + assert.NoError(t, err) + + // Should have metadata file + 6 retained build artifacts (2 builds × 3 files each) + assert.Len(t, filesAfter, 7) + + // Check that metadata file is still there + var hasMetadata bool + var retainedBuilds []string + for _, file := range filesAfter { + if file.Name == "maven-metadata.xml" { + hasMetadata = true + } else { + retainedBuilds = append(retainedBuilds, file.Name) + } + } + + assert.True(t, hasMetadata, "maven-metadata.xml should be retained") + assert.Len(t, retainedBuilds, 6, "Should retain exactly 6 files (2 builds with 3 artifacts each)") + + t.Logf("Retained builds: %v", retainedBuilds) + + // Verify build 4 artifacts are retained + assert.Contains(t, retainedBuilds, "gitea-test-1.0-20230101.000000-4.jar") + assert.Contains(t, retainedBuilds, "gitea-test-1.0-20230101.000000-4-sources.jar") + assert.Contains(t, retainedBuilds, "gitea-test-1.0-20230101.000000-4-javadoc.jar") + + // Verify build 5 artifacts are retained + assert.Contains(t, retainedBuilds, "gitea-test-1.0-20230101.000000-5.jar") + assert.Contains(t, retainedBuilds, "gitea-test-1.0-20230101.000000-5-sources.jar") + assert.Contains(t, retainedBuilds, "gitea-test-1.0-20230101.000000-5-javadoc.jar") + }) +}