From 237382301bd930bbacec8eecce4d0f23db506911 Mon Sep 17 00:00:00 2001 From: SparrowBrain Date: Sat, 14 Sep 2024 22:03:38 +0300 Subject: [PATCH 1/7] Renamed GamingSession to ServerSession --- .../Core/GamingSessionTests.cs | 190 ------------------ .../Core/ServerSessionTests.cs | 190 ++++++++++++++++++ BuddySave/Configuration/IoC.cs | 2 +- .../{GamingSession.cs => ServerSession.cs} | 4 +- BuddySave/config.example.json | 4 + 5 files changed, 197 insertions(+), 193 deletions(-) delete mode 100644 BuddySave.UnitTests/Core/GamingSessionTests.cs create mode 100644 BuddySave.UnitTests/Core/ServerSessionTests.cs rename BuddySave/Core/{GamingSession.cs => ServerSession.cs} (96%) diff --git a/BuddySave.UnitTests/Core/GamingSessionTests.cs b/BuddySave.UnitTests/Core/GamingSessionTests.cs deleted file mode 100644 index 0d5a156..0000000 --- a/BuddySave.UnitTests/Core/GamingSessionTests.cs +++ /dev/null @@ -1,190 +0,0 @@ -using System; -using System.Diagnostics; -using System.Threading.Tasks; -using AutoFixture.Xunit2; -using BuddySave.Core; -using BuddySave.Core.Models; -using BuddySave.System; -using BuddySave.TestTools; -using Moq; -using Xunit; - -namespace BuddySave.UnitTests.Core; - -public class GamingSessionTests -{ - [Theory] - [InlineAutoMoqData((string)null)] - [InlineAutoMoqData("")] - public async Task Run_ThrowsException_WhenNoServerPathIsEmpty( - string serverPath, - GameSave gameSave, - Session session, - ServerParameters serverParameters, - GamingSession sut) - { - // Arrange - serverParameters.Path = serverPath; - - // Act - var act = new Func(() => sut.RunServerWithAutoSave(gameSave, session, serverParameters)); - - // Assert - await Assert.ThrowsAsync(act); - } - - [Theory] - [AutoMoqData] - public async Task Run_DoesNotStartTheServer_WhenLoadingSaveFails( - [Frozen] Mock sharedSaveOrchestratorMock, - [Frozen] Mock processProviderMock, - Exception exception, - GameSave gameSave, - Session session, - ServerParameters serverParameters, - GamingSession sut) - { - // Arrange - sharedSaveOrchestratorMock.Setup(x => x.Load(It.IsAny(), It.IsAny())).Throws(exception); - - // Act - var act = new Func(() => sut.RunServerWithAutoSave(gameSave, session, serverParameters)); - - // Assert - await Assert.ThrowsAnyAsync(act); - processProviderMock.Verify(x => x.Start(It.IsAny()), Times.Never()); - } - - [Theory] - [InlineAutoMoqData(OrchestratorResult.SaveLocked)] - [InlineAutoMoqData(OrchestratorResult.Failed)] - public async Task Run_DoesNotStartTheServer_WhenGameSaveIsNotLoaded( - OrchestratorResult orchestratorResult, - [Frozen] Mock sharedSaveOrchestratorMock, - [Frozen] Mock processProviderMock, - GameSave gameSave, - Session session, - ServerParameters serverParameters, - GamingSession sut) - { - // Arrange - sharedSaveOrchestratorMock.Setup(x => x.Load(It.IsAny(), It.IsAny())).ReturnsAsync(orchestratorResult); - - // Act - await sut.RunServerWithAutoSave(gameSave, session, serverParameters); - - // Assert - processProviderMock.Verify(x => x.Start(It.IsAny()), Times.Never()); - } - - [Theory] - [InlineAutoMoqData(OrchestratorResult.SaveLocked)] - [InlineAutoMoqData(OrchestratorResult.Failed)] - public async Task Run_DoesWaitForServerToStop_WhenGameSaveIsNotLoaded( - OrchestratorResult orchestratorResult, - [Frozen] Mock sharedSaveOrchestratorMock, - [Frozen] Mock processProviderMock, - GameSave gameSave, - Session session, - ServerParameters serverParameters, - GamingSession sut) - { - // Arrange - sharedSaveOrchestratorMock.Setup(x => x.Load(It.IsAny(), It.IsAny())).ReturnsAsync(orchestratorResult); - - // Act - await sut.RunServerWithAutoSave(gameSave, session, serverParameters); - - // Assert - processProviderMock.Verify(x => x.WaitForExitAsync(It.IsAny()), Times.Never()); - } - - [Theory] - [InlineAutoMoqData(OrchestratorResult.SaveLocked)] - [InlineAutoMoqData(OrchestratorResult.Failed)] - public async Task Run_DoesNotCallSave_WhenGameSaveIsNotLoaded( - OrchestratorResult orchestratorResult, - [Frozen] Mock sharedSaveOrchestratorMock, - GameSave gameSave, - Session session, - ServerParameters serverParameters, - GamingSession sut) - { - // Arrange - sharedSaveOrchestratorMock.Setup(x => x.Load(It.IsAny(), It.IsAny())).ReturnsAsync(orchestratorResult); - - // Act - await sut.RunServerWithAutoSave(gameSave, session, serverParameters); - - // Assert - sharedSaveOrchestratorMock.Verify(x => x.Save(It.IsAny(), It.IsAny()), Times.Never()); - } - - [Theory] - [AutoMoqData] - public async Task Run_DoesNotSave_WhenStartingServerFails( - [Frozen] Mock sharedSaveOrchestratorMock, - [Frozen] Mock processProviderMock, - Exception exception, - GameSave gameSave, - Session session, - ServerParameters serverParameters, - GamingSession sut) - { - // Arrange - sharedSaveOrchestratorMock - .Setup(x => x.Load(It.IsAny(), It.IsAny())) - .ReturnsAsync(OrchestratorResult.Loaded); - processProviderMock.Setup(x => x.Start(It.IsAny())).Throws(exception); - - // Act - var act = new Func(() => sut.RunServerWithAutoSave(gameSave, session, serverParameters)); - - // Assert - await Assert.ThrowsAnyAsync(act); - sharedSaveOrchestratorMock.Verify(x => x.Save(It.IsAny(), It.IsAny()), Times.Never()); - } - - [Theory] - [AutoMoqData] - public async Task Run_WaitsForServerStop_WhenServerStarts( - [Frozen] Mock sharedSaveOrchestratorMock, - [Frozen] Mock processProviderMock, - GameSave gameSave, - Session session, - ServerParameters serverParameters, - GamingSession sut) - { - // Arrange - sharedSaveOrchestratorMock - .Setup(x => x.Load(It.IsAny(), It.IsAny())) - .ReturnsAsync(OrchestratorResult.Loaded); - - // Act - await sut.RunServerWithAutoSave(gameSave, session, serverParameters); - - // Assert - processProviderMock.Verify(x => x.WaitForExitAsync(It.IsAny())); - } - - [Theory] - [AutoMoqData] - public async Task Run_Saves_WhenServerStops( - [Frozen] Mock sharedSaveOrchestratorMock, - GameSave gameSave, - Session session, - ServerParameters serverParameters, - GamingSession sut) - { - // Arrange - sharedSaveOrchestratorMock - .Setup(x => x.Load(It.IsAny(), It.IsAny())) - .ReturnsAsync(OrchestratorResult.Loaded); - - // Act - await sut.RunServerWithAutoSave(gameSave, session, serverParameters); - - // Assert - sharedSaveOrchestratorMock.Verify(x => x.Save(It.IsAny(), It.IsAny())); - } -} \ No newline at end of file diff --git a/BuddySave.UnitTests/Core/ServerSessionTests.cs b/BuddySave.UnitTests/Core/ServerSessionTests.cs new file mode 100644 index 0000000..e038181 --- /dev/null +++ b/BuddySave.UnitTests/Core/ServerSessionTests.cs @@ -0,0 +1,190 @@ +using AutoFixture.Xunit2; +using BuddySave.Core; +using BuddySave.Core.Models; +using BuddySave.System; +using BuddySave.TestTools; +using Moq; +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using Xunit; + +namespace BuddySave.UnitTests.Core; + +public class ServerSessionTests +{ + [Theory] + [InlineAutoMoqData((string)null)] + [InlineAutoMoqData("")] + public async Task Run_ThrowsException_WhenNoServerPathIsEmpty( + string serverPath, + GameSave gameSave, + Session session, + ServerParameters serverParameters, + ServerSession sut) + { + // Arrange + serverParameters.Path = serverPath; + + // Act + var act = new Func(() => sut.RunServerWithAutoSave(gameSave, session, serverParameters)); + + // Assert + await Assert.ThrowsAsync(act); + } + + [Theory] + [AutoMoqData] + public async Task Run_DoesNotStartTheServer_WhenLoadingSaveFails( + [Frozen] Mock sharedSaveOrchestratorMock, + [Frozen] Mock processProviderMock, + Exception exception, + GameSave gameSave, + Session session, + ServerParameters serverParameters, + ServerSession sut) + { + // Arrange + sharedSaveOrchestratorMock.Setup(x => x.Load(It.IsAny(), It.IsAny())).Throws(exception); + + // Act + var act = new Func(() => sut.RunServerWithAutoSave(gameSave, session, serverParameters)); + + // Assert + await Assert.ThrowsAnyAsync(act); + processProviderMock.Verify(x => x.Start(It.IsAny()), Times.Never()); + } + + [Theory] + [InlineAutoMoqData(OrchestratorResult.SaveLocked)] + [InlineAutoMoqData(OrchestratorResult.Failed)] + public async Task Run_DoesNotStartTheServer_WhenGameSaveIsNotLoaded( + OrchestratorResult orchestratorResult, + [Frozen] Mock sharedSaveOrchestratorMock, + [Frozen] Mock processProviderMock, + GameSave gameSave, + Session session, + ServerParameters serverParameters, + ServerSession sut) + { + // Arrange + sharedSaveOrchestratorMock.Setup(x => x.Load(It.IsAny(), It.IsAny())).ReturnsAsync(orchestratorResult); + + // Act + await sut.RunServerWithAutoSave(gameSave, session, serverParameters); + + // Assert + processProviderMock.Verify(x => x.Start(It.IsAny()), Times.Never()); + } + + [Theory] + [InlineAutoMoqData(OrchestratorResult.SaveLocked)] + [InlineAutoMoqData(OrchestratorResult.Failed)] + public async Task Run_DoesWaitForServerToStop_WhenGameSaveIsNotLoaded( + OrchestratorResult orchestratorResult, + [Frozen] Mock sharedSaveOrchestratorMock, + [Frozen] Mock processProviderMock, + GameSave gameSave, + Session session, + ServerParameters serverParameters, + ServerSession sut) + { + // Arrange + sharedSaveOrchestratorMock.Setup(x => x.Load(It.IsAny(), It.IsAny())).ReturnsAsync(orchestratorResult); + + // Act + await sut.RunServerWithAutoSave(gameSave, session, serverParameters); + + // Assert + processProviderMock.Verify(x => x.WaitForExitAsync(It.IsAny()), Times.Never()); + } + + [Theory] + [InlineAutoMoqData(OrchestratorResult.SaveLocked)] + [InlineAutoMoqData(OrchestratorResult.Failed)] + public async Task Run_DoesNotCallSave_WhenGameSaveIsNotLoaded( + OrchestratorResult orchestratorResult, + [Frozen] Mock sharedSaveOrchestratorMock, + GameSave gameSave, + Session session, + ServerParameters serverParameters, + ServerSession sut) + { + // Arrange + sharedSaveOrchestratorMock.Setup(x => x.Load(It.IsAny(), It.IsAny())).ReturnsAsync(orchestratorResult); + + // Act + await sut.RunServerWithAutoSave(gameSave, session, serverParameters); + + // Assert + sharedSaveOrchestratorMock.Verify(x => x.Save(It.IsAny(), It.IsAny()), Times.Never()); + } + + [Theory] + [AutoMoqData] + public async Task Run_DoesNotSave_WhenStartingServerFails( + [Frozen] Mock sharedSaveOrchestratorMock, + [Frozen] Mock processProviderMock, + Exception exception, + GameSave gameSave, + Session session, + ServerParameters serverParameters, + ServerSession sut) + { + // Arrange + sharedSaveOrchestratorMock + .Setup(x => x.Load(It.IsAny(), It.IsAny())) + .ReturnsAsync(OrchestratorResult.Loaded); + processProviderMock.Setup(x => x.Start(It.IsAny())).Throws(exception); + + // Act + var act = new Func(() => sut.RunServerWithAutoSave(gameSave, session, serverParameters)); + + // Assert + await Assert.ThrowsAnyAsync(act); + sharedSaveOrchestratorMock.Verify(x => x.Save(It.IsAny(), It.IsAny()), Times.Never()); + } + + [Theory] + [AutoMoqData] + public async Task Run_WaitsForServerStop_WhenServerStarts( + [Frozen] Mock sharedSaveOrchestratorMock, + [Frozen] Mock processProviderMock, + GameSave gameSave, + Session session, + ServerParameters serverParameters, + ServerSession sut) + { + // Arrange + sharedSaveOrchestratorMock + .Setup(x => x.Load(It.IsAny(), It.IsAny())) + .ReturnsAsync(OrchestratorResult.Loaded); + + // Act + await sut.RunServerWithAutoSave(gameSave, session, serverParameters); + + // Assert + processProviderMock.Verify(x => x.WaitForExitAsync(It.IsAny())); + } + + [Theory] + [AutoMoqData] + public async Task Run_Saves_WhenServerStops( + [Frozen] Mock sharedSaveOrchestratorMock, + GameSave gameSave, + Session session, + ServerParameters serverParameters, + ServerSession sut) + { + // Arrange + sharedSaveOrchestratorMock + .Setup(x => x.Load(It.IsAny(), It.IsAny())) + .ReturnsAsync(OrchestratorResult.Loaded); + + // Act + await sut.RunServerWithAutoSave(gameSave, session, serverParameters); + + // Assert + sharedSaveOrchestratorMock.Verify(x => x.Save(It.IsAny(), It.IsAny())); + } +} \ No newline at end of file diff --git a/BuddySave/Configuration/IoC.cs b/BuddySave/Configuration/IoC.cs index 99b44d4..2af50f1 100644 --- a/BuddySave/Configuration/IoC.cs +++ b/BuddySave/Configuration/IoC.cs @@ -36,7 +36,7 @@ public static ServiceProvider Setup() .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton() + .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() diff --git a/BuddySave/Core/GamingSession.cs b/BuddySave/Core/ServerSession.cs similarity index 96% rename from BuddySave/Core/GamingSession.cs rename to BuddySave/Core/ServerSession.cs index a93fc14..b68530c 100644 --- a/BuddySave/Core/GamingSession.cs +++ b/BuddySave/Core/ServerSession.cs @@ -5,8 +5,8 @@ namespace BuddySave.Core; -public class GamingSession( - ILogger logger, +public class ServerSession( + ILogger logger, ISharedSaveOrchestrator sharedSaveOrchestrator, IProcessProvider processProvider) : IGamingSession diff --git a/BuddySave/config.example.json b/BuddySave/config.example.json index ba0465d..63e6108 100644 --- a/BuddySave/config.example.json +++ b/BuddySave/config.example.json @@ -9,6 +9,10 @@ "Path": "C:\\Program Files\\Steam\\steamapps\\common\\Valheim dedicated server\\start_headless_server.bat", "Arguments": "" }, + "ClientParameters":{ + "Path": "steam://rungameid/892970//", + "Arguments": "+connect {0}:{1}" + },} "GameSave": { "GameName": "Valheim", "SaveName": "ServerWorld", From 17ef34f6d29249bd098e26cfd3b2e4ef6bd59ea6 Mon Sep 17 00:00:00 2001 From: SparrowBrain Date: Sat, 14 Sep 2024 23:33:05 +0300 Subject: [PATCH 2/7] Added client session --- .../Core/ClientSessionTests.cs | 57 ++++++++++++++++++ .../Core/GamingSessionTests.cs | 58 +++++++++++++++++++ .../Core/ServerSessionTests.cs | 2 +- BuddySave/App.cs | 4 +- BuddySave/Configuration/IoC.cs | 2 +- BuddySave/Core/ClientParameters.cs | 8 +++ BuddySave/Core/ClientSession.cs | 25 ++++++++ BuddySave/Core/GamingSession.cs | 22 +++++++ BuddySave/Core/IClientSession.cs | 8 +++ .../{IGamingSession.cs => IServerSession.cs} | 2 +- BuddySave/Core/ServerSession.cs | 2 +- BuddySave/config.example.json | 2 +- 12 files changed, 185 insertions(+), 7 deletions(-) create mode 100644 BuddySave.UnitTests/Core/ClientSessionTests.cs create mode 100644 BuddySave.UnitTests/Core/GamingSessionTests.cs create mode 100644 BuddySave/Core/ClientParameters.cs create mode 100644 BuddySave/Core/ClientSession.cs create mode 100644 BuddySave/Core/GamingSession.cs create mode 100644 BuddySave/Core/IClientSession.cs rename BuddySave/Core/{IGamingSession.cs => IServerSession.cs} (83%) diff --git a/BuddySave.UnitTests/Core/ClientSessionTests.cs b/BuddySave.UnitTests/Core/ClientSessionTests.cs new file mode 100644 index 0000000..5daf242 --- /dev/null +++ b/BuddySave.UnitTests/Core/ClientSessionTests.cs @@ -0,0 +1,57 @@ +using AutoFixture.Xunit2; +using BuddySave.Core.Models; +using BuddySave.System; +using BuddySave.TestTools; +using Moq; +using System; +using System.Diagnostics; +using BuddySave.Core; +using Xunit; + +namespace BuddySave.UnitTests.Core; + +public class ClientSessionTests +{ + [Theory] + [InlineAutoMoqData("")] + [InlineAutoMoqData((string)null)] + public void RunClient_ThrowsArgumentException_WhenClientPathIsNull( + string path, + Session session, + ClientParameters clientParameters, + ClientSession sut) + { + // Arrange + clientParameters.Path = path; + + // Act + var exception = Record.Exception(() => sut.RunClient(session, clientParameters)); + + // Assert + Assert.NotNull(exception); + Assert.IsType(exception); + Assert.Equal("No client path provided. Cannot start a client session.", exception.Message); + } + + [Theory] + [AutoMoqData] + public void RunClient_StartsClient( + [Frozen] Mock processProviderMock, + Session session, + ClientParameters clientParameters, + ClientSession sut) + { + // Arrange + var expectedArguments = $"+connect {session.Ip}:{session.Port}"; + + // Act + sut.RunClient(session, clientParameters); + + // Assert + processProviderMock.Verify( + x => x.Start(It.Is(x => + x.FileName == clientParameters.Path + && x.Arguments == expectedArguments)), + Times.Once()); + } +} \ No newline at end of file diff --git a/BuddySave.UnitTests/Core/GamingSessionTests.cs b/BuddySave.UnitTests/Core/GamingSessionTests.cs new file mode 100644 index 0000000..87b536e --- /dev/null +++ b/BuddySave.UnitTests/Core/GamingSessionTests.cs @@ -0,0 +1,58 @@ +using AutoFixture.Xunit2; +using BuddySave.Core; +using BuddySave.Core.Models; +using BuddySave.TestTools; +using Moq; +using System.Threading.Tasks; +using Xunit; + +namespace BuddySave.UnitTests.Core; + +public class GamingSessionTests +{ + [Theory] + [AutoMoqData] + public async Task Play_StartsClient_WhenLockExists( + [Frozen] Mock lockManagerMock, + [Frozen] Mock clientSessionMock, + GameSave gameSave, + Session ourSession, + Session lockSession, + ServerParameters serverParameters, + ClientParameters clientParameters, + GamingSession sut) + { + // Arrange + lockManagerMock.Setup(x => x.LockExists(gameSave)).Returns(true); + lockManagerMock.Setup(x => x.GetLockedSession(gameSave)).ReturnsAsync(lockSession); + + // Act + await sut.Play(gameSave, ourSession, serverParameters, clientParameters); + + // Assert + clientSessionMock.Verify(x => x.RunClient(lockSession, clientParameters), Times.Once()); + } + + [Theory] + [AutoMoqData] + public async Task Play_StartsServerAndClient_WhenLockDoesNotExist( + [Frozen] Mock lockManagerMock, + [Frozen] Mock clientSessionMock, + [Frozen] Mock serverSessionMock, + GameSave gameSave, + Session session, + ServerParameters serverParameters, + ClientParameters clientParameters, + GamingSession sut) + { + // Arrange + lockManagerMock.Setup(x => x.LockExists(gameSave)).Returns(false); + + // Act + await sut.Play(gameSave, session, serverParameters, clientParameters); + + // Assert + serverSessionMock.Verify(x => x.RunServerWithAutoSave(gameSave, session, serverParameters), Times.Once()); + clientSessionMock.Verify(x => x.RunClient(session, clientParameters), Times.Once()); + } +} \ No newline at end of file diff --git a/BuddySave.UnitTests/Core/ServerSessionTests.cs b/BuddySave.UnitTests/Core/ServerSessionTests.cs index e038181..8b24420 100644 --- a/BuddySave.UnitTests/Core/ServerSessionTests.cs +++ b/BuddySave.UnitTests/Core/ServerSessionTests.cs @@ -16,7 +16,7 @@ public class ServerSessionTests [Theory] [InlineAutoMoqData((string)null)] [InlineAutoMoqData("")] - public async Task Run_ThrowsException_WhenNoServerPathIsEmpty( + public async Task Run_ThrowsException_WhenServerPathIsEmpty( string serverPath, GameSave gameSave, Session session, diff --git a/BuddySave/App.cs b/BuddySave/App.cs index d7c46a6..4d296a3 100644 --- a/BuddySave/App.cs +++ b/BuddySave/App.cs @@ -7,7 +7,7 @@ namespace BuddySave; internal sealed class App( ISharedSaveOrchestrator sharedSaveOrchestrator, - IGamingSession gamingSession, + IServerSession serverSession, ILogger logger, IConfigurationLoader configurationLoader) { @@ -44,7 +44,7 @@ private async Task Run(GameSave gameSave, Session session, ServerParameters serv switch (input?.ToLowerInvariant()) { case "run": - await gamingSession.RunServerWithAutoSave(gameSave, session, serverParameters); + await serverSession.RunServerWithAutoSave(gameSave, session, serverParameters); break; case "load": diff --git a/BuddySave/Configuration/IoC.cs b/BuddySave/Configuration/IoC.cs index 2af50f1..2f7cf3f 100644 --- a/BuddySave/Configuration/IoC.cs +++ b/BuddySave/Configuration/IoC.cs @@ -36,7 +36,7 @@ public static ServiceProvider Setup() .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton() + .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() diff --git a/BuddySave/Core/ClientParameters.cs b/BuddySave/Core/ClientParameters.cs new file mode 100644 index 0000000..0ea10d3 --- /dev/null +++ b/BuddySave/Core/ClientParameters.cs @@ -0,0 +1,8 @@ +namespace BuddySave.Core; + +public class ClientParameters +{ + public string Path { get; set; } + + public string Arguments { get; set; } +} \ No newline at end of file diff --git a/BuddySave/Core/ClientSession.cs b/BuddySave/Core/ClientSession.cs new file mode 100644 index 0000000..762660a --- /dev/null +++ b/BuddySave/Core/ClientSession.cs @@ -0,0 +1,25 @@ +using System.Diagnostics; +using BuddySave.Core.Models; +using BuddySave.System; + +namespace BuddySave.Core; + +public class ClientSession(IProcessProvider processProvider) : IClientSession +{ + public void RunClient(Session session, ClientParameters clientParameters) + { + if (string.IsNullOrEmpty(clientParameters.Path)) + { + throw new ArgumentException("No client path provided. Cannot start a client session."); + } + + var arguments = $"+connect {session.Ip}:{session.Port}"; + var startInfo = new ProcessStartInfo + { + FileName = clientParameters.Path, + Arguments = arguments, + }; + + processProvider.Start(startInfo); + } +} \ No newline at end of file diff --git a/BuddySave/Core/GamingSession.cs b/BuddySave/Core/GamingSession.cs new file mode 100644 index 0000000..3ce2bde --- /dev/null +++ b/BuddySave/Core/GamingSession.cs @@ -0,0 +1,22 @@ +using BuddySave.Core.Models; + +namespace BuddySave.Core; + +public class GamingSession(ILockManager lockManager, IServerSession serverSession, IClientSession clientSession) +{ + public async Task Play(GameSave gameSave, Session session, ServerParameters serverParameters, ClientParameters clientParameters) + { + var lockExists = lockManager.LockExists(gameSave); + var sessionToConnectTo = lockExists ? await lockManager.GetLockedSession(gameSave) : session; + + var serverTask = Task.CompletedTask; + if (!lockExists) + { + serverTask = serverSession.RunServerWithAutoSave(gameSave, sessionToConnectTo, serverParameters); + } + + clientSession.RunClient(sessionToConnectTo, clientParameters); + + await serverTask; + } +} \ No newline at end of file diff --git a/BuddySave/Core/IClientSession.cs b/BuddySave/Core/IClientSession.cs new file mode 100644 index 0000000..c8f9151 --- /dev/null +++ b/BuddySave/Core/IClientSession.cs @@ -0,0 +1,8 @@ +using BuddySave.Core.Models; + +namespace BuddySave.Core; + +public interface IClientSession +{ + void RunClient(Session session, ClientParameters clientParameters); +} \ No newline at end of file diff --git a/BuddySave/Core/IGamingSession.cs b/BuddySave/Core/IServerSession.cs similarity index 83% rename from BuddySave/Core/IGamingSession.cs rename to BuddySave/Core/IServerSession.cs index 59a8793..64dd9be 100644 --- a/BuddySave/Core/IGamingSession.cs +++ b/BuddySave/Core/IServerSession.cs @@ -2,7 +2,7 @@ namespace BuddySave.Core; -public interface IGamingSession +public interface IServerSession { Task RunServerWithAutoSave(GameSave gameSave, Session session, ServerParameters serverParameters); } \ No newline at end of file diff --git a/BuddySave/Core/ServerSession.cs b/BuddySave/Core/ServerSession.cs index b68530c..2d9a740 100644 --- a/BuddySave/Core/ServerSession.cs +++ b/BuddySave/Core/ServerSession.cs @@ -9,7 +9,7 @@ public class ServerSession( ILogger logger, ISharedSaveOrchestrator sharedSaveOrchestrator, IProcessProvider processProvider) - : IGamingSession + : IServerSession { public async Task RunServerWithAutoSave(GameSave gameSave, Session session, ServerParameters serverParameters) { diff --git a/BuddySave/config.example.json b/BuddySave/config.example.json index 63e6108..a160c6e 100644 --- a/BuddySave/config.example.json +++ b/BuddySave/config.example.json @@ -12,7 +12,7 @@ "ClientParameters":{ "Path": "steam://rungameid/892970//", "Arguments": "+connect {0}:{1}" - },} + }, "GameSave": { "GameName": "Valheim", "SaveName": "ServerWorld", From c39737b35bfadf2705b3abd456efce1fbc8e507f Mon Sep 17 00:00:00 2001 From: SparrowBrain Date: Sun, 15 Sep 2024 00:06:56 +0300 Subject: [PATCH 3/7] Fixed client launch --- .../Core/ClientSessionTests.cs | 6 +- .../Core/GamingSessionTests.cs | 4 +- BuddySave/App.cs | 111 +++++++++--------- .../Configuration/BuddySaveConfiguration.cs | 13 +- .../Configuration/IBuddySaveConfiguration.cs | 13 +- BuddySave/Configuration/IoC.cs | 66 ++++++----- BuddySave/Core/ClientSession.cs | 12 +- BuddySave/Core/GamingSession.cs | 9 +- BuddySave/Core/IGamingSession.cs | 8 ++ 9 files changed, 136 insertions(+), 106 deletions(-) create mode 100644 BuddySave/Core/IGamingSession.cs diff --git a/BuddySave.UnitTests/Core/ClientSessionTests.cs b/BuddySave.UnitTests/Core/ClientSessionTests.cs index 5daf242..8642207 100644 --- a/BuddySave.UnitTests/Core/ClientSessionTests.cs +++ b/BuddySave.UnitTests/Core/ClientSessionTests.cs @@ -1,11 +1,11 @@ using AutoFixture.Xunit2; +using BuddySave.Core; using BuddySave.Core.Models; using BuddySave.System; using BuddySave.TestTools; using Moq; using System; using System.Diagnostics; -using BuddySave.Core; using Xunit; namespace BuddySave.UnitTests.Core; @@ -50,8 +50,8 @@ public void RunClient_StartsClient( // Assert processProviderMock.Verify( x => x.Start(It.Is(x => - x.FileName == clientParameters.Path - && x.Arguments == expectedArguments)), + x.FileName == $"{clientParameters.Path} {expectedArguments}" + && x.UseShellExecute == true)), Times.Once()); } } \ No newline at end of file diff --git a/BuddySave.UnitTests/Core/GamingSessionTests.cs b/BuddySave.UnitTests/Core/GamingSessionTests.cs index 87b536e..5d455c4 100644 --- a/BuddySave.UnitTests/Core/GamingSessionTests.cs +++ b/BuddySave.UnitTests/Core/GamingSessionTests.cs @@ -53,6 +53,8 @@ public async Task Play_StartsServerAndClient_WhenLockDoesNotExist( // Assert serverSessionMock.Verify(x => x.RunServerWithAutoSave(gameSave, session, serverParameters), Times.Once()); - clientSessionMock.Verify(x => x.RunClient(session, clientParameters), Times.Once()); + clientSessionMock.Verify( + x => x.RunClient(It.Is(s => s.Ip == "127.0.0.1" && s.Port == session.Port), clientParameters), + Times.Once()); } } \ No newline at end of file diff --git a/BuddySave/App.cs b/BuddySave/App.cs index 4d296a3..4c5bfa7 100644 --- a/BuddySave/App.cs +++ b/BuddySave/App.cs @@ -6,58 +6,63 @@ namespace BuddySave; internal sealed class App( - ISharedSaveOrchestrator sharedSaveOrchestrator, - IServerSession serverSession, - ILogger logger, - IConfigurationLoader configurationLoader) + ISharedSaveOrchestrator sharedSaveOrchestrator, + IServerSession serverSession, + IGamingSession gamingSession, + ILogger logger, + IConfigurationLoader configurationLoader) { - public async Task Start() - { - logger.LogInformation("Start"); - Console.WriteLine("∞∞∞∞∞∞∞ Buddy Save ∞∞∞∞∞∞∞"); - - try - { - var configuration = await configurationLoader.Load(); - await Run(configuration.GameSave, configuration.Session, configuration.ServerParameters); - } - catch (Exception ex) - { - logger.LogError(ex, "Failed to start main App."); - } - - Console.WriteLine("Bye Buddy! ;)"); - Console.WriteLine("Press any key to exit..."); - Console.ReadKey(); - Console.WriteLine(); - logger.LogInformation("Exit"); - } - - private async Task Run(GameSave gameSave, Session session, ServerParameters serverParameters) - { - var input = string.Empty; - while (!string.Equals(input, "exit", StringComparison.OrdinalIgnoreCase)) - { - Console.WriteLine("Waiting for action command (run, load, save, exit):"); - input = Console.ReadLine(); - - switch (input?.ToLowerInvariant()) - { - case "run": - await serverSession.RunServerWithAutoSave(gameSave, session, serverParameters); - break; - - case "load": - await sharedSaveOrchestrator.Load(gameSave, session); - break; - - case "save": - await sharedSaveOrchestrator.Save(gameSave, session); - break; - - case "exit": - break; - } - } - } + public async Task Start() + { + logger.LogInformation("Start"); + Console.WriteLine("∞∞∞∞∞∞∞ Buddy Save ∞∞∞∞∞∞∞"); + + try + { + var configuration = await configurationLoader.Load(); + await Run(configuration.GameSave, configuration.Session, configuration.ServerParameters, configuration.ClientParameters); + } + catch (Exception ex) + { + logger.LogError(ex, "Failed to start main App."); + } + + Console.WriteLine("Bye Buddy! ;)"); + Console.WriteLine("Press any key to exit..."); + Console.ReadKey(); + Console.WriteLine(); + logger.LogInformation("Exit"); + } + + private async Task Run(GameSave gameSave, Session session, ServerParameters serverParameters, ClientParameters clientParameters) + { + var input = string.Empty; + while (!string.Equals(input, "exit", StringComparison.OrdinalIgnoreCase)) + { + Console.WriteLine("Waiting for action command (play, run, load, save, exit):"); + input = Console.ReadLine(); + + switch (input?.ToLowerInvariant()) + { + case "play": + await gamingSession.Play(gameSave, session, serverParameters, clientParameters); + break; + + case "run": + await serverSession.RunServerWithAutoSave(gameSave, session, serverParameters); + break; + + case "load": + await sharedSaveOrchestrator.Load(gameSave, session); + break; + + case "save": + await sharedSaveOrchestrator.Save(gameSave, session); + break; + + case "exit": + break; + } + } + } } \ No newline at end of file diff --git a/BuddySave/Configuration/BuddySaveConfiguration.cs b/BuddySave/Configuration/BuddySaveConfiguration.cs index b7184e5..155b5af 100644 --- a/BuddySave/Configuration/BuddySaveConfiguration.cs +++ b/BuddySave/Configuration/BuddySaveConfiguration.cs @@ -1,14 +1,17 @@ -using BuddySave.Core.Models; +using BuddySave.Core; +using BuddySave.Core.Models; namespace BuddySave.Configuration; public class BuddySaveConfiguration : IBuddySaveConfiguration { - public string CloudPath { get; set; } + public string CloudPath { get; set; } - public Session Session { get; set; } + public Session Session { get; set; } - public ServerParameters ServerParameters { get; set; } + public ServerParameters ServerParameters { get; set; } - public GameSave GameSave { get; set; } + public ClientParameters ClientParameters { get; set; } + + public GameSave GameSave { get; set; } } \ No newline at end of file diff --git a/BuddySave/Configuration/IBuddySaveConfiguration.cs b/BuddySave/Configuration/IBuddySaveConfiguration.cs index b015f33..4dcc12b 100644 --- a/BuddySave/Configuration/IBuddySaveConfiguration.cs +++ b/BuddySave/Configuration/IBuddySaveConfiguration.cs @@ -1,14 +1,17 @@ -using BuddySave.Core.Models; +using BuddySave.Core; +using BuddySave.Core.Models; namespace BuddySave.Configuration; public interface IBuddySaveConfiguration { - public string CloudPath { get; } + string CloudPath { get; set; } - public Session Session { get; } + Session Session { get; } - ServerParameters ServerParameters { get; set; } + ServerParameters ServerParameters { get; set; } - public GameSave GameSave { get; } + ClientParameters ClientParameters { get; set; } + + GameSave GameSave { get; } } \ No newline at end of file diff --git a/BuddySave/Configuration/IoC.cs b/BuddySave/Configuration/IoC.cs index 2f7cf3f..ce84e4f 100644 --- a/BuddySave/Configuration/IoC.cs +++ b/BuddySave/Configuration/IoC.cs @@ -11,37 +11,39 @@ namespace BuddySave.Configuration; public static class IoC { - public static ServiceProvider Setup() - { - var config = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) - .Build(); - - var serviceProvider = new ServiceCollection() - .AddTransient() - .AddLogging(loggingBuilder => - { - loggingBuilder.ClearProviders(); - loggingBuilder.SetMinimumLevel(LogLevel.Debug); - loggingBuilder.AddNLog(config); - }) - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .BuildServiceProvider(); + public static ServiceProvider Setup() + { + var config = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .Build(); - return serviceProvider; - } + var serviceProvider = new ServiceCollection() + .AddTransient() + .AddLogging(loggingBuilder => + { + loggingBuilder.ClearProviders(); + loggingBuilder.SetMinimumLevel(LogLevel.Debug); + loggingBuilder.AddNLog(config); + }) + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .BuildServiceProvider(); + + return serviceProvider; + } } \ No newline at end of file diff --git a/BuddySave/Core/ClientSession.cs b/BuddySave/Core/ClientSession.cs index 762660a..b4bd7de 100644 --- a/BuddySave/Core/ClientSession.cs +++ b/BuddySave/Core/ClientSession.cs @@ -1,10 +1,11 @@ -using System.Diagnostics; -using BuddySave.Core.Models; +using BuddySave.Core.Models; using BuddySave.System; +using Microsoft.Extensions.Logging; +using System.Diagnostics; namespace BuddySave.Core; -public class ClientSession(IProcessProvider processProvider) : IClientSession +public class ClientSession(IProcessProvider processProvider, ILogger logger) : IClientSession { public void RunClient(Session session, ClientParameters clientParameters) { @@ -16,10 +17,11 @@ public void RunClient(Session session, ClientParameters clientParameters) var arguments = $"+connect {session.Ip}:{session.Port}"; var startInfo = new ProcessStartInfo { - FileName = clientParameters.Path, - Arguments = arguments, + FileName = $"{clientParameters.Path} {arguments}", + UseShellExecute = true }; processProvider.Start(startInfo); + logger.LogInformation($@"Client started: ""{clientParameters.Path} {arguments}"""); } } \ No newline at end of file diff --git a/BuddySave/Core/GamingSession.cs b/BuddySave/Core/GamingSession.cs index 3ce2bde..732b506 100644 --- a/BuddySave/Core/GamingSession.cs +++ b/BuddySave/Core/GamingSession.cs @@ -2,12 +2,12 @@ namespace BuddySave.Core; -public class GamingSession(ILockManager lockManager, IServerSession serverSession, IClientSession clientSession) +public class GamingSession(ILockManager lockManager, IServerSession serverSession, IClientSession clientSession) : IGamingSession { public async Task Play(GameSave gameSave, Session session, ServerParameters serverParameters, ClientParameters clientParameters) { var lockExists = lockManager.LockExists(gameSave); - var sessionToConnectTo = lockExists ? await lockManager.GetLockedSession(gameSave) : session; + var sessionToConnectTo = lockExists ? await lockManager.GetLockedSession(gameSave) : GetLocalSession(session); var serverTask = Task.CompletedTask; if (!lockExists) @@ -19,4 +19,9 @@ public async Task Play(GameSave gameSave, Session session, ServerParameters serv await serverTask; } + + private static Session GetLocalSession(Session session) + { + return new Session(session.UserName, "127.0.0.1", session.Port); + } } \ No newline at end of file diff --git a/BuddySave/Core/IGamingSession.cs b/BuddySave/Core/IGamingSession.cs new file mode 100644 index 0000000..6b40ec4 --- /dev/null +++ b/BuddySave/Core/IGamingSession.cs @@ -0,0 +1,8 @@ +using BuddySave.Core.Models; + +namespace BuddySave.Core; + +public interface IGamingSession +{ + Task Play(GameSave gameSave, Session session, ServerParameters serverParameters, ClientParameters clientParameters); +} \ No newline at end of file From c03c2b6e1696b736a7b74eae90af01b7632da766 Mon Sep 17 00:00:00 2001 From: SparrowBrain Date: Sun, 15 Sep 2024 00:47:58 +0300 Subject: [PATCH 4/7] Fixed session used for server --- BuddySave/Core/GamingSession.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BuddySave/Core/GamingSession.cs b/BuddySave/Core/GamingSession.cs index 732b506..5fecd3a 100644 --- a/BuddySave/Core/GamingSession.cs +++ b/BuddySave/Core/GamingSession.cs @@ -12,7 +12,7 @@ public async Task Play(GameSave gameSave, Session session, ServerParameters serv var serverTask = Task.CompletedTask; if (!lockExists) { - serverTask = serverSession.RunServerWithAutoSave(gameSave, sessionToConnectTo, serverParameters); + serverTask = serverSession.RunServerWithAutoSave(gameSave, session, serverParameters); } clientSession.RunClient(sessionToConnectTo, clientParameters); From f7aeab619b3be604e12c73726dcdaa4dc99d436b Mon Sep 17 00:00:00 2001 From: SparrowBrain Date: Sun, 15 Sep 2024 15:16:57 +0300 Subject: [PATCH 5/7] Fixed client arguments not being read from config --- BuddySave.UnitTests/Core/ClientSessionTests.cs | 9 +++++---- BuddySave.UnitTests/Core/GamingSessionTests.cs | 4 ++-- BuddySave/Core/ClientSession.cs | 4 ++-- BuddySave/Core/GamingSession.cs | 2 +- BuddySave/Core/IClientSession.cs | 2 +- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/BuddySave.UnitTests/Core/ClientSessionTests.cs b/BuddySave.UnitTests/Core/ClientSessionTests.cs index 8642207..a9564fb 100644 --- a/BuddySave.UnitTests/Core/ClientSessionTests.cs +++ b/BuddySave.UnitTests/Core/ClientSessionTests.cs @@ -15,7 +15,7 @@ public class ClientSessionTests [Theory] [InlineAutoMoqData("")] [InlineAutoMoqData((string)null)] - public void RunClient_ThrowsArgumentException_WhenClientPathIsNull( + public void StartClient_ThrowsArgumentException_WhenClientPathIsNull( string path, Session session, ClientParameters clientParameters, @@ -25,7 +25,7 @@ public void RunClient_ThrowsArgumentException_WhenClientPathIsNull( clientParameters.Path = path; // Act - var exception = Record.Exception(() => sut.RunClient(session, clientParameters)); + var exception = Record.Exception(() => sut.StartClient(session, clientParameters)); // Assert Assert.NotNull(exception); @@ -35,17 +35,18 @@ public void RunClient_ThrowsArgumentException_WhenClientPathIsNull( [Theory] [AutoMoqData] - public void RunClient_StartsClient( + public void StartClient_StartsClient( [Frozen] Mock processProviderMock, Session session, ClientParameters clientParameters, ClientSession sut) { // Arrange + clientParameters.Arguments = "+connect {{Ip}}:{{Port}}"; var expectedArguments = $"+connect {session.Ip}:{session.Port}"; // Act - sut.RunClient(session, clientParameters); + sut.StartClient(session, clientParameters); // Assert processProviderMock.Verify( diff --git a/BuddySave.UnitTests/Core/GamingSessionTests.cs b/BuddySave.UnitTests/Core/GamingSessionTests.cs index 5d455c4..f1314a5 100644 --- a/BuddySave.UnitTests/Core/GamingSessionTests.cs +++ b/BuddySave.UnitTests/Core/GamingSessionTests.cs @@ -30,7 +30,7 @@ public async Task Play_StartsClient_WhenLockExists( await sut.Play(gameSave, ourSession, serverParameters, clientParameters); // Assert - clientSessionMock.Verify(x => x.RunClient(lockSession, clientParameters), Times.Once()); + clientSessionMock.Verify(x => x.StartClient(lockSession, clientParameters), Times.Once()); } [Theory] @@ -54,7 +54,7 @@ public async Task Play_StartsServerAndClient_WhenLockDoesNotExist( // Assert serverSessionMock.Verify(x => x.RunServerWithAutoSave(gameSave, session, serverParameters), Times.Once()); clientSessionMock.Verify( - x => x.RunClient(It.Is(s => s.Ip == "127.0.0.1" && s.Port == session.Port), clientParameters), + x => x.StartClient(It.Is(s => s.Ip == "127.0.0.1" && s.Port == session.Port), clientParameters), Times.Once()); } } \ No newline at end of file diff --git a/BuddySave/Core/ClientSession.cs b/BuddySave/Core/ClientSession.cs index b4bd7de..1d68c80 100644 --- a/BuddySave/Core/ClientSession.cs +++ b/BuddySave/Core/ClientSession.cs @@ -7,14 +7,14 @@ namespace BuddySave.Core; public class ClientSession(IProcessProvider processProvider, ILogger logger) : IClientSession { - public void RunClient(Session session, ClientParameters clientParameters) + public void StartClient(Session session, ClientParameters clientParameters) { if (string.IsNullOrEmpty(clientParameters.Path)) { throw new ArgumentException("No client path provided. Cannot start a client session."); } - var arguments = $"+connect {session.Ip}:{session.Port}"; + var arguments = clientParameters.Arguments.Replace("{{Ip}}", session.Ip).Replace("{{Port}}", session.Port); var startInfo = new ProcessStartInfo { FileName = $"{clientParameters.Path} {arguments}", diff --git a/BuddySave/Core/GamingSession.cs b/BuddySave/Core/GamingSession.cs index 5fecd3a..0ccaf98 100644 --- a/BuddySave/Core/GamingSession.cs +++ b/BuddySave/Core/GamingSession.cs @@ -15,7 +15,7 @@ public async Task Play(GameSave gameSave, Session session, ServerParameters serv serverTask = serverSession.RunServerWithAutoSave(gameSave, session, serverParameters); } - clientSession.RunClient(sessionToConnectTo, clientParameters); + clientSession.StartClient(sessionToConnectTo, clientParameters); await serverTask; } diff --git a/BuddySave/Core/IClientSession.cs b/BuddySave/Core/IClientSession.cs index c8f9151..83915d3 100644 --- a/BuddySave/Core/IClientSession.cs +++ b/BuddySave/Core/IClientSession.cs @@ -4,5 +4,5 @@ namespace BuddySave.Core; public interface IClientSession { - void RunClient(Session session, ClientParameters clientParameters); + void StartClient(Session session, ClientParameters clientParameters); } \ No newline at end of file From 4296c3137ff72819b82f5b1c97d591118f00dd6f Mon Sep 17 00:00:00 2001 From: SparrowBrain Date: Sun, 15 Sep 2024 16:18:40 +0300 Subject: [PATCH 6/7] Fixed config example --- BuddySave/config.example.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BuddySave/config.example.json b/BuddySave/config.example.json index a160c6e..a6a907f 100644 --- a/BuddySave/config.example.json +++ b/BuddySave/config.example.json @@ -11,7 +11,7 @@ }, "ClientParameters":{ "Path": "steam://rungameid/892970//", - "Arguments": "+connect {0}:{1}" + "Arguments": "+connect {{Ip}}:{{Port}}" }, "GameSave": { "GameName": "Valheim", From b193ce9a25635d09f75bcf8cc71f18f6c49050d3 Mon Sep 17 00:00:00 2001 From: SparrowBrain Date: Mon, 16 Sep 2024 22:02:43 +0300 Subject: [PATCH 7/7] PR fixes --- .../Core/ClientSessionTests.cs | 21 +++++++++++++++++++ .../Core/GamingSessionTests.cs | 4 ++++ BuddySave/Core/ClientSession.cs | 5 +++++ BuddySave/Core/GamingSession.cs | 10 +++++---- 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/BuddySave.UnitTests/Core/ClientSessionTests.cs b/BuddySave.UnitTests/Core/ClientSessionTests.cs index a9564fb..f8c87ce 100644 --- a/BuddySave.UnitTests/Core/ClientSessionTests.cs +++ b/BuddySave.UnitTests/Core/ClientSessionTests.cs @@ -33,6 +33,27 @@ public void StartClient_ThrowsArgumentException_WhenClientPathIsNull( Assert.Equal("No client path provided. Cannot start a client session.", exception.Message); } + [Theory] + [InlineAutoMoqData("")] + [InlineAutoMoqData((string)null)] + public void StartClient_ThrowsArgumentException_WhenClientArgumentsIsNull( + string arguments, + Session session, + ClientParameters clientParameters, + ClientSession sut) + { + // Arrange + clientParameters.Arguments = arguments; + + // Act + var exception = Record.Exception(() => sut.StartClient(session, clientParameters)); + + // Assert + Assert.NotNull(exception); + Assert.IsType(exception); + Assert.Equal("No launch arguments provided for client. Cannot start a client session.", exception.Message); + } + [Theory] [AutoMoqData] public void StartClient_StartsClient( diff --git a/BuddySave.UnitTests/Core/GamingSessionTests.cs b/BuddySave.UnitTests/Core/GamingSessionTests.cs index f1314a5..0d3bd0f 100644 --- a/BuddySave.UnitTests/Core/GamingSessionTests.cs +++ b/BuddySave.UnitTests/Core/GamingSessionTests.cs @@ -15,6 +15,7 @@ public class GamingSessionTests public async Task Play_StartsClient_WhenLockExists( [Frozen] Mock lockManagerMock, [Frozen] Mock clientSessionMock, + [Frozen] Mock serverSessionMock, GameSave gameSave, Session ourSession, Session lockSession, @@ -31,6 +32,9 @@ public async Task Play_StartsClient_WhenLockExists( // Assert clientSessionMock.Verify(x => x.StartClient(lockSession, clientParameters), Times.Once()); + serverSessionMock.Verify( + x => x.RunServerWithAutoSave(It.IsAny(), It.IsAny(), It.IsAny()), + Times.Never); } [Theory] diff --git a/BuddySave/Core/ClientSession.cs b/BuddySave/Core/ClientSession.cs index 1d68c80..454f5dd 100644 --- a/BuddySave/Core/ClientSession.cs +++ b/BuddySave/Core/ClientSession.cs @@ -14,6 +14,11 @@ public void StartClient(Session session, ClientParameters clientParameters) throw new ArgumentException("No client path provided. Cannot start a client session."); } + if(string.IsNullOrEmpty(clientParameters.Arguments)) + { + throw new ArgumentException("No launch arguments provided for client. Cannot start a client session."); + } + var arguments = clientParameters.Arguments.Replace("{{Ip}}", session.Ip).Replace("{{Port}}", session.Port); var startInfo = new ProcessStartInfo { diff --git a/BuddySave/Core/GamingSession.cs b/BuddySave/Core/GamingSession.cs index 0ccaf98..356b6d5 100644 --- a/BuddySave/Core/GamingSession.cs +++ b/BuddySave/Core/GamingSession.cs @@ -4,24 +4,26 @@ namespace BuddySave.Core; public class GamingSession(ILockManager lockManager, IServerSession serverSession, IClientSession clientSession) : IGamingSession { + private const string LocalhostIp = "127.0.0.1"; + public async Task Play(GameSave gameSave, Session session, ServerParameters serverParameters, ClientParameters clientParameters) { var lockExists = lockManager.LockExists(gameSave); var sessionToConnectTo = lockExists ? await lockManager.GetLockedSession(gameSave) : GetLocalSession(session); - var serverTask = Task.CompletedTask; + var runServerWithAutoSave = Task.CompletedTask; if (!lockExists) { - serverTask = serverSession.RunServerWithAutoSave(gameSave, session, serverParameters); + runServerWithAutoSave = serverSession.RunServerWithAutoSave(gameSave, session, serverParameters); } clientSession.StartClient(sessionToConnectTo, clientParameters); - await serverTask; + await runServerWithAutoSave; } private static Session GetLocalSession(Session session) { - return new Session(session.UserName, "127.0.0.1", session.Port); + return new Session(session.UserName, LocalhostIp, session.Port); } } \ No newline at end of file