Skip to content

Commit 6682d97

Browse files
committed
Introduce inspection area polygon
1 parent abb8d67 commit 6682d97

19 files changed

Lines changed: 1716 additions & 155 deletions

backend/api.test/Controllers/InspectionAreaControllerTests.cs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Net;
45
using System.Net.Http;
56
using System.Net.Http.Json;
67
using System.Text.Json;
@@ -152,5 +153,118 @@ public async Task CheckThatMissionDefinitionIsCreatedInInspectionAreaWhenSchedul
152153
)
153154
);
154155
}
156+
157+
[Fact]
158+
public async Task TestUpdatingInspectionAreaPolygon()
159+
{
160+
// Arrange
161+
var installation = await DatabaseUtilities.NewInstallation();
162+
var plant = await DatabaseUtilities.NewPlant(installation.InstallationCode);
163+
var inspectionArea = await DatabaseUtilities.NewInspectionArea(
164+
installation.InstallationCode,
165+
plant.PlantCode
166+
);
167+
168+
var jsonString =
169+
@"{
170+
""zmin"": 0,
171+
""zmax"": 10,
172+
""positions"": [
173+
{ ""x"": 0, ""y"": 0 },
174+
{ ""x"": 0, ""y"": 10 },
175+
{ ""x"": 10, ""y"": 10 },
176+
{ ""x"": 10, ""y"": 0 }
177+
]
178+
}";
179+
180+
var content = new StringContent(jsonString, null, "application/json");
181+
182+
var expecedJsonString = await content.ReadAsStringAsync();
183+
expecedJsonString = expecedJsonString.Replace("\n", "").Replace(" ", "");
184+
185+
// Act
186+
var response = await Client.PatchAsync(
187+
$"/inspectionAreas/{inspectionArea.Id}/area-polygon",
188+
content
189+
);
190+
var inspectionAreaResponse = await response.Content.ReadFromJsonAsync<InspectionArea>(
191+
SerializerOptions
192+
);
193+
194+
// Assert
195+
Assert.True(response.IsSuccessStatusCode);
196+
Assert.Equal(expecedJsonString, inspectionAreaResponse!.AreaPolygonJson!);
197+
}
198+
199+
[Fact]
200+
public async Task ScheduleMissionOutsideInspectionAreaPolygonFails()
201+
{
202+
// Arrange
203+
var installation = await DatabaseUtilities.NewInstallation();
204+
var plant = await DatabaseUtilities.NewPlant(installation.InstallationCode);
205+
var inspectionArea = await DatabaseUtilities.NewInspectionArea(
206+
installation.InstallationCode,
207+
plant.PlantCode
208+
);
209+
var jsonString =
210+
@"{
211+
""zmin"": 0,
212+
""zmax"": 10,
213+
""positions"": [
214+
{ ""x"": 0, ""y"": 0 },
215+
{ ""x"": 0, ""y"": 10 },
216+
{ ""x"": 10, ""y"": 10 },
217+
{ ""x"": 10, ""y"": 0 }
218+
]
219+
}";
220+
221+
var content = new StringContent(jsonString, null, "application/json");
222+
var response = await Client.PatchAsync(
223+
$"/inspectionAreas/{inspectionArea.Id}/area-polygon",
224+
content
225+
);
226+
227+
Assert.True(response.IsSuccessStatusCode);
228+
229+
var robot = await DatabaseUtilities.NewRobot(RobotStatus.Available, installation);
230+
231+
var inspection = new CustomInspectionQuery
232+
{
233+
AnalysisType = AnalysisType.CarSeal,
234+
InspectionTarget = new Position(),
235+
InspectionType = InspectionType.Image,
236+
};
237+
var tasks = new List<CustomTaskQuery>
238+
{
239+
new()
240+
{
241+
Inspection = inspection,
242+
TagId = "test",
243+
RobotPose = new Pose(11, 11, 11, 0, 0, 0, 1), // Position outside polygon
244+
TaskOrder = 0,
245+
},
246+
};
247+
var missionQuery = new CustomMissionQuery
248+
{
249+
RobotId = robot.Id,
250+
DesiredStartTime = DateTime.UtcNow,
251+
InstallationCode = installation.InstallationCode,
252+
InspectionAreaName = inspectionArea.Name,
253+
Name = "TestMission",
254+
Tasks = tasks,
255+
};
256+
257+
var missionContent = new StringContent(
258+
JsonSerializer.Serialize(missionQuery),
259+
null,
260+
"application/json"
261+
);
262+
263+
// Act
264+
var missionResponse = await Client.PostAsync("/missions/custom", missionContent);
265+
266+
// Assert
267+
Assert.Equal(HttpStatusCode.BadRequest, missionResponse.StatusCode);
268+
}
155269
}
156270
}

backend/api.test/Controllers/MissionSchedulingControllerTests.cs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Api.Controllers.Models;
1111
using Api.Database.Models;
1212
using Api.Services;
13+
using Api.Services.Models;
1314
using Api.Test.Database;
1415
using Microsoft.Extensions.DependencyInjection;
1516
using Testcontainers.PostgreSql;
@@ -325,16 +326,42 @@ public async Task CheckThatMissionFailsIfRobotIsNotInSameInspectionAreaAsMission
325326
var installation = await DatabaseUtilities.NewInstallation();
326327
var plant = await DatabaseUtilities.NewPlant(installation.InstallationCode);
327328

329+
var inspectionPolygonOne = new InspectionAreaPolygon
330+
{
331+
ZMin = 0,
332+
ZMax = 10,
333+
Positions =
334+
[
335+
new XYPosition { X = 0, Y = 0 },
336+
new XYPosition { X = 0, Y = 10 },
337+
new XYPosition { X = 10, Y = 10 },
338+
new XYPosition { X = 10, Y = 0 },
339+
],
340+
};
328341
var inspectionAreaOne = await DatabaseUtilities.NewInspectionArea(
329342
installation.InstallationCode,
330343
plant.PlantCode,
331-
"InspectionAreaOne"
344+
"InspectionAreaOne",
345+
inspectionPolygonOne
332346
);
333347

348+
var inspectionPolygonTwo = new InspectionAreaPolygon
349+
{
350+
ZMin = 0,
351+
ZMax = 10,
352+
Positions =
353+
[
354+
new XYPosition { X = 11, Y = 11 },
355+
new XYPosition { X = 11, Y = 20 },
356+
new XYPosition { X = 20, Y = 20 },
357+
new XYPosition { X = 20, Y = 11 },
358+
],
359+
};
334360
var inspectionAreaTwo = await DatabaseUtilities.NewInspectionArea(
335361
installation.InstallationCode,
336362
plant.PlantCode,
337-
"InspectionAreaTwo"
363+
"InspectionAreaTwo",
364+
inspectionPolygonTwo
338365
);
339366

340367
var robot = await DatabaseUtilities.NewRobot(
@@ -357,7 +384,7 @@ public async Task CheckThatMissionFailsIfRobotIsNotInSameInspectionAreaAsMission
357384
// Act
358385
const string CustomMissionsUrl = "/missions/custom";
359386
var missionResponse = await Client.PostAsync(CustomMissionsUrl, content);
360-
Assert.Equal(HttpStatusCode.Conflict, missionResponse.StatusCode);
387+
Assert.Equal(HttpStatusCode.BadRequest, missionResponse.StatusCode);
361388
}
362389

363390
private static CustomMissionQuery CreateDefaultCustomMissionQuery(

backend/api.test/Database/DatabaseUtilities.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Api.Database.Context;
55
using Api.Database.Models;
66
using Api.Services;
7+
using Api.Services.Models;
78
using Api.Test.Mocks;
89
using Microsoft.AspNetCore.Http;
910
using Microsoft.Extensions.Logging;
@@ -33,7 +34,11 @@ public class DatabaseUtilities
3334
public DatabaseUtilities(FlotillaDbContext context)
3435
{
3536
_accessRoleService = new AccessRoleService(context, new HttpContextAccessor());
36-
_installationService = new InstallationService(context, _accessRoleService);
37+
_installationService = new InstallationService(
38+
context,
39+
_accessRoleService,
40+
new Mock<ILogger<InstallationService>>().Object
41+
);
3742
_missionTaskService = new MissionTaskService(
3843
context,
3944
new Mock<ILogger<MissionTaskService>>().Object
@@ -44,7 +49,8 @@ public DatabaseUtilities(FlotillaDbContext context)
4449
_installationService,
4550
_plantService,
4651
_accessRoleService,
47-
new MockSignalRService()
52+
new MockSignalRService(),
53+
new Mock<ILogger<InspectionAreaService>>().Object
4854
);
4955
_areaService = new AreaService(
5056
context,
@@ -150,7 +156,8 @@ public async Task<Plant> NewPlant(string installationCode)
150156
public async Task<InspectionArea> NewInspectionArea(
151157
string installationCode,
152158
string plantCode,
153-
string inspectionAreaName = ""
159+
string inspectionAreaName = "",
160+
InspectionAreaPolygon? areaPolygonJson = null
154161
)
155162
{
156163
if (string.IsNullOrEmpty(inspectionAreaName))
@@ -160,6 +167,7 @@ public async Task<InspectionArea> NewInspectionArea(
160167
InstallationCode = installationCode,
161168
PlantCode = plantCode,
162169
Name = inspectionAreaName,
170+
AreaPolygonJson = areaPolygonJson,
163171
};
164172

165173
return await _inspectionAreaService.Create(createInspectionAreaQuery);
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using Api.Controllers.Models;
6+
using Api.Database.Models;
7+
using Api.Services;
8+
using Api.Test.Database;
9+
using Microsoft.Extensions.DependencyInjection;
10+
using Testcontainers.PostgreSql;
11+
using Xunit;
12+
13+
namespace Api.Test.Services
14+
{
15+
public class InspectionAreaServiceTest : IAsyncLifetime
16+
{
17+
public required DatabaseUtilities DatabaseUtilities;
18+
public required PostgreSqlContainer Container;
19+
public required IMissionRunService MissionRunService;
20+
public required IInspectionAreaService InspectionAreaService;
21+
22+
public async Task InitializeAsync()
23+
{
24+
(Container, string connectionString, var connection) =
25+
await TestSetupHelpers.ConfigurePostgreSqlDatabase();
26+
var factory = TestSetupHelpers.ConfigureWebApplicationFactory(
27+
postgreSqlConnectionString: connectionString
28+
);
29+
var serviceProvider = TestSetupHelpers.ConfigureServiceProvider(factory);
30+
31+
DatabaseUtilities = new DatabaseUtilities(
32+
TestSetupHelpers.ConfigurePostgreSqlContext(connectionString)
33+
);
34+
MissionRunService = serviceProvider.GetRequiredService<IMissionRunService>();
35+
InspectionAreaService = serviceProvider.GetRequiredService<IInspectionAreaService>();
36+
}
37+
38+
public Task DisposeAsync() => Task.CompletedTask;
39+
40+
[Fact]
41+
public async Task TestTasksInsidePolygon()
42+
{
43+
var installation = await DatabaseUtilities.NewInstallation();
44+
var plant = await DatabaseUtilities.NewPlant(installation.InstallationCode);
45+
var inspectionArea = await DatabaseUtilities.NewInspectionArea(
46+
installation.InstallationCode,
47+
plant.PlantCode
48+
);
49+
inspectionArea.AreaPolygonJson =
50+
@"{
51+
""zmin"": 0,
52+
""zmax"": 10,
53+
""positions"": [
54+
{ ""x"": 0, ""y"": 0 },
55+
{ ""x"": 0, ""y"": 10 },
56+
{ ""x"": 10, ""y"": 10 },
57+
{ ""x"": 10, ""y"": 0 }
58+
]
59+
}";
60+
61+
List<MissionTask> missionTasks =
62+
[
63+
new(new Pose(1, 1, 1, 0, 0, 0, 1), MissionTaskType.Inspection),
64+
new(new Pose(2, 2, 2, 0, 0, 0, 1), MissionTaskType.ReturnHome),
65+
];
66+
67+
var testBool = InspectionAreaService.MissionTasksAreInsideInspectionAreaPolygon(
68+
missionTasks,
69+
inspectionArea
70+
);
71+
Assert.True(testBool);
72+
}
73+
74+
[Fact]
75+
public async Task TestTasksOutsidePolygon()
76+
{
77+
var installation = await DatabaseUtilities.NewInstallation();
78+
var plant = await DatabaseUtilities.NewPlant(installation.InstallationCode);
79+
var inspectionArea = await DatabaseUtilities.NewInspectionArea(
80+
installation.InstallationCode,
81+
plant.PlantCode
82+
);
83+
inspectionArea.AreaPolygonJson =
84+
@"{
85+
""zmin"": 0,
86+
""zmax"": 10,
87+
""positions"": [
88+
{ ""x"": 0, ""y"": 0 },
89+
{ ""x"": 0, ""y"": 10 },
90+
{ ""x"": 10, ""y"": 10 },
91+
{ ""x"": 10, ""y"": 0 }
92+
]
93+
}";
94+
List<MissionTask> missionTasks =
95+
[
96+
new(new Pose(1, 1, 1, 0, 0, 0, 1), MissionTaskType.ReturnHome),
97+
new(new Pose(11, 11, 11, 0, 0, 0, 1), MissionTaskType.ReturnHome),
98+
];
99+
100+
var testBool = InspectionAreaService.MissionTasksAreInsideInspectionAreaPolygon(
101+
missionTasks,
102+
inspectionArea
103+
);
104+
Assert.False(testBool);
105+
}
106+
}
107+
}

0 commit comments

Comments
 (0)