Files
Workspace/Tools/AgentSupport/RuntimeTests/SaveSnapshotTests.cs
T
cneicy 08246ddb01
Validate ShrinkSDK Workspace / catalog (push) Successful in 5s
Validate ShrinkSDK Workspace / unity (push) Successful in 3m20s
feat: integrate performance upgrade and agent inspection tooling
2026-09-29 10:16:02 +08:00

80 lines
4.2 KiB
C#

using NUnit.Framework;
using ShrinkDataSaver;
using ShrinkSDK.Inspection;
using ShrinkNetwork;
using Cysharp.Threading.Tasks;
[NonParallelizable]
public class SaveSnapshotTests
{
private string _directory = null!;
[SetUp] public void Setup()
{
_directory = Path.Combine(Path.GetTempPath(), "ShrinkSaveTests", Guid.NewGuid().ToString("N"));
ShrinkSave.Initialize(new LocalStorageProvider(_directory), "saves", ".json", 1);
}
[TearDown] public void Cleanup()
{
ShrinkSave.UnregisterModule("test-snapshot");
if (Directory.Exists(_directory)) Directory.Delete(_directory, true);
}
[TestCase(false)] [TestCase(true)]
public async Task CaptureRunsOnCallerAndWorkerEncodingPreservesFormat(bool encrypt)
{
var owner = Environment.CurrentManagedThreadId;
var captured = 0;
var value = new SaveDto { Value = "original" };
ShrinkSave.RegisterModule("test-snapshot", () => { captured = Environment.CurrentManagedThreadId; return value; }, _ => { });
var options = new SaveOptions { EncodeInBackground = true, CollectTimings = true, Encrypt = encrypt, EncryptionKey = "test-only" };
var saving = ShrinkSave.SaveSlotAsync(0, options).AsTask();
value.Value = "changed-after-capture";
await saving;
var file = Directory.GetFiles(Path.Combine(_directory, "saves"), "*.json").Single();
var packet = DataSerializer.Deserialize<SavePacket>(await File.ReadAllBytesAsync(file));
var text = encrypt ? System.Text.Encoding.UTF8.GetString(SaveEncryptor.Decrypt(Convert.FromBase64String(packet.EncryptedModules), "test-only")) : packet.Modules["test-snapshot"].ToString();
Assert.That(captured, Is.EqualTo(owner));
Assert.That(text, Does.Contain("original").And.Not.Contain("changed-after-capture"));
Assert.That(options.LastTimings.EncodedBytes, Is.GreaterThan(0));
Assert.That(options.LastTimings.CaptureMilliseconds, Is.GreaterThanOrEqualTo(0));
}
[Test]
public async Task CancellationLeavesExistingFileAndBackupsRecoverCorruption()
{
var storage = new LocalStorageProvider(_directory);
await storage.WriteAsync("slot.json", new byte[] { 1 });
await storage.WriteAsync("slot.json", new byte[] { 2 });
using var cancellation = new CancellationTokenSource(); cancellation.Cancel();
Assert.CatchAsync<OperationCanceledException>(async () => await storage.WriteAsync("slot.json", new byte[] { 3 }, cancellation.Token));
Assert.That(await storage.ReadAsync("slot.json"), Is.EqualTo(new byte[] { 2 }));
Assert.That(await storage.ReadAsync("slot.json.bak1"), Is.EqualTo(new byte[] { 1 }));
Assert.That(File.Exists(Path.Combine(_directory, "slot.json.tmp")), Is.False);
}
[Test]
public async Task CorruptPrimarySaveFallsBackToPreviousValidPacket()
{
await ShrinkSave.SaveSlotAsync(0, new SaveOptions { SlotName = "previous" });
await ShrinkSave.SaveSlotAsync(0, new SaveOptions { SlotName = "latest" });
var primary = Directory.GetFiles(Path.Combine(_directory, "saves"), "*.json").Single();
await File.WriteAllTextAsync(primary, "corrupt");
Assert.That((await ShrinkSave.GetMetaAsync(0)).SlotName, Is.EqualTo("previous"));
}
[Test]
public void RuntimeSnapshotExportsBindingsWithoutSessionSecrets()
{
var service = new ShrinkNetworkService(); service.RegisterMessage<CodecMessage>(42, "test/message");
service.RegisterHandler<CodecMessage>(Receive);
var snapshot = new ShrinkInspectionSnapshot("build-a");
snapshot.AddNetwork("server", service);
var json = snapshot.ToJson();
Assert.That(snapshot.Relations.Any(r => r.From == "opcode:42" && r.To == "type:CodecMessage"));
Assert.That(snapshot.Relations.Any(r => r.To == "M:SaveSnapshotTests.Receive(ShrinkNetwork.ShrinkNetworkContext,CodecMessage)"));
Assert.That(json, Does.Not.Contain("Payload").And.Not.Contain("SessionToken"));
}
private static UniTask Receive(ShrinkNetworkContext ctx, CodecMessage message) => UniTask.CompletedTask;
public sealed class SaveDto { public string Value { get; set; } = ""; }
}