mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2024-10-06 13:26:28 +02:00
470 lines
17 KiB
C#
470 lines
17 KiB
C#
|
using System;
|
||
|
using System.Threading;
|
||
|
using System.Threading.Tasks;
|
||
|
using NSubstitute;
|
||
|
using NUnit.Framework;
|
||
|
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||
|
using ShareeBike.Services.BluetoothLock;
|
||
|
using ShareeBike.Services.Geolocation;
|
||
|
using ShareeBike.Repository.Request;
|
||
|
using ShareeBike.Model.Connector;
|
||
|
using static ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.EndRentalCommand;
|
||
|
using ShareeBike.Model;
|
||
|
using ShareeBike.Repository.Exception;
|
||
|
using ShareeBike.Model.State;
|
||
|
|
||
|
namespace SharedBusinessLogic.Tests.Model.Bikes.BikeInfoNS.BikeNS.Command
|
||
|
{
|
||
|
[TestFixture]
|
||
|
public class TestEndRentalCommand
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Use case: End rental.
|
||
|
/// Final state: Rental ended successfully
|
||
|
/// </summary>
|
||
|
[Test]
|
||
|
[Ignore("bike.State.Value should be FeedbackPending")]
|
||
|
public async Task TestReturnClosingLockLocationAvailable()
|
||
|
{
|
||
|
var bike = Substitute.For<IBikeInfoMutable>();
|
||
|
var geolocation = Substitute.For<IGeolocationService>();
|
||
|
var locks = Substitute.For<ILocksService>();
|
||
|
static DateTime dateTime() => DateTime.MinValue;
|
||
|
var connector = Substitute.For<IConnector>();
|
||
|
var listener = Substitute.For<IEndRentalCommandListener>();
|
||
|
|
||
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
||
|
|
||
|
var closingLockLocation = Substitute.For<IGeolocation>();
|
||
|
closingLockLocation.Latitude.Returns(7);
|
||
|
closingLockLocation.Longitude.Returns(9);
|
||
|
closingLockLocation.Timestamp.Returns(DateTimeOffset.MinValue);
|
||
|
|
||
|
bike.LockInfo.Location.Returns((IGeolocation)closingLockLocation); // When locking bike geolocation was available.
|
||
|
|
||
|
var endRentalLocation = closingLockLocation;
|
||
|
|
||
|
var bookingFinished = connector.Command.DoReturn(bike, Arg.Is<LocationDto>(x => x.Latitude == 7 && x.Longitude == 9));
|
||
|
|
||
|
await InvokeAsync<TestEndRentalCommand>(
|
||
|
bike,
|
||
|
geolocation,
|
||
|
locks,
|
||
|
dateTime,
|
||
|
() => true, // isConnectedDelegate
|
||
|
(isConnected) => connector,
|
||
|
listener);
|
||
|
|
||
|
// Verify behavior
|
||
|
Received.InOrder(async () =>
|
||
|
{
|
||
|
listener.ReportStep(Step.GetLocation);
|
||
|
var location = bike.LockInfo.Location;
|
||
|
|
||
|
listener.ReportStep(Step.ReturnBike);
|
||
|
var bookingFinished = await connector.Command.DoReturn(bike, Arg.Is<LocationDto>(x => x.Latitude == 7 && x.Longitude == 9));
|
||
|
});
|
||
|
|
||
|
Assert.That(bookingFinished, Is.Not.Null);
|
||
|
Assert.That(bike.State.Value, Is.EqualTo(InUseStateEnum.FeedbackPending));
|
||
|
}
|
||
|
|
||
|
// <summary>
|
||
|
// Use case: End rental.
|
||
|
// Final state: Rental ended successfully
|
||
|
// </summary>
|
||
|
[Test]
|
||
|
[Ignore("bike.State.Value should be FeedbackPending")]
|
||
|
public async Task TestReturnLastGeolocationNullLockInReach()
|
||
|
{
|
||
|
var bike = Substitute.For<IBikeInfoMutable>();
|
||
|
var geolocation = Substitute.For<IGeolocationService>();
|
||
|
var locks = Substitute.For<ILocksService>();
|
||
|
static DateTime dateTime() => DateTime.MinValue;
|
||
|
var connector = Substitute.For<IConnector>();
|
||
|
var listener = Substitute.For<IEndRentalCommandListener>();
|
||
|
|
||
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
||
|
|
||
|
bike.LockInfo.Location.Returns((IGeolocation)null); // Simulate that when locking bike geolocation was not available
|
||
|
|
||
|
var newLockLocation = Substitute.For<IGeolocation>(); // Get geolocation from end rental
|
||
|
newLockLocation.Latitude.Returns(7);
|
||
|
newLockLocation.Longitude.Returns(9);
|
||
|
newLockLocation.Timestamp.Returns(DateTimeOffset.MinValue);
|
||
|
var endRentalLocation = geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
|
||
|
.Returns(Task.FromResult(newLockLocation));
|
||
|
|
||
|
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach.
|
||
|
|
||
|
await InvokeAsync<TestEndRentalCommand>(
|
||
|
bike,
|
||
|
geolocation,
|
||
|
locks,
|
||
|
dateTime,
|
||
|
() => true, // isConnectedDelegate
|
||
|
(isConnected) => connector,
|
||
|
listener);
|
||
|
|
||
|
var bookingFinished = connector.Command.DoReturn(bike, Arg.Is<LocationDto>(x => x.Latitude == 7 && x.Longitude == 9));
|
||
|
|
||
|
// Verify behavior
|
||
|
Received.InOrder(async () =>
|
||
|
{
|
||
|
listener.ReportStep(Step.GetLocation);
|
||
|
var location = bike.LockInfo.Location;
|
||
|
locks[0].GetDeviceState();
|
||
|
var endRentalLocation = await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
|
||
|
|
||
|
listener.ReportStep(Step.ReturnBike);
|
||
|
var bookingFinished = await connector.Command.DoReturn(bike, Arg.Is<LocationDto>(x => x.Latitude == 7 && x.Longitude == 9));
|
||
|
});
|
||
|
|
||
|
Assert.That(bookingFinished, Is.Not.Null);
|
||
|
Assert.That(bike.State.Value, Is.EqualTo(InUseStateEnum.FeedbackPending));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Use case: End rental.
|
||
|
/// Final state: Still rented.
|
||
|
/// </summary>
|
||
|
[Test]
|
||
|
public async Task TestReturnLastGeolocatonNullLockOutOfReachNoGPSDataDoNotReturn()
|
||
|
{
|
||
|
var bike = Substitute.For<IBikeInfoMutable>();
|
||
|
var geolocation = Substitute.For<IGeolocationService>();
|
||
|
var locks = Substitute.For<ILocksService>();
|
||
|
static DateTime dateTime() => DateTime.MinValue;
|
||
|
var connector = Substitute.For<IConnector>();
|
||
|
var listener = Substitute.For<IEndRentalCommandListener>();
|
||
|
|
||
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
||
|
|
||
|
bike.LockInfo.Location.Returns((IGeolocation)null); // When locking bike geolocation was not available.
|
||
|
|
||
|
locks[0].GetDeviceState().Returns(DeviceState.Disconnected); // Simulate bike not in reach.
|
||
|
|
||
|
await InvokeAsync<TestEndRentalCommand>(
|
||
|
bike,
|
||
|
geolocation,
|
||
|
locks,
|
||
|
dateTime,
|
||
|
() => true, // isConnectedDelegate
|
||
|
(isConnected) => connector,
|
||
|
listener);
|
||
|
|
||
|
var task = connector.Command.DidNotReceive().DoReturn(Arg.Any<IBikeInfoMutable>(), Arg.Any<LocationDto>());
|
||
|
|
||
|
// Verify behavior
|
||
|
Received.InOrder(async () =>
|
||
|
{
|
||
|
listener.ReportStep(Step.GetLocation);
|
||
|
var location = bike.LockInfo.Location;
|
||
|
locks[0].GetDeviceState();
|
||
|
await listener.ReportStateAsync(State.NoGPSData, "There is no geolocation information available since lock is not connected");
|
||
|
});
|
||
|
|
||
|
Assert.That(bike.State.Value, Is.EqualTo(InUseStateEnum.Booked));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Use case: End rental.
|
||
|
/// Final state: Still rented.
|
||
|
/// </summary>
|
||
|
[Test]
|
||
|
public void TestReturnLastGeolocatonNullLockInReachGetGeolocationException()
|
||
|
{
|
||
|
var bike = Substitute.For<IBikeInfoMutable>();
|
||
|
var geolocation = Substitute.For<IGeolocationService>();
|
||
|
var locks = Substitute.For<ILocksService>();
|
||
|
static DateTime dateTime() => DateTime.MinValue;
|
||
|
var connector = Substitute.For<IConnector>();
|
||
|
var listener = Substitute.For<IEndRentalCommandListener>();
|
||
|
|
||
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
||
|
|
||
|
bike.LockInfo.Location.Returns((IGeolocation)null); // When locking bike geolocation was not available.
|
||
|
|
||
|
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach.
|
||
|
|
||
|
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
|
||
|
.Returns<Task<IGeolocation>>(x => throw new Exception("Ups...")); // Simulate error query for geolocation.
|
||
|
|
||
|
Assert.That(
|
||
|
async () => await InvokeAsync<TestEndRentalCommand>(
|
||
|
bike,
|
||
|
geolocation,
|
||
|
locks,
|
||
|
dateTime,
|
||
|
() => true, // isConnectedDelegate
|
||
|
(isConnected) => connector,
|
||
|
listener),
|
||
|
Throws.InstanceOf<Exception>());
|
||
|
|
||
|
connector.Command.DidNotReceive().DoReturn(Arg.Any<IBikeInfoMutable>(), Arg.Any<LocationDto>());
|
||
|
|
||
|
// Verify behavior
|
||
|
Received.InOrder(async () =>
|
||
|
{
|
||
|
listener.ReportStep(Step.GetLocation);
|
||
|
var location = bike.LockInfo.Location;
|
||
|
locks[0].GetDeviceState();
|
||
|
var endRentalLocation = await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
|
||
|
await listener.ReportStateAsync(State.GeneralQueryLocationFailed, "Ups...");
|
||
|
});
|
||
|
|
||
|
Assert.That(bike.State.Value, Is.EqualTo(InUseStateEnum.Booked));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Use case: End rental.
|
||
|
/// Final state: Still rented.
|
||
|
/// </summary>
|
||
|
[Test]
|
||
|
[Ignore("bookingFinished should be null")]
|
||
|
public void TestReturnLastGeolocatonNullReturnException()
|
||
|
{
|
||
|
var bike = Substitute.For<IBikeInfoMutable>();
|
||
|
var geolocation = Substitute.For<IGeolocationService>();
|
||
|
var locks = Substitute.For<ILocksService>();
|
||
|
static DateTime dateTime() => DateTime.MinValue;
|
||
|
var connector = Substitute.For<IConnector>();
|
||
|
var listener = Substitute.For<IEndRentalCommandListener>();
|
||
|
|
||
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
||
|
|
||
|
bike.LockInfo.Location.Returns((IGeolocation)null); // When locking bike geolocation was not available.
|
||
|
|
||
|
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach.
|
||
|
|
||
|
var newLockLocation = Substitute.For<IGeolocation>(); // Get geolocation from end rental
|
||
|
newLockLocation.Latitude.Returns(7);
|
||
|
newLockLocation.Longitude.Returns(9);
|
||
|
newLockLocation.Timestamp.Returns(DateTimeOffset.MinValue);
|
||
|
var endRentalLocation = geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
|
||
|
.Returns(Task.FromResult(newLockLocation));
|
||
|
|
||
|
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
|
||
|
.Returns(Task.FromResult(newLockLocation));
|
||
|
|
||
|
var bookingFinished = connector.Command.DoReturn(Arg.Any<IBikeInfoMutable>(), Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x =>
|
||
|
throw new Exception("Ups..."));
|
||
|
|
||
|
Assert.That(
|
||
|
async () => await InvokeAsync<TestEndRentalCommand>(
|
||
|
bike,
|
||
|
geolocation,
|
||
|
locks,
|
||
|
dateTime,
|
||
|
() => true, // isConnectedDelegate
|
||
|
(isConnected) => connector,
|
||
|
listener),
|
||
|
Throws.InstanceOf<Exception>());
|
||
|
|
||
|
// Verify behavior
|
||
|
Received.InOrder(async () =>
|
||
|
{
|
||
|
listener.ReportStep(Step.GetLocation);
|
||
|
var location = bike.LockInfo.Location;
|
||
|
locks[0].GetDeviceState();
|
||
|
var endRentalLocation = await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
|
||
|
|
||
|
listener.ReportStep(Step.ReturnBike);
|
||
|
var bookingFinished = await connector.Command.DoReturn(bike, Arg.Is<LocationDto>(x => x.Latitude == 7 && x.Longitude == 9));
|
||
|
await listener.ReportStateAsync(State.GeneralEndRentalError, "Ups...");
|
||
|
});
|
||
|
|
||
|
Assert.That(bookingFinished, Is.Null);
|
||
|
Assert.That(bike.State.Value, Is.EqualTo(InUseStateEnum.Booked));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Use case: End rental.
|
||
|
/// Final state: Still rented.
|
||
|
/// </summary>
|
||
|
[Test]
|
||
|
[Ignore("bookingFinished should be null")]
|
||
|
public void TestReturnReturnNoWebException()
|
||
|
{
|
||
|
var bike = Substitute.For<IBikeInfoMutable>();
|
||
|
var geolocation = Substitute.For<IGeolocationService>();
|
||
|
var locks = Substitute.For<ILocksService>();
|
||
|
static DateTime dateTime() => DateTime.MinValue;
|
||
|
var connector = Substitute.For<IConnector>();
|
||
|
var listener = Substitute.For<IEndRentalCommandListener>();
|
||
|
|
||
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
||
|
|
||
|
bike.LockInfo.Location.Returns((IGeolocation)null); // When locking bike geolocation was not available.
|
||
|
|
||
|
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach.
|
||
|
|
||
|
var newLockLocation = Substitute.For<IGeolocation>(); // Get geolocation from end rental
|
||
|
newLockLocation.Latitude.Returns(7);
|
||
|
newLockLocation.Longitude.Returns(9);
|
||
|
newLockLocation.Timestamp.Returns(DateTimeOffset.MinValue);
|
||
|
var endRentalLocation = geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
|
||
|
.Returns(Task.FromResult(newLockLocation));
|
||
|
|
||
|
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
|
||
|
.Returns(Task.FromResult(newLockLocation));
|
||
|
|
||
|
var bookingFinished = connector.Command.DoReturn(Arg.Any<IBikeInfoMutable>(), Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x
|
||
|
=> throw new WebConnectFailureException("Context info.", new System.Exception("hoppla")));
|
||
|
|
||
|
Assert.That(
|
||
|
async () => await InvokeAsync<TestEndRentalCommand>(
|
||
|
bike,
|
||
|
geolocation,
|
||
|
locks,
|
||
|
dateTime,
|
||
|
() => false, // isConnectedDelegate
|
||
|
(isConnected) => connector,
|
||
|
listener),
|
||
|
Throws.InstanceOf<WebConnectFailureException>());
|
||
|
|
||
|
// Verify behavior
|
||
|
Received.InOrder(async () =>
|
||
|
{
|
||
|
listener.ReportStep(Step.GetLocation);
|
||
|
var location = bike.LockInfo.Location;
|
||
|
locks[0].GetDeviceState();
|
||
|
var endRentalLocation = await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
|
||
|
|
||
|
listener.ReportStep(Step.ReturnBike);
|
||
|
var bookingFinished = await connector.Command.DoReturn(bike, Arg.Is<LocationDto>(x => x.Latitude == 7 && x.Longitude == 9));
|
||
|
await listener.ReportStateAsync(State.WebConnectFailed, "Context info.");
|
||
|
});
|
||
|
|
||
|
Assert.That(bookingFinished, Is.Null);
|
||
|
Assert.That(bike.State.Value, Is.EqualTo(InUseStateEnum.Booked));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Use case: End rental.
|
||
|
/// Final state: Still rented.
|
||
|
/// </summary>
|
||
|
[Test]
|
||
|
[Ignore("Exception needs to be initialized correctly. bookingFinished should be null")]
|
||
|
public void TestReturnNotAtStationException()
|
||
|
{
|
||
|
var bike = Substitute.For<IBikeInfoMutable>();
|
||
|
var geolocation = Substitute.For<IGeolocationService>();
|
||
|
var locks = Substitute.For<ILocksService>();
|
||
|
static DateTime dateTime() => DateTime.MinValue;
|
||
|
var connector = Substitute.For<IConnector>();
|
||
|
var listener = Substitute.For<IEndRentalCommandListener>();
|
||
|
|
||
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
||
|
bike.Id.Returns("1545");
|
||
|
|
||
|
bike.LockInfo.Location.Returns((IGeolocation)null); // When locking bike geolocation was not available.
|
||
|
|
||
|
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach.
|
||
|
|
||
|
var newLockLocation = Substitute.For<IGeolocation>(); // Get geolocation from end rental
|
||
|
newLockLocation.Latitude.Returns(7);
|
||
|
newLockLocation.Longitude.Returns(9);
|
||
|
newLockLocation.Timestamp.Returns(DateTimeOffset.MinValue);
|
||
|
var endRentalLocation = geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
|
||
|
.Returns(Task.FromResult(newLockLocation));
|
||
|
|
||
|
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
|
||
|
.Returns(Task.FromResult(newLockLocation));
|
||
|
|
||
|
NotAtStationException.IsNotAtStation("Failure 2178: bike 1545 out of GEO fencing. 15986 meter distance to next station 42. OK: bike 1545 locked confirmed", out NotAtStationException notAtStationException);
|
||
|
notAtStationException.Distance.Returns(15986);
|
||
|
notAtStationException.StationNr.Returns("42");
|
||
|
|
||
|
var bookingFinished = connector.Command.DoReturn(Arg.Any<IBikeInfoMutable>(), Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x
|
||
|
=> throw notAtStationException);
|
||
|
|
||
|
Assert.That(
|
||
|
async () => await InvokeAsync<TestEndRentalCommand>(
|
||
|
bike,
|
||
|
geolocation,
|
||
|
locks,
|
||
|
dateTime,
|
||
|
() => true, // isConnectedDelegate
|
||
|
(isConnected) => connector,
|
||
|
listener),
|
||
|
Throws.InstanceOf<NotAtStationException>());
|
||
|
|
||
|
// Verify behavior
|
||
|
Received.InOrder(async () =>
|
||
|
{
|
||
|
listener.ReportStep(Step.GetLocation);
|
||
|
var location = bike.LockInfo.Location;
|
||
|
locks[0].GetDeviceState();
|
||
|
var endRentalLocation = await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
|
||
|
|
||
|
listener.ReportStep(Step.ReturnBike);
|
||
|
var bookingFinished = await connector.Command.DoReturn(bike, Arg.Is<LocationDto>(x => x.Latitude == 7 && x.Longitude == 9));
|
||
|
await listener.ReportStateAsync(State.NotAtStation, "End rental outside or at unsuitable station is not possible. Distance to next suitable station 42 is 15986 m.\r\n\r\nNote: Your GPS data may not be up to date. So if you are at a suitable station, please simply try again so that your location is queried again.");
|
||
|
});
|
||
|
|
||
|
Assert.That(bookingFinished, Is.Null);
|
||
|
Assert.That(bike.State.Value, Is.EqualTo(InUseStateEnum.Booked));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Use case: End rental.
|
||
|
/// Final state: Still rented.
|
||
|
/// </summary>
|
||
|
[Test]
|
||
|
[Ignore("Exception needs to be initialized correctly. bookingFinished should be null")]
|
||
|
public void TestReturnNoGPSDataException()
|
||
|
{
|
||
|
var bike = Substitute.For<IBikeInfoMutable>();
|
||
|
var geolocation = Substitute.For<IGeolocationService>();
|
||
|
var locks = Substitute.For<ILocksService>();
|
||
|
static DateTime dateTime() => DateTime.MinValue;
|
||
|
var connector = Substitute.For<IConnector>();
|
||
|
var listener = Substitute.For<IEndRentalCommandListener>();
|
||
|
|
||
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
||
|
|
||
|
bike.LockInfo.Location.Returns((IGeolocation)null); // When locking bike geolocation was not available.
|
||
|
|
||
|
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach.
|
||
|
|
||
|
var endRentalLocation = geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
|
||
|
.Returns((IGeolocation)null);
|
||
|
|
||
|
NoGPSDataException.IsNoGPSData("Failure 2245: No GPS data, state change forbidden.", out NoGPSDataException noGPSDataException);
|
||
|
|
||
|
var bookingFinished = connector.Command.DoReturn(Arg.Any<IBikeInfoMutable>(), Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x =>
|
||
|
throw noGPSDataException);
|
||
|
|
||
|
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
||
|
|
||
|
Assert.That(
|
||
|
async () => await InvokeAsync<TestEndRentalCommand>(
|
||
|
bike,
|
||
|
geolocation,
|
||
|
locks,
|
||
|
dateTime,
|
||
|
() => true, // isConnectedDelegate
|
||
|
(isConnected) => connector,
|
||
|
listener),
|
||
|
Throws.InstanceOf<NoGPSDataException>());
|
||
|
|
||
|
// Verify behavior
|
||
|
Received.InOrder(async () =>
|
||
|
{
|
||
|
listener.ReportStep(Step.GetLocation);
|
||
|
var location = bike.LockInfo.Location;
|
||
|
locks[0].GetDeviceState();
|
||
|
var endRentalLocation = await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
|
||
|
|
||
|
listener.ReportStep(Step.ReturnBike);
|
||
|
var bookingFinished = await connector.Command.DoReturn(bike, null);
|
||
|
await listener.ReportStateAsync(State.NoGPSData, "Failure 2245: No GPS data, state change forbidden.");
|
||
|
});
|
||
|
|
||
|
Assert.That(bookingFinished, Is.Null);
|
||
|
Assert.That(bike.State.Value, Is.EqualTo(InUseStateEnum.Booked));
|
||
|
}
|
||
|
}
|
||
|
}
|