Files
Gateway-keepaliveForDotnet/tests/GatewayKeepalive.Tests/JsonStoreTests.cs
T
chuzhongzai 2d85527656 实现 .NET 10 托盘版网关保活
包含分层探测、可补偿的 IPv4 路由/DNS 切换、自动策略、托盘与分组设置界面、只读诊断工具、离线测试和发布脚本。
2026-10-23 23:35:20 +08:00

54 lines
3.0 KiB
C#

using GatewayKeepalive.Core;
namespace GatewayKeepalive.Tests;
internal static class JsonStoreTests
{
public static async Task AtomicReplacementAsync()
{
using var temp = new TempDirectory();
var nested = Path.Combine(temp.DirectoryPath, "nested");
var store = new JsonStore(nested);
var first = new SwitchJournal(
Fixtures.Baseline(),
Fixtures.Baseline() with { Dns = new DnsConfiguration(false, ["192.168.6.2"], []) },
"Prepared",
new DateTimeOffset(2026, 2, 3, 4, 5, 6, TimeSpan.Zero));
const string file = "switch-journal.json";
store.Write(file, first);
var read = store.Read<SwitchJournal>(file);
Check.True(read is not null, "A written journal should be readable");
Check.Equal(first.Stage, read!.Stage, "String data should round trip");
Check.Equal(first.StartedAt, read.StartedAt, "DateTimeOffset should round trip");
Check.True(NetworkComparison.SameConfiguration(first.Before, read.Before), "Nested before snapshot should round trip");
Check.True(NetworkComparison.SameConfiguration(first.Intended, read.Intended), "Nested intended snapshot should round trip");
Check.Equal(0, Directory.GetFiles(nested, "*.tmp").Length, "Successful write must clean its temporary file");
var second = first with { Stage = "Verified" };
store.Write(file, second);
Check.Equal("Verified", store.Read<SwitchJournal>(file)?.Stage, "The target should contain the replacement");
Check.Equal("Prepared", store.Read<SwitchJournal>(file + ".bak")?.Stage, "The previous complete file should be retained as a backup");
Check.Equal(0, Directory.GetFiles(nested, "*.tmp").Length, "Replacement must clean its temporary file");
var beforeFailure = File.ReadAllText(Path.Combine(nested, file));
var backupBeforeFailure = File.ReadAllText(Path.Combine(nested, file + ".bak"));
var failure = await Check.ThrowsAnyAsync(
() => Task.Run(() => store.Write(file, new UnserializablePayload())),
"A serialization failure should be observable");
Check.Contains("intentional serialization fault", failure.ToString(), "The expected serialization fault should surface");
Check.Equal(beforeFailure, File.ReadAllText(Path.Combine(nested, file)), "A failed write must leave the target byte-for-byte intact");
Check.Equal(backupBeforeFailure, File.ReadAllText(Path.Combine(nested, file + ".bak")), "A failed write must leave the backup intact");
Check.Equal(0, Directory.GetFiles(nested, "*.tmp").Length, "A failed write must delete its temporary file");
var empty = Path.Combine(nested, "empty.json");
File.WriteAllText(empty, string.Empty);
Check.Throws<System.Text.Json.JsonException>(() => store.Read<SwitchJournal>("empty.json"), "Malformed JSON must be rejected");
}
private sealed class UnserializablePayload
{
public string Value => throw new InvalidOperationException("intentional serialization fault");
}
}