sharee.bike-App/SharedBusinessLogic.Tests/Model/Bikes/BikeInfoNS/BluetoothLock/Command/TestOpenCommand.cs
2024-04-09 12:53:23 +02:00

330 lines
12 KiB
C#

using System;
using System.Threading.Tasks;
using NSubstitute;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
using ShareeBike.Model.Connector;
using ShareeBike.Model.State;
using ShareeBike.Repository.Request;
using ShareeBike.Services.BluetoothLock;
using ShareeBike.Services.BluetoothLock.Tdo;
using static ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.OpenCommand;
using ShareeBike.Services.BluetoothLock.Exception;
using ShareeBike.Repository.Exception;
using Newtonsoft.Json;
using ShareeBike.Repository.Response;
using ShareeBike.ViewModel;
namespace SharedBusinessLogic.Tests.Model.Bikes.BikeInfoNS.BluetoothLock.Command
{
[TestFixture]
public class TestOpenCommand
{
/// <summary>
/// Use case: Open lock
/// </summary>
[Test]
public async Task TestOpen()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Closed);
locks[0].OpenAsync()
.Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Open)); // Return lock state indicating success
await InvokeAsync<TestOpenCommand>(
bike,
locks,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener, null);
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
listener.Received().ReportStep(Step.GetLockInfos);
listener.Received().ReportStep(Step.WaitStopPolling);
listener.Received().ReportStep(Step.UpdateLockingState);
await connector.Command.UpdateLockingStateAsync(bike);
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.Open));
}
[Test]
public void TestOpenOpenFailsOutOfReachException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Closed);
locks[0].OpenAsync()
.Returns<Task<LockitLockingState?>>(x => throw new OutOfReachException());
Assert.That(
async () => await InvokeAsync<TestOpenCommand>(
bike,
locks,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener, null),
Throws.InstanceOf<OutOfReachException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
await listener.ReportStateAsync(State.OutOfReachError, "Exception of type 'ShareeBike.Services.BluetoothLock.Exception.OutOfReachException' was thrown.");
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.UnknownDisconnected));
}
[Test]
public void TestOpenOpenFailsBoltStatusUnknownException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Closed);
locks[0].OpenAsync()
.Returns<Task<LockitLockingState?>>(x => throw new CouldntOpenBoldStatusIsUnknownException());
Assert.That(
async () => await InvokeAsync<TestOpenCommand>(
bike,
locks,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener, null),
Throws.InstanceOf<CouldntOpenBoldStatusIsUnknownException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
await listener.ReportStateAsync(State.CouldntOpenBoldStatusIsUnknownError, "Position of lock bolt is unknown. Lock could be closed or open. Please try again or contact customer support.");
listener.Received().ReportStep(Step.GetLockInfos);
listener.Received().ReportStep(Step.UpdateLockingState);
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.UnknownFromHardwareError));
}
[Test]
public void TestOpenOpenFailsCouldntOpenBoltBlockedException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Closed);
locks[0].OpenAsync()
.Returns<Task<LockitLockingState?>>(x => throw new CouldntOpenBoldIsBlockedException());
Assert.That(
async () => await InvokeAsync<TestOpenCommand>(bike, locks, () => true, (isConnected) => connector, listener, null),
Throws.InstanceOf<CouldntOpenBoldIsBlockedException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
await listener.ReportStateAsync(State.CouldntOpenBoldIsBlockedError, "Lock bolt is blocked. Make sure that no spoke presses against the lock bolt and try again.");
listener.Received().ReportStep(Step.GetLockInfos);
listener.Received().ReportStep(Step.UpdateLockingState);
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.UnknownFromHardwareError));
}
[Test]
public void TestOpenOpenFailsCouldntOpenInconsistentStateException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Closed);
locks[0].OpenAsync()
.Returns<Task<LockitLockingState?>>(x => throw new CouldntOpenInconsistentStateExecption(LockitLockingState.Closed.GetLockingState()));
Assert.That(
async () => await InvokeAsync<TestOpenCommand>(bike, locks, () => true, (isConnected) => connector, listener, null),
Throws.InstanceOf<CouldntOpenInconsistentStateExecption>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
await listener.ReportStateAsync(State.CouldntOpenInconsistentStateError, "Unexpected locking state \"Closed\" detected after sending open command. Please try again or contact customer support.");
listener.Received().ReportStep(Step.GetLockInfos);
listener.Received().ReportStep(Step.UpdateLockingState);
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.Closed));
}
[Test]
public void TestOpenOpenFailsException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
locks[0].OpenAsync()
.Returns<Task<LockitLockingState?>>(x => throw new Exception("Exception message."));
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Closed);
Assert.That(
async () => await InvokeAsync<TestOpenCommand>(bike, locks, () => true, (isConnected) => connector, listener, null),
Throws.InstanceOf<Exception>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
await listener.ReportStateAsync(State.GeneralOpenError, "Exception message.");
listener.Received().ReportStep(Step.GetLockInfos);
listener.Received().ReportStep(Step.UpdateLockingState);
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.UnknownDisconnected));
}
[Test]
public async Task TestOpenUpdateLockingStateFailsWebConnectFailure()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>()).Returns(x => throw new WebConnectFailureException("Context info.", new System.Exception("hoppla")));
await InvokeAsync<TestOpenCommand>(bike, locks, () => true, (isConnected) => connector, listener, null);
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
listener.Received().ReportStep(Step.GetLockInfos);
listener.Received().ReportStep(Step.WaitStopPolling);
listener.Received().ReportStep(Step.UpdateLockingState);
await listener.ReportStateAsync(State.WebConnectFailed, "Context info.");
});
}
[Test]
public async Task TestOpenUpdateLockingStateFailsInvalidResponse()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>()).Returns(x =>
throw new ReturnBikeException(JsonConvert.DeserializeObject<DoReturnResponse>(@"{ ""response_text"" : ""Some invalid data received!""}"), "Outer message."));
await InvokeAsync<TestOpenCommand>(bike, locks, () => true, (isConnected) => connector, listener, null);
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
listener.Received().ReportStep(Step.GetLockInfos);
listener.Received().ReportStep(Step.WaitStopPolling);
listener.Received().ReportStep(Step.UpdateLockingState);
await listener.ReportStateAsync(State.ResponseIsInvalid, "Outer message.");
});
}
[Test]
public async Task TestOpenUpdateLockingStateFails()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
locks[0].OpenAsync()
.Returns(LockitLockingState.Open); // Return lock state indicating success
connector.Command.UpdateLockingStateAsync(bike).Returns(x => throw new Exception("Exception message."));
await InvokeAsync<TestOpenCommand>(bike, locks, () => true, (isConnected) => connector, listener, null);
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
listener.Received().ReportStep(Step.GetLockInfos);
listener.Received().ReportStep(Step.WaitStopPolling);
listener.Received().ReportStep(Step.UpdateLockingState);
await connector.Command.UpdateLockingStateAsync(bike);
await listener.ReportStateAsync(State.BackendUpdateFailed, "Exception message.");
});
}
}
}