Files
actions/sh.actions.package-cleanup.Tests/Service/PackageServiceVersionDetectionTests.cs
edraft 98abbe661c
Some checks failed
Build on push / prepare (push) Successful in 5s
Build on push / build (push) Failing after 15s
Added package filtering
2026-02-14 20:48:40 +01:00

350 lines
12 KiB
C#

using Microsoft.Extensions.Configuration;
using Moq;
using sh.actions.package_cleanup.Models;
using sh.actions.package_cleanup.Service;
using Xunit;
namespace sh.actions.package_cleanup.Tests.Service;
public class PackageServiceVersionDetectionTests
{
private readonly IPackageService _packageService;
private readonly Mock<IConfiguration> _configurationMock;
private readonly Mock<IGiteaPackageService> _giteaPackageServiceMock;
public PackageServiceVersionDetectionTests()
{
_configurationMock = new Mock<IConfiguration>();
_giteaPackageServiceMock = new Mock<IGiteaPackageService>();
_packageService = new PackageService(_configurationMock.Object, _giteaPackageServiceMock.Object);
}
#region Release Type Detection Tests
[Theory]
[InlineData("1.0.0")]
[InlineData("2.5.3")]
[InlineData("10.20.30")]
[InlineData("2025.2.14.1")]
public void FilterPackagesToDelete_WithProdReleases_ShouldIdentifyAsNonDeletable(string version)
{
// Arrange
var packages = new List<GiteaPackage>
{
new() { Id = 1, Name = "test", Version = version, Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Prod releases should not be in delete list (CLEAN_PROD_VERSIONS=false by default)
Assert.DoesNotContain(result, p => p.Id == 1);
Assert.Empty(result); // No packages should be deleted without CLEAN_PROD_VERSIONS=true
}
[Theory]
[InlineData("1.0.0-alpha")]
[InlineData("1.0.0-ALPHA")]
[InlineData("2.5.3-alpha123")]
[InlineData("1.0.0-beta")]
[InlineData("1.0.0-BETA")]
[InlineData("1.0.0-rc")]
[InlineData("1.0.0-RC1")]
[InlineData("1.0.0-preview")]
[InlineData("1.0.0-PREVIEW")]
public void FilterPackagesToDelete_WithPrereleaseVersions_ShouldIdentifyCorrectly(string version)
{
// Arrange
var packages = new List<GiteaPackage>
{
new() { Id = 1, Name = "test", Version = version, Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Prerelease should be kept (default KEEP_PRERELEASE_VERSIONS=3, so 1 package is kept)
Assert.NotNull(result);
Assert.Empty(result); // Single prerelease should be kept as it's within the limit
}
[Theory]
[InlineData("1.0.0-dev")]
[InlineData("1.0.0-DEV")]
[InlineData("2.5.3-dev123")]
[InlineData("1.0.0-development")]
[InlineData("1.0.0-DEV")]
public void FilterPackagesToDelete_WithDevVersions_ShouldIdentifyCorrectly(string version)
{
// Arrange
var packages = new List<GiteaPackage>
{
new() { Id = 1, Name = "test", Version = version, Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Dev version should be kept (default KEEP_DEV_VERSIONS=5, so 1 package is kept)
Assert.NotNull(result);
Assert.Empty(result); // Single dev version should be kept as it's within the limit
}
#endregion
#region Semantic Version Detection Tests
[Theory]
[InlineData("1.0")]
[InlineData("1.0.0")]
[InlineData("1.0.0.0")]
[InlineData("2.5")]
[InlineData("2.5.3")]
[InlineData("2.5.3.100")]
[InlineData("0.0.0.0")]
[InlineData("99.99.99.99")]
public void FilterPackagesToDelete_WithValidSemanticVersions_ShouldProcess(string version)
{
// Arrange
var packages = new List<GiteaPackage>
{
new() { Id = 1, Name = "test", Version = version, Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Should process without throwing and not delete prod releases
Assert.NotNull(result);
Assert.DoesNotContain(result, p => p.Id == 1); // Prod version should not be deleted
}
[Theory]
[InlineData("1")] // Only 1 component
[InlineData("1.0.0.0.0")] // 5 components
[InlineData("1.a.0.0")] // Non-numeric
[InlineData("a.b.c.d")] // All non-numeric
public void FilterPackagesToDelete_WithInvalidSemanticVersions_ShouldSkip(string version)
{
// Arrange
var packages = new List<GiteaPackage>
{
new() { Id = 1, Name = "test", Version = version, Type = "docker", CreatedAt = DateTime.UtcNow },
new() { Id = 2, Name = "test", Version = "2.0.0.0", Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Invalid version should be skipped, only valid semantic version (id=2) is processed
Assert.NotNull(result);
// Should not crash and should only consider the valid version
Assert.DoesNotContain(result, p => p.Id == 2); // Valid prod should not be deleted
}
[Theory]
[InlineData("101.0.0.0")]
[InlineData("200.5.3.100")]
[InlineData("1000.0.0.0")]
public void FilterPackagesToDelete_WithLargeMajorVersion_ShouldTreatAsDateVersion(string version)
{
// Arrange
var packages = new List<GiteaPackage>
{
new() { Id = 1, Name = "test", Version = version, Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Large major versions (>100) are detected as date versions, not semantic
// These will fail date validation (invalid month/day) and be skipped
Assert.NotNull(result);
}
#endregion
#region Date Version Detection Tests
[Theory]
[InlineData("2024.1.1.1")]
[InlineData("2025.2.14.1")]
[InlineData("2026.12.31.999")]
[InlineData("2000.6.15.100")]
[InlineData("1999.1.1.1")]
public void FilterPackagesToDelete_WithValidDateVersions_ShouldProcess(string version)
{
// Arrange
var packages = new List<GiteaPackage>
{
new() { Id = 1, Name = "test", Version = version, Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Should process without throwing and not delete prod date versions
Assert.NotNull(result);
Assert.DoesNotContain(result, p => p.Id == 1); // Prod date version should not be deleted
}
[Theory]
[InlineData("2025.1.1")] // 3 components (missing build)
[InlineData("2025.1.1.1.1")] // 5 components
[InlineData("2025.13.1.1")] // Month out of range
[InlineData("2025.0.1.1")] // Month zero
[InlineData("2025.2.32.1")] // Day out of range
[InlineData("2025.2.0.1")] // Day zero
[InlineData("999.2.14.1")] // Year too small
[InlineData("3000.2.14.1")] // Year too large
[InlineData("2025.a.14.1")] // Non-numeric month
public void FilterPackagesToDelete_WithInvalidDateVersions_ShouldSkip(string version)
{
// Arrange
var packages = new List<GiteaPackage>
{
new() { Id = 1, Name = "test", Version = version, Type = "docker", CreatedAt = DateTime.UtcNow },
new() { Id = 2, Name = "test", Version = "1.0.0.0", Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Invalid date version should be skipped, valid semantic version (id=2) is processed as prod
Assert.NotNull(result);
Assert.DoesNotContain(result, p => p.Id == 2); // Valid semantic prod should not be deleted
}
[Theory]
[InlineData("1000.1.1.1")] // Minimum valid year
[InlineData("2999.12.31.999")] // Maximum valid year
[InlineData("2025.1.1.1")] // January 1
[InlineData("2025.12.31.1")] // December 31
public void FilterPackagesToDelete_WithDateVersionBoundaries_ShouldProcess(string version)
{
// Arrange
var packages = new List<GiteaPackage>
{
new() { Id = 1, Name = "test", Version = version, Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Boundary date versions should be recognized as valid
Assert.NotNull(result);
Assert.DoesNotContain(result, p => p.Id == 1); // Prod date version should not be deleted
}
#endregion
#region Case Sensitivity Tests
[Theory]
[InlineData("1.0.0-alpha")]
[InlineData("1.0.0-ALPHA")]
[InlineData("1.0.0-Alpha")]
[InlineData("1.0.0-AlPhA")]
public void FilterPackagesToDelete_WithDifferentCasePrerelease_ShouldHandleCorrectly(string version)
{
// Arrange
var packages = new List<GiteaPackage>
{
new() { Id = 1, Name = "test", Version = version, Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - All case variations should be recognized as prerelease
Assert.NotNull(result);
Assert.Empty(result); // Single prerelease should be kept
}
[Theory]
[InlineData("1.0.0-dev")]
[InlineData("1.0.0-DEV")]
[InlineData("1.0.0-Dev")]
[InlineData("1.0.0-DeV")]
public void FilterPackagesToDelete_WithDifferentCaseDev_ShouldHandleCorrectly(string version)
{
// Arrange
var packages = new List<GiteaPackage>
{
new() { Id = 1, Name = "test", Version = version, Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - All case variations should be recognized as dev version
Assert.NotNull(result);
Assert.Empty(result); // Single dev version should be kept
}
#endregion
#region Suffix/Identifier Tests
[Theory]
[InlineData("1.0.0-alpha1")]
[InlineData("1.0.0-alpha.1")]
[InlineData("1.0.0-beta2")]
[InlineData("1.0.0-rc.1")]
[InlineData("2025.2.14.1-dev.1")]
[InlineData("2025.2.14.1-dev123")]
public void FilterPackagesToDelete_WithCompoundSuffixes_ShouldIdentifyCorrectly(string version)
{
// Arrange
var packages = new List<GiteaPackage>
{
new() { Id = 1, Name = "test", Version = version, Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Compound suffixes should be recognized and not cause errors
Assert.NotNull(result);
Assert.Empty(result); // Single prerelease/dev should be kept
}
#endregion
#region Empty and Null Tests
[Fact]
public void FilterPackagesToDelete_WithEmptyList_ShouldReturnEmpty()
{
// Arrange
var packages = new List<GiteaPackage>();
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Empty input should return empty result
Assert.NotNull(result);
Assert.Empty(result);
}
[Fact]
public void FilterPackagesToDelete_WithNullableInputs_ShouldHandleGracefully()
{
// Arrange
var packages = new List<GiteaPackage>
{
new() { Id = 1, Name = "test", Version = "1.0.0", Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Should handle without throwing and not delete prod
Assert.NotNull(result);
Assert.Empty(result); // Prod should not be deleted
}
#endregion
}