Skip to content

Commit a76f39f

Browse files
Implement additional tests for ARI renewal checks
1 parent fba8248 commit a76f39f

File tree

3 files changed

+124
-3
lines changed

3 files changed

+124
-3
lines changed

src/Certify.Core/Management/CertifyManager/CertifyManager.Account.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public partial class CertifyManager
2828
/// </summary>
2929
/// <param name="managedItem"></param>
3030
/// <returns></returns>
31-
public async Task<IACMEClientProvider> GetACMEProvider(ManagedCertificate managedItem, AccountDetails caAccount)
31+
public virtual async Task<IACMEClientProvider> GetACMEProvider(ManagedCertificate managedItem, AccountDetails caAccount)
3232
{
3333
// determine account to use for the given managed cert
3434

@@ -106,7 +106,7 @@ private async Task<IACMEClientProvider> GetACMEProvider(string storageKey, strin
106106
/// <param name="allowCache">if true, allow use of cached account list</param>
107107
/// <param name="allowFailover">if true, select a fallback CA account if item has recently failed renewal, if false use same account as last renewal/attempt</param>
108108
/// <returns>Account Details or null if there is no matching account</returns>
109-
public async Task<AccountDetails> GetAccountDetails(ManagedCertificate item, bool allowCache = true, bool allowFailover = false, bool isResumedOrder = false)
109+
public virtual async Task<AccountDetails> GetAccountDetails(ManagedCertificate item, bool allowCache = true, bool allowFailover = false, bool isResumedOrder = false)
110110
{
111111
if (OverrideAccountDetails != null)
112112
{

src/Certify.Core/Management/CertifyManager/CertifyManager.Maintenance.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Certify.Models;
99
using Certify.Models.Config;
1010
using Certify.Models.Hub;
11+
using Certify.Models.Providers;
1112
using Certify.Models.Shared;
1213

1314
namespace Certify.Management
@@ -439,7 +440,7 @@ public virtual async Task<string> ComputeARICertificateId(ManagedCertificate ite
439440
#if NET9_0_OR_GREATER
440441
var x509Cert2 = System.Security.Cryptography.X509Certificates.X509CertificateLoader.LoadPkcs12FromFile(item.CertificatePath, await GetPfxPassword(item));
441442
#else
442-
var x509Cert2 = new System.Security.Cryptography.X509Certificates.X509Certificate2(File.ReadAllBytes(item.CertificatePath), await GetPfxPassword(item));
443+
var x509Cert2 = new System.Security.Cryptography.X509Certificates.X509Certificate2(File.ReadAllBytes(item.CertificatePath), await GetPfxPassword(item));
443444
#endif
444445
var ariCertId = item.ARICertificateId ?? Certify.Shared.Core.Utils.PKI.CertUtils.GetARICertIdBase64(x509Cert2);
445446
return ariCertId;
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading.Tasks;
4+
using Certify.Management;
5+
using Certify.Models;
6+
using Certify.Models.Providers;
7+
using Certify.Models.Shared;
8+
using Microsoft.Extensions.Logging;
9+
using Microsoft.VisualStudio.TestTools.UnitTesting;
10+
using Moq;
11+
12+
namespace Certify.Core.Tests.Unit
13+
{
14+
[TestClass]
15+
public class CertifyManagerMaintenanceTests
16+
{
17+
[DataTestMethod]
18+
[DataRow(90, null, 1, 10, DisplayName = "No scheduled renewal, ARI window in future")]
19+
[DataRow(90, 60, 1, 10, DisplayName = "Scheduled renewal in future, ARI window in future")]
20+
[DataRow(10, null, -5, 5, DisplayName = "No scheduled renewal, ARI window started")]
21+
[DataRow(10, 2, -5, 5, DisplayName = "Scheduled renewal soon, ARI window started")]
22+
[DataRow(1, null, -10, -1, DisplayName = "No scheduled renewal, ARI window in past")]
23+
[DataRow(1, 0, -10, -1, DisplayName = "Scheduled renewal now, ARI window in past")]
24+
[DataRow(10, 2, -5, 5, true, DisplayName = "Revoked, Scheduled renewal soon, ARI window started")]
25+
public async Task PerformRenewalInfoCheck_VariousInputs(
26+
int expiryDays,
27+
int? scheduledRenewalDays,
28+
int renewalWindowStartOffset,
29+
int renewalWindowEndOffset, bool revoked = false, bool alreadyScheduled = false)
30+
{
31+
// Arrange
32+
var renewalWindow = new RenewalWindow
33+
{
34+
Start = DateTimeOffset.UtcNow.AddDays(renewalWindowStartOffset),
35+
End = DateTimeOffset.UtcNow.AddDays(renewalWindowEndOffset)
36+
};
37+
38+
var managerMock = GetMockCertifyManager(renewalWindow);
39+
40+
var completedRenewalInfoChecks = new List<string>();
41+
var itemsWhichRequireRenewal = new List<string>();
42+
var itemsViaARI = new Dictionary<string, DateTimeOffset>();
43+
var directoryInfoCache = new Dictionary<string, AcmeDirectoryInfo>();
44+
var managedCert = new ManagedCertificate
45+
{
46+
Id = "test-cert",
47+
Name = "Test Cert",
48+
CertificateThumbprintHash = "abc123",
49+
DateExpiry = DateTimeOffset.UtcNow.AddDays(expiryDays),
50+
CertificatePath = "dummy.pfx"
51+
};
52+
53+
if (revoked)
54+
{
55+
managedCert.CertificateRevoked = true;
56+
}
57+
58+
if (scheduledRenewalDays.HasValue)
59+
{
60+
managedCert.DateNextScheduledRenewalAttempt = DateTimeOffset.UtcNow.AddDays(scheduledRenewalDays.Value);
61+
}
62+
63+
var log = new Loggy(LoggerFactory.Create(builder => builder.AddDebug()).CreateLogger<CertifyManagerMaintenanceTests>());
64+
65+
// Act
66+
var newAriRenewalScheduled = await managerMock.Object.PerformRenewalInfoCheck(
67+
log,
68+
completedRenewalInfoChecks,
69+
itemsWhichRequireRenewal,
70+
itemsViaARI,
71+
directoryInfoCache,
72+
managedCert
73+
);
74+
75+
// Assert
76+
Assert.IsTrue(completedRenewalInfoChecks.Contains("test-cert"), "Certificate ID should be added to completedRenewalInfoChecks");
77+
78+
var nextRenewal = ManagedCertificate.CalculateNextRenewalAttempt(managedCert, CoreAppSettings.Current.RenewalIntervalDays, CoreAppSettings.Current.RenewalIntervalMode ?? RenewalIntervalModes.DaysAfterLastRenewal);
79+
80+
if (newAriRenewalScheduled)
81+
{
82+
Assert.IsTrue(itemsViaARI.ContainsKey("test-cert"), "Certificate ID should be added to itemsViaARI");
83+
84+
if (nextRenewal.DateNextRenewalAttempt < DateTimeOffset.UtcNow)
85+
{
86+
Assert.IsTrue(itemsWhichRequireRenewal.Contains("test-cert"), "Certificate ID should be added to itemsWhichRequireRenewal");
87+
}
88+
}
89+
else
90+
{
91+
Assert.IsFalse(itemsViaARI.ContainsKey("test-cert"), "Certificate ID should not be added to itemsViaARI if no renewal is scheduled");
92+
}
93+
}
94+
95+
private Mock<CertifyManager> GetMockCertifyManager(RenewalWindow mockRenewalWindow)
96+
{
97+
var mockAcmeProvider = new Mock<IACMEClientProvider>();
98+
99+
mockAcmeProvider.Setup(p => p.GetRenewalInfo(It.IsAny<string>()))
100+
.ReturnsAsync(new RenewalInfo
101+
{
102+
SuggestedWindow = mockRenewalWindow,
103+
ExplanationURL = new Uri("https://example.com/renewalinfo")
104+
});
105+
mockAcmeProvider.Setup(p => p.GetAcmeDirectory()).ReturnsAsync(new AcmeDirectoryInfo { RenewalInfo = new Uri("https://example-acme.com/renewalinfo") });
106+
mockAcmeProvider.Setup(p => p.GetAcmeBaseURI()).Returns("https://example-acme.com/");
107+
108+
var managerMock = new Mock<CertifyManager>();
109+
110+
managerMock.Setup(m => m.GetAccountDetails(It.IsAny<ManagedCertificate>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<bool>()))
111+
.ReturnsAsync(new AccountDetails());
112+
113+
managerMock.Setup(m => m.GetACMEProvider(It.IsAny<ManagedCertificate>(), It.IsAny<AccountDetails>())).ReturnsAsync(mockAcmeProvider.Object);
114+
115+
managerMock.Setup(m => m.ComputeARICertificateId(It.IsAny<ManagedCertificate>())).ReturnsAsync("ARICertId12345");
116+
117+
return managerMock;
118+
}
119+
}
120+
}

0 commit comments

Comments
 (0)