564 lines
21 KiB
C#
564 lines
21 KiB
C#
using IW4MAdmin;
|
|
using IW4MAdmin.Application.Misc;
|
|
using SharedLibraryCore.Interfaces;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using NUnit.Framework;
|
|
using FakeItEasy;
|
|
using System;
|
|
using ApplicationTests.Fixtures;
|
|
using SharedLibraryCore.Services;
|
|
using SharedLibraryCore.Database.Models;
|
|
using System.Threading.Tasks;
|
|
using ApplicationTests.Mocks;
|
|
using System.Linq;
|
|
using Microsoft.Extensions.Logging;
|
|
using SharedLibraryCore;
|
|
using SharedLibraryCore.Exceptions;
|
|
using SharedLibraryCore.Configuration;
|
|
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
|
|
namespace ApplicationTests
|
|
{
|
|
[TestFixture]
|
|
public class IW4MServerTests
|
|
{
|
|
private IServiceProvider serviceProvider;
|
|
private ILogger fakeLogger;
|
|
private IManager fakeManager;
|
|
private IRConConnection fakeRConConnection;
|
|
private IRConParser fakeRConParser;
|
|
private EventHandlerMock mockEventHandler;
|
|
private ApplicationConfiguration appConfig;
|
|
|
|
[SetUp]
|
|
public void Setup()
|
|
{
|
|
serviceProvider = new ServiceCollection().BuildBase().BuildServiceProvider();
|
|
|
|
fakeLogger = serviceProvider.GetRequiredService<ILogger>();
|
|
fakeManager = serviceProvider.GetRequiredService<IManager>();
|
|
fakeRConConnection = serviceProvider.GetRequiredService<IRConConnection>();
|
|
fakeRConParser = serviceProvider.GetRequiredService<IRConParser>();
|
|
mockEventHandler = serviceProvider.GetRequiredService<EventHandlerMock>();
|
|
appConfig = serviceProvider.GetRequiredService<ApplicationConfiguration>();
|
|
serviceProvider.GetService<IW4MServer>().RconParser =
|
|
serviceProvider.GetService<IRConParser>();
|
|
|
|
var rconConnectionFactory = serviceProvider.GetRequiredService<IRConConnectionFactory>();
|
|
|
|
A.CallTo(() => rconConnectionFactory.CreateConnection(A<string>.Ignored, A<int>.Ignored, A<string>.Ignored))
|
|
.Returns(fakeRConConnection);
|
|
|
|
A.CallTo(() => fakeRConParser.Configuration)
|
|
.Returns(ConfigurationGenerators.CreateRConParserConfiguration(serviceProvider.GetRequiredService<IParserRegexFactory>()));
|
|
|
|
A.CallTo(() => fakeManager.AddEvent(A<GameEvent>.Ignored))
|
|
.Invokes((fakeCall) => mockEventHandler.HandleEvent(fakeManager, fakeCall.Arguments[0] as GameEvent));
|
|
|
|
}
|
|
|
|
#region LOG
|
|
[Test]
|
|
public void Test_GenerateLogPath_Basic()
|
|
{
|
|
string expected = "C:\\Game\\main\\log.log";
|
|
var info = new LogPathGeneratorInfo()
|
|
{
|
|
BasePathDirectory = "C:\\Game",
|
|
GameDirectory = "main",
|
|
LogFile = "log.log"
|
|
};
|
|
string generated = IW4MServer.GenerateLogPath(info);
|
|
|
|
Assert.AreEqual(expected, generated);
|
|
}
|
|
|
|
[Test]
|
|
public void Test_GenerateLogPath_WithMod()
|
|
{
|
|
string expected = "C:\\Game\\mods\\mod\\log.log";
|
|
var info = new LogPathGeneratorInfo()
|
|
{
|
|
BasePathDirectory = "C:\\Game",
|
|
GameDirectory = "main",
|
|
ModDirectory = "mods\\mod",
|
|
LogFile = "log.log"
|
|
};
|
|
string generated = IW4MServer.GenerateLogPath(info);
|
|
|
|
Assert.AreEqual(expected, generated);
|
|
}
|
|
|
|
[Test]
|
|
public void Test_GenerateLogPath_WithBaseGame()
|
|
{
|
|
string expected = "C:\\GameAlt\\main\\log.log";
|
|
var info = new LogPathGeneratorInfo()
|
|
{
|
|
BaseGameDirectory = "C:\\GameAlt",
|
|
BasePathDirectory = "C:\\Game",
|
|
GameDirectory = "main",
|
|
LogFile = "log.log"
|
|
};
|
|
string generated = IW4MServer.GenerateLogPath(info);
|
|
|
|
Assert.AreEqual(expected, generated);
|
|
}
|
|
|
|
[Test]
|
|
public void Test_GenerateLogPath_WithBaseGameAndMod()
|
|
{
|
|
string expected = "C:\\GameAlt\\mods\\mod\\log.log";
|
|
var info = new LogPathGeneratorInfo()
|
|
{
|
|
BaseGameDirectory = "C:\\GameAlt",
|
|
BasePathDirectory = "C:\\Game",
|
|
GameDirectory = "main",
|
|
ModDirectory = "mods\\mod",
|
|
LogFile = "log.log"
|
|
};
|
|
string generated = IW4MServer.GenerateLogPath(info);
|
|
|
|
Assert.AreEqual(expected, generated);
|
|
}
|
|
|
|
[Test]
|
|
public void Test_GenerateLogPath_InvalidBasePath()
|
|
{
|
|
string expected = "C:\\Game\\main\\log.log";
|
|
var info = new LogPathGeneratorInfo()
|
|
{
|
|
BaseGameDirectory = "game",
|
|
BasePathDirectory = "C:\\Game",
|
|
GameDirectory = "main",
|
|
LogFile = "log.log"
|
|
};
|
|
string generated = IW4MServer.GenerateLogPath(info);
|
|
|
|
Assert.AreEqual(expected, generated);
|
|
}
|
|
|
|
[Test]
|
|
public void Test_GenerateLogPath_BadSeparators()
|
|
{
|
|
string expected = "C:\\Game\\main\\folder\\log.log";
|
|
var info = new LogPathGeneratorInfo()
|
|
{
|
|
BasePathDirectory = "C:/Game",
|
|
GameDirectory = "main/folder",
|
|
LogFile = "log.log"
|
|
};
|
|
string generated = IW4MServer.GenerateLogPath(info);
|
|
|
|
Assert.AreEqual(expected, generated);
|
|
}
|
|
|
|
[Test]
|
|
public void Test_GenerateLogPath_RelativeBasePath()
|
|
{
|
|
string expected = "C:\\Game\\main\\folder\\log.log";
|
|
var info = new LogPathGeneratorInfo()
|
|
{
|
|
BaseGameDirectory = "main\\folder",
|
|
BasePathDirectory = "C:\\Game",
|
|
GameDirectory = "main\\folder",
|
|
LogFile = "log.log"
|
|
};
|
|
string generated = IW4MServer.GenerateLogPath(info);
|
|
|
|
Assert.AreEqual(expected, generated);
|
|
}
|
|
|
|
[Test]
|
|
public void Test_GenerateLogPath_FixWineDriveMangling()
|
|
{
|
|
string expected = "/opt/server/game/log.log";
|
|
var info = new LogPathGeneratorInfo()
|
|
{
|
|
BasePathDirectory = "Z:\\opt\\server",
|
|
GameDirectory = "game",
|
|
LogFile = "log.log",
|
|
IsWindows = false
|
|
};
|
|
string generated = IW4MServer.GenerateLogPath(info).Replace('\\', '/');
|
|
|
|
Assert.AreEqual(expected, generated);
|
|
}
|
|
#endregion
|
|
|
|
#region BAN
|
|
[Test]
|
|
public async Task Test_BanCreatesPenalty()
|
|
{
|
|
var fakePenaltyService = A.Fake<PenaltyService>();
|
|
A.CallTo(() => fakeManager.GetPenaltyService())
|
|
.Returns(fakePenaltyService);
|
|
|
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
var target = ClientGenerators.CreateBasicClient(server);
|
|
var origin = ClientGenerators.CreateBasicClient(server);
|
|
|
|
await server.Ban("test reason", target, origin);
|
|
|
|
A.CallTo(() => fakePenaltyService.Create(A<EFPenalty>.Ignored))
|
|
.MustHaveHappenedOnceExactly();
|
|
}
|
|
|
|
[Test]
|
|
public async Task Test_BanExecutesKickCommand()
|
|
{
|
|
var fakePenaltyService = A.Fake<PenaltyService>();
|
|
A.CallTo(() => fakeManager.GetPenaltyService())
|
|
.Returns(fakePenaltyService);
|
|
|
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
var target = ClientGenerators.CreateBasicClient(server);
|
|
var origin = ClientGenerators.CreateBasicClient(server);
|
|
|
|
await server.Ban("test reason", target, origin);
|
|
|
|
A.CallTo(() => server.RconParser.ExecuteCommandAsync(A<IRConConnection>.Ignored, "kick"))
|
|
.MustHaveHappenedOnceExactly();
|
|
}
|
|
|
|
[Test]
|
|
public async Task Test_BanQueuesSetLevelEvent()
|
|
{
|
|
var fakePenaltyService = A.Fake<PenaltyService>();
|
|
A.CallTo(() => fakeManager.GetPenaltyService())
|
|
.Returns(fakePenaltyService);
|
|
|
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
var target = ClientGenerators.CreateBasicClient(server);
|
|
var origin = ClientGenerators.CreateBasicClient(server);
|
|
|
|
await server.Ban("test reason", target, origin);
|
|
|
|
Assert.IsTrue(mockEventHandler.Events.Any(_event => _event.Type == SharedLibraryCore.GameEvent.EventType.ChangePermission &&
|
|
_event.Origin == origin &&
|
|
_event.Target == target &&
|
|
(EFClient.Permission)_event.Extra == EFClient.Permission.Banned));
|
|
}
|
|
|
|
[Test]
|
|
public async Task Test_BanFindsIngameClientToExecuteFor()
|
|
{
|
|
var fakePenaltyService = A.Fake<PenaltyService>();
|
|
A.CallTo(() => fakeManager.GetPenaltyService())
|
|
.Returns(fakePenaltyService);
|
|
|
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
var origin = ClientGenerators.CreateBasicClient(server);
|
|
var target = ClientGenerators.CreateBasicClient(server, isIngame: false);
|
|
var ingameTarget = ClientGenerators.CreateBasicClient(server);
|
|
|
|
A.CallTo(() => fakeManager.GetActiveClients())
|
|
.Returns(new[] { ingameTarget });
|
|
|
|
await server.Ban("test reason", target, origin);
|
|
|
|
Assert.IsTrue(mockEventHandler.Events.Any(_event => _event.Target == ingameTarget));
|
|
}
|
|
#endregion
|
|
|
|
#region TEMPBAN
|
|
[Test]
|
|
public async Task Test_TempBanCreatesPenalty()
|
|
{
|
|
var fakePenaltyService = A.Fake<PenaltyService>();
|
|
A.CallTo(() => fakeManager.GetPenaltyService())
|
|
.Returns(fakePenaltyService);
|
|
|
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
var target = ClientGenerators.CreateBasicClient(server);
|
|
var origin = ClientGenerators.CreateBasicClient(server);
|
|
|
|
await server.TempBan("test reason", TimeSpan.Zero, target, origin);
|
|
|
|
A.CallTo(() => fakePenaltyService.Create(A<EFPenalty>.Ignored))
|
|
.MustHaveHappenedOnceExactly();
|
|
}
|
|
|
|
[Test]
|
|
public async Task Test_TempBanExecutesKickCommand()
|
|
{
|
|
var fakePenaltyService = A.Fake<PenaltyService>();
|
|
A.CallTo(() => fakeManager.GetPenaltyService())
|
|
.Returns(fakePenaltyService);
|
|
|
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
var target = ClientGenerators.CreateBasicClient(server);
|
|
var origin = ClientGenerators.CreateBasicClient(server);
|
|
|
|
await server.TempBan("test reason", TimeSpan.Zero, target, origin);
|
|
|
|
A.CallTo(() => server.RconParser.ExecuteCommandAsync(A<IRConConnection>.Ignored, "kick"))
|
|
.MustHaveHappenedOnceExactly();
|
|
}
|
|
|
|
[Test]
|
|
public async Task Test_TempBanFindsIngameClientToExecuteFor()
|
|
{
|
|
var fakePenaltyService = A.Fake<PenaltyService>();
|
|
A.CallTo(() => fakeManager.GetPenaltyService())
|
|
.Returns(fakePenaltyService);
|
|
|
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
var origin = ClientGenerators.CreateBasicClient(server);
|
|
var target = ClientGenerators.CreateBasicClient(server, isIngame: false);
|
|
|
|
var ingameTarget = ClientGenerators.CreateBasicClient(server);
|
|
|
|
A.CallTo(() => fakeManager.GetActiveClients())
|
|
.Returns(new[] { ingameTarget });
|
|
|
|
await server.TempBan("test reason", TimeSpan.Zero, target, origin);
|
|
|
|
A.CallTo(() => server.RconParser.ExecuteCommandAsync(A<IRConConnection>.Ignored, "kick"))
|
|
.MustHaveHappenedOnceExactly();
|
|
}
|
|
#endregion
|
|
|
|
#region KICK
|
|
[Test]
|
|
public async Task Test_KickCreatesPenalty()
|
|
{
|
|
var fakePenaltyService = A.Fake<PenaltyService>();
|
|
A.CallTo(() => fakeManager.GetPenaltyService())
|
|
.Returns(fakePenaltyService);
|
|
|
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
var target = ClientGenerators.CreateBasicClient(server);
|
|
var origin = ClientGenerators.CreateBasicClient(server);
|
|
|
|
await server.Kick("test reason", target, origin);
|
|
|
|
A.CallTo(() => fakePenaltyService.Create(A<EFPenalty>.Ignored))
|
|
.MustHaveHappenedOnceExactly();
|
|
}
|
|
|
|
[Test]
|
|
public async Task Test_KickExecutesKickCommand()
|
|
{
|
|
var fakePenaltyService = A.Fake<PenaltyService>();
|
|
A.CallTo(() => fakeManager.GetPenaltyService())
|
|
.Returns(fakePenaltyService);
|
|
|
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
var target = ClientGenerators.CreateBasicClient(server);
|
|
var origin = ClientGenerators.CreateBasicClient(server);
|
|
|
|
await server.Kick("test reason", target, origin);
|
|
|
|
A.CallTo(() => server.RconParser.ExecuteCommandAsync(A<IRConConnection>.Ignored, "kick"))
|
|
.MustHaveHappenedOnceExactly();
|
|
}
|
|
|
|
[Test]
|
|
public async Task Test_KickQueuesPredisconnectEvent()
|
|
{
|
|
var fakePenaltyService = A.Fake<PenaltyService>();
|
|
A.CallTo(() => fakeManager.GetPenaltyService())
|
|
.Returns(fakePenaltyService);
|
|
|
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
var target = ClientGenerators.CreateBasicClient(server);
|
|
var origin = ClientGenerators.CreateBasicClient(server);
|
|
|
|
await server.Kick("test reason", target, origin);
|
|
|
|
Assert.IsTrue(mockEventHandler.Events.Any(_event => _event.Type == SharedLibraryCore.GameEvent.EventType.PreDisconnect && _event.Origin == target));
|
|
}
|
|
|
|
[Test]
|
|
public async Task Test_KickFindsIngameClientToExecuteFor()
|
|
{
|
|
var fakePenaltyService = A.Fake<PenaltyService>();
|
|
A.CallTo(() => fakeManager.GetPenaltyService())
|
|
.Returns(fakePenaltyService);
|
|
|
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
var origin = ClientGenerators.CreateBasicClient(server);
|
|
var target = ClientGenerators.CreateBasicClient(server, isIngame: false);
|
|
|
|
var ingameTarget = ClientGenerators.CreateBasicClient(server);
|
|
|
|
A.CallTo(() => fakeManager.GetActiveClients())
|
|
.Returns(new[] { ingameTarget });
|
|
|
|
await server.Kick("test reason", target, origin);
|
|
|
|
// kick creates a pre disconnect event
|
|
Assert.IsTrue(mockEventHandler.Events.Any(_event => _event.Origin == ingameTarget));
|
|
}
|
|
#endregion
|
|
|
|
#region WARN
|
|
[Test]
|
|
public async Task Test_WarnCreatesPenalty()
|
|
{
|
|
var fakePenaltyService = A.Fake<PenaltyService>();
|
|
A.CallTo(() => fakeManager.GetPenaltyService())
|
|
.Returns(fakePenaltyService);
|
|
|
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
var target = ClientGenerators.CreateBasicClient(server);
|
|
var origin = ClientGenerators.CreateBasicClient(server);
|
|
|
|
await server.Warn("test reason", target, origin);
|
|
|
|
A.CallTo(() => fakePenaltyService.Create(A<EFPenalty>.Ignored))
|
|
.MustHaveHappenedOnceExactly();
|
|
}
|
|
|
|
[Test]
|
|
public async Task Test_WarnBroadCastMessageForIngameClient()
|
|
{
|
|
var fakePenaltyService = A.Fake<PenaltyService>();
|
|
A.CallTo(() => fakeManager.GetPenaltyService())
|
|
.Returns(fakePenaltyService);
|
|
|
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
var target = ClientGenerators.CreateBasicClient(server);
|
|
var origin = ClientGenerators.CreateBasicClient(server);
|
|
|
|
await server.Warn("test reason", target, origin);
|
|
|
|
Assert.IsTrue(mockEventHandler.Events.Any(_event => _event.Type == SharedLibraryCore.GameEvent.EventType.Broadcast));
|
|
}
|
|
|
|
[Test]
|
|
public async Task Test_WarnLimitReachedQueuesKickEvent()
|
|
{
|
|
var fakePenaltyService = A.Fake<PenaltyService>();
|
|
A.CallTo(() => fakeManager.GetPenaltyService())
|
|
.Returns(fakePenaltyService);
|
|
|
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
var target = ClientGenerators.CreateBasicClient(server);
|
|
var origin = ClientGenerators.CreateBasicClient(server);
|
|
target.Warnings = 5;
|
|
|
|
await server.Warn("test reason", target, origin);
|
|
|
|
Assert.IsTrue(mockEventHandler.Events.Any(_event => _event.Type == SharedLibraryCore.GameEvent.EventType.Kick && _event.Target == target));
|
|
}
|
|
#endregion
|
|
|
|
#region UNBAN
|
|
[Test]
|
|
public async Task Test_UnbanQueuesSetLevelEvent()
|
|
{
|
|
var fakePenaltyService = A.Fake<PenaltyService>();
|
|
A.CallTo(() => fakeManager.GetPenaltyService())
|
|
.Returns(fakePenaltyService);
|
|
A.CallTo(() => fakePenaltyService.RemoveActivePenalties(A<int>.Ignored))
|
|
.Returns(Task.CompletedTask);
|
|
|
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
var origin = ClientGenerators.CreateBasicClient(server);
|
|
var target = ClientGenerators.CreateBasicClient(server);
|
|
|
|
target.Level = EFClient.Permission.Banned;
|
|
target.AliasLink = new EFAliasLink();
|
|
|
|
await server.Unban("test reason", target, origin);
|
|
|
|
Assert.IsTrue(mockEventHandler.Events.Any(_event => _event.Type == SharedLibraryCore.GameEvent.EventType.ChangePermission && _event.Target == target));
|
|
}
|
|
|
|
[Test]
|
|
public async Task Test_UnbanRemovedActivePenalties()
|
|
{
|
|
var fakePenaltyService = A.Fake<PenaltyService>();
|
|
A.CallTo(() => fakeManager.GetPenaltyService())
|
|
.Returns(fakePenaltyService);
|
|
A.CallTo(() => fakePenaltyService.RemoveActivePenalties(A<int>.Ignored))
|
|
.Returns(Task.CompletedTask);
|
|
|
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
var origin = ClientGenerators.CreateBasicClient(server);
|
|
var target = ClientGenerators.CreateBasicClient(server);
|
|
|
|
target.Level = EFClient.Permission.Banned;
|
|
target.AliasLink = new EFAliasLink()
|
|
{
|
|
AliasLinkId = 1
|
|
};
|
|
|
|
await server.Unban("test reason", target, origin);
|
|
|
|
A.CallTo(() => fakePenaltyService.RemoveActivePenalties(target.AliasLink.AliasLinkId))
|
|
.MustHaveHappened();
|
|
}
|
|
|
|
[Test]
|
|
public async Task Test_UnbanCreatesPenalty()
|
|
{
|
|
var fakePenaltyService = A.Fake<PenaltyService>();
|
|
A.CallTo(() => fakeManager.GetPenaltyService())
|
|
.Returns(fakePenaltyService);
|
|
A.CallTo(() => fakePenaltyService.RemoveActivePenalties(A<int>.Ignored))
|
|
.Returns(Task.CompletedTask);
|
|
|
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
var origin = ClientGenerators.CreateBasicClient(server);
|
|
var target = ClientGenerators.CreateBasicClient(server);
|
|
|
|
target.Level = EFClient.Permission.Banned;
|
|
target.AliasLink = new EFAliasLink()
|
|
{
|
|
AliasLinkId = 1
|
|
};
|
|
|
|
await server.Unban("test reason", target, origin);
|
|
|
|
A.CallTo(() => fakePenaltyService.Create(A<EFPenalty>.Ignored))
|
|
.MustHaveHappened();
|
|
}
|
|
#endregion
|
|
|
|
[Test]
|
|
public async Task Test_ConnectionLostNotificationDisabled()
|
|
{
|
|
var server = serviceProvider.GetService<IW4MServer>();
|
|
var fakeConfigHandler = A.Fake<IConfigurationHandler<ApplicationConfiguration>>();
|
|
appConfig.IgnoreServerConnectionLost = true;
|
|
|
|
A.CallTo(() => fakeRConParser.GetStatusAsync(A<IRConConnection>.Ignored))
|
|
.ThrowsAsync(new NetworkException("err"));
|
|
|
|
// simulate failed connection attempts
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
await server.ProcessUpdatesAsync(new System.Threading.CancellationToken());
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task Test_ConnectionLostNotificationEnabled()
|
|
{
|
|
var server = serviceProvider.GetService<IW4MServer>();
|
|
var fakeConfigHandler = A.Fake<IConfigurationHandler<ApplicationConfiguration>>();
|
|
|
|
A.CallTo(() => fakeRConParser.GetStatusAsync(A<IRConConnection>.Ignored))
|
|
.ThrowsAsync(new NetworkException("err"));
|
|
|
|
// simulate failed connection attempts
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
await server.ProcessUpdatesAsync(new System.Threading.CancellationToken());
|
|
}
|
|
|
|
// execute the connection lost event
|
|
foreach(var e in mockEventHandler.Events.ToList())
|
|
{
|
|
await server.ExecuteEvent(e);
|
|
}
|
|
|
|
Assert.IsNotEmpty(mockEventHandler.Events.Where(_event => _event.Type == GameEvent.EventType.ConnectionLost));
|
|
Assert.AreEqual("err", (mockEventHandler.Events[0].Extra as NetworkException).Message);
|
|
}
|
|
}
|
|
}
|