110 lines
3.6 KiB
C#
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() { }
|
|
}
|
|
}
|