diff --git a/BuddySave.UnitTests/Core/GamingSessionTests.cs b/BuddySave.UnitTests/Core/GamingSessionTests.cs index 11bcb77..0d5a156 100644 --- a/BuddySave.UnitTests/Core/GamingSessionTests.cs +++ b/BuddySave.UnitTests/Core/GamingSessionTests.cs @@ -55,6 +55,71 @@ public async Task Run_DoesNotStartTheServer_WhenLoadingSaveFails( 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( @@ -67,6 +132,9 @@ public async Task Run_DoesNotSave_WhenStartingServerFails( 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 @@ -80,12 +148,18 @@ public async Task Run_DoesNotSave_WhenStartingServerFails( [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); @@ -102,6 +176,11 @@ public async Task Run_Saves_WhenServerStops( ServerParameters serverParameters, GamingSession sut) { + // Arrange + sharedSaveOrchestratorMock + .Setup(x => x.Load(It.IsAny(), It.IsAny())) + .ReturnsAsync(OrchestratorResult.Loaded); + // Act await sut.RunServerWithAutoSave(gameSave, session, serverParameters); diff --git a/BuddySave.UnitTests/Core/SharedSaveOrchestratorTests.cs b/BuddySave.UnitTests/Core/SharedSaveOrchestratorTests.cs index 4f26cbf..914601d 100644 --- a/BuddySave.UnitTests/Core/SharedSaveOrchestratorTests.cs +++ b/BuddySave.UnitTests/Core/SharedSaveOrchestratorTests.cs @@ -33,6 +33,23 @@ public async Task Load_NotifyClient_When_GameSaveIsLocked( lockManagerMock.Verify(x => x.CreateLock(It.IsAny(), It.IsAny()), Times.Never); gameSaveSyncManagerMock.Verify(x => x.DownloadSave(gameSave), Times.Never); } + + [Theory, AutoMoqData] + public async Task Load_ReturnSaveLockedResult_When_GameSaveIsLocked( + GameSave gameSave, + Session session, + [Frozen] Mock lockManagerMock, + SharedSaveOrchestrator sut) + { + // Arrange + lockManagerMock.Setup(x => x.LockExists(It.IsAny())).Returns(true); + + // Act + var result = await sut.Load(gameSave, session); + + // Assert + Assert.Equal(OrchestratorResult.SaveLocked, result); + } [Theory, AutoMoqData] public async Task Load_CallDeleteLock_When_CreateLockThrowsException( @@ -53,6 +70,23 @@ public async Task Load_CallDeleteLock_When_CreateLockThrowsException( clientNotifierMock.Verify(x => x.Notify("Failed loading game save. Deleting game save lock..."), Times.Once); clientNotifierMock.Verify(x => x.Notify("Game save lock released."), Times.Once); } + + [Theory, AutoMoqData] + public async Task Load_ReturnFailedResult_When_CreateLockThrowsException( + GameSave gameSave, + Session session, + [Frozen] Mock lockManagerMock, + SharedSaveOrchestrator sut) + { + // Arrange + lockManagerMock.Setup(x => x.CreateLock(It.IsAny(), It.IsAny())).Throws(); + + // Act + var result = await sut.Load(gameSave, session); + + // Assert + Assert.Equal(OrchestratorResult.Failed, result); + } [Theory, AutoMoqData] public async Task Load_CallDeleteLock_When_DownloadThrowsException( @@ -74,6 +108,23 @@ public async Task Load_CallDeleteLock_When_DownloadThrowsException( clientNotifierMock.Verify(x => x.Notify("Failed loading game save. Deleting game save lock..."), Times.Once); clientNotifierMock.Verify(x => x.Notify("Game save lock released."), Times.Once); } + + [Theory, AutoMoqData] + public async Task Load_ReturnFailedResult_When_DownloadThrowsException( + GameSave gameSave, + Session session, + [Frozen] Mock gameSaveSyncManagerMock, + SharedSaveOrchestrator sut) + { + // Arrange + gameSaveSyncManagerMock.Setup(x => x.DownloadSave(It.IsAny())).Throws(); + + // Act + var result = await sut.Load(gameSave, session); + + // Assert + Assert.Equal(OrchestratorResult.Failed, result); + } [Theory, AutoMoqData] public async Task Load_LogException_When_DownloadThrowsException( @@ -137,6 +188,23 @@ public async Task Load_DownloadCloudSave_When_GameIsNotLocked( gameSaveSyncManagerMock.Verify(x => x.DownloadSave(gameSave), Times.Once); clientNotifierMock.Verify(x => x.Notify("Game save is prepared! Enjoy Buddy :)"), Times.Once); } + + [Theory, AutoMoqData] + public async Task Load_ReturnLoadedResult_When_LoadIsSuccessful( + GameSave gameSave, + Session session, + [Frozen] Mock lockManagerMock, + SharedSaveOrchestrator sut) + { + // Arrange + lockManagerMock.Setup(x => x.LockExists(It.IsAny(), It.IsAny())).ReturnsAsync(false); + + // Act + var result = await sut.Load(gameSave, session); + + // Assert + Assert.Equal(OrchestratorResult.Loaded, result); + } [Theory, AutoMoqData] public async Task Save_NotifyClient_When_LockFileDoesNotExist( diff --git a/BuddySave/Core/GamingSession.cs b/BuddySave/Core/GamingSession.cs index f7dd374..a93fc14 100644 --- a/BuddySave/Core/GamingSession.cs +++ b/BuddySave/Core/GamingSession.cs @@ -18,7 +18,12 @@ public async Task RunServerWithAutoSave(GameSave gameSave, Session session, Serv throw new ArgumentException("No server path provided. Cannot start a gaming session."); } - await sharedSaveOrchestrator.Load(gameSave, session); + var loadResult = await sharedSaveOrchestrator.Load(gameSave, session); + if (loadResult is not OrchestratorResult.Loaded) + { + return; + } + var process = StartServer(serverParameters); await WaitForServerToStop(process); await sharedSaveOrchestrator.Save(gameSave, session); diff --git a/BuddySave/Core/ISharedSaveOrchestrator.cs b/BuddySave/Core/ISharedSaveOrchestrator.cs index af154c4..e8809d7 100644 --- a/BuddySave/Core/ISharedSaveOrchestrator.cs +++ b/BuddySave/Core/ISharedSaveOrchestrator.cs @@ -4,7 +4,7 @@ namespace BuddySave.Core; public interface ISharedSaveOrchestrator { - Task Load(GameSave gameSave, Session session); + Task Load(GameSave gameSave, Session session); Task Save(GameSave gameSave, Session session); } \ No newline at end of file diff --git a/BuddySave/Core/Models/OrchestratorResult.cs b/BuddySave/Core/Models/OrchestratorResult.cs new file mode 100644 index 0000000..4cd59f7 --- /dev/null +++ b/BuddySave/Core/Models/OrchestratorResult.cs @@ -0,0 +1,8 @@ +namespace BuddySave.Core.Models; + +public enum OrchestratorResult +{ + Failed = 0, + Loaded, + SaveLocked +} \ No newline at end of file diff --git a/BuddySave/Core/SharedSaveOrchestrator.cs b/BuddySave/Core/SharedSaveOrchestrator.cs index 242eb77..8bdfd4b 100644 --- a/BuddySave/Core/SharedSaveOrchestrator.cs +++ b/BuddySave/Core/SharedSaveOrchestrator.cs @@ -11,29 +11,32 @@ public class SharedSaveOrchestrator( IClientNotifier clientNotifier) : ISharedSaveOrchestrator { - public async Task Load(GameSave gameSave, Session session) + public async Task Load(GameSave gameSave, Session session) { + OrchestratorResult result; if (lockManager.LockExists(gameSave)) { clientNotifier.Notify("Game save is locked, your friends are playing!"); - return; + return OrchestratorResult.SaveLocked; } try { await lockManager.CreateLock(gameSave, session); gameSaveSyncManager.DownloadSave(gameSave); + result = OrchestratorResult.Loaded; } catch (Exception ex) { + result = OrchestratorResult.Failed; logger.LogError(ex, "Error while loading."); clientNotifier.Notify("Failed loading game save. Deleting game save lock..."); await lockManager.DeleteLock(gameSave, session); clientNotifier.Notify("Game save lock released."); - return; } clientNotifier.Notify("Game save is prepared! Enjoy Buddy :)"); + return result; } public async Task Save(GameSave gameSave, Session session)