test(headless): cover K4 death and cancellation
This commit is contained in:
parent
97c174fbb2
commit
bd236ce553
2 changed files with 115 additions and 17 deletions
|
|
@ -358,6 +358,76 @@ public sealed class HeadlessProcessSchedulerTests
|
|||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ThirtySessionsConvergeAcrossRandomizedCancellationEdges()
|
||||
{
|
||||
const int sessionCount = 30;
|
||||
var random = new Random(0xAC2013);
|
||||
for (int iteration = 0; iteration < 5; iteration++)
|
||||
{
|
||||
var configuration = new HeadlessConfiguration
|
||||
{
|
||||
Version = 1,
|
||||
Sessions = Enumerable.Range(0, sessionCount)
|
||||
.Select(index => Descriptor(
|
||||
$"cancel-{iteration}-{index}",
|
||||
$"cancel-{iteration}-{index}-stdin"))
|
||||
.Cast<HeadlessSessionDescriptor?>()
|
||||
.ToList(),
|
||||
};
|
||||
var operations = new FixtureSessionOperations();
|
||||
using var diagnostics = new StringWriter();
|
||||
using var host = new HeadlessProcessHost(
|
||||
configuration,
|
||||
HeadlessPathSet.Resolve(
|
||||
new HeadlessPathOverrides()),
|
||||
new System.IO.StringReader(string.Concat(
|
||||
Enumerable.Repeat(
|
||||
"random-cancel-password"
|
||||
+ Environment.NewLine,
|
||||
sessionCount))),
|
||||
diagnostics,
|
||||
operations);
|
||||
using var cancellation = new CancellationTokenSource(
|
||||
TimeSpan.FromMilliseconds(random.Next(37, 144)));
|
||||
|
||||
HeadlessExitCode result =
|
||||
await host.RunAsync(cancellation.Token);
|
||||
|
||||
Assert.True(cancellation.IsCancellationRequested);
|
||||
Assert.Equal(HeadlessExitCode.Success, result);
|
||||
Assert.Equal(sessionCount, operations.CreatedSessionCount);
|
||||
Assert.All(
|
||||
host.Sessions,
|
||||
static session =>
|
||||
Assert.False(session.IsFaulted));
|
||||
|
||||
host.Dispose();
|
||||
|
||||
Assert.Equal(sessionCount, operations.DisposedSessionCount);
|
||||
Assert.All(
|
||||
host.Sessions,
|
||||
static session =>
|
||||
Assert.True(
|
||||
session.Runtime
|
||||
.CaptureOwnership()
|
||||
.IsConverged));
|
||||
string output = diagnostics.ToString();
|
||||
Assert.Contains(
|
||||
"\"state\":\"disposed\"",
|
||||
output,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
$"\"convergedRuntimeCount\":{sessionCount}",
|
||||
output,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain(
|
||||
"random-cancel-password",
|
||||
output,
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ThrowingPolicyQuarantinesOnlyItsOwnSession()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ public sealed class HeadlessSessionIsolationTests
|
|||
.Select(index => CreateHost(index, operations, time))
|
||||
.ToArray();
|
||||
var reconnectCounts = new int[sessionCount];
|
||||
var deathCounts = new int[sessionCount];
|
||||
var random = new Random(0xAC2013);
|
||||
try
|
||||
{
|
||||
|
|
@ -197,6 +198,16 @@ public sealed class HeadlessSessionIsolationTests
|
|||
2 + reconnectCounts[index]
|
||||
+ (frame / 211))));
|
||||
}
|
||||
if (frame % 5003 == 0)
|
||||
{
|
||||
int index = (frame / 5003) % sessionCount;
|
||||
Death(
|
||||
operations.ActiveSession(
|
||||
hosts[index].SessionId),
|
||||
sharedPlayerGuid,
|
||||
frame);
|
||||
deathCounts[index]++;
|
||||
}
|
||||
if (frame % 353 == 0)
|
||||
{
|
||||
int index = random.Next(sessionCount);
|
||||
|
|
@ -289,25 +300,30 @@ public sealed class HeadlessSessionIsolationTests
|
|||
Assert.All(
|
||||
reconnectCounts,
|
||||
static count => Assert.True(count > 0));
|
||||
Assert.All(
|
||||
deathCounts,
|
||||
static count => Assert.True(count > 0));
|
||||
var finalRecords = new List<RuntimeEntityRecord>(
|
||||
sessionCount);
|
||||
Assert.All(
|
||||
hosts,
|
||||
host =>
|
||||
{
|
||||
Assert.Equal(
|
||||
(ulong)frameCount,
|
||||
host.Runtime.Clock.FrameNumber);
|
||||
Assert.True(
|
||||
host.Runtime.EntityObjects.Entities.TryGetActive(
|
||||
sharedPlayerGuid,
|
||||
out RuntimeEntityRecord finalRecord));
|
||||
finalRecords.Add(finalRecord);
|
||||
Assert.True(
|
||||
host.Runtime.TransitOwner
|
||||
.CaptureOwnership()
|
||||
.IsSessionIdle);
|
||||
});
|
||||
for (int index = 0; index < hosts.Length; index++)
|
||||
{
|
||||
HeadlessSessionHost host = hosts[index];
|
||||
Assert.Equal(
|
||||
(ulong)frameCount,
|
||||
host.Runtime.Clock.FrameNumber);
|
||||
Assert.True(
|
||||
host.Runtime.EntityObjects.Entities.TryGetActive(
|
||||
sharedPlayerGuid,
|
||||
out RuntimeEntityRecord finalRecord));
|
||||
finalRecords.Add(finalRecord);
|
||||
Assert.True(
|
||||
host.Runtime.TransitOwner
|
||||
.CaptureOwnership()
|
||||
.IsSessionIdle);
|
||||
Assert.True(
|
||||
host.Runtime.CommunicationOwner.View.Count
|
||||
>= deathCounts[index]);
|
||||
}
|
||||
Assert.Equal(
|
||||
sessionCount,
|
||||
finalRecords
|
||||
|
|
@ -420,6 +436,18 @@ public sealed class HeadlessSessionIsolationTests
|
|||
ForcePositionSequence: 0));
|
||||
}
|
||||
|
||||
private static void Death(
|
||||
WorldSession session,
|
||||
uint victimGuid,
|
||||
int sequence) =>
|
||||
EventDelegate<Action<PlayerKilled.Parsed>>(
|
||||
session,
|
||||
nameof(session.PlayerKilledReceived))(
|
||||
new PlayerKilled.Parsed(
|
||||
$"Headless death {sequence}.",
|
||||
victimGuid,
|
||||
0x5000FFFFu));
|
||||
|
||||
private static WorldSession.EntitySpawn Spawn(
|
||||
uint guid,
|
||||
float positionX)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue