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; } }