refactor(battlenode): split BattleSessionPhase into HandshakePhase + SessionLifecycle
Behavior-preserving; 231 BattleNode tests green. One enum conflated two axes. Split: - HandshakePhase (per participant): AwaitingInitNetwork..AfterReady. On IHasHandshakePhase.Phase, FrameDispatchContext.SenderPhase, the handler gates. - SessionLifecycle (per battle): Active | Terminal. On the renamed BattleSessionState.Lifecycle (was SessionPhase, defaulting to a handshake value) and BattleSession.Lifecycle (was Phase). Reads are only != Terminal, so the Active default is behavior-identical. OpponentTurn was dead (never assigned) -> dropped. BattleSessionPhase deleted; the two axes can no longer be cross-assigned. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -103,7 +103,7 @@ public class BattleSessionDispatchConcurrencyTests
|
||||
private readonly ConcurrencyDetector _detector;
|
||||
public long ViewerId { get; }
|
||||
public MatchContext Context { get; }
|
||||
public BattleSessionPhase Phase { get; set; } = BattleSessionPhase.AwaitingInitNetwork;
|
||||
public HandshakePhase Phase { get; set; } = HandshakePhase.AwaitingInitNetwork;
|
||||
public event Func<MsgEnvelope, CancellationToken, Task>? FrameEmitted;
|
||||
|
||||
public ProbeParticipant(long viewerId, MatchContext context, ConcurrencyDetector detector)
|
||||
|
||||
@@ -44,19 +44,19 @@ public class BattleSessionDispatchTests
|
||||
var s = new BattleSession("bid-1", BattleType.Pvp, a, b, NullLogger<BattleSession>.Instance);
|
||||
|
||||
// A is AwaitingInitNetwork; B is AwaitingInitBattle (manually set).
|
||||
b.Phase = BattleSessionPhase.AwaitingInitBattle;
|
||||
b.Phase = HandshakePhase.AwaitingInitBattle;
|
||||
|
||||
// A's InitNetwork should ack (matches A's phase).
|
||||
var routesA = s.ComputeFrames(a, NewEnvelope(NetworkBattleUri.InitNetwork));
|
||||
Assert.That(routesA.Count, Is.EqualTo(1));
|
||||
Assert.That(routesA[0].Frame.Uri, Is.EqualTo(NetworkBattleUri.InitNetwork));
|
||||
Assert.That(a.Phase, Is.EqualTo(BattleSessionPhase.AwaitingInitBattle));
|
||||
Assert.That(a.Phase, Is.EqualTo(HandshakePhase.AwaitingInitBattle));
|
||||
|
||||
// B's InitBattle should produce Matched (matches B's phase, set above).
|
||||
var routesB = s.ComputeFrames(b, NewEnvelope(NetworkBattleUri.InitBattle));
|
||||
Assert.That(routesB.Count, Is.EqualTo(1));
|
||||
Assert.That(routesB[0].Frame.Uri, Is.EqualTo(NetworkBattleUri.Matched));
|
||||
Assert.That(b.Phase, Is.EqualTo(BattleSessionPhase.AwaitingLoaded));
|
||||
Assert.That(b.Phase, Is.EqualTo(HandshakePhase.AwaitingLoaded));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -66,7 +66,7 @@ public class BattleSessionDispatchTests
|
||||
var routes = s.ComputeFrames(a, NewEnvelope(NetworkBattleUri.Swap));
|
||||
|
||||
Assert.That(routes, Is.Empty);
|
||||
Assert.That(a.Phase, Is.EqualTo(BattleSessionPhase.AwaitingInitNetwork));
|
||||
Assert.That(a.Phase, Is.EqualTo(HandshakePhase.AwaitingInitNetwork));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -169,7 +169,7 @@ public class BattleSessionDispatchTests
|
||||
|
||||
Assert.That(routes.Select(r => r.Frame.Uri), Is.EqualTo(new[] { NetworkBattleUri.Swap }),
|
||||
"Ready is withheld until BOTH sides have mulliganed.");
|
||||
Assert.That(a.Phase, Is.EqualTo(BattleSessionPhase.AfterReady),
|
||||
Assert.That(a.Phase, Is.EqualTo(HandshakePhase.AfterReady),
|
||||
"Phase advances on Swap even though Ready is withheld.");
|
||||
}
|
||||
|
||||
@@ -833,7 +833,7 @@ public class BattleSessionDispatchTests
|
||||
Assert.That(routes[2].Frame.Uri, Is.EqualTo(NetworkBattleUri.BattleFinish));
|
||||
Assert.That(((BattleFinishBody)routes[2].Frame.Body).Result, Is.EqualTo(BattleResult.LifeLose));
|
||||
|
||||
Assert.That(s.Phase, Is.EqualTo(BattleSessionPhase.Terminal));
|
||||
Assert.That(s.Lifecycle, Is.EqualTo(SessionLifecycle.Terminal));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -866,7 +866,7 @@ public class BattleSessionDispatchTests
|
||||
Assert.That(((BattleFinishBody)bRoute.Frame.Body).Result, Is.EqualTo(BattleResult.RetireWin));
|
||||
Assert.That(aRoute.Stock, Is.EqualTo(Stock.Bypass));
|
||||
Assert.That(bRoute.Stock, Is.EqualTo(Stock.Bypass));
|
||||
Assert.That(s.Phase, Is.EqualTo(BattleSessionPhase.Terminal));
|
||||
Assert.That(s.Lifecycle, Is.EqualTo(SessionLifecycle.Terminal));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -879,7 +879,7 @@ public class BattleSessionDispatchTests
|
||||
var routes = s.ComputeFrames(a, NewEnvelope(NetworkBattleUri.Kill));
|
||||
|
||||
Assert.That(routes.Count, Is.EqualTo(2));
|
||||
Assert.That(s.Phase, Is.EqualTo(BattleSessionPhase.Terminal));
|
||||
Assert.That(s.Lifecycle, Is.EqualTo(SessionLifecycle.Terminal));
|
||||
}
|
||||
|
||||
private static (BattleSession, FakeRealParticipant, FakeParticipant) NewBotSession()
|
||||
@@ -905,7 +905,7 @@ public class BattleSessionDispatchTests
|
||||
Assert.That(routes.Count, Is.EqualTo(1));
|
||||
Assert.That(routes[0].Target, Is.SameAs(a));
|
||||
Assert.That(routes[0].Frame.Uri, Is.EqualTo(NetworkBattleUri.InitNetwork));
|
||||
Assert.That(a.Phase, Is.EqualTo(BattleSessionPhase.AwaitingInitBattle));
|
||||
Assert.That(a.Phase, Is.EqualTo(HandshakePhase.AwaitingInitBattle));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -923,7 +923,7 @@ public class BattleSessionDispatchTests
|
||||
Assert.That(routes[0].Target, Is.SameAs(a));
|
||||
Assert.That(routes[0].Frame.Uri, Is.EqualTo(NetworkBattleUri.InitBattle),
|
||||
"Expected an ack envelope for InitBattle, NOT a Matched envelope.");
|
||||
Assert.That(a.Phase, Is.EqualTo(BattleSessionPhase.AwaitingLoaded));
|
||||
Assert.That(a.Phase, Is.EqualTo(HandshakePhase.AwaitingLoaded));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -939,7 +939,7 @@ public class BattleSessionDispatchTests
|
||||
// handler at Matching.cs:417 → SetNetworkInfo overwrites it with our
|
||||
// placeholder NoOpBotParticipant.Context zeros).
|
||||
Assert.That(routes, Is.Empty, "Bot Loaded is silent.");
|
||||
Assert.That(a.Phase, Is.EqualTo(BattleSessionPhase.AwaitingSwap),
|
||||
Assert.That(a.Phase, Is.EqualTo(HandshakePhase.AwaitingSwap),
|
||||
"Phase still advances even though there are no outbound routes.");
|
||||
}
|
||||
|
||||
@@ -956,7 +956,7 @@ public class BattleSessionDispatchTests
|
||||
Assert.That(routes.Select(r => r.Frame.Uri),
|
||||
Is.EqualTo(new[] { NetworkBattleUri.Swap, NetworkBattleUri.Ready }));
|
||||
Assert.That(routes.All(r => ReferenceEquals(r.Target, a)), Is.True);
|
||||
Assert.That(a.Phase, Is.EqualTo(BattleSessionPhase.AfterReady));
|
||||
Assert.That(a.Phase, Is.EqualTo(HandshakePhase.AfterReady));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -1114,7 +1114,7 @@ public class BattleSessionDispatchTests
|
||||
{
|
||||
public long ViewerId { get; }
|
||||
public MatchContext Context { get; }
|
||||
public BattleSessionPhase Phase { get; set; } = BattleSessionPhase.AwaitingInitNetwork;
|
||||
public HandshakePhase Phase { get; set; } = HandshakePhase.AwaitingInitNetwork;
|
||||
public event Func<MsgEnvelope, CancellationToken, Task>? FrameEmitted;
|
||||
public FakeRealParticipant(long viewerId, MatchContext context) { ViewerId = viewerId; Context = context; }
|
||||
public Task PushAsync(MsgEnvelope env, Stock stock, CancellationToken ct) => Task.CompletedTask;
|
||||
|
||||
@@ -97,7 +97,7 @@ public class RealParticipantTests
|
||||
var p = new RealParticipant(ws, viewerId: 1, FixtureCtx(),
|
||||
NullLogger<RealParticipant>.Instance);
|
||||
|
||||
Assert.That(p.Phase, Is.EqualTo(SVSim.BattleNode.Sessions.BattleSessionPhase.AwaitingInitNetwork));
|
||||
Assert.That(p.Phase, Is.EqualTo(SVSim.BattleNode.Sessions.HandshakePhase.AwaitingInitNetwork));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -108,9 +108,9 @@ public class RealParticipantTests
|
||||
NullLogger<RealParticipant>.Instance);
|
||||
|
||||
// Setter is `internal`; SVSim.UnitTests has InternalsVisibleTo on SVSim.BattleNode.
|
||||
p.Phase = SVSim.BattleNode.Sessions.BattleSessionPhase.AfterReady;
|
||||
p.Phase = SVSim.BattleNode.Sessions.HandshakePhase.AfterReady;
|
||||
|
||||
Assert.That(p.Phase, Is.EqualTo(SVSim.BattleNode.Sessions.BattleSessionPhase.AfterReady));
|
||||
Assert.That(p.Phase, Is.EqualTo(SVSim.BattleNode.Sessions.HandshakePhase.AfterReady));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -121,9 +121,9 @@ public class RealParticipantTests
|
||||
var a = new RealParticipant(wsA, viewerId: 1, FixtureCtx(), NullLogger<RealParticipant>.Instance);
|
||||
var b = new RealParticipant(wsB, viewerId: 2, FixtureCtx(), NullLogger<RealParticipant>.Instance);
|
||||
|
||||
a.Phase = SVSim.BattleNode.Sessions.BattleSessionPhase.AfterReady;
|
||||
a.Phase = SVSim.BattleNode.Sessions.HandshakePhase.AfterReady;
|
||||
|
||||
Assert.That(b.Phase, Is.EqualTo(SVSim.BattleNode.Sessions.BattleSessionPhase.AwaitingInitNetwork),
|
||||
Assert.That(b.Phase, Is.EqualTo(SVSim.BattleNode.Sessions.HandshakePhase.AwaitingInitNetwork),
|
||||
"B's Phase must not change when A's Phase is set.");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user