From e4e5e891db5e097cfb364d66a2193df4a3b32e67 Mon Sep 17 00:00:00 2001 From: Christian de Jonge Date: Tue, 15 Oct 2024 14:42:05 +0200 Subject: [PATCH] Improve consistency of tests by removing InitDb in tests --- backend/README.md | 2 +- backend/api.test/Client/AreaTests.cs | 79 ++- backend/api.test/Client/MissionTests.cs | 564 +++++------------- backend/api.test/Client/RobotTests.cs | 47 +- backend/api.test/Client/RoleAccessTests.cs | 17 - .../api.test/Database/DatabaseUtilities.cs | 86 ++- backend/api.test/DbContextTestSetup.cs | 1 - .../EventHandlers/TestMissionEventHandler.cs | 102 ++-- backend/api.test/Mocks/BlobServiceMock.cs | 7 +- backend/api.test/Mocks/IsarServiceMock.cs | 7 +- backend/api.test/Mocks/StidServiceMock.cs | 3 +- backend/api.test/Services/MissionService.cs | 8 +- backend/api.test/Services/RobotService.cs | 28 +- backend/api.test/api.test.csproj | 1 - .../CustomServiceConfigurations.cs | 3 +- .../api/Controllers/AccessRoleController.cs | 2 +- backend/api/Controllers/DeckController.cs | 4 +- .../api/Controllers/InstallationController.cs | 2 +- .../MissionSchedulingController.cs | 2 +- backend/api/Controllers/PlantController.cs | 4 +- backend/api/Database/Context/InitDb.cs | 103 ++-- backend/api/Database/Models/Robot.cs | 4 +- backend/api/EventHandlers/MqttEventHandler.cs | 2 +- backend/api/Services/AreaService.cs | 12 +- backend/api/Services/DeckService.cs | 8 +- backend/api/Services/InstallationService.cs | 6 +- backend/api/Services/LocalizationService.cs | 2 +- .../api/Services/MissionSchedulingService.cs | 6 +- backend/api/Services/PlantService.cs | 26 +- backend/api/Services/ReturnToHomeService.cs | 6 +- backend/api/Services/RobotModelService.cs | 1 + backend/api/Services/RobotService.cs | 2 +- backend/api/appsettings.Local.json | 7 +- backend/api/appsettings.json | 3 +- 34 files changed, 471 insertions(+), 686 deletions(-) diff --git a/backend/README.md b/backend/README.md index b204899b4..7750b2b5d 100644 --- a/backend/README.md +++ b/backend/README.md @@ -245,7 +245,7 @@ We use [dotnet format](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet to format and verify code style in backend based on the [C# coding conventions](https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions). -Dotnet format is included in the .NET6 SDK. +Dotnet format is included in the .NET SDK. To check the formatting, run the following command in the backend folder: diff --git a/backend/api.test/Client/AreaTests.cs b/backend/api.test/Client/AreaTests.cs index 11c4ad3b6..dbaae8d69 100644 --- a/backend/api.test/Client/AreaTests.cs +++ b/backend/api.test/Client/AreaTests.cs @@ -8,15 +8,18 @@ using System.Text.Json.Serialization; using System.Threading.Tasks; using Api.Controllers.Models; +using Api.Database.Context; using Api.Database.Models; +using Api.Test.Database; using Microsoft.AspNetCore.Mvc.Testing; using Xunit; -namespace Api.Test +namespace Api.Test.Client { [Collection("Database collection")] public class AreaTests : IClassFixture> { private readonly HttpClient _client; + private readonly DatabaseUtilities _databaseUtilities; private readonly JsonSerializerOptions _serializerOptions = new() { @@ -37,6 +40,10 @@ public AreaTests(TestWebApplicationFactory factory) _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( TestAuthHandler.AuthenticationScheme ); + + object? context = factory.Services.GetService(typeof(FlotillaDbContext)) as FlotillaDbContext ?? throw new ArgumentNullException(nameof(factory)); + _databaseUtilities = new DatabaseUtilities((FlotillaDbContext)context); + } [Fact] @@ -139,32 +146,15 @@ public async Task AreaTest() [Fact] public async Task MissionIsCreatedInArea() { - // Arrange - // Robot - string robotUrl = "/robots"; - var robotResponse = await _client.GetAsync(robotUrl); - Assert.True(robotResponse.IsSuccessStatusCode); - var robots = await robotResponse.Content.ReadFromJsonAsync>(_serializerOptions); - Assert.NotNull(robots); - var robot = robots.Where(robot => robot.Name == "Shockwave").First(); - string robotId = robot.Id; + // Arrange - Initialise area + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); - // Installation - string installationUrl = "/installations"; - var installationResponse = await _client.GetAsync(installationUrl); - Assert.True(installationResponse.IsSuccessStatusCode); - var installations = await installationResponse.Content.ReadFromJsonAsync>(_serializerOptions); - Assert.NotNull(installations); - var installation = installations.Where(installation => installation.InstallationCode == robot.CurrentInstallation?.InstallationCode).First(); - - // Area - string areaUrl = "/areas"; - var areaResponse = await _client.GetAsync(areaUrl); - Assert.True(areaResponse.IsSuccessStatusCode); - var areas = await areaResponse.Content.ReadFromJsonAsync>(_serializerOptions); - Assert.NotNull(areas); - var area = areas.Where(area => area.InstallationCode == installation.InstallationCode).First(); - string areaId = area.Id; + // Arrange - Robot + var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, installation); + string robotId = robot.Id; string testMissionName = "testMissionInAreaTest"; @@ -189,7 +179,7 @@ public async Task MissionIsCreatedInArea() RobotId = robotId, DesiredStartTime = DateTime.UtcNow, InstallationCode = installation.InstallationCode, - AreaName = area.AreaName, + AreaName = area.Name, Name = testMissionName, Tasks = tasks }; @@ -208,8 +198,8 @@ public async Task MissionIsCreatedInArea() var mission = await missionResponse.Content.ReadFromJsonAsync(_serializerOptions); Assert.NotNull(mission); Assert.NotNull(mission.MissionId); - - var areaMissionsResponse = await _client.GetAsync(areaUrl + $"/{areaId}/mission-definitions"); + string areaUrl = "/areas"; + var areaMissionsResponse = await _client.GetAsync(areaUrl + $"/{area.Id}/mission-definitions"); // Assert Assert.True(areaMissionsResponse.IsSuccessStatusCode); @@ -222,14 +212,12 @@ public async Task MissionIsCreatedInArea() public async Task SafePositionTest() { // Arrange - string areaUrl = "/areas"; - var areaResponse = await _client.GetAsync(areaUrl); - Assert.True(areaResponse.IsSuccessStatusCode); - var areaResponses = await areaResponse.Content.ReadFromJsonAsync>(_serializerOptions); - Assert.NotNull(areaResponses); - var area = areaResponses[0]; - string areaName = area.AreaName; - string installationCode = area.InstallationCode; + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + string areaName = area.Name; + string installationCode = installation.InstallationCode; string addSafePositionUrl = $"/areas/{installationCode}/{areaName}/safe-position"; var testPosition = new Position @@ -255,7 +243,7 @@ public async Task SafePositionTest() "application/json" ); - areaResponse = await _client.PostAsync(addSafePositionUrl, content); + var areaResponse = await _client.PostAsync(addSafePositionUrl, content); Assert.True(areaResponse.IsSuccessStatusCode); var areaContent = await areaResponse.Content.ReadFromJsonAsync(_serializerOptions); Assert.NotNull(areaContent); @@ -275,12 +263,11 @@ public async Task SafePositionTest() [Fact] public async Task UpdateDefaultLocalizationPoseOnDeck() { - string deckUrl = "/decks"; - var deckResponse = await _client.GetAsync(deckUrl); - Assert.True(deckResponse.IsSuccessStatusCode); - var decks = await deckResponse.Content.ReadFromJsonAsync>(_serializerOptions); - Assert.NotNull(decks); - var deck = decks[0]; + // Arrange + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + string deckId = deck.Id; string url = $"/decks/{deckId}/update-default-localization-pose"; @@ -308,9 +295,13 @@ public async Task UpdateDefaultLocalizationPoseOnDeck() null, "application/json" ); + + // Act var putResponse = await _client.PutAsync(url, content); Assert.True(putResponse.IsSuccessStatusCode); var putDeck = await putResponse.Content.ReadFromJsonAsync(_serializerOptions); + + // Assert Assert.NotNull(putDeck); Assert.NotNull(putDeck.DefaultLocalizationPose); Assert.True(putDeck.DefaultLocalizationPose.Position.Z.Equals(query.Pose.Position.Z)); diff --git a/backend/api.test/Client/MissionTests.cs b/backend/api.test/Client/MissionTests.cs index f732c789c..2766cb68b 100644 --- a/backend/api.test/Client/MissionTests.cs +++ b/backend/api.test/Client/MissionTests.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Net; using System.Net.Http; @@ -10,16 +9,18 @@ using System.Text.Json.Serialization; using System.Threading.Tasks; using Api.Controllers.Models; +using Api.Database.Context; using Api.Database.Models; +using Api.Test.Database; using Microsoft.AspNetCore.Mvc.Testing; using Xunit; -using Xunit.Sdk; -namespace Api.Test +namespace Api.Test.Client { [Collection("Database collection")] public class MissionTests : IClassFixture> { private readonly HttpClient _client; + private readonly DatabaseUtilities _databaseUtilities; private readonly JsonSerializerOptions _serializerOptions = new() { @@ -40,254 +41,33 @@ public MissionTests(TestWebApplicationFactory factory) _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( TestAuthHandler.AuthenticationScheme ); - } - - private async Task PostToDb(string postUrl, TQueryType stringContent) - { - var content = new StringContent( - JsonSerializer.Serialize(stringContent), - null, - "application/json" - ); - var response = await _client.PostAsync(postUrl, content); - Assert.True(response != null, $"Failed to post to {postUrl}. Null returned"); - Assert.True(response.IsSuccessStatusCode, $"Failed to post to {postUrl}. Status code: {response.StatusCode}"); - var responseObject = await response.Content.ReadFromJsonAsync(_serializerOptions); - Assert.True(responseObject != null, $"No object returned from post to {postUrl}"); - return responseObject; - } - - private async Task GetInstallation(string installationCode) - { - string installationUrl = "/installations"; - var installationResponse = await _client.GetAsync(installationUrl); - Assert.True(installationResponse.IsSuccessStatusCode); - var installationResponses = await installationResponse.Content.ReadFromJsonAsync>(_serializerOptions); - Assert.NotNull(installationResponses); - return installationResponses.Where((i) => i.InstallationCode.Equals(installationCode, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); - } - - private async Task GetPlant(string installationCode, string plantCode) - { - string installationUrl = "/installations"; - var installationResponse = await _client.GetAsync(installationUrl); - Assert.True(installationResponse.IsSuccessStatusCode); - var installationResponses = await installationResponse.Content.ReadFromJsonAsync>(_serializerOptions); - Assert.NotNull(installationResponses); - if (!installationResponses.Where((i) => i.InstallationCode.Equals(installationCode, StringComparison.OrdinalIgnoreCase)).Any()) return null; - - string plantUrl = "/plants"; - var plantResponse = await _client.GetAsync(plantUrl); - Assert.True(plantResponse.IsSuccessStatusCode); - var plantResponses = await plantResponse.Content.ReadFromJsonAsync>(_serializerOptions); - Assert.NotNull(plantResponses); - return plantResponses.Where((p) => p.PlantCode.Equals(plantCode, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); - } - private async Task GetDeck(string installationCode, string plantCode, string deckName) - { - string installationUrl = "/installations"; - var installationResponse = await _client.GetAsync(installationUrl); - Assert.True(installationResponse.IsSuccessStatusCode); - var installationResponses = await installationResponse.Content.ReadFromJsonAsync>(_serializerOptions); - Assert.NotNull(installationResponses); - if (!installationResponses.Where((i) => i.InstallationCode.Equals(installationCode.ToLower(CultureInfo.CurrentCulture), StringComparison.OrdinalIgnoreCase)).Any()) return null; - - string plantUrl = "/plants"; - var plantResponse = await _client.GetAsync(plantUrl); - Assert.True(plantResponse.IsSuccessStatusCode); - var plantResponses = await plantResponse.Content.ReadFromJsonAsync>(_serializerOptions); - Assert.NotNull(plantResponses); - if (!plantResponses.Where((p) => p.PlantCode.Equals(plantCode.ToLower(CultureInfo.CurrentCulture), StringComparison.OrdinalIgnoreCase)).Any()) return null; - - string deckUrl = "/decks"; - var deckResponse = await _client.GetAsync(deckUrl); - Assert.True(deckResponse.IsSuccessStatusCode); - var deckResponses = await deckResponse.Content.ReadFromJsonAsync>(_serializerOptions); - Assert.NotNull(deckResponses); - return deckResponses.Where((d) => d.DeckName.Equals(deckName.ToLower(CultureInfo.CurrentCulture), StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); - } - - private async Task VerifyNonDuplicateAreaDbNames(string areaName) - { - string areaUrl = "/areas"; - var areaResponse = await _client.GetAsync(areaUrl); - Assert.True(areaResponse.IsSuccessStatusCode); - var areaResponses = await areaResponse.Content.ReadFromJsonAsync>(_serializerOptions); - Assert.NotNull(areaResponses); - Assert.False(areaResponses.Where((a) => a.AreaName == areaName).Any(), $"Duplicate area name detected: {areaName}"); - } - - private async Task VerifyNonDuplicateInstallationDbName(string installationCode) - { - string installationUrl = "/installations"; - var installationResponse = await _client.GetAsync(installationUrl); - Assert.True(installationResponse.IsSuccessStatusCode); - var installationResponses = await installationResponse.Content.ReadFromJsonAsync>(_serializerOptions); - Assert.NotNull(installationResponses); - Assert.False(installationResponses.Where((i) => i.InstallationCode == installationCode).Any(), $"Duplicate installation name detected: {installationCode}"); - } - - private static (StringContent installationContent, StringContent plantContent, StringContent deckContent, StringContent areaContent) ArrangeAreaPostQueries(string installationCode, string plantCode, string deckName, string areaName) - { - var testPose = new Pose - { - Position = new Position - { - X = 1, - Y = 2, - Z = 2 - }, - Orientation = new Orientation - { - X = 0, - Y = 0, - Z = 0, - W = 1 - } - }; - - var installationQuery = new CreateInstallationQuery - { - InstallationCode = installationCode, - Name = installationCode - }; - - var plantQuery = new CreatePlantQuery - { - InstallationCode = installationCode, - PlantCode = plantCode, - Name = plantCode - }; - - var deckQuery = new CreateDeckQuery - { - InstallationCode = installationCode, - PlantCode = plantCode, - Name = deckName, - DefaultLocalizationPose = new CreateDefaultLocalizationPose() - { - Pose = testPose, - IsDockingStation = false - } - }; - - var areaQuery = new CreateAreaQuery - { - InstallationCode = installationCode, - PlantCode = plantCode, - DeckName = deckName, - AreaName = areaName, - DefaultLocalizationPose = testPose - }; - - var installationContent = new StringContent( - JsonSerializer.Serialize(installationQuery), - null, - "application/json" - ); - - var plantContent = new StringContent( - JsonSerializer.Serialize(plantQuery), - null, - "application/json" - ); - - var deckContent = new StringContent( - JsonSerializer.Serialize(deckQuery), - null, - "application/json" - ); - - var areaContent = new StringContent( - JsonSerializer.Serialize(areaQuery), - null, - "application/json" - ); - - return (installationContent, plantContent, deckContent, areaContent); - } - - private async Task PostToDb(string postUrl, StringContent content) - { - var response = await _client.PostAsync(postUrl, content); - Assert.True(response != null, $"Failed to post to {postUrl}. Null returned"); - Assert.True(response.IsSuccessStatusCode, $"Failed to post to {postUrl}. Status code: {response.StatusCode}"); - var responseObject = await response.Content.ReadFromJsonAsync(_serializerOptions); - Assert.True(responseObject != null, $"No object returned from post to {postUrl}"); - return responseObject; - } - - private async Task<(Installation installation, Plant plant, DeckResponse deck, AreaResponse area)> PostAssetInformationToDb(string installationCode, string plantCode, string deckName, string areaName) - { - await VerifyNonDuplicateAreaDbNames(areaName); - - string installationUrl = "/installations"; - string plantUrl = "/plants"; - string deckUrl = "/decks"; - string areaUrl = "/areas"; - - (var installationContent, var plantContent, var deckContent, var areaContent) = ArrangeAreaPostQueries(installationCode, plantCode, deckName, areaName); - - var installation = await GetInstallation(installationCode) ?? await PostToDb(installationUrl, installationContent); - var plant = await GetPlant(installation.InstallationCode, plantCode) ?? await PostToDb(plantUrl, plantContent); - var deck = await GetDeck(installation.InstallationCode, plant.PlantCode, deckName) ?? await PostToDb(deckUrl, deckContent); - var area = await PostToDb(areaUrl, areaContent); - - return (installation, plant, deck, area); - } - - private async Task PostInstallationInformationToDb(string installationCode) - { - await VerifyNonDuplicateInstallationDbName(installationCode); - - string installationUrl = "/installations"; - - var installationQuery = new CreateInstallationQuery - { - InstallationCode = installationCode, - Name = installationCode - }; - - var installationContent = new StringContent( - JsonSerializer.Serialize(installationQuery), - null, - "application/json" - ); - - var installation = await PostToDb(installationUrl, installationContent); - - return installation; + object? context = factory.Services.GetService(typeof(FlotillaDbContext)) as FlotillaDbContext ?? throw new ArgumentNullException(nameof(factory)); + _databaseUtilities = new DatabaseUtilities((FlotillaDbContext)context); } [Fact] public async Task ScheduleOneMissionTest() { + // Arrange - Area + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + // Arrange - Robot - string robotUrl = "/robots"; - string missionsUrl = "/missions"; - var response = await _client.GetAsync(robotUrl); - Assert.True(response.IsSuccessStatusCode, $"Failed to get robot from path: {robotUrl}, with status code {response.StatusCode}"); - var robots = await response.Content.ReadFromJsonAsync>(_serializerOptions); - Assert.NotNull(robots); - var robot = robots.Where(robot => robot.Name == "Shockwave").First(); + var robot = await _databaseUtilities.NewRobot(RobotStatus.Busy, installation); string robotId = robot.Id; - // Arrange - Area - string installationCode = "installationScheduleOneMissionTest"; - string plantCode = "plantScheduleOneMissionTest"; - string deckName = "deckScheduleOneMissionTest"; - string areaName = "areaScheduleOneMissionTest"; - (_, _, _, _) = await PostAssetInformationToDb(installationCode, plantCode, deckName, areaName); - + string missionsUrl = "/missions"; string missionSourceId = "95"; // Act var query = new ScheduledMissionQuery { RobotId = robotId, - InstallationCode = installationCode, - AreaName = areaName, + InstallationCode = installation.InstallationCode, + AreaName = area.Name, MissionSourceId = missionSourceId, DesiredStartTime = DateTime.UtcNow }; @@ -297,7 +77,7 @@ public async Task ScheduleOneMissionTest() "application/json" ); - response = await _client.PostAsync(missionsUrl, content); + var response = await _client.PostAsync(missionsUrl, content); // Assert Assert.True(response.IsSuccessStatusCode); @@ -310,22 +90,16 @@ public async Task ScheduleOneMissionTest() [Fact] public async Task Schedule3MissionsTest() { + // Arrange - Area + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + // Arrange - Robot - string robotUrl = "/robots"; - string missionsUrl = "/missions"; - var robotResponse = await _client.GetAsync(robotUrl); - Assert.True(robotResponse.IsSuccessStatusCode); - var robots = await robotResponse.Content.ReadFromJsonAsync>(_serializerOptions); - Assert.NotNull(robots); - var robot = robots.Where(robot => robot.Name == "Shockwave").First(); + var robot = await _databaseUtilities.NewRobot(RobotStatus.Busy, installation); string robotId = robot.Id; - // Arrange - Area - string installationCode = "installationSchedule3MissionsTest"; - string plantCode = "plantSchedule3MissionsTest"; - string deckName = "deckSchedule3MissionsTest"; - string areaName = "areaSchedule3MissionsTest"; - (_, _, _, _) = await PostAssetInformationToDb(installationCode, plantCode, deckName, areaName); string missionSourceId = "97"; @@ -333,8 +107,8 @@ public async Task Schedule3MissionsTest() var query = new ScheduledMissionQuery { RobotId = robotId, - InstallationCode = installationCode, - AreaName = areaName, + InstallationCode = installation.InstallationCode, + AreaName = area.Name, MissionSourceId = missionSourceId, DesiredStartTime = DateTime.UtcNow }; @@ -354,6 +128,7 @@ public async Task Schedule3MissionsTest() Assert.NotNull(missionRuns); int missionRunsBefore = missionRuns.Count; + string missionsUrl = "/missions"; response = await _client.PostAsync(missionsUrl, content); // Assert @@ -387,46 +162,94 @@ public async Task Schedule3MissionsTest() Assert.Single(missionRuns.Where((m) => m.Id == missionRun3.Id).ToList()); } -#pragma warning disable xUnit1004 - [Fact(Skip = "Skipping until a solution has been found for ExecuteUpdate in tests")] -#pragma warning restore xUnit1004 + [Fact] public async Task AddNonDuplicateAreasToDb() { - // Arrange - Area - string installationCode = "installationAddNonDuplicateAreasToDb"; - string plantCode = "plantAddNonDuplicateAreasToDb"; - string deckName = "deckAddNonDuplicateAreasToDb"; - string areaName = "areaAddNonDuplicateAreasToDb"; - (_, _, _, _) = await PostAssetInformationToDb(installationCode, plantCode, deckName, areaName); - - await Task.Delay(1000); - - string installationCode2 = "installationAddNonDuplicateAreasToDb2"; - string plantCode2 = "plantAddNonDuplicateAreasToDb2"; - string deckName2 = "deckAddNonDuplicateAreasToDb2"; - string areaName2 = "areaAddNonDuplicateAreasToDb2"; - (_, _, _, _) = await PostAssetInformationToDb(installationCode2, plantCode2, deckName2, areaName2); + // Arrange + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var _ = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + + var testPose = new Pose + { + Position = new Position + { + X = 1, + Y = 2, + Z = 2 + }, + Orientation = new Orientation + { + X = 0, + Y = 0, + Z = 0, + W = 1 + } + }; + var areaQuery = new CreateAreaQuery + { + InstallationCode = installation.InstallationCode, + PlantCode = plant.PlantCode, + DeckName = deck.Name, + AreaName = "AddNonDuplicateAreasToDb_Area", + DefaultLocalizationPose = testPose + }; + var areaContent = new StringContent( + JsonSerializer.Serialize(areaQuery), + null, + "application/json" + ); + string areaUrl = "/areas"; + var response = await _client.PostAsync(areaUrl, areaContent); + Assert.True(response.IsSuccessStatusCode, $"Failed to post to {areaUrl}. Status code: {response.StatusCode}"); + + Assert.True(response != null, $"Failed to post to {areaUrl}. Null returned"); + var responseObject = await response.Content.ReadFromJsonAsync(_serializerOptions); + Assert.True(responseObject != null, $"No object returned from post to {areaUrl}"); } -#pragma warning disable xUnit1004 - [Fact(Skip = "Skipping until a solution has been found for ExecuteUpdate in tests")] -#pragma warning restore xUnit1004 + [Fact] public async Task AddDuplicateAreasToDb_Fails() { - // Arrange - Area - string installationCode = "installationAddDuplicateAreasToDb_Fails"; - string plantCode = "plantAddDuplicateAreasToDb_Fails"; - string deckName = "deckAddDuplicateAreasToDb_Fails"; - string areaName = "areaAddDuplicateAreasToDb_Fails"; - (_, _, _, _) = await PostAssetInformationToDb(installationCode, plantCode, deckName, areaName); - - await Task.Delay(1000); - - string installationCode2 = "installationAddDuplicateAreasToDb_Fails2"; - string plantCode2 = "plantAddDuplicateAreasToDb_Fails2"; - string deckName2 = "deckAddDuplicateAreasToDb_Fails"; - string areaName2 = "areaAddDuplicateAreasToDb_Fails"; - await Assert.ThrowsAsync(async () => await PostAssetInformationToDb(installationCode2, plantCode2, deckName2, areaName2)); + // Arrange + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + + var testPose = new Pose + { + Position = new Position + { + X = 1, + Y = 2, + Z = 2 + }, + Orientation = new Orientation + { + X = 0, + Y = 0, + Z = 0, + W = 1 + } + }; + var areaQuery = new CreateAreaQuery + { + InstallationCode = installation.InstallationCode, + PlantCode = plant.PlantCode, + DeckName = deck.Name, + AreaName = area.Name, + DefaultLocalizationPose = testPose + }; + var areaContent = new StringContent( + JsonSerializer.Serialize(areaQuery), + null, + "application/json" + ); + string areaUrl = "/areas"; + var response = await _client.PostAsync(areaUrl, areaContent); + Assert.Equal(HttpStatusCode.Conflict, response.StatusCode); } [Fact] @@ -450,42 +273,24 @@ public async Task DeleteMission_ShouldReturnNotFound() [Fact] public async Task ScheduleDuplicateCustomMissionDefinitions() { - // Arrange - Initialise area - string installationCode = "installationScheduleDuplicateCustomMissionDefinitions"; - string plantCode = "plantScheduleDuplicateCustomMissionDefinitions"; - string deckName = "deckScheduleDuplicateCustomMissionDefinitions"; - string areaName = "areaScheduleDuplicateCustomMissionDefinitions"; - (var installation, _, _, _) = await PostAssetInformationToDb(installationCode, plantCode, deckName, areaName); + // Arrange + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); string testMissionName = "testMissionScheduleDuplicateCustomMissionDefinitions"; - // Arrange - Create robot - var robotQuery = new CreateRobotQuery - { - IsarId = Guid.NewGuid().ToString(), - Name = "RobotGetNextRun", - SerialNumber = "GetNextRun", - RobotType = RobotType.Robot, - Status = RobotStatus.Available, - Host = "localhost", - Port = 3000, - CurrentInstallationCode = installationCode, - CurrentAreaName = null, - VideoStreams = new List(), - Documentation = new List(), - RobotCapabilities = [RobotCapabilitiesEnum.take_image] - }; - - string robotUrl = "/robots"; - var robot = await PostToDb(robotUrl, robotQuery); + // Arrange - Robot + var robot = await _databaseUtilities.NewRobot(RobotStatus.Busy, installation); string robotId = robot.Id; // Arrange - Create custom mission definition var query = new CustomMissionQuery { RobotId = robotId, - InstallationCode = installationCode, - AreaName = areaName, + InstallationCode = installation.InstallationCode, + AreaName = area.Name, DesiredStartTime = DateTime.SpecifyKind(new DateTime(3050, 1, 1), DateTimeKind.Utc), InspectionFrequency = new TimeSpan(14, 0, 0, 0), Name = testMissionName, @@ -545,31 +350,13 @@ public async Task ScheduleDuplicateCustomMissionDefinitions() public async Task GetNextRun() { // Arrange - Initialise area - string installationCode = "installationGetNextRun"; - string plantCode = "plantGetNextRun"; - string deckName = "deckGetNextRun"; - string areaName = "areaGetNextRun"; - (var installation, _, _, _) = await PostAssetInformationToDb(installationCode, plantCode, deckName, areaName); - - // Arrange - Create robot - var robotQuery = new CreateRobotQuery - { - IsarId = Guid.NewGuid().ToString(), - Name = "RobotGetNextRun", - SerialNumber = "GetNextRun", - RobotType = RobotType.Robot, - Status = RobotStatus.Available, - Host = "localhost", - Port = 3000, - CurrentInstallationCode = installation.InstallationCode, - CurrentAreaName = areaName, - RobotCapabilities = [RobotCapabilitiesEnum.take_image], - VideoStreams = new List(), - Documentation = new List() - }; + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); - string robotUrl = "/robots"; - var robot = await PostToDb(robotUrl, robotQuery); + // Arrange - Robot + var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, installation); string robotId = robot.Id; // Arrange - Schedule custom mission - create mission definition @@ -577,8 +364,8 @@ public async Task GetNextRun() var query = new CustomMissionQuery { RobotId = robotId, - InstallationCode = installationCode, - AreaName = areaName, + InstallationCode = installation.InstallationCode, + AreaName = area.Name, DesiredStartTime = DateTime.SpecifyKind(new DateTime(3050, 1, 1), DateTimeKind.Utc), InspectionFrequency = new TimeSpan(14, 0, 0, 0), Name = testMissionName, @@ -669,28 +456,24 @@ public async Task GetNextRun() [Fact] public async Task ScheduleDuplicatMissionDefinitions() { - // Arrange - Initialise areas - string installationCode = "installationScheduleDuplicatMissionDefinitions"; - string plantCode = "plantScheduleDuplicatMissionDefinitions"; - string deckName = "deckScheduleDuplicatMissionDefinitions"; - string areaName = "areaScheduleDuplicatMissionDefinitions"; - (_, _, _, _) = await PostAssetInformationToDb(installationCode, plantCode, deckName, areaName); - - // Arrange - Create mission definition - string robotUrl = "/robots"; - var response = await _client.GetAsync(robotUrl); - Assert.True(response.IsSuccessStatusCode); - var robots = await response.Content.ReadFromJsonAsync>(_serializerOptions); - Assert.NotNull(robots); - var robot = robots.Where(robot => robot.Name == "Shockwave").First(); + // Arrange - Initialise area + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + + // Arrange - Robot + var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, installation); string robotId = robot.Id; - string missionSourceId = "986"; // Corresponds to mock in ServiceMock.cs + + string missionSourceId = "986"; + var source = await _databaseUtilities.NewSource(missionSourceId); var query = new ScheduledMissionQuery { RobotId = robotId, - InstallationCode = installationCode, - AreaName = areaName, + InstallationCode = installation.InstallationCode, + AreaName = area.Name, MissionSourceId = missionSourceId, DesiredStartTime = DateTime.UtcNow }; @@ -726,37 +509,19 @@ public async Task ScheduleDuplicatMissionDefinitions() public async Task MissionDoesNotStartIfRobotIsNotInSameInstallationAsMission() { // Arrange - Initialise area - string installationCode = "installationMissionDoesNotStartIfRobotIsNotInSameInstallationAsMission"; - string plantCode = "plantMissionDoesNotStartIfRobotIsNotInSameInstallationAsMission"; - string deckName = "deckMissionDoesNotStartIfRobotIsNotInSameInstallationAsMission"; - string areaName = "areaMissionDoesNotStartIfRobotIsNotInSameInstallationAsMission"; - (var installation, _, _, _) = await PostAssetInformationToDb(installationCode, plantCode, deckName, areaName); + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); string testMissionName = "testMissionDoesNotStartIfRobotIsNotInSameInstallationAsMission"; // Arrange - Get different installation string otherInstallationCode = "installationMissionDoesNotStartIfRobotIsNotInSameInstallationAsMission_Other"; - var otherInstallation = await PostInstallationInformationToDb(otherInstallationCode); - - // Arrange - Create robot - var robotQuery = new CreateRobotQuery - { - IsarId = Guid.NewGuid().ToString(), - Name = "RobotGetNextRun", - SerialNumber = "GetNextRun", - RobotType = RobotType.Robot, - Status = RobotStatus.Available, - Host = "localhost", - Port = 3000, - CurrentInstallationCode = otherInstallation.InstallationCode, - CurrentAreaName = null, - RobotCapabilities = [RobotCapabilitiesEnum.take_image], - VideoStreams = new List(), - Documentation = new List() - }; + var otherInstallation = await _databaseUtilities.NewInstallation(otherInstallationCode); - string robotUrl = "/robots"; - var robot = await PostToDb(robotUrl, robotQuery); + // Arrange - Robot + var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, otherInstallation); string robotId = robot.Id; // Arrange - Create custom mission definition @@ -764,7 +529,7 @@ public async Task MissionDoesNotStartIfRobotIsNotInSameInstallationAsMission() { RobotId = robotId, InstallationCode = installation.InstallationCode, - AreaName = areaName, + AreaName = area.Name, DesiredStartTime = DateTime.SpecifyKind(new DateTime(3050, 1, 1), DateTimeKind.Utc), InspectionFrequency = new TimeSpan(14, 0, 0, 0), Name = testMissionName, @@ -807,36 +572,23 @@ public async Task MissionDoesNotStartIfRobotIsNotInSameInstallationAsMission() public async Task MissionFailsIfRobotIsNotInSameDeckAsMission() { // Arrange - Initialise area - string installationCode = "installationMissionFailsIfRobotIsNotInSameDeckAsMission"; - string plantCode = "plantMissionFailsIfRobotIsNotInSameDeckAsMission"; + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + string deckName1 = "deckMissionFailsIfRobotIsNotInSameDeckAsMission1"; + var deck1 = await _databaseUtilities.NewDeck(installation.InstallationCode, plant.PlantCode, deckName1); string areaName1 = "areaMissionFailsIfRobotIsNotInSameDeckAsMission1"; + var area1 = await _databaseUtilities.NewArea(installation.InstallationCode, plant.PlantCode, deck1.Name, areaName1); + string deckName2 = "deckMissionFailsIfRobotIsNotInSameDeckAsMission2"; + var deck2 = await _databaseUtilities.NewDeck(installation.InstallationCode, plant.PlantCode, deckName2); string areaName2 = "areaMissionFailsIfRobotIsNotInSameDeckAsMission2"; - (var installation, _, _, var area1) = await PostAssetInformationToDb(installationCode, plantCode, deckName1, areaName1); - (_, _, _, var area2) = await PostAssetInformationToDb(installationCode, plantCode, deckName2, areaName2); + var area2 = await _databaseUtilities.NewArea(installation.InstallationCode, plant.PlantCode, deck2.Name, areaName2); string testMissionName = "testMissionFailsIfRobotIsNotInSameDeckAsMission"; - // Arrange - Create robot - var robotQuery = new CreateRobotQuery - { - IsarId = Guid.NewGuid().ToString(), - Name = "RobotMissionFailsIfRobotIsNotInSameDeckAsMission", - SerialNumber = "GetMissionFailsIfRobotIsNotInSameDeckAsMission", - RobotType = RobotType.Robot, - Status = RobotStatus.Available, - Host = "localhost", - Port = 3000, - CurrentInstallationCode = installation.InstallationCode, - CurrentAreaName = area1.AreaName, - RobotCapabilities = [RobotCapabilitiesEnum.take_image], - VideoStreams = new List(), - Documentation = new List() - }; - - string robotUrl = "/robots"; - var robot = await PostToDb(robotUrl, robotQuery); + // Arrange - Robot + var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, installation, area1); string robotId = robot.Id; // Arrange - Mission Run Query @@ -844,7 +596,7 @@ public async Task MissionFailsIfRobotIsNotInSameDeckAsMission() { RobotId = robotId, InstallationCode = installation.InstallationCode, - AreaName = area2.AreaName, + AreaName = area2.Name, DesiredStartTime = DateTime.SpecifyKind(new DateTime(3050, 1, 1), DateTimeKind.Utc), InspectionFrequency = new TimeSpan(14, 0, 0, 0), Name = testMissionName, diff --git a/backend/api.test/Client/RobotTests.cs b/backend/api.test/Client/RobotTests.cs index c58866150..c97701dec 100644 --- a/backend/api.test/Client/RobotTests.cs +++ b/backend/api.test/Client/RobotTests.cs @@ -8,16 +8,19 @@ using System.Text.Json.Serialization; using System.Threading.Tasks; using Api.Controllers.Models; +using Api.Database.Context; using Api.Database.Models; +using Api.Test.Database; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.EntityFrameworkCore; using Xunit; -namespace Api.Test +namespace Api.Test.Client { [Collection("Database collection")] public class RobotTests : IClassFixture> { private readonly HttpClient _client; + private readonly DatabaseUtilities _databaseUtilities; private readonly JsonSerializerOptions _serializerOptions = new() { @@ -38,6 +41,8 @@ public RobotTests(TestWebApplicationFactory factory) _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( TestAuthHandler.AuthenticationScheme ); + object? context = factory.Services.GetService(typeof(FlotillaDbContext)) as FlotillaDbContext ?? throw new ArgumentNullException(nameof(factory)); + _databaseUtilities = new DatabaseUtilities((FlotillaDbContext)context); } [Fact] @@ -80,33 +85,13 @@ public async Task GetRobotById_ShouldReturnRobot() [Fact] public async Task RobotIsNotCreatedWithAreaNotInInstallation() { - // Area - string areaUrl = "/areas"; - var areaResponse = await _client.GetAsync(areaUrl); - Assert.True(areaResponse.IsSuccessStatusCode); - var areas = await areaResponse.Content.ReadFromJsonAsync>(_serializerOptions); - Assert.NotNull(areas); - var area = areas[0]; + // Arrange - Area + var installation = await _databaseUtilities.ReadOrNewInstallation(); - // Installation - string testInstallation = "InstallationRobotIsNotCreatedWithAreaNotInInstallation"; - var installationQuery = new CreateInstallationQuery - { - InstallationCode = testInstallation, - Name = testInstallation - }; - - var installationContent = new StringContent( - JsonSerializer.Serialize(installationQuery), - null, - "application/json" - ); - - string installationUrl = "/installations"; - var installationResponse = await _client.PostAsync(installationUrl, installationContent); - Assert.True(installationResponse.IsSuccessStatusCode); - var wrongInstallation = await installationResponse.Content.ReadFromJsonAsync(_serializerOptions); - Assert.NotNull(wrongInstallation); + var wrongInstallation = await _databaseUtilities.NewInstallation("wrongInstallation"); + var wrongPlant = await _databaseUtilities.ReadOrNewPlant(wrongInstallation.InstallationCode); + var wrongDeck = await _databaseUtilities.ReadOrNewDeck(wrongInstallation.InstallationCode, wrongPlant.PlantCode); + var wrongArea = await _databaseUtilities.ReadOrNewArea(wrongInstallation.InstallationCode, wrongPlant.PlantCode, wrongDeck.Name); // Arrange - Create robot var robotQuery = new CreateRobotQuery @@ -118,8 +103,9 @@ public async Task RobotIsNotCreatedWithAreaNotInInstallation() Status = RobotStatus.Available, Host = "localhost", Port = 3000, - CurrentInstallationCode = wrongInstallation.InstallationCode, - VideoStreams = new List() + CurrentInstallationCode = installation.InstallationCode, + CurrentAreaName = wrongArea.Name, + VideoStreams = [] }; string robotUrl = "/robots"; @@ -135,9 +121,8 @@ public async Task RobotIsNotCreatedWithAreaNotInInstallation() } catch (DbUpdateException ex) { - Assert.True(ex.Message == $"Could not create new robot in database as area '{area.AreaName}' does not exist in installation {wrongInstallation.InstallationCode}"); + Assert.True(ex.Message == $"Could not create new robot in database as area '{wrongArea.Name}' does not exist in installation {installation.InstallationCode}"); } } - } } diff --git a/backend/api.test/Client/RoleAccessTests.cs b/backend/api.test/Client/RoleAccessTests.cs index 55df096d3..b0d575a27 100644 --- a/backend/api.test/Client/RoleAccessTests.cs +++ b/backend/api.test/Client/RoleAccessTests.cs @@ -60,23 +60,6 @@ public async Task AuthorisedGetPlantTest_NotFound() "application/json" ); - var testPose = new Pose - { - Position = new Position - { - X = 1, - Y = 2, - Z = 2 - }, - Orientation = new Orientation - { - X = 0, - Y = 0, - Z = 0, - W = 1 - } - }; - string testInstallation = "AuthorisedGetPlantTest_NotFoundInstallation"; var installationQuery = new CreateInstallationQuery { diff --git a/backend/api.test/Database/DatabaseUtilities.cs b/backend/api.test/Database/DatabaseUtilities.cs index ee3e65c7d..3ec161a6f 100644 --- a/backend/api.test/Database/DatabaseUtilities.cs +++ b/backend/api.test/Database/DatabaseUtilities.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Threading.Tasks; using Api.Controllers.Models; using Api.Database.Context; @@ -22,6 +21,13 @@ public class DatabaseUtilities private readonly RobotModelService _robotModelService; private readonly RobotService _robotService; private readonly UserInfoService _userInfoService; + private readonly SourceService _sourceService; + private readonly string _testInstallationCode = "testInstallationCode"; + private readonly string _testInstallationName = "testInstallation"; + private readonly string _testPlantCode = "testPlantCode"; + private readonly string _testDeckName = "testDeck"; + private readonly string _testAreaName = "testArea"; + public DatabaseUtilities(FlotillaDbContext context) { @@ -37,6 +43,7 @@ public DatabaseUtilities(FlotillaDbContext context) _robotModelService = new RobotModelService(context); _robotService = new RobotService(context, new Mock>().Object, _robotModelService, new MockSignalRService(), _accessRoleService, _installationService, _areaService); _missionRunService = new MissionRunService(context, new MockSignalRService(), new Mock>().Object, _accessRoleService, _missionTaskService, _areaService, _robotService, _userInfoService); + _sourceService = new SourceService(context, new Mock>().Object); } public async Task NewMissionRun( @@ -46,10 +53,11 @@ public async Task NewMissionRun( bool writeToDatabase = false, MissionRunType missionRunType = MissionRunType.Normal, MissionStatus missionStatus = MissionStatus.Pending, - string? isarMissionId = null, + string isarMissionId = "", Api.Database.Models.TaskStatus taskStatus = Api.Database.Models.TaskStatus.Successful ) { + if (string.IsNullOrEmpty(isarMissionId)) isarMissionId = Guid.NewGuid().ToString(); var missionRun = new MissionRun { Name = "testMission", @@ -66,25 +74,25 @@ public async Task NewMissionRun( }; if (missionRunType == MissionRunType.Localization) { - missionRun.Tasks = new List - { + missionRun.Tasks = + [ new(new Pose(), MissionTaskType.Localization) - }; + ]; missionRun.Tasks[0].Status = taskStatus; } else if (missionRunType == MissionRunType.ReturnHome) { - missionRun.Tasks = new List - { + missionRun.Tasks = + [ new(new Pose(), MissionTaskType.ReturnHome) - }; + ]; } else { - missionRun.Tasks = new List - { + missionRun.Tasks = + [ new(new Pose(), MissionTaskType.Inspection) - }; + ]; } if (writeToDatabase) { @@ -93,31 +101,50 @@ public async Task NewMissionRun( return missionRun; } - public async Task NewInstallation() + public async Task ReadOrNewInstallation() { + if (await _installationService.ReadByInstallationCode(_testInstallationCode) is Installation installation) return installation; + return await NewInstallation(); + } + + public async Task NewInstallation(string installationCode = "") + { + if (string.IsNullOrEmpty(installationCode)) installationCode = _testInstallationCode; var createInstallationQuery = new CreateInstallationQuery { - InstallationCode = "testInstallationCode", - Name = "testInstallation" + InstallationCode = installationCode, + Name = _testInstallationName }; - return await _installationService.Create(createInstallationQuery); } + public async Task ReadOrNewPlant(string installationCode) + { + if (await _plantService.ReadByPlantCode(_testPlantCode) is Plant plant) return plant; + return await NewPlant(installationCode); + } + public async Task NewPlant(string installationCode) { var createPlantQuery = new CreatePlantQuery { InstallationCode = installationCode, - PlantCode = "testPlantCode", + PlantCode = _testPlantCode, Name = "testPlant" }; return await _plantService.Create(createPlantQuery); } - public async Task NewDeck(string installationCode, string plantCode, string deckName = "testDeck") + public async Task ReadOrNewDeck(string installationCode, string plantCode) + { + if (await _deckService.ReadByName(_testDeckName) is Deck deck) return deck; + return await NewDeck(installationCode, plantCode); + } + + public async Task NewDeck(string installationCode, string plantCode, string deckName = "") { + if (string.IsNullOrEmpty(deckName)) deckName = _testDeckName; var createDeckQuery = new CreateDeckQuery { InstallationCode = installationCode, @@ -132,14 +159,21 @@ public async Task NewDeck(string installationCode, string plantCode, strin return await _deckService.Create(createDeckQuery); } - public async Task NewArea(string installationCode, string plantCode, string deckName) + public async Task ReadOrNewArea(string installationCode, string plantCode, string deckName) { + if (await _areaService.ReadByInstallationAndName(_testInstallationCode, _testAreaName) is Area area) return area; + return await NewArea(installationCode, plantCode, deckName); + } + + public async Task NewArea(string installationCode, string plantCode, string deckName, string areaName = "") + { + if (string.IsNullOrEmpty(areaName)) areaName = _testAreaName; var createAreaQuery = new CreateAreaQuery { InstallationCode = installationCode, PlantCode = plantCode, DeckName = deckName, - AreaName = "testArea", + AreaName = areaName, DefaultLocalizationPose = new Pose() }; @@ -150,14 +184,14 @@ public async Task NewRobot(RobotStatus status, Installation installation, { var createRobotQuery = new CreateRobotQuery { - Name = "TestBot", + Name = Guid.NewGuid().ToString(), IsarId = Guid.NewGuid().ToString(), RobotType = RobotType.Robot, SerialNumber = "0001", CurrentInstallationCode = installation.InstallationCode, CurrentAreaName = area?.Name, - VideoStreams = new List(), - Documentation = new List(), + VideoStreams = [], + Documentation = [], Host = "localhost", Port = 3000, Status = status, @@ -168,5 +202,13 @@ public async Task NewRobot(RobotStatus status, Installation installation, var robot = new Robot(createRobotQuery, installation, robotModel!, area); return await _robotService.Create(robot); } + + public async Task NewSource(string sourceId) + { + return await _sourceService.Create(new Source + { + SourceId = sourceId + }); + } } } diff --git a/backend/api.test/DbContextTestSetup.cs b/backend/api.test/DbContextTestSetup.cs index fe640404f..83e485ab4 100644 --- a/backend/api.test/DbContextTestSetup.cs +++ b/backend/api.test/DbContextTestSetup.cs @@ -38,7 +38,6 @@ public FlotillaDbContext CreateContext() var options = CreateOptions(); var context = new FlotillaDbContext(options); context.Database.EnsureCreated(); - InitDb.PopulateDb(context); return context; } diff --git a/backend/api.test/EventHandlers/TestMissionEventHandler.cs b/backend/api.test/EventHandlers/TestMissionEventHandler.cs index b0ec4ecb4..54898d0cc 100644 --- a/backend/api.test/EventHandlers/TestMissionEventHandler.cs +++ b/backend/api.test/EventHandlers/TestMissionEventHandler.cs @@ -155,10 +155,10 @@ public void Dispose() public async Task ScheduledMissionStartedWhenSystemIsAvailable() { // Arrange - var installation = await _databaseUtilities.NewInstallation(); - var plant = await _databaseUtilities.NewPlant(installation.InstallationCode); - var deck = await _databaseUtilities.NewDeck(installation.InstallationCode, plant.PlantCode); - var area = await _databaseUtilities.NewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, installation, area); var missionRun = await _databaseUtilities.NewMissionRun(installation.InstallationCode, robot, area); @@ -175,10 +175,10 @@ public async Task ScheduledMissionStartedWhenSystemIsAvailable() public async Task SecondScheduledMissionQueuedIfRobotIsBusy() { // Arrange - var installation = await _databaseUtilities.NewInstallation(); - var plant = await _databaseUtilities.NewPlant(installation.InstallationCode); - var deck = await _databaseUtilities.NewDeck(installation.InstallationCode, plant.PlantCode); - var area = await _databaseUtilities.NewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, installation, area); var missionRunOne = await _databaseUtilities.NewMissionRun(installation.InstallationCode, robot, area); var missionRunTwo = await _databaseUtilities.NewMissionRun(installation.InstallationCode, robot, area); @@ -195,16 +195,14 @@ public async Task SecondScheduledMissionQueuedIfRobotIsBusy() Assert.Equal(MissionStatus.Pending, postTestMissionRunTwo!.Status); } -#pragma warning disable xUnit1004 - [Fact(Skip = "Skipping until a solution has been found for ExecuteUpdate in tests")] -#pragma warning restore xUnit1004 + [Fact] public async Task NewMissionIsStartedWhenRobotBecomesAvailable() { // Arrange - var installation = await _databaseUtilities.NewInstallation(); - var plant = await _databaseUtilities.NewPlant(installation.InstallationCode); - var deck = await _databaseUtilities.NewDeck(installation.InstallationCode, plant.PlantCode); - var area = await _databaseUtilities.NewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); var robot = await _databaseUtilities.NewRobot(RobotStatus.Busy, installation, area); var missionRun = await _databaseUtilities.NewMissionRun(installation.InstallationCode, robot, area); @@ -233,10 +231,10 @@ public async Task NewMissionIsStartedWhenRobotBecomesAvailable() public async Task ReturnToHomeMissionIsStartedIfQueueIsEmptyWhenRobotBecomesAvailable() { // Arrange - var installation = await _databaseUtilities.NewInstallation(); - var plant = await _databaseUtilities.NewPlant(installation.InstallationCode); - var deck = await _databaseUtilities.NewDeck(installation.InstallationCode, plant.PlantCode); - var area = await _databaseUtilities.NewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); var robot = await _databaseUtilities.NewRobot(RobotStatus.Busy, installation, area); var mqttEventArgs = new MqttReceivedArgs( @@ -269,10 +267,10 @@ public async Task ReturnToHomeMissionIsStartedIfQueueIsEmptyWhenRobotBecomesAvai public async Task ReturnToHomeMissionIsNotStartedIfReturnToHomeIsNotSupported() { // Arrange - var installation = await _databaseUtilities.NewInstallation(); - var plant = await _databaseUtilities.NewPlant(installation.InstallationCode); - var deck = await _databaseUtilities.NewDeck(installation.InstallationCode, plant.PlantCode); - var area = await _databaseUtilities.NewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); var robot = await _databaseUtilities.NewRobot(RobotStatus.Busy, installation, area); robot.RobotCapabilities!.Remove(RobotCapabilitiesEnum.return_to_home); await _robotService.Update(robot); @@ -307,10 +305,10 @@ public async Task ReturnToHomeMissionIsNotStartedIfReturnToHomeIsNotSupported() public async Task MissionRunIsStartedForOtherAvailableRobotIfOneRobotHasAnOngoingMissionRun() { // Arrange - var installation = await _databaseUtilities.NewInstallation(); - var plant = await _databaseUtilities.NewPlant(installation.InstallationCode); - var deck = await _databaseUtilities.NewDeck(installation.InstallationCode, plant.PlantCode); - var area = await _databaseUtilities.NewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); var robotOne = await _databaseUtilities.NewRobot(RobotStatus.Available, installation, area); var robotTwo = await _databaseUtilities.NewRobot(RobotStatus.Available, installation, area); var missionRunOne = await _databaseUtilities.NewMissionRun(installation.InstallationCode, robotOne, area); @@ -339,12 +337,12 @@ public async Task MissionRunIsStartedForOtherAvailableRobotIfOneRobotHasAnOngoin public async Task QueuedMissionsAreAbortedWhenLocalizationFails() { // Arrange - var installation = await _databaseUtilities.NewInstallation(); - var plant = await _databaseUtilities.NewPlant(installation.InstallationCode); - var deck = await _databaseUtilities.NewDeck(installation.InstallationCode, plant.PlantCode); - var area = await _databaseUtilities.NewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, installation, area); - var localizationMissionRun = await _databaseUtilities.NewMissionRun(installation.InstallationCode, robot, area, true, MissionRunType.Localization, MissionStatus.Ongoing, Guid.NewGuid().ToString(), Api.Database.Models.TaskStatus.Failed); + var localizationMissionRun = await _databaseUtilities.NewMissionRun(installation.InstallationCode, robot, area, true, MissionRunType.Localization, MissionStatus.Ongoing, taskStatus: Api.Database.Models.TaskStatus.Failed); var missionRun1 = await _databaseUtilities.NewMissionRun(installation.InstallationCode, robot, area, true); Thread.Sleep(100); @@ -372,10 +370,10 @@ public async Task QueuedMissionsAreAbortedWhenLocalizationFails() public async Task QueuedMissionsAreNotAbortedWhenRobotAvailableHappensAtTheSameTimeAsOnIsarMissionCompleted() { // Arrange - var installation = await _databaseUtilities.NewInstallation(); - var plant = await _databaseUtilities.NewPlant(installation.InstallationCode); - var deck = await _databaseUtilities.NewDeck(installation.InstallationCode, plant.PlantCode); - var area = await _databaseUtilities.NewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, installation, null); var missionRun1 = await _databaseUtilities.NewMissionRun(installation.InstallationCode, robot, area, true); Thread.Sleep(100); @@ -414,15 +412,17 @@ public async Task QueuedMissionsAreNotAbortedWhenRobotAvailableHappensAtTheSameT Assert.Equal(MissionStatus.Pending, postTestMissionRun2!.Status); } - [Fact] +#pragma warning disable xUnit1004 + [Fact(Skip = "Skipping until issue #1767 is solved because test is unreliable")] +#pragma warning restore xUnit1004 public async Task QueuedContinuesWhenOnIsarStatusHappensAtTheSameTimeAsOnIsarMissionCompleted() { // Arrange - var installation = await _databaseUtilities.NewInstallation(); - var plant = await _databaseUtilities.NewPlant(installation.InstallationCode); - var deck = await _databaseUtilities.NewDeck(installation.InstallationCode, plant.PlantCode); - var area = await _databaseUtilities.NewArea(installation.InstallationCode, plant.PlantCode, deck.Name); - var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, installation, null); + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, installation, area); var missionRun1 = await _databaseUtilities.NewMissionRun(installation.InstallationCode, robot, area, true, MissionRunType.Localization, MissionStatus.Ongoing, Guid.NewGuid().ToString()); var missionRun2 = await _databaseUtilities.NewMissionRun(installation.InstallationCode, robot, area, true); Thread.Sleep(100); @@ -467,10 +467,10 @@ public async Task QueuedContinuesWhenOnIsarStatusHappensAtTheSameTimeAsOnIsarMis public async Task LocalizationMissionCompletesAfterPressingSendToSafeZoneButton() { // Arrange - var installation = await _databaseUtilities.NewInstallation(); - var plant = await _databaseUtilities.NewPlant(installation.InstallationCode); - var deck = await _databaseUtilities.NewDeck(installation.InstallationCode, plant.PlantCode); - var area = await _databaseUtilities.NewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); var robot = await _databaseUtilities.NewRobot(RobotStatus.Busy, installation, area); await _databaseUtilities.NewMissionRun(installation.InstallationCode, robot, area, true, MissionRunType.Localization, MissionStatus.Ongoing, Guid.NewGuid().ToString()); @@ -494,7 +494,7 @@ public async Task LocalizationMissionCompletesAfterPressingSendToSafeZoneButton( public async Task ReturnHomeMissionNotScheduledIfRobotIsNotLocalized() { // Arrange - var installation = await _databaseUtilities.NewInstallation(); + var installation = await _databaseUtilities.ReadOrNewInstallation(); var robot = await _databaseUtilities.NewRobot(RobotStatus.Busy, installation, null); Thread.Sleep(100); @@ -516,10 +516,10 @@ public async Task ReturnHomeMissionNotScheduledIfRobotIsNotLocalized() public async Task ReturnHomeMissionAbortedIfNewMissionScheduled() { // Arrange - var installation = await _databaseUtilities.NewInstallation(); - var plant = await _databaseUtilities.NewPlant(installation.InstallationCode); - var deck = await _databaseUtilities.NewDeck(installation.InstallationCode, plant.PlantCode); - var area = await _databaseUtilities.NewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); var robot = await _databaseUtilities.NewRobot(RobotStatus.Busy, installation, area); var returnToHomeMission = await _databaseUtilities.NewMissionRun(installation.InstallationCode, robot, area, true, MissionRunType.ReturnHome, MissionStatus.Ongoing, Guid.NewGuid().ToString()); var missionRun = await _databaseUtilities.NewMissionRun(installation.InstallationCode, robot, area, true, MissionRunType.Normal, MissionStatus.Pending, Guid.NewGuid().ToString()); diff --git a/backend/api.test/Mocks/BlobServiceMock.cs b/backend/api.test/Mocks/BlobServiceMock.cs index c6ac8e728..97a2dc7b0 100644 --- a/backend/api.test/Mocks/BlobServiceMock.cs +++ b/backend/api.test/Mocks/BlobServiceMock.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Threading.Tasks; +using System.Threading.Tasks; using Api.Services; using Azure; using Azure.Storage.Blobs.Models; @@ -17,8 +16,8 @@ public async Task DownloadBlob(string blobName, string containerName, st public AsyncPageable FetchAllBlobs(string containerName, string accountName) { - var page = Page.FromValues(new List(), continuationToken: null, response: null!); - var pages = AsyncPageable.FromPages(new[] { page }); + var page = Page.FromValues([], continuationToken: null, response: null!); + var pages = AsyncPageable.FromPages([page]); return pages; } diff --git a/backend/api.test/Mocks/IsarServiceMock.cs b/backend/api.test/Mocks/IsarServiceMock.cs index efef0ea08..476769f03 100644 --- a/backend/api.test/Mocks/IsarServiceMock.cs +++ b/backend/api.test/Mocks/IsarServiceMock.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Threading; +using System.Threading; using System.Threading.Tasks; using Api.Database.Models; using Api.Services; @@ -16,7 +15,7 @@ public async Task StartMission(Robot robot, MissionRun mission) new IsarStartMissionResponse { MissionId = System.Guid.NewGuid().ToString(), - Tasks = new List() + Tasks = [] } ); return isarServiceMissionResponse; @@ -47,7 +46,7 @@ public async Task StartMoveArm(Robot robot, string position) new IsarStartMissionResponse { MissionId = "testStartMoveArm", - Tasks = new List() + Tasks = [] } ); return isarServiceMissionResponse; diff --git a/backend/api.test/Mocks/StidServiceMock.cs b/backend/api.test/Mocks/StidServiceMock.cs index 791774ea5..1df84bc60 100644 --- a/backend/api.test/Mocks/StidServiceMock.cs +++ b/backend/api.test/Mocks/StidServiceMock.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Api.Database.Context; @@ -56,7 +55,7 @@ public class MockStidService(FlotillaDbContext context) : IStidService Name = testAreaName, MapMetadata = new MapMetadata(), DefaultLocalizationPose = new DefaultLocalizationPose(), - SafePositions = new List() + SafePositions = [] }; context.Add(testInstallation); diff --git a/backend/api.test/Services/MissionService.cs b/backend/api.test/Services/MissionService.cs index b4a4ab720..601a8edbe 100644 --- a/backend/api.test/Services/MissionService.cs +++ b/backend/api.test/Services/MissionService.cs @@ -70,10 +70,10 @@ public async Task Create() ); int nReportsBefore = reportsBefore.Count; - var installation = await _databaseUtilities.NewInstallation(); - var plant = await _databaseUtilities.NewPlant(installation.InstallationCode); - var deck = await _databaseUtilities.NewDeck(installation.InstallationCode, plant.PlantCode); - var area = await _databaseUtilities.NewArea(installation.InstallationCode, plant.PlantCode, deck.Name); + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var deck = await _databaseUtilities.ReadOrNewDeck(installation.InstallationCode, plant.PlantCode); + var area = await _databaseUtilities.ReadOrNewArea(installation.InstallationCode, plant.PlantCode, deck.Name); var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, installation); var missionRun = await _databaseUtilities.NewMissionRun(installation.InstallationCode, robot, area); diff --git a/backend/api.test/Services/RobotService.cs b/backend/api.test/Services/RobotService.cs index 220b51f2b..d75a6bcf8 100644 --- a/backend/api.test/Services/RobotService.cs +++ b/backend/api.test/Services/RobotService.cs @@ -1,11 +1,11 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Api.Controllers.Models; using Api.Database.Context; using Api.Database.Models; using Api.Services; +using Api.Test.Database; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Moq; @@ -25,10 +25,12 @@ public class RobotServiceTest : IDisposable private readonly IDefaultLocalizationPoseService _defaultLocalizationPoseService; private readonly IDeckService _deckService; private readonly IAreaService _areaService; + private readonly DatabaseUtilities _databaseUtilities; public RobotServiceTest(DatabaseFixture fixture) { _context = fixture.NewContext; + _databaseUtilities = new DatabaseUtilities(_context); _logger = new Mock>().Object; _robotModelService = new RobotModelService(_context); _signalRService = new MockSignalRService(); @@ -49,6 +51,8 @@ public void Dispose() [Fact] public async Task ReadAll() { + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var _ = await _databaseUtilities.NewRobot(RobotStatus.Available, installation); var robotService = new RobotService(_context, _logger, _robotModelService, _signalRService, _accessRoleService, _installationService, _areaService); var robots = await robotService.ReadAll(); @@ -59,11 +63,11 @@ public async Task ReadAll() public async Task Read() { var robotService = new RobotService(_context, _logger, _robotModelService, _signalRService, _accessRoleService, _installationService, _areaService); - var robots = await robotService.ReadAll(readOnly: false); - var firstRobot = robots.First(); - var robotById = await robotService.ReadById(firstRobot.Id, readOnly: false); - - Assert.Equal(firstRobot, robotById); // To compare the objects directly, we need to use readOnly = false. Otherwise we will read in a new object + var installation = await _databaseUtilities.ReadOrNewInstallation(); + var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, installation); + var robotById = await robotService.ReadById(robot.Id, readOnly: false); + Assert.NotNull(robotById); + Assert.Equal(robot.Id, robotById.Id); } [Fact] @@ -104,14 +108,14 @@ public async Task Create() Name = "", IsarId = "", SerialNumber = "", - VideoStreams = new List - { + VideoStreams = + [ videoStreamQuery - }, - Documentation = new List - { + ], + Documentation = + [ documentationQuery - }, + ], CurrentInstallationCode = installation.InstallationCode, RobotType = RobotType.Robot, Host = "", diff --git a/backend/api.test/api.test.csproj b/backend/api.test/api.test.csproj index 42f0eb2cb..3d20daa7e 100644 --- a/backend/api.test/api.test.csproj +++ b/backend/api.test/api.test.csproj @@ -28,5 +28,4 @@ - diff --git a/backend/api/Configurations/CustomServiceConfigurations.cs b/backend/api/Configurations/CustomServiceConfigurations.cs index afdd3a6dc..88b9cf93b 100644 --- a/backend/api/Configurations/CustomServiceConfigurations.cs +++ b/backend/api/Configurations/CustomServiceConfigurations.cs @@ -34,7 +34,8 @@ IConfiguration configuration using var context = new FlotillaDbContext(dbBuilder.Options); context.Database.EnsureCreated(); - InitDb.PopulateDb(context); + bool initializeDb = configuration.GetSection("Database").GetValue("InitializeInMemDb"); + if (initializeDb) InitDb.PopulateDb(context); // Setting splitting behavior explicitly to avoid warning services.AddDbContext( diff --git a/backend/api/Controllers/AccessRoleController.cs b/backend/api/Controllers/AccessRoleController.cs index 22e011a07..6d35ebf4d 100644 --- a/backend/api/Controllers/AccessRoleController.cs +++ b/backend/api/Controllers/AccessRoleController.cs @@ -62,7 +62,7 @@ public async Task> Create([FromBody] CreateAccessRoleQu if (accessRoleQuery.AccessLevel == RoleAccessLevel.ADMIN) return Unauthorized("Cannot create admin roles using API endpoints"); - var installation = await installationService.ReadByName(accessRoleQuery.InstallationCode, readOnly: true); + var installation = await installationService.ReadByInstallationCode(accessRoleQuery.InstallationCode, readOnly: true); if (installation is null) { logger.LogInformation("Installation not found when creating new access roles"); diff --git a/backend/api/Controllers/DeckController.cs b/backend/api/Controllers/DeckController.cs index 039887fb6..9100cbf05 100644 --- a/backend/api/Controllers/DeckController.cs +++ b/backend/api/Controllers/DeckController.cs @@ -150,12 +150,12 @@ public async Task> Create([FromBody] CreateDeckQuery logger.LogInformation("Creating new deck"); try { - var existingInstallation = await installationService.ReadByName(deck.InstallationCode, readOnly: true); + var existingInstallation = await installationService.ReadByInstallationCode(deck.InstallationCode, readOnly: true); if (existingInstallation == null) { return NotFound($"Could not find installation with name {deck.InstallationCode}"); } - var existingPlant = await plantService.ReadByInstallationAndName(existingInstallation, deck.PlantCode, readOnly: true); + var existingPlant = await plantService.ReadByInstallationAndPlantCode(existingInstallation, deck.PlantCode, readOnly: true); if (existingPlant == null) { return NotFound($"Could not find plant with name {deck.PlantCode}"); diff --git a/backend/api/Controllers/InstallationController.cs b/backend/api/Controllers/InstallationController.cs index e570bf117..e8720e17b 100644 --- a/backend/api/Controllers/InstallationController.cs +++ b/backend/api/Controllers/InstallationController.cs @@ -86,7 +86,7 @@ public async Task> Create([FromBody] CreateInstallati logger.LogInformation("Creating new installation"); try { - var existingInstallation = await installationService.ReadByName(installation.InstallationCode, readOnly: true); + var existingInstallation = await installationService.ReadByInstallationCode(installation.InstallationCode, readOnly: true); if (existingInstallation != null) { logger.LogInformation("An installation for given name and installation already exists"); diff --git a/backend/api/Controllers/MissionSchedulingController.cs b/backend/api/Controllers/MissionSchedulingController.cs index c4951a5f4..ffdd27aec 100644 --- a/backend/api/Controllers/MissionSchedulingController.cs +++ b/backend/api/Controllers/MissionSchedulingController.cs @@ -362,7 +362,7 @@ [FromBody] CustomMissionQuery customMissionQuery catch (Exception e) when (e is RobotNotFoundException) { return NotFound(e.Message); } catch (Exception e) when (e is RobotPreCheckFailedException) { return BadRequest(e.Message); } - var installation = await installationService.ReadByName(customMissionQuery.InstallationCode, readOnly: true); + var installation = await installationService.ReadByInstallationCode(customMissionQuery.InstallationCode, readOnly: true); if (installation == null) { return NotFound($"Could not find installation with name {customMissionQuery.InstallationCode}"); } var missionTasks = customMissionQuery.Tasks.Select(task => new MissionTask(task)).ToList(); diff --git a/backend/api/Controllers/PlantController.cs b/backend/api/Controllers/PlantController.cs index 3da65bb80..ef9fe25da 100644 --- a/backend/api/Controllers/PlantController.cs +++ b/backend/api/Controllers/PlantController.cs @@ -87,12 +87,12 @@ public async Task> Create([FromBody] CreatePlantQuery plant) logger.LogInformation("Creating new plant"); try { - var existingInstallation = await installationService.ReadByName(plant.InstallationCode, readOnly: true); + var existingInstallation = await installationService.ReadByInstallationCode(plant.InstallationCode, readOnly: true); if (existingInstallation == null) { return NotFound($"Installation with installation code {plant.InstallationCode} not found"); } - var existingPlant = await plantService.ReadByInstallationAndName(existingInstallation, plant.PlantCode, readOnly: true); + var existingPlant = await plantService.ReadByInstallationAndPlantCode(existingInstallation, plant.PlantCode, readOnly: true); if (existingPlant != null) { logger.LogInformation("A plant for given name and plant already exists"); diff --git a/backend/api/Database/Context/InitDb.cs b/backend/api/Database/Context/InitDb.cs index 4e1ee816c..fc9992bef 100644 --- a/backend/api/Database/Context/InitDb.cs +++ b/backend/api/Database/Context/InitDb.cs @@ -37,10 +37,11 @@ private static List GetInspections() InspectionType = InspectionType.ThermalImage }; - return new List(new[] - { - inspection1, inspection2 - }); + return new List( + [ + inspection1, + inspection2 + ]); } private static List GetAccessRoles() @@ -52,10 +53,10 @@ private static List GetAccessRoles() RoleName = "Role.User.HUA" }; - return new List(new[] - { + return new List( + [ accessRole1 - }); + ]); } private static List GetInstallations() @@ -74,10 +75,11 @@ private static List GetInstallations() InstallationCode = "KAA" }; - return new List(new[] - { - installation1, installation2 - }); + return new List( + [ + installation1, + installation2 + ]); } private static List GetPlants() @@ -98,10 +100,11 @@ private static List GetPlants() PlantCode = "Kårstø" }; - return new List(new[] - { - plant1, plant2 - }); + return new List( + [ + plant1, + plant2 + ]); } private static List GetDecks() @@ -151,10 +154,14 @@ private static List GetDecks() Name = "Huldra Mezzanine Deck" }; - return new List(new[] - { - deck1, deck2, deck3, deck4, deckHuldraMezzanine - }); + return new List( + [ + deck1, + deck2, + deck3, + deck4, + deckHuldraMezzanine + ]); } private static List GetAreas() @@ -168,7 +175,7 @@ private static List GetAreas() Name = "testArea", MapMetadata = new MapMetadata(), DefaultLocalizationPose = new DefaultLocalizationPose(), - SafePositions = new List(new[] { new SafePosition() }) + SafePositions = new List([new SafePosition()]) }; var area2 = new Area @@ -180,7 +187,7 @@ private static List GetAreas() Name = "testArea2", MapMetadata = new MapMetadata(), DefaultLocalizationPose = new DefaultLocalizationPose(), - SafePositions = new List(new[] { new SafePosition() }) + SafePositions = new List([new SafePosition()]) }; var area3 = new Area @@ -192,7 +199,7 @@ private static List GetAreas() Name = "testArea3", MapMetadata = new MapMetadata(), DefaultLocalizationPose = new DefaultLocalizationPose(), - SafePositions = new List(new[] { new SafePosition() }) + SafePositions = new List([new SafePosition()]) }; var area4 = new Area @@ -204,7 +211,7 @@ private static List GetAreas() Name = "testArea4", MapMetadata = new MapMetadata(), DefaultLocalizationPose = new DefaultLocalizationPose(), - SafePositions = new List(new[] { new SafePosition() }) + SafePositions = new List([new SafePosition()]) }; var area5 = new Area @@ -216,7 +223,7 @@ private static List GetAreas() Name = "testArea5", MapMetadata = new MapMetadata(), DefaultLocalizationPose = new DefaultLocalizationPose(), - SafePositions = new List(new[] { new SafePosition() }) + SafePositions = new List([new SafePosition()]) }; var area6 = new Area @@ -228,7 +235,7 @@ private static List GetAreas() Name = "testArea6", MapMetadata = new MapMetadata(), DefaultLocalizationPose = new DefaultLocalizationPose(), - SafePositions = new List(new[] { new SafePosition() }) + SafePositions = new List([new SafePosition()]) }; var areaHuldraHB = new Area @@ -240,13 +247,19 @@ private static List GetAreas() Name = "HB", MapMetadata = new MapMetadata(), DefaultLocalizationPose = new DefaultLocalizationPose(), - SafePositions = new List(new[] { new SafePosition() }) + SafePositions = new List([new SafePosition()]) }; - return new List(new[] - { - area1, area2, area3, area4, area5, area6,areaHuldraHB - }); + return new List( + [ + area1, + area2, + area3, + area4, + area5, + area6, + areaHuldraHB + ]); } private static List GetSources() @@ -285,8 +298,8 @@ private static List GetRobots() Host = "localhost", Port = 3000, CurrentInstallation = installations[0], - VideoStreams = new List(), - Documentation = new List(), + VideoStreams = [], + Documentation = [], Pose = new Pose() }; @@ -299,8 +312,8 @@ private static List GetRobots() Host = "localhost", Port = 3000, CurrentInstallation = installations[0], - VideoStreams = new List(), - Documentation = new List(), + VideoStreams = [], + Documentation = [], Pose = new Pose() }; @@ -313,8 +326,8 @@ private static List GetRobots() Host = "localhost", Port = 3000, CurrentInstallation = installations[0], - VideoStreams = new List(), - Documentation = new List(), + VideoStreams = [], + Documentation = [], Pose = new Pose() }; @@ -511,7 +524,7 @@ private static List GetMissionRuns() MissionId = missionDefinitions[0].Id, Status = MissionStatus.Successful, DesiredStartTime = DateTime.UtcNow, - Tasks = new List(), + Tasks = [], Map = new MapMetadata() }; @@ -524,7 +537,7 @@ private static List GetMissionRuns() MissionId = missionDefinitions[0].Id, Status = MissionStatus.Successful, DesiredStartTime = DateTime.UtcNow, - Tasks = new List(), + Tasks = [], Map = new MapMetadata() }; missionDefinitions[0].LastSuccessfulRun = missionRun2; @@ -617,10 +630,16 @@ private static List GetMissionRuns() missionDefinitions[1].LastSuccessfulRun = missionRun3; - return new List(new[] - { - missionRun1, missionRun2, missionRun3, missionRun4, missionRun5, missionRun6, missionRun7 - }); + return new List( + [ + missionRun1, + missionRun2, + missionRun3, + missionRun4, + missionRun5, + missionRun6, + missionRun7 + ]); } public static void AddRobotModelsToContext(FlotillaDbContext context) diff --git a/backend/api/Database/Models/Robot.cs b/backend/api/Database/Models/Robot.cs index 54fae7dba..81bf5304e 100644 --- a/backend/api/Database/Models/Robot.cs +++ b/backend/api/Database/Models/Robot.cs @@ -8,8 +8,8 @@ public class Robot { public Robot() { - Documentation = new List(); - VideoStreams = new List(); + Documentation = []; + VideoStreams = []; IsarId = "defaultIsarId"; Name = "defaultId"; SerialNumber = "defaultSerialNumber"; diff --git a/backend/api/EventHandlers/MqttEventHandler.cs b/backend/api/EventHandlers/MqttEventHandler.cs index 3140a4a81..4d8bbf273 100644 --- a/backend/api/EventHandlers/MqttEventHandler.cs +++ b/backend/api/EventHandlers/MqttEventHandler.cs @@ -117,7 +117,7 @@ private async void OnIsarRobotInfo(object? sender, MqttReceivedArgs mqttArgs) { var isarRobotInfo = (IsarRobotInfoMessage)mqttArgs.Message; - var installation = await InstallationService.ReadByName(isarRobotInfo.CurrentInstallation, readOnly: true); + var installation = await InstallationService.ReadByInstallationCode(isarRobotInfo.CurrentInstallation, readOnly: true); if (installation is null) { diff --git a/backend/api/Services/AreaService.cs b/backend/api/Services/AreaService.cs index 66aa47df3..ae7e1dc07 100644 --- a/backend/api/Services/AreaService.cs +++ b/backend/api/Services/AreaService.cs @@ -65,13 +65,13 @@ public async Task> ReadAll(AreaQueryStringParameters parameters, public async Task> ReadByDeckId(string deckId, bool readOnly = true) { - if (deckId == null) { return new List(); } + if (deckId == null) { return []; } return await GetAreas(readOnly: readOnly).Where(a => a.Deck != null && a.Deck.Id.Equals(deckId)).ToListAsync(); } public async Task ReadByInstallationAndName(string installationCode, string areaName, bool readOnly = true) { - var installation = await installationService.ReadByName(installationCode, readOnly: true); + var installation = await installationService.ReadByInstallationCode(installationCode, readOnly: true); if (installation == null) { return null; } return await GetAreas(readOnly: readOnly).Where(a => @@ -79,8 +79,8 @@ public async Task> ReadAll(AreaQueryStringParameters parameters, } public async Task> ReadByInstallation(string installationCode) { - var installation = await installationService.ReadByName(installationCode, readOnly: true); - if (installation == null) { return new List(); } + var installation = await installationService.ReadByInstallationCode(installationCode, readOnly: true); + if (installation == null) { return []; } return await GetAreas().Where(a => a.Installation.Id.Equals(installation.Id)).ToListAsync(); } @@ -92,10 +92,10 @@ public async Task Create(CreateAreaQuery newAreaQuery, List position safePositions.Add(new SafePosition(pose)); } - var installation = await installationService.ReadByName(newAreaQuery.InstallationCode, readOnly: true) ?? + var installation = await installationService.ReadByInstallationCode(newAreaQuery.InstallationCode, readOnly: true) ?? throw new InstallationNotFoundException($"No installation with name {newAreaQuery.InstallationCode} could be found"); - var plant = await plantService.ReadByInstallationAndName(installation, newAreaQuery.PlantCode, readOnly: true) ?? + var plant = await plantService.ReadByInstallationAndPlantCode(installation, newAreaQuery.PlantCode, readOnly: true) ?? throw new PlantNotFoundException($"No plant with name {newAreaQuery.PlantCode} could be found"); var deck = await deckService.ReadByInstallationAndPlantAndName(installation, plant, newAreaQuery.DeckName, readOnly: true) ?? diff --git a/backend/api/Services/DeckService.cs b/backend/api/Services/DeckService.cs index 3f480525f..71f9360ae 100644 --- a/backend/api/Services/DeckService.cs +++ b/backend/api/Services/DeckService.cs @@ -59,8 +59,8 @@ public async Task> ReadAll(bool readOnly = true) public async Task> ReadByInstallation(string installationCode, bool readOnly = true) { - var installation = await installationService.ReadByName(installationCode, readOnly: true); - if (installation == null) { return new List(); } + var installation = await installationService.ReadByInstallationCode(installationCode, readOnly: true); + if (installation == null) { return []; } return await GetDecks(readOnly: readOnly).Where(a => a.Installation != null && a.Installation.Id.Equals(installation.Id)).ToListAsync(); } @@ -84,9 +84,9 @@ public async Task> ReadByInstallation(string installationCode, public async Task Create(CreateDeckQuery newDeckQuery) { - var installation = await installationService.ReadByName(newDeckQuery.InstallationCode, readOnly: true) ?? + var installation = await installationService.ReadByInstallationCode(newDeckQuery.InstallationCode, readOnly: true) ?? throw new InstallationNotFoundException($"No installation with name {newDeckQuery.InstallationCode} could be found"); - var plant = await plantService.ReadByInstallationAndName(installation, newDeckQuery.PlantCode, readOnly: true) ?? + var plant = await plantService.ReadByInstallationAndPlantCode(installation, newDeckQuery.PlantCode, readOnly: true) ?? throw new PlantNotFoundException($"No plant with name {newDeckQuery.PlantCode} could be found"); var existingDeck = await ReadByInstallationAndPlantAndName(installation, plant, newDeckQuery.Name, readOnly: true); diff --git a/backend/api/Services/InstallationService.cs b/backend/api/Services/InstallationService.cs index dd0e786d2..b520c2941 100644 --- a/backend/api/Services/InstallationService.cs +++ b/backend/api/Services/InstallationService.cs @@ -12,7 +12,7 @@ public interface IInstallationService public abstract Task ReadById(string id, bool readOnly = true); - public abstract Task ReadByName(string installation, bool readOnly = true); + public abstract Task ReadByInstallationCode(string installation, bool readOnly = true); public abstract Task Create(CreateInstallationQuery newInstallation); @@ -68,7 +68,7 @@ private async Task ApplyDatabaseUpdate(Installation? installation) .FirstOrDefaultAsync(a => a.Id.Equals(id)); } - public async Task ReadByName(string installationCode, bool readOnly = true) + public async Task ReadByInstallationCode(string installationCode, bool readOnly = true) { if (installationCode == null) return null; @@ -79,7 +79,7 @@ private async Task ApplyDatabaseUpdate(Installation? installation) public async Task Create(CreateInstallationQuery newInstallationQuery) { - var installation = await ReadByName(newInstallationQuery.InstallationCode, readOnly: true); + var installation = await ReadByInstallationCode(newInstallationQuery.InstallationCode, readOnly: true); if (installation == null) { installation = new Installation diff --git a/backend/api/Services/LocalizationService.cs b/backend/api/Services/LocalizationService.cs index 834dde290..ca374da29 100644 --- a/backend/api/Services/LocalizationService.cs +++ b/backend/api/Services/LocalizationService.cs @@ -14,7 +14,7 @@ public class LocalizationService(ILogger logger, IRobotServ public async Task EnsureRobotIsOnSameInstallationAsMission(Robot robot, MissionDefinition missionDefinition) { - var missionInstallation = await installationService.ReadByName(missionDefinition.InstallationCode, readOnly: true); + var missionInstallation = await installationService.ReadByInstallationCode(missionDefinition.InstallationCode, readOnly: true); if (missionInstallation is null) { diff --git a/backend/api/Services/MissionSchedulingService.cs b/backend/api/Services/MissionSchedulingService.cs index 5e12a927e..0094beff6 100644 --- a/backend/api/Services/MissionSchedulingService.cs +++ b/backend/api/Services/MissionSchedulingService.cs @@ -312,10 +312,10 @@ public async Task ScheduleMissionToDriveToSafePosition(string robotId, string ar Area = area, Status = MissionStatus.Pending, DesiredStartTime = DateTime.UtcNow, - Tasks = new List(new[] - { + Tasks = new List( + [ new MissionTask(customTaskQuery) - }), + ]), Map = new MapMetadata() }; diff --git a/backend/api/Services/PlantService.cs b/backend/api/Services/PlantService.cs index 05978d86c..14b0163e8 100644 --- a/backend/api/Services/PlantService.cs +++ b/backend/api/Services/PlantService.cs @@ -15,9 +15,11 @@ public interface IPlantService public Task> ReadByInstallation(string installationCode, bool readOnly = true); - public Task ReadByInstallationAndName(Installation installation, string plantCode, bool readOnly = true); + public Task ReadByPlantCode(string plantCode, bool readOnly = true); - public Task ReadByInstallationAndName(string installationCode, string plantCode, bool readOnly = true); + public Task ReadByInstallationAndPlantCode(Installation installation, string plantCode, bool readOnly = true); + + public Task ReadByInstallationAndPlantCode(string installationCode, string plantCode, bool readOnly = true); public Task Create(CreatePlantQuery newPlant); @@ -53,22 +55,28 @@ public async Task> ReadAll(bool readOnly = true) public async Task> ReadByInstallation(string installationCode, bool readOnly = true) { - var installation = await installationService.ReadByName(installationCode, readOnly: true); - if (installation == null) { return new List(); } + var installation = await installationService.ReadByInstallationCode(installationCode, readOnly: true); + if (installation == null) { return []; } return await GetPlants(readOnly: readOnly).Where(a => a.Installation != null && a.Installation.Id.Equals(installation.Id)).ToListAsync(); } - public async Task ReadByInstallationAndName(Installation installation, string plantCode, bool readOnly = true) + public async Task ReadByPlantCode(string plantCode, bool readOnly = true) + { + return await GetPlants(readOnly: readOnly).Where(a => + a.PlantCode.ToLower().Equals(plantCode.ToLower())).FirstOrDefaultAsync(); + } + + public async Task ReadByInstallationAndPlantCode(Installation installation, string plantCode, bool readOnly = true) { return await GetPlants(readOnly: readOnly).Where(a => a.PlantCode.ToLower().Equals(plantCode.ToLower()) && a.Installation != null && a.Installation.Id.Equals(installation.Id)).FirstOrDefaultAsync(); } - public async Task ReadByInstallationAndName(string installationCode, string plantCode, bool readOnly = true) + public async Task ReadByInstallationAndPlantCode(string installationCode, string plantCode, bool readOnly = true) { - var installation = await installationService.ReadByName(installationCode, readOnly: true); + var installation = await installationService.ReadByInstallationCode(installationCode, readOnly: true); if (installation == null) { return null; } return await GetPlants(readOnly: readOnly).Where(a => a.Installation != null && a.Installation.Id.Equals(installation.Id) && @@ -78,10 +86,10 @@ public async Task> ReadByInstallation(string installationCode public async Task Create(CreatePlantQuery newPlantQuery) { - var installation = await installationService.ReadByName(newPlantQuery.InstallationCode, readOnly: true) ?? + var installation = await installationService.ReadByInstallationCode(newPlantQuery.InstallationCode, readOnly: true) ?? throw new InstallationNotFoundException($"No installation with name {newPlantQuery.InstallationCode} could be found"); - var plant = await ReadByInstallationAndName(installation, newPlantQuery.PlantCode, readOnly: true); + var plant = await ReadByInstallationAndPlantCode(installation, newPlantQuery.PlantCode, readOnly: true); if (plant == null) { plant = new Plant diff --git a/backend/api/Services/ReturnToHomeService.cs b/backend/api/Services/ReturnToHomeService.cs index abbc9fe9d..2b51d75bf 100644 --- a/backend/api/Services/ReturnToHomeService.cs +++ b/backend/api/Services/ReturnToHomeService.cs @@ -97,10 +97,10 @@ private async Task ScheduleReturnToHomeMissionRun(string robotId) Area = robot.CurrentArea, Status = MissionStatus.Pending, DesiredStartTime = DateTime.UtcNow, - Tasks = new List - { + Tasks = + [ new(new Pose(robot.CurrentArea.Deck.DefaultLocalizationPose.Pose), MissionTaskType.ReturnHome) - }, + ], Map = new MapMetadata() }; await mapService.AssignMapToMission(returnToHomeMissionRun); diff --git a/backend/api/Services/RobotModelService.cs b/backend/api/Services/RobotModelService.cs index 96fb43c5c..bf8ce9d01 100644 --- a/backend/api/Services/RobotModelService.cs +++ b/backend/api/Services/RobotModelService.cs @@ -41,6 +41,7 @@ public RobotModelService(FlotillaDbContext context) // They can then be modified later with other values if needed InitDb.AddRobotModelsToContext(context); context.SaveChanges(); + context.ChangeTracker.Clear(); } } diff --git a/backend/api/Services/RobotService.cs b/backend/api/Services/RobotService.cs index 8ccfe5448..609aea080 100644 --- a/backend/api/Services/RobotService.cs +++ b/backend/api/Services/RobotService.cs @@ -64,7 +64,7 @@ public async Task CreateFromQuery(CreateRobotQuery robotQuery) var robotModel = await robotModelService.ReadByRobotType(robotQuery.RobotType, readOnly: true); if (robotModel != null) { - var installation = await installationService.ReadByName(robotQuery.CurrentInstallationCode, readOnly: true); + var installation = await installationService.ReadByInstallationCode(robotQuery.CurrentInstallationCode, readOnly: true); if (installation is null) { logger.LogError("Installation {CurrentInstallation} does not exist", robotQuery.CurrentInstallationCode); diff --git a/backend/api/appsettings.Local.json b/backend/api/appsettings.Local.json index 04a227247..5aea17f4d 100644 --- a/backend/api/appsettings.Local.json +++ b/backend/api/appsettings.Local.json @@ -7,7 +7,9 @@ "VaultUri": "https://flotilladevkv.vault.azure.net/" }, "Isar": { - "Scopes": ["fd384acd-5c1b-4c44-a1ac-d41d720ed0fe/.default"] + "Scopes": [ + "fd384acd-5c1b-4c44-a1ac-d41d720ed0fe/.default" + ] }, "Maps": { "StorageAccount": "flotillamaps" @@ -41,7 +43,8 @@ "ConnectionString": "" }, "Database": { - "UseInMemoryDatabase": true + "UseInMemoryDatabase": true, + "InitializeInMemDb": true }, "Local": { "DevUserId": "" diff --git a/backend/api/appsettings.json b/backend/api/appsettings.json index 7055edc3c..e26994f26 100644 --- a/backend/api/appsettings.json +++ b/backend/api/appsettings.json @@ -33,7 +33,8 @@ "https://*.equinor.com/" ], "Database": { - "ConnectionString": "" + "ConnectionString": "", + "InitializeInMemDb": false }, "MissionLoader": { "FileName": "Api.Services.MissionLoaders.EchoAndCustomMissionLoader"