From 3ccd986e658bf229dfa4f56f9855da19c3ba4fe2 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Wed, 3 Jun 2026 19:42:20 -0400 Subject: [PATCH] test(battle-node): drop scripted smoke test; retarget deck-plumbing test to PvP Co-Authored-By: Claude Opus 4.8 --- .../Integration/BattleNodeFlowTests.cs | 91 +++---------------- 1 file changed, 13 insertions(+), 78 deletions(-) diff --git a/SVSim.UnitTests/BattleNode/Integration/BattleNodeFlowTests.cs b/SVSim.UnitTests/BattleNode/Integration/BattleNodeFlowTests.cs index 452af9e..a2f7500 100644 --- a/SVSim.UnitTests/BattleNode/Integration/BattleNodeFlowTests.cs +++ b/SVSim.UnitTests/BattleNode/Integration/BattleNodeFlowTests.cs @@ -15,73 +15,6 @@ namespace SVSim.UnitTests.BattleNode.Integration; [TestFixture] public class BattleNodeFlowTests { - /// - /// End-to-end smoke for the v1.2 scripted lifecycle. Boots the EmulatedEntrypoint via - /// SVSimTestFactory, mints a battle through IMatchingBridge with a fixture MatchContext, - /// opens a raw Socket.IO v2 client against the in-process TestServer, and drives - /// InitNetwork → Loaded → Swap → TurnEnd × 2, asserting the right scripted frames come - /// back in order including the two-cycle three-frame opponent-turn loop (TurnStart + - /// TurnEnd + Judge per cycle). - /// - [Test] - [Timeout(30000)] - public async Task ClientWalksHandshakeToReady_ReceivesAllScriptedFrames() - { - await using var factory = new SVSimTestFactory(); - var bridge = factory.Services.GetRequiredService(); - - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15)); - var ct = cts.Token; - var pending = bridge.RegisterBattle( - new SVSim.BattleNode.Bridge.BattlePlayer(906243102, FixtureCtx()), - p2: null, - SVSim.BattleNode.Sessions.BattleType.Scripted); - - var key = MakeKey(); - var encryptedVid = NodeCrypto.EncryptForNode("906243102", key); - var wsUri = new Uri($"ws://localhost/socket.io/?BattleId={pending.BattleId}&viewerId={Uri.EscapeDataString(encryptedVid)}&EIO=3&transport=websocket"); - - var wsClient = factory.Server.CreateWebSocketClient(); - var ws = await wsClient.ConnectAsync(wsUri, ct); - await using var client = new RawSocketIoTestClient(ws); - await client.ConsumeHandshakeAsync(ct); - - await client.SendMsgAsync(MakeEnvelope(NetworkBattleUri.InitNetwork, pubSeq: 1), key, ct); - Assert.That((await client.ReceiveSynchronizeAsync(ct)).Uri, Is.EqualTo(NetworkBattleUri.InitNetwork)); - - await client.SendMsgAsync(MakeEnvelope(NetworkBattleUri.InitBattle, pubSeq: 2), key, ct); - Assert.That((await client.ReceiveSynchronizeAsync(ct)).Uri, Is.EqualTo(NetworkBattleUri.Matched)); - - await client.SendMsgAsync(MakeEnvelope(NetworkBattleUri.Loaded, pubSeq: 3), key, ct); - Assert.That((await client.ReceiveSynchronizeAsync(ct)).Uri, Is.EqualTo(NetworkBattleUri.BattleStart)); - Assert.That((await client.ReceiveSynchronizeAsync(ct)).Uri, Is.EqualTo(NetworkBattleUri.Deal)); - - await client.SendMsgAsync(MakeEnvelope(NetworkBattleUri.Swap, pubSeq: 4, - body: new Dictionary { ["idxList"] = new List() }), key, ct); - Assert.That((await client.ReceiveSynchronizeAsync(ct)).Uri, Is.EqualTo(NetworkBattleUri.Swap)); - Assert.That((await client.ReceiveSynchronizeAsync(ct)).Uri, Is.EqualTo(NetworkBattleUri.Ready)); - - // --- v1.2 opponent turn loop: drive two consecutive cycles --- - // Cycle 1: player ends turn -> server pushes opponent TurnStart + TurnEnd + Judge. - await client.SendMsgAsync(MakeEnvelope(NetworkBattleUri.TurnEnd, pubSeq: 5), key, ct); - Assert.That((await client.ReceiveSynchronizeAsync(ct)).Uri, Is.EqualTo(NetworkBattleUri.TurnStart)); - Assert.That((await client.ReceiveSynchronizeAsync(ct)).Uri, Is.EqualTo(NetworkBattleUri.TurnEnd)); - Assert.That((await client.ReceiveSynchronizeAsync(ct)).Uri, Is.EqualTo(NetworkBattleUri.Judge)); - - // Cycle 2: same burst again -- session phase reset to AfterReady, so the next TurnEnd matches. - await client.SendMsgAsync(MakeEnvelope(NetworkBattleUri.TurnEnd, pubSeq: 6), key, ct); - Assert.That((await client.ReceiveSynchronizeAsync(ct)).Uri, Is.EqualTo(NetworkBattleUri.TurnStart)); - Assert.That((await client.ReceiveSynchronizeAsync(ct)).Uri, Is.EqualTo(NetworkBattleUri.TurnEnd)); - Assert.That((await client.ReceiveSynchronizeAsync(ct)).Uri, Is.EqualTo(NetworkBattleUri.Judge)); - } - - private static MsgEnvelope MakeEnvelope(NetworkBattleUri uri, long pubSeq, Dictionary? body = null) => - new(uri, ViewerId: 906243102, Uuid: "udid-test", Bid: null, Try: 0, - Cat: uri == NetworkBattleUri.InitNetwork ? EmitCategory.General - : uri == NetworkBattleUri.InitBattle ? EmitCategory.Matching - : EmitCategory.Battle, - PubSeq: pubSeq, PlaySeq: null, Body: new RawBody(body ?? new Dictionary())); - private static string MakeKey() { var seq = 0; @@ -101,7 +34,7 @@ public class BattleNodeFlowTests /// against an actual seeded viewer. /// [Test] - [Timeout(30000)] + [Timeout(60000)] public async Task Matched_frame_contains_drafted_deck_cards() { await using var factory = new SVSimTestFactory(); @@ -133,21 +66,23 @@ public class BattleNodeFlowTests var ctx = await builder.BuildForTwoPickAsync(vid); var bridge = factory.Services.GetRequiredService(); - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15)); + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(45)); var ct = cts.Token; + var vidB = vid + 1; var pending = bridge.RegisterBattle( new SVSim.BattleNode.Bridge.BattlePlayer(vid, ctx), - p2: null, - SVSim.BattleNode.Sessions.BattleType.Scripted); + new SVSim.BattleNode.Bridge.BattlePlayer(vidB, FixtureCtx()), + SVSim.BattleNode.Sessions.BattleType.Pvp); var key = MakeKey(); - var encryptedVid = NodeCrypto.EncryptForNode(vid.ToString(), key); - var wsUri = new Uri($"ws://localhost/socket.io/?BattleId={pending.BattleId}&viewerId={Uri.EscapeDataString(encryptedVid)}&EIO=3&transport=websocket"); - - var wsClient = factory.Server.CreateWebSocketClient(); - var ws = await wsClient.ConnectAsync(wsUri, ct); - await using var client = new RawSocketIoTestClient(ws); - await client.ConsumeHandshakeAsync(ct); + // PvP constructs the BattleSession on the SECOND arriver, so connecting only P1 parks it + // forever. Connect BOTH clients, then drive P1 (the seeded viewer) through + // InitNetwork/InitBattle to harvest its own Matched — pushed to the sender before the + // mulligan barrier, so B's handshake is not needed for P1's Matched to arrive. + var (client, clientB) = await ConnectBothAsync(factory, pending.BattleId, vid, vidB, key, ct); + await using var _a = client; + await using var _b = clientB; + await Task.WhenAll(client.ConsumeHandshakeAsync(ct), clientB.ConsumeHandshakeAsync(ct)); // InitNetwork → ack await client.SendMsgAsync(MakeEnvelopeWith(vid, NetworkBattleUri.InitNetwork, pubSeq: 1), key, ct);