Release QVPN 1.0.5 with Xray and resilient tunnel recovery
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.
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
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.");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user