Integrate Xray 26.9.9 with the sing-box system tunnel and verify Windows routes during health checks. Improve endpoint selection, network recovery, subscription refresh deadlines, diagnostics, packaging, and regression coverage.
62 lines
3.1 KiB
C#
62 lines
3.1 KiB
C#
using QVPN.Core;
|
|
|
|
internal static class SubscriptionRefreshPolicyTests
|
|
{
|
|
public static async Task RunAsync(Func<string, Action, Task> test)
|
|
{
|
|
var now = DateTimeOffset.Parse("2026-10-06T21:00:00Z");
|
|
await test("Service startup refreshes stale or undated subscription before health succeeds", () =>
|
|
{
|
|
var policy = new SubscriptionRefreshPolicy();
|
|
Check(policy.ShouldRefreshOnConnect(now.AddHours(-2), now));
|
|
Check(policy.ShouldRefreshOnConnect(null, now));
|
|
Check(policy.ShouldRefreshOnConnect(now.AddMinutes(-15), now));
|
|
Check(!policy.ShouldRefreshOnConnect(now.AddMinutes(-14), now));
|
|
});
|
|
await test("A new explicit connect checks current endpoint even with recently cached subscription", () =>
|
|
{
|
|
var policy = new SubscriptionRefreshPolicy();
|
|
Check(policy.ShouldRefreshOnConnect(now, now, explicitConnect: true));
|
|
policy.Attempted(now);
|
|
Check(!policy.ShouldRefreshOnConnect(now, now.AddSeconds(59), explicitConnect: true));
|
|
Check(policy.ShouldRefreshOnConnect(now, now.AddSeconds(60), explicitConnect: true));
|
|
});
|
|
await test("Endpoint outage refresh is allowed without a connected engine and limited to once per minute", () =>
|
|
{
|
|
var policy = new SubscriptionRefreshPolicy();
|
|
Check(policy.ShouldRefreshAfterEndpointFailure(now));
|
|
policy.Attempted(now);
|
|
for (int seconds = 0; seconds < 60; seconds++) Check(!policy.ShouldRefreshAfterEndpointFailure(now.AddSeconds(seconds)));
|
|
Check(policy.ShouldRefreshAfterEndpointFailure(now.AddSeconds(60)));
|
|
});
|
|
await test("Manual or routine subscription attempts also suppress immediate outage refresh loops", () =>
|
|
{
|
|
var policy = new SubscriptionRefreshPolicy();
|
|
policy.Attempted(now);
|
|
Check(!policy.ShouldRefreshAfterEndpointFailure(now.AddSeconds(1)));
|
|
Check(!policy.ShouldRefreshOnConnect(now.AddHours(-2), now.AddSeconds(1)));
|
|
policy.Attempted(now.AddSeconds(60));
|
|
Check(!policy.ShouldRefreshAfterEndpointFailure(now.AddSeconds(61)));
|
|
});
|
|
await test("A fresh successful subscription prevents automatic startup refresh after the retry cooldown", () =>
|
|
{
|
|
var policy = new SubscriptionRefreshPolicy();
|
|
policy.Attempted(now);
|
|
Check(!policy.ShouldRefreshOnConnect(now, now.AddMinutes(2)));
|
|
Check(policy.ShouldRefreshOnConnect(now, now.AddMinutes(15)));
|
|
});
|
|
await test("Clock rollback does not cause repeated automatic subscription refresh", () =>
|
|
{
|
|
var policy = new SubscriptionRefreshPolicy();
|
|
policy.Attempted(now);
|
|
Check(!policy.ShouldRefreshAfterEndpointFailure(now.AddMinutes(-5)));
|
|
Check(!policy.ShouldRefreshOnConnect(now.AddHours(-2), now.AddMinutes(-5), explicitConnect: true));
|
|
});
|
|
}
|
|
|
|
private static void Check(bool condition)
|
|
{
|
|
if (!condition) throw new InvalidOperationException("Subscription refresh policy regression.");
|
|
}
|
|
}
|