Skip to content

Commit

Permalink
Move create return home to starting mission
Browse files Browse the repository at this point in the history
  • Loading branch information
andchiind committed Jan 17, 2025
1 parent 0775a4b commit ece90bc
Show file tree
Hide file tree
Showing 10 changed files with 197 additions and 240 deletions.
43 changes: 0 additions & 43 deletions backend/api.test/EventHandlers/TestMissionEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,49 +192,6 @@ public async Task NewMissionIsStartedWhenRobotBecomesAvailable()
Assert.Equal(MissionStatus.Ongoing, postTestMissionRun!.Status);
}

[Fact]
public async Task ReturnToHomeMissionIsStartedIfQueueIsEmptyWhenRobotBecomesAvailable()
{
// Arrange
var installation = await DatabaseUtilities.NewInstallation();
var plant = await DatabaseUtilities.NewPlant(installation.InstallationCode);
var inspectionArea = await DatabaseUtilities.NewInspectionArea(
installation.InstallationCode,
plant.PlantCode
);
var robot = await DatabaseUtilities.NewRobot(
RobotStatus.Busy,
installation,
inspectionArea
);

var mqttEventArgs = new MqttReceivedArgs(
new IsarStatusMessage
{
RobotName = robot.Name,
IsarId = robot.IsarId,
Status = RobotStatus.Available,
Timestamp = DateTime.UtcNow,
}
);

// Act
MqttService.RaiseEvent(nameof(MqttService.MqttIsarStatusReceived), mqttEventArgs);

// Assert
Thread.Sleep(1000);
var ongoingMission = await MissionRunService.ReadAll(
new MissionRunQueryStringParameters
{
Statuses = [MissionStatus.Ongoing],
OrderBy = "DesiredStartTime",
PageSize = 100,
},
readOnly: true
);
Assert.True(ongoingMission.Any());
}

[Fact]
public async Task ReturnToHomeMissionIsNotStartedIfReturnToHomeIsNotSupported()
{
Expand Down
36 changes: 1 addition & 35 deletions backend/api.test/Services/MissionRunService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Api.Controllers.Models;
using Api.Database.Models;
Expand Down Expand Up @@ -37,40 +38,5 @@ public async Task CheckThatReadByIdWithUnknownIdFails()
var missionRun = await MissionRunService.ReadById("IDoNotExist", readOnly: true);
Assert.Null(missionRun);
}

[Fact]
public async Task CheckThatNumberOfMissionRunReportsIncreaseByOneWhenNewMissionRunIsCreated()
{
// Arrange
var installation = await DatabaseUtilities.NewInstallation();
var plant = await DatabaseUtilities.NewPlant(installation.InstallationCode);
var inspectionArea = await DatabaseUtilities.NewInspectionArea(
installation.InstallationCode,
plant.PlantCode
);
var robot = await DatabaseUtilities.NewRobot(RobotStatus.Available, installation);
var missionRun = await DatabaseUtilities.NewMissionRun(
installation.InstallationCode,
robot,
inspectionArea
);

var reportsBefore = await MissionRunService.ReadAll(
new MissionRunQueryStringParameters(),
readOnly: true
);
int nReportsBefore = reportsBefore.Count;

// Act
await MissionRunService.Create(missionRun);

// Assert
var reportsAfter = await MissionRunService.ReadAll(
new MissionRunQueryStringParameters()
);
int nReportsAfter = reportsAfter.Count;

Assert.Equal(nReportsBefore + 1, nReportsAfter);
}
}
}
76 changes: 76 additions & 0 deletions backend/api.test/Services/MissionSchedulingService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Api.Controllers.Models;
using Api.Database.Models;
using Api.Services;
using Api.Test.Database;
using Microsoft.Extensions.DependencyInjection;
using Xunit;

namespace Api.Test.Services
{
public class MissionSchedulingServiceTest : IAsyncLifetime
{
public required DatabaseUtilities DatabaseUtilities;
public required IMissionSchedulingService MissionSchedulingService;

public required IMissionRunService MissionRunService;

public async Task InitializeAsync()
{
string databaseName = Guid.NewGuid().ToString();
(string connectionString, var connection) = await TestSetupHelpers.ConfigureDatabase(
databaseName
);
var factory = TestSetupHelpers.ConfigureWebApplicationFactory(databaseName);
var serviceProvider = TestSetupHelpers.ConfigureServiceProvider(factory);

DatabaseUtilities = new DatabaseUtilities(
TestSetupHelpers.ConfigureFlotillaDbContext(connectionString)
);
MissionSchedulingService =
serviceProvider.GetRequiredService<IMissionSchedulingService>();
MissionRunService = serviceProvider.GetRequiredService<IMissionRunService>();
}

public Task DisposeAsync() => Task.CompletedTask;

[Fact]
public async Task CheckThatReturnHomeIsCreatedWhenRunningMission()
{
// Arrange
var installation = await DatabaseUtilities.NewInstallation();
var plant = await DatabaseUtilities.NewPlant(installation.InstallationCode);
var inspectionArea = await DatabaseUtilities.NewInspectionArea(
installation.InstallationCode,
plant.PlantCode
);
var robot = await DatabaseUtilities.NewRobot(RobotStatus.Available, installation);
await DatabaseUtilities.NewMissionRun(
installation.InstallationCode,
robot,
inspectionArea,
writeToDatabase: true
);

var reportsBefore = await MissionRunService.ReadAll(
new MissionRunQueryStringParameters(),
readOnly: true
);
int nReportsBefore = reportsBefore.Count;

// Act
await MissionSchedulingService.StartNextMissionRunIfSystemIsAvailable(robot);

// Assert
var reportsAfter = await MissionRunService.ReadAll(
new MissionRunQueryStringParameters()
);
int nReportsAfter = reportsAfter.Count;

// We expect two new missions since a return home mission will also be scheduled
Assert.Equal(nReportsBefore + 1, nReportsAfter);
}
}
}
4 changes: 2 additions & 2 deletions backend/api/Controllers/ReturnToHomeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ [FromRoute] string robotId
}

var returnToHomeMission =
await returnToHomeService.ScheduleReturnToHomeMissionRunIfNotAlreadyScheduledOrRobotIsHome(
robot.Id
await returnToHomeService.ScheduleReturnToHomeMissionRunIfNotAlreadyScheduled(
robot
);
if (returnToHomeMission is null)
{
Expand Down
2 changes: 1 addition & 1 deletion backend/api/Controllers/RobotController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,7 @@ public async Task<ActionResult> ResetRobot([FromRoute] string robotId)

try
{
await missionSchedulingService.AbortAllScheduledMissions(
await missionSchedulingService.AbortAllScheduledNormalMissions(
robot.Id,
"Aborted: Robot was reset"
);
Expand Down
18 changes: 14 additions & 4 deletions backend/api/EventHandlers/IsarConnectionEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,20 @@ private async void OnTimeoutEvent(IsarRobotHeartbeatMessage robotHeartbeatMessag
missionRun.Id,
missionRun.Name
);
await MissionRunService.SetMissionRunToFailed(
missionRun.Id,
"Lost connection to ISAR during mission"
);
try
{
await MissionRunService.SetMissionRunToFailed(
missionRun.Id,
"Lost connection to ISAR during mission"
);
}
catch (MissionRunNotFoundException)
{
_logger.LogError(
"Mission '{MissionId}' could not be set to failed as it no longer exists",
missionRun.Id
);
}
}
}

Expand Down
11 changes: 1 addition & 10 deletions backend/api/EventHandlers/MissionEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ IServiceScopeFactory scopeFactory
private ISignalRService SignalRService =>
_scopeFactory.CreateScope().ServiceProvider.GetRequiredService<ISignalRService>();

private IReturnToHomeService ReturnToHomeService =>
_scopeFactory.CreateScope().ServiceProvider.GetRequiredService<IReturnToHomeService>();

public override void Subscribe()
{
MissionRunService.MissionRunCreated += OnMissionRunCreated;
Expand Down Expand Up @@ -71,13 +68,7 @@ private async void OnMissionRunCreated(object? sender, MissionRunCreatedEventArg

_startMissionSemaphore.WaitOne();

if (
missionRun.MissionRunType != MissionRunType.ReturnHome
&& await ReturnToHomeService.GetActiveReturnToHomeMissionRun(
missionRun.Robot.Id,
readOnly: true
) != null
)
if (missionRun.MissionRunType != MissionRunType.ReturnHome)
{
await MissionScheduling.AbortActiveReturnToHomeMission(missionRun.Robot.Id);
}
Expand Down
59 changes: 34 additions & 25 deletions backend/api/Services/MissionRunService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,20 @@ public Task<PagedList<MissionRun>> ReadAll(

public Task<MissionRun?> ReadByIsarMissionId(string isarMissionId, bool readOnly = true);

public Task<IList<MissionRun>> ReadMissionRunQueue(string robotId, bool readOnly = true);
public Task<IList<MissionRun>> ReadMissionRunQueue(
string robotId,
MissionRunType type = MissionRunType.Normal,
bool readOnly = true
);

public Task<MissionRun?> ReadNextScheduledRunByMissionId(
string missionId,
bool readOnly = true
);

public Task<MissionRun?> ReadNextScheduledMissionRun(string robotId, bool readOnly = true);

public Task<MissionRun?> ReadNextScheduledEmergencyMissionRun(
public Task<MissionRun?> ReadNextScheduledMissionRun(
string robotId,
MissionRunType type = MissionRunType.Normal,
bool readOnly = true
);

Expand Down Expand Up @@ -188,40 +191,32 @@ public async Task<PagedList<MissionRun>> ReadAll(

public async Task<IList<MissionRun>> ReadMissionRunQueue(
string robotId,
MissionRunType type = MissionRunType.Normal,
bool readOnly = true
)
{
return await GetMissionRunsWithSubModels(readOnly: readOnly)
.Where(missionRun =>
missionRun.Robot.Id == robotId && missionRun.Status == MissionStatus.Pending
missionRun.Robot.Id == robotId
&& missionRun.Status == MissionStatus.Pending
&& missionRun.MissionRunType == type
)
.OrderBy(missionRun => missionRun.DesiredStartTime)
.ToListAsync();
}

public async Task<MissionRun?> ReadNextScheduledMissionRun(
string robotId,
bool readOnly = true
)
{
return await GetMissionRunsWithSubModels(readOnly: readOnly)
.OrderBy(missionRun => missionRun.DesiredStartTime)
.FirstOrDefaultAsync(missionRun =>
missionRun.Robot.Id == robotId && missionRun.Status == MissionStatus.Pending
);
}

public async Task<MissionRun?> ReadNextScheduledEmergencyMissionRun(
string robotId,
MissionRunType type = MissionRunType.Normal,
bool readOnly = true
)
{
return await GetMissionRunsWithSubModels(readOnly: readOnly)
.OrderBy(missionRun => missionRun.DesiredStartTime)
.FirstOrDefaultAsync(missionRun =>
missionRun.Robot.Id == robotId
&& missionRun.MissionRunType == MissionRunType.Emergency
&& missionRun.Status == MissionStatus.Pending
&& missionRun.MissionRunType == type
);
}

Expand Down Expand Up @@ -273,8 +268,12 @@ public async Task<IList<MissionRun>> ReadMissionRuns(

public async Task<bool> PendingOrOngoingReturnToHomeMissionRunExists(string robotId)
{
var pendingMissionRuns = await ReadMissionRunQueue(robotId, readOnly: true);
if (pendingMissionRuns.Any((m) => m.IsReturnHomeMission()))
var pendingMissionRuns = await ReadNextScheduledMissionRun(
robotId,
type: MissionRunType.ReturnHome,
readOnly: true
);
if (pendingMissionRuns != null)
return true;

var ongoingMissionRuns = await GetMissionRunsWithSubModels(readOnly: true)
Expand Down Expand Up @@ -728,13 +727,23 @@ await robotService.ReadById(robotId, readOnly: true)
);
if (robot.CurrentMissionId != null)
{
var missionRun = await SetMissionRunToFailed(
robot.CurrentMissionId,
"Lost connection to ISAR during mission"
);
try
{
await SetMissionRunToFailed(
robot.CurrentMissionId,
"Lost connection to ISAR during mission"
);
}
catch (MissionRunNotFoundException)
{
logger.LogError(
"Mission '{MissionId}' could not be set to failed as it no longer exists",
robot.CurrentMissionId
);
}
logger.LogWarning(
"Mission '{Id}' failed because ISAR could not be reached",
missionRun.Id
robot.CurrentMissionId
);
}
}
Expand Down
Loading

0 comments on commit ece90bc

Please sign in to comment.