mirror of
https://github.com/JogmansonReal/Radicade.git
synced 2026-10-26 07:29:00 -07:00
111 lines
4.7 KiB
C#
111 lines
4.7 KiB
C#
using System.Security.Claims;
|
|
using Microsoft.AspNetCore.Http.Features;
|
|
using Microsoft.AspNetCore.SignalR;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using RadicadeServer.API.Notifications;
|
|
using RadicadeServer.DB;
|
|
using RadicadeServer.RecNet.Accounts;
|
|
using Xunit;
|
|
|
|
namespace RadicadeServer.Tests;
|
|
|
|
[Collection(DbFactoryCollection.Name)]
|
|
public class ConnectionRecoveryTests
|
|
{
|
|
[Theory]
|
|
[InlineData(true)]
|
|
[InlineData(false)]
|
|
public async Task ReconnectReplaysActiveBanWithoutRoomPresence(bool active)
|
|
{
|
|
var options = TestDbOptions.Create()
|
|
.UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;
|
|
await using var db = new RecDBContext(options);
|
|
db.Moderation.Add(new RadicadeServer.RecNet.Moderation.ModerationDB
|
|
{
|
|
PlayerId = 987654322, IsBan = true, Message = "test ban",
|
|
ExpireDuration = DateTime.UtcNow.AddHours(active ? 1 : -1)
|
|
});
|
|
await db.SaveChangesAsync();
|
|
var proxy = new RecordingClient();
|
|
var clients = System.Reflection.DispatchProxy.Create<IHubCallerClients, CallerClientsProxy>();
|
|
((CallerClientsProxy)(object)clients).Client = proxy;
|
|
var previousContext = Notify.Context;
|
|
var previousFactory = Notify.DbFactory;
|
|
try
|
|
{
|
|
Notify.DbFactory = null!;
|
|
var hub = new NotifyHub(previousContext, db)
|
|
{
|
|
Context = new TestHubContext(987654322), Clients = clients
|
|
};
|
|
await hub.OnConnectedAsync();
|
|
Assert.Equal(active ? 1 : 0, proxy.Messages.Count);
|
|
if (active)
|
|
{
|
|
Assert.Equal("Notification", proxy.Messages[0].Method);
|
|
// The replayed kick must carry the client enum's NUMBER (22) inside a JSON
|
|
// string; the name parses and lands on no handler, and a bare number does not
|
|
// parse at all - both leave a banned player kicked with no ban screen.
|
|
Assert.Contains("\"Id\":\"22\"", proxy.Messages[0].Json);
|
|
Assert.DoesNotContain("ModerationKick", proxy.Messages[0].Json);
|
|
Assert.Contains("test ban", proxy.Messages[0].Json);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
lock (Notify.ClientsLock) Notify.Clients.RemoveAll(c => c.AccountId == 987654322);
|
|
Notify.Context = previousContext;
|
|
Notify.DbFactory = previousFactory;
|
|
}
|
|
}
|
|
|
|
public class CallerClientsProxy : System.Reflection.DispatchProxy
|
|
{
|
|
public IClientProxy Client = null!;
|
|
protected override object? Invoke(System.Reflection.MethodInfo? method, object?[]? args)
|
|
=> method?.Name == "get_Caller" ? Client : throw new NotSupportedException();
|
|
}
|
|
|
|
private sealed class RecordingClient : ISingleClientProxy
|
|
{
|
|
public Task<T> InvokeCoreAsync<T>(string method, object?[] args, CancellationToken cancellationToken = default)
|
|
=> throw new NotSupportedException();
|
|
public List<(string Method, string Json)> Messages { get; } = new();
|
|
public Task SendCoreAsync(string method, object?[] args, CancellationToken cancellationToken = default)
|
|
{
|
|
Messages.Add((method, Assert.IsType<string>(args[0])));
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public async Task NotificationDisconnectDoesNotChangeGamePresence()
|
|
{
|
|
var options = TestDbOptions.Create()
|
|
.UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;
|
|
await using var db = new RecDBContext(options);
|
|
var presence = new RealPresence { playerId = 987654321, isOnline = true, roomInstance = 42 };
|
|
db.Presences.Add(presence);
|
|
await db.SaveChangesAsync();
|
|
var hub = new NotifyHub(Notify.Context, db) { Context = new TestHubContext(presence.playerId) };
|
|
|
|
await hub.OnDisconnectedAsync(new IOException("Transport interrupted"));
|
|
|
|
await db.Entry(presence).ReloadAsync();
|
|
Assert.Equal(42L, presence.roomInstance);
|
|
Assert.True(presence.isOnline);
|
|
}
|
|
|
|
private sealed class TestHubContext(long accountId) : HubCallerContext
|
|
{
|
|
public override string ConnectionId => "connection-recovery-test";
|
|
public override string? UserIdentifier => accountId.ToString();
|
|
public override ClaimsPrincipal User => new(new ClaimsIdentity(
|
|
[new Claim(ClaimTypes.NameIdentifier, accountId.ToString())], "test"));
|
|
public override IDictionary<object, object?> Items { get; } = new Dictionary<object, object?>();
|
|
public override IFeatureCollection Features { get; } = new FeatureCollection();
|
|
public override CancellationToken ConnectionAborted => CancellationToken.None;
|
|
public override void Abort() { }
|
|
}
|
|
}
|