Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: server is not started when game is save is locked #35

Merged
merged 2 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions BuddySave.UnitTests/Core/GamingSessionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,71 @@ public async Task Run_DoesNotStartTheServer_WhenLoadingSaveFails(
processProviderMock.Verify(x => x.Start(It.IsAny<ProcessStartInfo>()), Times.Never());
}

[Theory]
[InlineAutoMoqData(OrchestratorResult.SaveLocked)]
[InlineAutoMoqData(OrchestratorResult.Failed)]
public async Task Run_DoesNotStartTheServer_WhenGameSaveIsNotLoaded(
OrchestratorResult orchestratorResult,
[Frozen] Mock<ISharedSaveOrchestrator> sharedSaveOrchestratorMock,
[Frozen] Mock<IProcessProvider> processProviderMock,
GameSave gameSave,
Session session,
ServerParameters serverParameters,
GamingSession sut)
{
// Arrange
sharedSaveOrchestratorMock.Setup(x => x.Load(It.IsAny<GameSave>(), It.IsAny<Session>())).ReturnsAsync(orchestratorResult);

// Act
await sut.RunServerWithAutoSave(gameSave, session, serverParameters);

// Assert
processProviderMock.Verify(x => x.Start(It.IsAny<ProcessStartInfo>()), Times.Never());
}

[Theory]
[InlineAutoMoqData(OrchestratorResult.SaveLocked)]
[InlineAutoMoqData(OrchestratorResult.Failed)]
public async Task Run_DoesWaitForServerToStop_WhenGameSaveIsNotLoaded(
OrchestratorResult orchestratorResult,
[Frozen] Mock<ISharedSaveOrchestrator> sharedSaveOrchestratorMock,
[Frozen] Mock<IProcessProvider> processProviderMock,
GameSave gameSave,
Session session,
ServerParameters serverParameters,
GamingSession sut)
{
// Arrange
sharedSaveOrchestratorMock.Setup(x => x.Load(It.IsAny<GameSave>(), It.IsAny<Session>())).ReturnsAsync(orchestratorResult);

// Act
await sut.RunServerWithAutoSave(gameSave, session, serverParameters);

// Assert
processProviderMock.Verify(x => x.WaitForExitAsync(It.IsAny<Process>()), Times.Never());
}

[Theory]
[InlineAutoMoqData(OrchestratorResult.SaveLocked)]
[InlineAutoMoqData(OrchestratorResult.Failed)]
public async Task Run_DoesNotCallSave_WhenGameSaveIsNotLoaded(
OrchestratorResult orchestratorResult,
[Frozen] Mock<ISharedSaveOrchestrator> sharedSaveOrchestratorMock,
GameSave gameSave,
Session session,
ServerParameters serverParameters,
GamingSession sut)
{
// Arrange
sharedSaveOrchestratorMock.Setup(x => x.Load(It.IsAny<GameSave>(), It.IsAny<Session>())).ReturnsAsync(orchestratorResult);

// Act
await sut.RunServerWithAutoSave(gameSave, session, serverParameters);

// Assert
sharedSaveOrchestratorMock.Verify(x => x.Save(It.IsAny<GameSave>(), It.IsAny<Session>()), Times.Never());
}

[Theory]
[AutoMoqData]
public async Task Run_DoesNotSave_WhenStartingServerFails(
Expand All @@ -67,6 +132,9 @@ public async Task Run_DoesNotSave_WhenStartingServerFails(
GamingSession sut)
{
// Arrange
sharedSaveOrchestratorMock
.Setup(x => x.Load(It.IsAny<GameSave>(), It.IsAny<Session>()))
.ReturnsAsync(OrchestratorResult.Loaded);
processProviderMock.Setup(x => x.Start(It.IsAny<ProcessStartInfo>())).Throws(exception);

// Act
Expand All @@ -80,12 +148,18 @@ public async Task Run_DoesNotSave_WhenStartingServerFails(
[Theory]
[AutoMoqData]
public async Task Run_WaitsForServerStop_WhenServerStarts(
[Frozen] Mock<ISharedSaveOrchestrator> sharedSaveOrchestratorMock,
[Frozen] Mock<IProcessProvider> processProviderMock,
GameSave gameSave,
Session session,
ServerParameters serverParameters,
GamingSession sut)
{
// Arrange
sharedSaveOrchestratorMock
.Setup(x => x.Load(It.IsAny<GameSave>(), It.IsAny<Session>()))
.ReturnsAsync(OrchestratorResult.Loaded);

// Act
await sut.RunServerWithAutoSave(gameSave, session, serverParameters);

Expand All @@ -102,6 +176,11 @@ public async Task Run_Saves_WhenServerStops(
ServerParameters serverParameters,
GamingSession sut)
{
// Arrange
sharedSaveOrchestratorMock
.Setup(x => x.Load(It.IsAny<GameSave>(), It.IsAny<Session>()))
.ReturnsAsync(OrchestratorResult.Loaded);

// Act
await sut.RunServerWithAutoSave(gameSave, session, serverParameters);

Expand Down
68 changes: 68 additions & 0 deletions BuddySave.UnitTests/Core/SharedSaveOrchestratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,23 @@ public async Task Load_NotifyClient_When_GameSaveIsLocked(
lockManagerMock.Verify(x => x.CreateLock(It.IsAny<GameSave>(), It.IsAny<Session>()), 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<ILockManager> lockManagerMock,
SharedSaveOrchestrator sut)
{
// Arrange
lockManagerMock.Setup(x => x.LockExists(It.IsAny<GameSave>())).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(
Expand All @@ -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<ILockManager> lockManagerMock,
SharedSaveOrchestrator sut)
{
// Arrange
lockManagerMock.Setup(x => x.CreateLock(It.IsAny<GameSave>(), It.IsAny<Session>())).Throws<Exception>();

// Act
var result = await sut.Load(gameSave, session);

// Assert
Assert.Equal(OrchestratorResult.Failed, result);
}

[Theory, AutoMoqData]
public async Task Load_CallDeleteLock_When_DownloadThrowsException(
Expand All @@ -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<IGameSaveSyncManager> gameSaveSyncManagerMock,
SharedSaveOrchestrator sut)
{
// Arrange
gameSaveSyncManagerMock.Setup(x => x.DownloadSave(It.IsAny<GameSave>())).Throws<Exception>();

// Act
var result = await sut.Load(gameSave, session);

// Assert
Assert.Equal(OrchestratorResult.Failed, result);
}

[Theory, AutoMoqData]
public async Task Load_LogException_When_DownloadThrowsException(
Expand Down Expand Up @@ -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<ILockManager> lockManagerMock,
SharedSaveOrchestrator sut)
{
// Arrange
lockManagerMock.Setup(x => x.LockExists(It.IsAny<GameSave>(), It.IsAny<Session>())).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(
Expand Down
7 changes: 6 additions & 1 deletion BuddySave/Core/GamingSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion BuddySave/Core/ISharedSaveOrchestrator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace BuddySave.Core;

public interface ISharedSaveOrchestrator
{
Task Load(GameSave gameSave, Session session);
Task<OrchestratorResult> Load(GameSave gameSave, Session session);

Task Save(GameSave gameSave, Session session);
}
8 changes: 8 additions & 0 deletions BuddySave/Core/Models/OrchestratorResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace BuddySave.Core.Models;

public enum OrchestratorResult
{
Failed = 0,
Loaded,
SaveLocked
}
9 changes: 6 additions & 3 deletions BuddySave/Core/SharedSaveOrchestrator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,32 @@ public class SharedSaveOrchestrator(
IClientNotifier clientNotifier)
: ISharedSaveOrchestrator
{
public async Task Load(GameSave gameSave, Session session)
public async Task<OrchestratorResult> 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)
Expand Down
Loading