Files
actions/sh.actions.package-cleanup.Tests/Service/PackageServiceDateVersionTests.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

617 lines
20 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 PackageServiceDateVersionTests
{
private Mock<IConfiguration> _configurationMock;
private Mock<IGiteaPackageService> _giteaPackageServiceMock;
private IPackageService _packageService;
private void SetupMocks()
{
_configurationMock = new Mock<IConfiguration>();
_giteaPackageServiceMock = new Mock<IGiteaPackageService>();
_packageService = new PackageService(_configurationMock.Object, _giteaPackageServiceMock.Object);
}
// ...existing code...
#region Version Detection Tests
[Theory]
[InlineData("2024.12.25.1")]
[InlineData("2025.2.14.1")]
[InlineData("2026.1.1.100")]
[InlineData("2023.12.31.999")]
public void FilterPackagesToDelete_WithDateVersions_ShouldIdentifyCorrectly(string version)
{
// Arrange
SetupMocks();
var packages = new List<GiteaPackage>
{
new() { Id = 1, Name = "test", Version = version, Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Single prod date version should not be deleted
Assert.NotNull(result);
Assert.Empty(result);
}
[Theory]
[InlineData("2024.12.25.1-dev")]
[InlineData("2025.2.14.1-alpha")]
[InlineData("2026.1.1.100-beta")]
[InlineData("2023.12.31.999-rc")]
public void FilterPackagesToDelete_WithDateVersionsAndSuffixes_ShouldIdentifyCorrectly(string version)
{
// Arrange
SetupMocks();
var packages = new List<GiteaPackage>
{
new() { Id = 1, Name = "test", Version = version, Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Single prerelease/dev date version should be kept
Assert.NotNull(result);
Assert.Empty(result);
}
#endregion
#region Prod Release Tests - Date Versioning
[Fact]
public void FilterPackagesToDeleteByDateVersion_WithOnlyProdReleases_ShouldReturnEmpty()
{
// Arrange - CLEAN_PROD_VERSIONS not set, defaults to false
SetupMocks();
var packages = new List<GiteaPackage>
{
new()
{
Id = 1, Name = "test", Version = "2025.12.20.1", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-30)
},
new()
{
Id = 2, Name = "test", Version = "2025.12.25.1", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-20)
},
new()
{
Id = 3, Name = "test", Version = "2026.1.5.1", Type = "docker", CreatedAt = DateTime.UtcNow.AddDays(-10)
}
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Prod releases should be protected by default (CLEAN_PROD_VERSIONS=false)
Assert.Empty(result);
}
[Fact]
public void FilterPackagesToDeleteByDateVersion_WithProdReleasesAndCleaningEnabled_ShouldDeleteOldest()
{
// Arrange
SetupMocks();
_configurationMock.Setup(c => c["CLEAN_PROD_VERSIONS"]).Returns("true");
_configurationMock.Setup(c => c["KEEP_PROD_VERSIONS"]).Returns("2");
var packages = new List<GiteaPackage>
{
new()
{
Id = 1, Name = "test", Version = "2025.1.1.1", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-365)
},
new()
{
Id = 2, Name = "test", Version = "2025.6.15.1", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-200)
},
new()
{
Id = 3, Name = "test", Version = "2026.1.1.1", Type = "docker", CreatedAt = DateTime.UtcNow.AddDays(-45)
},
new() { Id = 4, Name = "test", Version = "2026.2.14.1", Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Should delete oldest 2 (2025.1.1 and 2025.6.15), keep newest 2
Assert.Equal(2, result.Count);
Assert.Contains(result, p => p.Id == 1);
Assert.Contains(result, p => p.Id == 2);
Assert.DoesNotContain(result, p => p.Id == 3 || p.Id == 4);
}
[Fact]
public void FilterPackagesToDeleteByDateVersion_WithMultipleProdVersions_ShouldKeepNewest()
{
// Arrange
SetupMocks();
var packages = new List<GiteaPackage>
{
new()
{
Id = 1, Name = "test", Version = "2025.1.1.1", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-365)
},
new()
{
Id = 2, Name = "test", Version = "2025.6.15.1", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-200)
},
new()
{
Id = 3, Name = "test", Version = "2026.1.1.1", Type = "docker", CreatedAt = DateTime.UtcNow.AddDays(-45)
},
new() { Id = 4, Name = "test", Version = "2026.2.14.1", Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Default is CLEAN_PROD_VERSIONS=false, so nothing should be deleted
Assert.Empty(result);
}
#endregion
#region Prerelease Tests - Date Versioning
[Fact]
public void FilterPackagesToDeleteByDateVersion_WithPrereleaseVersions_ShouldKeepLatest()
{
// Arrange - Default KEEP_PRERELEASE_VERSIONS=3
SetupMocks();
var packages = new List<GiteaPackage>
{
new()
{
Id = 1, Name = "test", Version = "2026.2.10.1-alpha", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-5)
},
new()
{
Id = 2, Name = "test", Version = "2026.2.11.1-beta", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-4)
},
new()
{
Id = 3, Name = "test", Version = "2026.2.12.1-rc", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-3)
},
new()
{
Id = 4, Name = "test", Version = "2026.2.13.1-preview", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-2)
}
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Should delete oldest 1 (alpha), keep newest 3
Assert.Single(result);
Assert.Contains(result, p => p.Id == 1); // alpha is oldest
Assert.DoesNotContain(result, p => p.Id == 2 || p.Id == 3 || p.Id == 4);
}
[Fact]
public void FilterPackagesToDeleteByDateVersion_WithManyPrereleases_ShouldEnforceLimit()
{
// Arrange - Custom KEEP_PRERELEASE_VERSIONS=2
SetupMocks();
_configurationMock.Setup(c => c["KEEP_PRERELEASE_VERSIONS"]).Returns("2");
var packages = new List<GiteaPackage>();
for (int i = 0; i < 10; i++)
{
var date = DateTime.UtcNow.AddDays(-i);
packages.Add(new GiteaPackage
{
Id = i,
Name = "test",
Version = $"{date.Year}.{date.Month}.{date.Day}.{i}-beta",
Type = "docker",
CreatedAt = date
});
}
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Should delete 8 oldest, keep only 2 newest (Id=0,1)
Assert.Equal(8, result.Count);
Assert.DoesNotContain(result, p => p.Id < 2);
Assert.Contains(result, p => p.Id >= 2);
}
[Fact]
public void FilterPackagesToDeleteByDateVersion_WithMixedPrereleases_ShouldOrderByDate()
{
// Arrange
SetupMocks();
var packages = new List<GiteaPackage>
{
new()
{
Id = 1, Name = "test", Version = "2025.12.1.1-beta", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-60)
},
new()
{
Id = 2, Name = "test", Version = "2026.1.15.1-beta", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-30)
},
new()
{
Id = 3, Name = "test", Version = "2026.2.1.1-alpha", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-14)
}
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Default keep 3, so all should be kept
Assert.Empty(result);
}
#endregion
#region Dev Release Tests - Date Versioning
[Fact]
public void FilterPackagesToDeleteByDateVersion_WithDevVersions_ShouldKeepLatest()
{
// Arrange - Default KEEP_DEV_VERSIONS=5
SetupMocks();
var packages = new List<GiteaPackage>
{
new()
{
Id = 1, Name = "test", Version = "2026.2.10.1-dev", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-5)
},
new()
{
Id = 2, Name = "test", Version = "2026.2.11.2-dev", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-4)
},
new()
{
Id = 3, Name = "test", Version = "2026.2.12.3-dev", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-3)
}
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Default keep 5, so all 3 should be kept
Assert.Empty(result);
}
[Fact]
public void FilterPackagesToDeleteByDateVersion_WithManyDailyDevReleases_ShouldEnforceLimit()
{
// Arrange - Custom KEEP_DEV_VERSIONS=3
SetupMocks();
_configurationMock.Setup(c => c["KEEP_DEV_VERSIONS"]).Returns("3");
var packages = new List<GiteaPackage>();
for (int i = 0; i < 30; i++)
{
var date = DateTime.UtcNow.AddDays(-i);
packages.Add(new GiteaPackage
{
Id = i,
Name = "test",
Version = $"{date.Year}.{date.Month}.{date.Day}.{i}-dev",
Type = "docker",
CreatedAt = date
});
}
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Should delete 27 oldest, keep only 3 newest (Id=0,1,2)
Assert.Equal(27, result.Count);
Assert.DoesNotContain(result, p => p.Id < 3);
Assert.Contains(result, p => p.Id >= 3);
}
[Fact]
public void FilterPackagesToDeleteByDateVersion_WithManyDailyDevReleasesDefaultLimit_ShouldIdentifyAll()
{
// Arrange
SetupMocks();
var packages = new List<GiteaPackage>();
for (int i = 0; i < 30; i++)
{
var date = DateTime.UtcNow.AddDays(-i);
packages.Add(new GiteaPackage
{
Id = i,
Name = "test",
Version = $"{date.Year}.{date.Month}.{date.Day}.{i}-dev",
Type = "docker",
CreatedAt = date
});
}
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Default keep 5, so 25 should be deleted
Assert.Equal(25, result.Count);
Assert.DoesNotContain(result, p => p.Id < 5); // Keep newest 5 (Id 0-4)
Assert.Contains(result, p => p.Id >= 5);
}
#endregion
#region Mixed Release Types - Date Versioning
[Fact]
public void FilterPackagesToDeleteByDateVersion_WithMixedReleaseTypes_ShouldSeparateAndCleanCorrectly()
{
// Arrange
SetupMocks();
_configurationMock.Setup(c => c["KEEP_PRERELEASE_VERSIONS"]).Returns("2");
_configurationMock.Setup(c => c["KEEP_DEV_VERSIONS"]).Returns("2");
var packages = new List<GiteaPackage>
{
// Prod releases (should not be deleted - CLEAN_PROD_VERSIONS=false)
new()
{
Id = 1, Name = "test", Version = "2025.12.1.1", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-80)
},
new()
{
Id = 2, Name = "test", Version = "2026.1.1.1", Type = "docker", CreatedAt = DateTime.UtcNow.AddDays(-45)
},
// Prerelease (keep 2 newest)
new()
{
Id = 3, Name = "test", Version = "2026.1.25.1-alpha", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-20)
},
new()
{
Id = 4, Name = "test", Version = "2026.2.1.1-beta", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-14)
},
new()
{
Id = 5, Name = "test", Version = "2026.2.5.1-rc", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-10)
},
// Dev (keep 2 newest)
new()
{
Id = 6, Name = "test", Version = "2026.2.10.1-dev", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-5)
},
new() { Id = 7, Name = "test", Version = "2026.2.14.1-dev", Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert
Assert.Equal(1, result.Count); // Should delete 1 prerelease (alpha), 0 dev (keep both)
Assert.DoesNotContain(result, p => p.Id <= 2); // Prod not deleted
Assert.DoesNotContain(result, p => p.Id >= 6); // Keep 2 latest dev
}
[Fact]
public void FilterPackagesToDeleteByDateVersion_WithLargeSet_ShouldHandleCorrectly()
{
// Arrange
SetupMocks();
_configurationMock.Setup(c => c["CLEAN_PROD_VERSIONS"]).Returns("false");
_configurationMock.Setup(c => c["KEEP_PRERELEASE_VERSIONS"]).Returns("3");
_configurationMock.Setup(c => c["KEEP_DEV_VERSIONS"]).Returns("5");
var packages = new List<GiteaPackage>();
// Add prod releases
for (int i = 0; i < 5; i++)
{
var date = DateTime.UtcNow.AddMonths(-(5 - i));
packages.Add(new GiteaPackage
{
Id = i,
Name = "test",
Version = $"{date.Year}.{date.Month}.1.1",
Type = "docker",
CreatedAt = date
});
}
// Add prerelease
for (int i = 5; i < 15; i++)
{
var date = DateTime.UtcNow.AddDays(-(15 - i) * 7);
packages.Add(new GiteaPackage
{
Id = i,
Name = "test",
Version = $"{date.Year}.{date.Month}.{date.Day}.1-beta",
Type = "docker",
CreatedAt = date
});
}
// Add dev
for (int i = 15; i < 30; i++)
{
var date = DateTime.UtcNow.AddDays(-(30 - i));
packages.Add(new GiteaPackage
{
Id = i,
Name = "test",
Version = $"{date.Year}.{date.Month}.{date.Day}.{(30 - i)}-dev",
Type = "docker",
CreatedAt = date
});
}
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert
Assert.NotNull(result);
// Prod releases should never be deleted
Assert.DoesNotContain(result, p => p.Id < 5);
// Should delete 7 oldest prerelease (keep 3 newest)
var prereleaseDeleted = result.Where(p => p.Id >= 5 && p.Id < 15).ToList();
Assert.Equal(7, prereleaseDeleted.Count);
// Should delete 10 oldest dev (keep 5 newest)
var devDeleted = result.Where(p => p.Id >= 15).ToList();
Assert.Equal(10, devDeleted.Count);
}
#endregion
#region Edge Cases - Date Versioning
[Theory]
[InlineData("1000.1.1.1")] // Minimum valid year
[InlineData("2999.12.31.999")] // Maximum valid year
[InlineData("2025.2.14.0")] // Build number 0
public void FilterPackagesToDeleteByDateVersion_WithBoundaryVersions_ShouldHandleCorrectly(string version)
{
// Arrange
SetupMocks();
var packages = new List<GiteaPackage>
{
new() { Id = 1, Name = "test", Version = version, Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert
Assert.NotNull(result);
}
[Theory]
[InlineData("999.12.31.1")] // Year too small
[InlineData("3000.1.1.1")] // Year too large
[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
public void FilterPackagesToDelete_WithInvalidDateVersions_ShouldNotProcess(string version)
{
// Arrange
SetupMocks();
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.1", Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert - Invalid date version should be skipped, only semantic version processed
Assert.NotNull(result);
}
[Fact]
public void FilterPackagesToDeleteByDateVersion_WithConsecutiveDates_ShouldOrderCorrectly()
{
// Arrange
SetupMocks();
var packages = new List<GiteaPackage>
{
new()
{
Id = 1, Name = "test", Version = "2025.2.10.1", Type = "docker", CreatedAt = DateTime.UtcNow.AddDays(-5)
},
new()
{
Id = 2, Name = "test", Version = "2025.2.11.1", Type = "docker", CreatedAt = DateTime.UtcNow.AddDays(-4)
},
new()
{
Id = 3, Name = "test", Version = "2025.2.12.1", Type = "docker", CreatedAt = DateTime.UtcNow.AddDays(-3)
},
new()
{
Id = 4, Name = "test", Version = "2025.2.13.1", Type = "docker", CreatedAt = DateTime.UtcNow.AddDays(-2)
},
new() { Id = 5, Name = "test", Version = "2025.2.14.1", Type = "docker", CreatedAt = DateTime.UtcNow }
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert
Assert.NotNull(result);
}
#endregion
#region Mixed Versioning Variants
[Fact]
public void FilterPackagesToDelete_WithMixedVersioningVariants_ShouldProcessBothTypes()
{
// Arrange
SetupMocks();
var packages = new List<GiteaPackage>
{
// Semantic versioning
new()
{
Id = 1, Name = "test", Version = "1.0.0", Type = "docker", CreatedAt = DateTime.UtcNow.AddDays(-30)
},
new()
{
Id = 2, Name = "test", Version = "1.1.0-dev", Type = "docker", CreatedAt = DateTime.UtcNow.AddDays(-10)
},
// Date versioning
new()
{
Id = 3, Name = "test", Version = "2025.1.1.1", Type = "docker", CreatedAt = DateTime.UtcNow.AddDays(-45)
},
new()
{
Id = 4, Name = "test", Version = "2025.2.10.1-dev", Type = "docker",
CreatedAt = DateTime.UtcNow.AddDays(-5)
}
};
// Act
var result = _packageService.FilterPackagesToDelete(packages);
// Assert
Assert.NotNull(result);
// Prod releases should not be in delete list
Assert.DoesNotContain(result, p => p.Id == 1 || p.Id == 3);
}
#endregion
}