97 lines
5.6 KiB
C#
97 lines
5.6 KiB
C#
using GatewayKeepalive.Core;
|
|
|
|
namespace GatewayKeepalive.Tests;
|
|
|
|
internal static class NetworkComparisonTests
|
|
{
|
|
public static Task EachOwnedFieldParticipatesAsync()
|
|
{
|
|
var baseline = Fixtures.Baseline();
|
|
var route = baseline.Routes[0];
|
|
|
|
Check.True(NetworkComparison.SameConfiguration(baseline, baseline with { CapturedAt = baseline.CapturedAt.AddMinutes(1) }), "Capture time is observational metadata, not network configuration");
|
|
Check.True(NetworkComparison.SameConfiguration(baseline, baseline with { EffectiveDns = ["192.168.6.254"] }), "Effective DNS is derived state; configured DNS owns the snapshot");
|
|
Check.True(NetworkComparison.SameConfiguration(baseline, baseline with { Routes = [route] }), "Identical route rows must compare equal");
|
|
|
|
foreach (var changed in new[]
|
|
{
|
|
baseline with { Routes = [route with { Metric = route.Metric + 1 }] },
|
|
baseline with { Routes = [route with { Protocol = route.Protocol + 1 }] },
|
|
baseline with { Routes = [route with { Publish = !route.Publish }] },
|
|
baseline with { Routes = [route with { Immortal = !route.Immortal }] },
|
|
baseline with { Routes = [route with { InterfaceLuid = route.InterfaceLuid + 1 }] },
|
|
baseline with { Routes = [route with { InterfaceIndex = route.InterfaceIndex + 1 }] },
|
|
baseline with { Routes = [route with { Gateway = "192.168.6.2" }] },
|
|
baseline with { Dns = new DnsConfiguration(Automatic: false, Servers: [], ProfileServers: []) },
|
|
baseline with { Dns = new DnsConfiguration(Automatic: true, Servers: ["192.168.6.1"], ProfileServers: []) },
|
|
baseline with { Dns = new DnsConfiguration(Automatic: true, Servers: [], ProfileServers: ["192.168.6.1"]) },
|
|
baseline with { Adapter = baseline.Adapter with { Id = Guid.NewGuid() } },
|
|
baseline with { Adapter = baseline.Adapter with { Index = baseline.Adapter.Index + 1 } },
|
|
baseline with { Adapter = baseline.Adapter with { NetworkFingerprint = "network-b" } },
|
|
baseline with { Adapter = baseline.Adapter with { NetworkFingerprint = " " } },
|
|
})
|
|
{
|
|
Check.False(NetworkComparison.SameConfiguration(baseline, changed), "Every identity, route ownership field, and DNS component must participate in equality");
|
|
}
|
|
|
|
Check.False(
|
|
NetworkComparison.SameRoutes([route], [route, new RouteEntry("192.168.6.2", 1, 0x1000, 7)]),
|
|
"An added route must change the owned route set");
|
|
Check.True(
|
|
NetworkComparison.SameRoutes(
|
|
[route, new RouteEntry("192.168.6.2", 1, 0x1000, 7)],
|
|
[new RouteEntry("192.168.6.2", 1, 0x1000, 7), route]),
|
|
"Route order should not matter");
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public static Task RecoveryRejectsForeignRowsAsync()
|
|
{
|
|
var before = Fixtures.Baseline();
|
|
var direct = before.Routes[0];
|
|
var proxy = new RouteEntry("192.168.6.2", 1, direct.InterfaceLuid, direct.InterfaceIndex);
|
|
var intended = before with
|
|
{
|
|
Routes = [direct with { Metric = 101 }, proxy],
|
|
Dns = new DnsConfiguration(Automatic: false, Servers: ["192.168.6.2"], ProfileServers: []),
|
|
};
|
|
var journal = new SwitchJournal(before, intended, "ApplyingDns", DateTimeOffset.UtcNow);
|
|
|
|
Check.True(NetworkComparison.BelongsToTransaction(journal, before), "The untouched pre-switch state belongs to the transaction");
|
|
Check.True(NetworkComparison.BelongsToTransaction(journal, intended), "The fully intended state belongs to the transaction");
|
|
Check.True(
|
|
NetworkComparison.BelongsToTransaction(journal, before with { Routes = intended.Routes }),
|
|
"Routes may be applied while DNS still has its prior value");
|
|
Check.True(
|
|
NetworkComparison.BelongsToTransaction(journal, before with { Dns = intended.Dns }),
|
|
"DNS may be applied while routes still have their prior value");
|
|
|
|
Check.False(
|
|
NetworkComparison.BelongsToTransaction(journal, before with { Routes = [direct with { Metric = 50 }, proxy] }),
|
|
"A same-gateway row with a foreign metric must not be treated as owned");
|
|
Check.False(
|
|
NetworkComparison.BelongsToTransaction(journal, before with { Routes = [direct, proxy with { Metric = 2 }] }),
|
|
"A same-gateway row with a foreign proxy metric must not be treated as owned");
|
|
Check.False(
|
|
NetworkComparison.BelongsToTransaction(journal, before with { Routes = [proxy] }),
|
|
"A missing row required by both before and intended must stop recovery");
|
|
Check.False(
|
|
NetworkComparison.BelongsToTransaction(journal, before with { Routes = [.. intended.Routes, new RouteEntry("10.1.2.3", 1, 0x2000, 8)] }),
|
|
"A foreign route added by another tool must stop recovery");
|
|
Check.False(
|
|
NetworkComparison.BelongsToTransaction(journal, before with { Dns = new DnsConfiguration(false, ["10.1.2.53"], []) }),
|
|
"Foreign DNS must stop recovery");
|
|
Check.False(
|
|
NetworkComparison.BelongsToTransaction(journal, before with { Adapter = before.Adapter with { NetworkFingerprint = "network-b" } }),
|
|
"A different network must stop recovery");
|
|
|
|
var reordered = before with
|
|
{
|
|
Routes = [proxy, direct with { Metric = 101 }],
|
|
Dns = intended.Dns,
|
|
};
|
|
Check.True(NetworkComparison.BelongsToTransaction(journal, reordered), "Owned route rows should be compared independently of order");
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|