acdream/tests/AcDream.App.Tests/Net/LiveSessionLifecycleHostTests.cs

110 lines
3.6 KiB
C#

using System.Net;
using AcDream.App.Net;
using AcDream.Core.Net;
using AcDream.UI.Abstractions;
namespace AcDream.App.Tests.Net;
public sealed class LiveSessionLifecycleHostTests
{
[Fact]
public void HostRoutesLifecycleAndReleasesOnlyTheExactBoundSession()
{
var calls = new List<string>();
using var sessionA = CreateSession(9000);
using var sessionB = CreateSession(9001);
var host = CreateHost(calls);
LiveSessionBinding binding = host.BindSession(sessionA);
host.ResetSessionState();
host.ReportConnecting("host", 9000, "user");
host.ReportConnected();
var selection = new LiveSessionCharacterSelection(2, 3u, "toon", "account");
host.ApplySelectedCharacter(selection);
binding.ActivateCommands();
host.ApplyEnteredWorld(selection);
Assert.Throws<InvalidOperationException>(() => host.DetachSession(sessionB));
binding.Dispose();
host.DetachSession(sessionA);
LiveSessionBinding replacement = host.BindSession(sessionB);
Assert.Equal(
[
"bind", "reset", "connecting:host:9000:user",
"connected", "selected:toon", "activate", "entered:toon",
"deactivate", "detach-events", "bind",
],
calls);
replacement.Dispose();
host.DetachSession(sessionB);
}
[Fact]
public void FailedBindingFactoryDoesNotClaimTheHost()
{
var calls = new List<string>();
using var session = CreateSession(9000);
bool fail = true;
LiveSessionLifecycleHost host = CreateHost(calls, _ =>
{
if (fail)
{
fail = false;
throw new InvalidOperationException("bind failure");
}
return CreateBinding(session, calls);
});
Assert.Throws<InvalidOperationException>(() => host.BindSession(session));
LiveSessionBinding retry = host.BindSession(session);
retry.Dispose();
host.DetachSession(session);
}
private static LiveSessionLifecycleHost CreateHost(
List<string> calls,
Func<WorldSession, LiveSessionBinding>? bind = null) =>
new(new LiveSessionLifecycleBindings(
Bind: bind ?? (session => CreateBinding(session, calls)),
Reset: () => calls.Add("reset"),
Connecting: (host, port, user) =>
calls.Add($"connecting:{host}:{port}:{user}"),
Connected: () => calls.Add("connected"),
Selected: selection => calls.Add($"selected:{selection.CharacterName}"),
Entered: selection => calls.Add($"entered:{selection.CharacterName}")));
private static LiveSessionBinding CreateBinding(
WorldSession session,
List<string> calls)
{
calls.Add("bind");
return new LiveSessionBinding(
session,
NullCommandBus.Instance,
activateCommands: () => calls.Add("activate"),
deactivateCommands: () => calls.Add("deactivate"),
detachEvents: () => calls.Add("detach-events"));
}
private static WorldSession CreateSession(int port) =>
new(
new IPEndPoint(IPAddress.Loopback, port),
new TestTransport());
private sealed class TestTransport : IWorldSessionTransport
{
public void Send(ReadOnlySpan<byte> datagram) { }
public void Send(IPEndPoint remote, ReadOnlySpan<byte> datagram) { }
public byte[]? Receive(TimeSpan timeout, out IPEndPoint? from)
{
from = null;
return null;
}
public void Dispose() { }
}
}