Skip to content

Commit

Permalink
Add test for system available for mission logic
Browse files Browse the repository at this point in the history
  • Loading branch information
aeshub committed Feb 20, 2025
1 parent a0a603f commit eee1317
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 53 deletions.
77 changes: 77 additions & 0 deletions backend/api.test/Services/Helpers/MissionSchedulingHelpersTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System.Threading.Tasks;
using Api.Database.Models;
using Api.Services;
using Api.Services.Helpers;
using Api.Test.Utilities;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;

namespace Api.Test.Services.Helpers;

public class MissionSchedulingHelpersTests : IAsyncLifetime
{
public async Task InitializeAsync() => await Task.CompletedTask;

public Task DisposeAsync() => Task.CompletedTask;

[Theory]
[InlineData(false, MissionRunType.Normal, RobotStatus.Available, true, false, true)]
[InlineData(false, MissionRunType.Normal, RobotStatus.Busy, true, false, false)]
[InlineData(false, MissionRunType.Normal, RobotStatus.Offline, true, false, false)]
[InlineData(false, MissionRunType.Normal, RobotStatus.Blocked, true, false, false)]
[InlineData(
false,
MissionRunType.Normal,
RobotStatus.BlockedProtectiveStop,
true,
false,
false
)]
[InlineData(true, MissionRunType.Normal, RobotStatus.Available, true, false, false)]
[InlineData(true, MissionRunType.Emergency, RobotStatus.Available, true, false, true)]
[InlineData(true, MissionRunType.ReturnHome, RobotStatus.Available, true, false, true)]
[InlineData(false, MissionRunType.Normal, RobotStatus.Available, false, false, false)]
[InlineData(false, MissionRunType.Normal, RobotStatus.Available, true, true, false)]
[InlineData(false, MissionRunType.Emergency, RobotStatus.Busy, true, false, true)]
public async Task CheckLogicOfSystemIsAvailableToRunAMissionFunction(

Check failure on line 37 in backend/api.test/Services/Helpers/MissionSchedulingHelpersTests.cs

View workflow job for this annotation

GitHub Actions / test_backend

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check failure on line 37 in backend/api.test/Services/Helpers/MissionSchedulingHelpersTests.cs

View workflow job for this annotation

GitHub Actions / test_backend

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 37 in backend/api.test/Services/Helpers/MissionSchedulingHelpersTests.cs

View workflow job for this annotation

GitHub Actions / build_backend

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 37 in backend/api.test/Services/Helpers/MissionSchedulingHelpersTests.cs

View workflow job for this annotation

GitHub Actions / build_backend

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
bool missionQueueFrozen,
MissionRunType missionRunType,
RobotStatus robotStatus,
bool isIsarConnected,
bool isRobotDeprecated,
bool expectedResult
)
{
// Arrange
var installation = TestObjectGenerator.NewInstallation();
var plant = TestObjectGenerator.NewPlant(installation);
var inspectionArea = TestObjectGenerator.NewInspectionArea(installation, plant);

var robot = TestObjectGenerator.NewRobot(
currentInstallation: installation,
currentInspectionArea: inspectionArea,
robotStatus: robotStatus,
isarConnected: isIsarConnected,
deprecated: isRobotDeprecated,
missionQueueFrozen: missionQueueFrozen
);

var missionRun = TestObjectGenerator.NewMissionRun(
installationCode: installation.InstallationCode,
robot: robot,
inspectionArea: inspectionArea,
missionRunType: missionRunType
);

// Act
var isSystemAvailable = MissionSchedulingHelpers.TheSystemIsAvailableToRunAMission(
robot,
missionRun,
new Mock<ILogger<MissionSchedulingService>>().Object
);

// Assert
Assert.Equal(expectedResult, isSystemAvailable);
}
}
6 changes: 1 addition & 5 deletions backend/api.test/Services/MissionRunService.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Api.Controllers.Models;
using Api.Database.Models;
using System.Threading.Tasks;
using Api.Services;
using Api.Test.Database;
using Microsoft.Extensions.DependencyInjection;
Expand Down
4 changes: 1 addition & 3 deletions backend/api.test/Services/RobotService.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Linq;
using System.Linq;
using System.Threading.Tasks;
using Api.Controllers.Models;
using Api.Database.Models;
using Api.Services;
using Api.Test.Database;
Expand Down
134 changes: 134 additions & 0 deletions backend/api.test/Utilities/TestObjectGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using Api.Database.Models;

namespace Api.Test.Utilities;

public static class TestObjectGenerator
{
public static Installation NewInstallation(
string? id = null,
string name = "TestInst",
string installationCode = "TestCode"
)
{
return new Installation
{
Id = id ?? Guid.NewGuid().ToString(),
Name = name,
InstallationCode = installationCode,
};
}

public static Plant NewPlant(
Installation installation,
string? id = null,
string name = "TestPlant",
string plantCode = "TestCode"
)
{
return new Plant
{
Id = id ?? Guid.NewGuid().ToString(),
Installation = installation,
PlantCode = plantCode,
Name = name,
};
}

public static InspectionArea NewInspectionArea(
Installation installation,
Plant plant,
string? id = null,
string name = "TestName"
)
{
return new InspectionArea
{
Id = id ?? Guid.NewGuid().ToString(),
Plant = plant,
Installation = installation,
Name = name,
};
}

public static Robot NewRobot(
Installation currentInstallation,
InspectionArea currentInspectionArea,
RobotModel? robotModel = null,
RobotStatus robotStatus = RobotStatus.Available,
string name = "Test Robot",
string? id = null,
string? isarId = null,
string serialNumber = "TestSerialNumber",
float batteryLevel = 100,
BatteryState batteryState = BatteryState.Normal,
float pressureLevel = 90,
string host = "localhost",
int port = 8080,
IList<RobotCapabilitiesEnum>? capabilities = null,
bool isarConnected = true,
bool deprecated = false,
bool missionQueueFrozen = false,
RobotFlotillaStatus flotillaStatus = RobotFlotillaStatus.Normal,
Pose? pose = null,
string? currentMissionId = null
)
{
return new Robot
{
Id = id ?? Guid.NewGuid().ToString(),
Name = name,
IsarId = isarId ?? Guid.NewGuid().ToString(),
Model = robotModel ?? new RobotModel(),
SerialNumber = serialNumber,
CurrentInstallation = currentInstallation,
CurrentInspectionArea = currentInspectionArea,
BatteryLevel = batteryLevel,
BatteryState = batteryState,
PressureLevel = pressureLevel,
Host = host,
Port = port,
RobotCapabilities = capabilities ?? [],
IsarConnected = isarConnected,
Deprecated = deprecated,
MissionQueueFrozen = missionQueueFrozen,
Status = robotStatus,
FlotillaStatus = flotillaStatus,
Pose = pose ?? new Pose(),
CurrentMissionId = currentMissionId,
};
}

public static MissionRun NewMissionRun(
string installationCode,
Robot robot,
InspectionArea inspectionArea,
string name = "TestName",
string? id = null,
string? missionId = null,
MissionStatus missionStatus = MissionStatus.Pending,
DateTime? startTime = null,
IList<MissionTask>? tasks = null,
MissionRunType missionRunType = MissionRunType.Normal,
string? isarMissionId = null,
bool isDeprecated = false
)
{
return new MissionRun
{
Id = id ?? Guid.NewGuid().ToString(),
MissionId = missionId ?? Guid.NewGuid().ToString(),
Status = missionStatus,
InstallationCode = installationCode,
DesiredStartTime = startTime ?? DateTime.UtcNow,
Robot = robot,
Tasks = tasks ?? [],
MissionRunType = missionRunType,
IsarMissionId = isarMissionId ?? Guid.NewGuid().ToString(),
InspectionArea = inspectionArea,
Name = name,
IsDeprecated = isDeprecated,
};
}
}
54 changes: 54 additions & 0 deletions backend/api/Services/Helpers/MissionSchedulingHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using Api.Database.Models;

namespace Api.Services.Helpers;

public static class MissionSchedulingHelpers
{
public static bool TheSystemIsAvailableToRunAMission(
Robot robot,
MissionRun missionRun,
ILogger logger
)
{
if (
robot.MissionQueueFrozen
&& !(missionRun.IsEmergencyMission() || missionRun.IsReturnHomeMission())
)
{
logger.LogInformation(
"Mission run {MissionRunId} was not started as the mission run queue for robot {RobotName} is frozen",
missionRun.Id,
robot.Name
);
return false;
}

if (robot.Status is not RobotStatus.Available)
{
logger.LogInformation(
"Mission run {MissionRunId} was not started as the robot is not available",
missionRun.Id
);
return false;
}
if (!robot.IsarConnected)
{
logger.LogWarning(
"Mission run {MissionRunId} was not started as the robots {RobotId} isar instance is disconnected",
missionRun.Id,
robot.Id
);
return false;
}
if (robot.Deprecated)
{
logger.LogWarning(
"Mission run {MissionRunId} was not started as the robot {RobotId} is deprecated",
missionRun.Id,
robot.Id
);
return false;
}
return true;
}
}
53 changes: 8 additions & 45 deletions backend/api/Services/MissionSchedulingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Api.Controllers.Models;
using Api.Database.Models;
using Api.Services.Events;
using Api.Services.Helpers;
using Api.Services.Models;
using Api.Utilities;

Expand Down Expand Up @@ -76,7 +77,13 @@ public async Task StartNextMissionRunIfSystemIsAvailable(Robot robot)
return;
}

if (!TheSystemIsAvailableToRunAMission(robot, missionRun))
if (
!MissionSchedulingHelpers.TheSystemIsAvailableToRunAMission(
robot,
missionRun,
logger
)
)
{
logger.LogInformation(
"Mission {MissionRunId} was put on the queue as the system may not start a mission now",
Expand Down Expand Up @@ -583,50 +590,6 @@ await missionRunService.UpdateMissionRunProperty(
return ongoingMissions;
}

private bool TheSystemIsAvailableToRunAMission(Robot robot, MissionRun missionRun)
{
if (
robot.MissionQueueFrozen
&& !(missionRun.IsEmergencyMission() || missionRun.IsReturnHomeMission())
)
{
logger.LogInformation(
"Mission run {MissionRunId} was not started as the mission run queue for robot {RobotName} is frozen",
missionRun.Id,
robot.Name
);
return false;
}

if (robot.Status is not RobotStatus.Available)
{
logger.LogInformation(
"Mission run {MissionRunId} was not started as the robot is not available",
missionRun.Id
);
return false;
}
if (!robot.IsarConnected)
{
logger.LogWarning(
"Mission run {MissionRunId} was not started as the robots {RobotId} isar instance is disconnected",
missionRun.Id,
robot.Id
);
return false;
}
if (robot.Deprecated)
{
logger.LogWarning(
"Mission run {MissionRunId} was not started as the robot {RobotId} is deprecated",
missionRun.Id,
robot.Id
);
return false;
}
return true;
}

public async Task AbortActiveReturnToHomeMission(string robotId)
{
var activeReturnToHomeMission =
Expand Down

0 comments on commit eee1317

Please sign in to comment.