diff --git a/backend/api.test/Client/AreaTests.cs b/backend/api.test/Client/AreaTests.cs index 448514df..ab50f5fb 100644 --- a/backend/api.test/Client/AreaTests.cs +++ b/backend/api.test/Client/AreaTests.cs @@ -2,51 +2,40 @@ using System.Collections.Generic; using System.Linq; using System.Net.Http; -using System.Net.Http.Headers; using System.Net.Http.Json; using System.Text.Json; -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.Client { - [Collection("Database collection")] - public class AreaTests : IClassFixture> + public class AreaTests : IAsyncLifetime { - private readonly HttpClient _client; - private readonly DatabaseUtilities _databaseUtilities; - private readonly JsonSerializerOptions _serializerOptions = - new() - { - Converters = { new JsonStringEnumConverter() }, - PropertyNameCaseInsensitive = true, - }; + public required DatabaseUtilities DatabaseUtilities; + public required HttpClient Client; + public required JsonSerializerOptions SerializerOptions; - public AreaTests(TestWebApplicationFactory factory) + public async Task InitializeAsync() { - _client = factory.CreateClient( - new WebApplicationFactoryClientOptions - { - AllowAutoRedirect = false, - BaseAddress = new Uri("https://localhost:8000"), - } - ); - _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( - TestAuthHandler.AuthenticationScheme + string databaseName = Guid.NewGuid().ToString(); + (string connectionString, var connection) = await TestSetupHelpers.ConfigureDatabase( + databaseName ); + var factory = TestSetupHelpers.ConfigureWebApplicationFactory(databaseName); - object? context = - factory.Services.GetService(typeof(FlotillaDbContext)) as FlotillaDbContext - ?? throw new ArgumentNullException(nameof(factory)); - _databaseUtilities = new DatabaseUtilities((FlotillaDbContext)context); + Client = TestSetupHelpers.ConfigureHttpClient(factory); + SerializerOptions = TestSetupHelpers.ConfigureJsonSerializerOptions(); + + DatabaseUtilities = new DatabaseUtilities( + TestSetupHelpers.ConfigureFlotillaDbContext(connectionString) + ); } + public Task DisposeAsync() => Task.CompletedTask; + [Fact] public async Task AreaTest() { @@ -127,19 +116,16 @@ public async Task AreaTest() // Act string installationUrl = "/installations"; - var installationResponse = await _client.PostAsync( - installationUrl, - installationContent - ); + var installationResponse = await Client.PostAsync(installationUrl, installationContent); string plantUrl = "/plants"; - var plantResponse = await _client.PostAsync(plantUrl, plantContent); + var plantResponse = await Client.PostAsync(plantUrl, plantContent); string inspectionAreaUrl = "/inspectionAreas"; - var inspectionAreaResponse = await _client.PostAsync( + var inspectionAreaResponse = await Client.PostAsync( inspectionAreaUrl, inspectionAreaContent ); string areaUrl = "/areas"; - var areaResponse = await _client.PostAsync(areaUrl, areaContent); + var areaResponse = await Client.PostAsync(areaUrl, areaContent); // Assert Assert.True(installationResponse.IsSuccessStatusCode); @@ -147,7 +133,7 @@ public async Task AreaTest() Assert.True(inspectionAreaResponse.IsSuccessStatusCode); Assert.True(areaResponse.IsSuccessStatusCode); var area = await areaResponse.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); Assert.NotNull(area); } @@ -156,15 +142,15 @@ public async Task AreaTest() public async Task MissionIsCreatedInInspectionArea() { // Arrange - Initialise area - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.ReadOrNewInstallation(); + var plant = await DatabaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.ReadOrNewInspectionArea( installation.InstallationCode, plant.PlantCode ); // Arrange - Robot - var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, installation); + var robot = await DatabaseUtilities.NewRobot(RobotStatus.Available, installation); string robotId = robot.Id; string testMissionName = "testMissionInInspectionAreaTest"; @@ -203,16 +189,16 @@ public async Task MissionIsCreatedInInspectionArea() // Act string missionUrl = "/missions/custom"; - var missionResponse = await _client.PostAsync(missionUrl, missionContent); + var missionResponse = await Client.PostAsync(missionUrl, missionContent); Assert.True(missionResponse.IsSuccessStatusCode); var mission = await missionResponse.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); Assert.NotNull(mission); Assert.NotNull(mission.MissionId); string inspectionAreaUrl = "/inspectionAreas"; - var inspectionareaMissionsResponse = await _client.GetAsync( + var inspectionareaMissionsResponse = await Client.GetAsync( inspectionAreaUrl + $"/{inspectionArea.Id}/mission-definitions" ); @@ -220,7 +206,7 @@ public async Task MissionIsCreatedInInspectionArea() Assert.True(inspectionareaMissionsResponse.IsSuccessStatusCode); var missions = await inspectionareaMissionsResponse.Content.ReadFromJsonAsync< IList - >(_serializerOptions); + >(SerializerOptions); Assert.NotNull(missions); Assert.Single( missions.Where(m => m.Id.Equals(mission.MissionId, StringComparison.Ordinal)) @@ -231,13 +217,13 @@ public async Task MissionIsCreatedInInspectionArea() public async Task EmergencyDockTest() { // Arrange - var installation = await _databaseUtilities.ReadOrNewInstallation(); + var installation = await DatabaseUtilities.ReadOrNewInstallation(); string installationCode = installation.InstallationCode; // Act string goToDockingPositionUrl = $"/emergency-action/{installationCode}/abort-current-missions-and-send-all-robots-to-safe-zone"; - var missionResponse = await _client.PostAsync(goToDockingPositionUrl, null); + var missionResponse = await Client.PostAsync(goToDockingPositionUrl, null); // Assert Assert.True(missionResponse.IsSuccessStatusCode); @@ -251,9 +237,9 @@ public async Task EmergencyDockTest() public async Task UpdateDefaultLocalizationPoseOnInspectionArea() { // Arrange - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.ReadOrNewInstallation(); + var plant = await DatabaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.ReadOrNewInspectionArea( installation.InstallationCode, plant.PlantCode ); @@ -287,11 +273,11 @@ public async Task UpdateDefaultLocalizationPoseOnInspectionArea() ); // Act - var putResponse = await _client.PutAsync(url, content); + var putResponse = await Client.PutAsync(url, content); Assert.True(putResponse.IsSuccessStatusCode); var putInspectionArea = await putResponse.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); // Assert diff --git a/backend/api.test/Client/MissionTests.cs b/backend/api.test/Client/MissionTests.cs index 5b710556..3ffef5c9 100644 --- a/backend/api.test/Client/MissionTests.cs +++ b/backend/api.test/Client/MissionTests.cs @@ -3,59 +3,48 @@ using System.Linq; using System.Net; using System.Net.Http; -using System.Net.Http.Headers; using System.Net.Http.Json; using System.Text.Json; -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.Client { - [Collection("Database collection")] - public class MissionTests : IClassFixture> + public class MissionTests : IAsyncLifetime { - private readonly HttpClient _client; - private readonly DatabaseUtilities _databaseUtilities; - private readonly JsonSerializerOptions _serializerOptions = - new() - { - Converters = { new JsonStringEnumConverter() }, - PropertyNameCaseInsensitive = true, - }; + public required DatabaseUtilities DatabaseUtilities; + public required HttpClient Client; + public required JsonSerializerOptions SerializerOptions; - public MissionTests(TestWebApplicationFactory factory) + public async Task InitializeAsync() { - _client = factory.CreateClient( - new WebApplicationFactoryClientOptions - { - AllowAutoRedirect = false, - BaseAddress = new Uri("https://localhost:8000"), - } - ); - _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( - TestAuthHandler.AuthenticationScheme + string databaseName = Guid.NewGuid().ToString(); + (string connectionString, var connection) = await TestSetupHelpers.ConfigureDatabase( + databaseName ); + var factory = TestSetupHelpers.ConfigureWebApplicationFactory(databaseName); + + Client = TestSetupHelpers.ConfigureHttpClient(factory); + SerializerOptions = TestSetupHelpers.ConfigureJsonSerializerOptions(); - object? context = - factory.Services.GetService(typeof(FlotillaDbContext)) as FlotillaDbContext - ?? throw new ArgumentNullException(nameof(factory)); - _databaseUtilities = new DatabaseUtilities((FlotillaDbContext)context); + DatabaseUtilities = new DatabaseUtilities( + TestSetupHelpers.ConfigureFlotillaDbContext(connectionString) + ); } + public Task DisposeAsync() => Task.CompletedTask; + [Fact] public async Task ScheduleOneMissionTest() { // Arrange - Area - var installation = await _databaseUtilities.ReadOrNewInstallation(); + var installation = await DatabaseUtilities.ReadOrNewInstallation(); // Arrange - Robot - var robot = await _databaseUtilities.NewRobot(RobotStatus.Busy, installation); + var robot = await DatabaseUtilities.NewRobot(RobotStatus.Busy, installation); string robotId = robot.Id; string missionsUrl = "/missions"; @@ -75,12 +64,12 @@ public async Task ScheduleOneMissionTest() "application/json" ); - var response = await _client.PostAsync(missionsUrl, content); + var response = await Client.PostAsync(missionsUrl, content); // Assert Assert.True(response.IsSuccessStatusCode); var missionRun = await response.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); Assert.NotNull(missionRun); Assert.NotNull(missionRun.Id); @@ -91,10 +80,10 @@ public async Task ScheduleOneMissionTest() public async Task Schedule3MissionsTest() { // Arrange - Area - var installation = await _databaseUtilities.ReadOrNewInstallation(); + var installation = await DatabaseUtilities.ReadOrNewInstallation(); // Arrange - Robot - var robot = await _databaseUtilities.NewRobot(RobotStatus.Busy, installation); + var robot = await DatabaseUtilities.NewRobot(RobotStatus.Busy, installation); string robotId = robot.Id; string missionSourceId = "97"; @@ -115,44 +104,44 @@ public async Task Schedule3MissionsTest() // Increasing pageSize to 50 to ensure the missions we are looking for is included string urlMissionRuns = "/missions/runs?pageSize=50"; - var response = await _client.GetAsync(urlMissionRuns); + var response = await Client.GetAsync(urlMissionRuns); var missionRuns = await response.Content.ReadFromJsonAsync>( - _serializerOptions + SerializerOptions ); Assert.True(response.IsSuccessStatusCode); Assert.NotNull(missionRuns); int missionRunsBefore = missionRuns.Count; string missionsUrl = "/missions"; - response = await _client.PostAsync(missionsUrl, content); + response = await Client.PostAsync(missionsUrl, content); // Assert Assert.True(response.IsSuccessStatusCode); - response = await _client.PostAsync(missionsUrl, content); + response = await Client.PostAsync(missionsUrl, content); var missionRun1 = await response.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); Assert.True(response.IsSuccessStatusCode); Assert.NotNull(missionRun1); - response = await _client.PostAsync(missionsUrl, content); + response = await Client.PostAsync(missionsUrl, content); var missionRun2 = await response.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); Assert.True(response.IsSuccessStatusCode); Assert.NotNull(missionRun2); - response = await _client.PostAsync(missionsUrl, content); + response = await Client.PostAsync(missionsUrl, content); var missionRun3 = await response.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); Assert.True(response.IsSuccessStatusCode); Assert.NotNull(missionRun3); - response = await _client.GetAsync(urlMissionRuns); + response = await Client.GetAsync(urlMissionRuns); missionRuns = await response.Content.ReadFromJsonAsync>( - _serializerOptions + SerializerOptions ); // Assert @@ -167,13 +156,13 @@ public async Task Schedule3MissionsTest() public async Task AddNonDuplicateAreasToDb() { // Arrange - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.ReadOrNewInstallation(); + var plant = await DatabaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.ReadOrNewInspectionArea( installation.InstallationCode, plant.PlantCode ); - var _ = await _databaseUtilities.ReadOrNewArea( + var _ = await DatabaseUtilities.ReadOrNewArea( installation.InstallationCode, plant.PlantCode, inspectionArea.Name @@ -209,7 +198,7 @@ public async Task AddNonDuplicateAreasToDb() "application/json" ); string areaUrl = "/areas"; - var response = await _client.PostAsync(areaUrl, areaContent); + var response = await Client.PostAsync(areaUrl, areaContent); Assert.True( response.IsSuccessStatusCode, $"Failed to post to {areaUrl}. Status code: {response.StatusCode}" @@ -217,7 +206,7 @@ public async Task AddNonDuplicateAreasToDb() Assert.True(response != null, $"Failed to post to {areaUrl}. Null returned"); var responseObject = await response.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); Assert.True(responseObject != null, $"No object returned from post to {areaUrl}"); } @@ -226,13 +215,13 @@ public async Task AddNonDuplicateAreasToDb() public async Task AddDuplicateAreasToDb_Fails() { // Arrange - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.ReadOrNewInstallation(); + var plant = await DatabaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.ReadOrNewInspectionArea( installation.InstallationCode, plant.PlantCode ); - var area = await _databaseUtilities.ReadOrNewArea( + var area = await DatabaseUtilities.ReadOrNewArea( installation.InstallationCode, plant.PlantCode, inspectionArea.Name @@ -268,7 +257,7 @@ public async Task AddDuplicateAreasToDb_Fails() "application/json" ); string areaUrl = "/areas"; - var response = await _client.PostAsync(areaUrl, areaContent); + var response = await Client.PostAsync(areaUrl, areaContent); Assert.Equal(HttpStatusCode.Conflict, response.StatusCode); } @@ -277,7 +266,7 @@ public async Task GetMissionById_ShouldReturnNotFound() { string missionId = "RandomString"; string url = "/missions/runs/" + missionId; - var response = await _client.GetAsync(url); + var response = await Client.GetAsync(url); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } @@ -286,7 +275,7 @@ public async Task DeleteMission_ShouldReturnNotFound() { string missionId = "RandomString"; string url = "/missions/runs/" + missionId; - var response = await _client.DeleteAsync(url); + var response = await Client.DeleteAsync(url); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } @@ -294,9 +283,9 @@ public async Task DeleteMission_ShouldReturnNotFound() public async Task ScheduleDuplicateCustomMissionDefinitions() { // Arrange - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.ReadOrNewInstallation(); + var plant = await DatabaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.ReadOrNewInspectionArea( installation.InstallationCode, plant.PlantCode ); @@ -304,7 +293,7 @@ public async Task ScheduleDuplicateCustomMissionDefinitions() string testMissionName = "testMissionScheduleDuplicateCustomMissionDefinitions"; // Arrange - Robot - var robot = await _databaseUtilities.NewRobot(RobotStatus.Busy, installation); + var robot = await DatabaseUtilities.NewRobot(RobotStatus.Busy, installation); string robotId = robot.Id; // Arrange - Create custom mission definition @@ -348,17 +337,17 @@ public async Task ScheduleDuplicateCustomMissionDefinitions() // Act string customMissionsUrl = "/missions/custom"; - var response1 = await _client.PostAsync(customMissionsUrl, content); - var response2 = await _client.PostAsync(customMissionsUrl, content); + var response1 = await Client.PostAsync(customMissionsUrl, content); + var response2 = await Client.PostAsync(customMissionsUrl, content); // Assert Assert.True(response1.IsSuccessStatusCode); Assert.True(response2.IsSuccessStatusCode); var missionRun1 = await response1.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); var missionRun2 = await response2.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); Assert.NotNull(missionRun1); Assert.NotNull(missionRun2); @@ -367,10 +356,10 @@ public async Task ScheduleDuplicateCustomMissionDefinitions() Assert.Equal(missionId1, missionId2); // Increasing pageSize to 50 to ensure the missions we are looking for is included string missionDefinitionsUrl = "/missions/definitions?pageSize=50"; - var missionDefinitionsResponse = await _client.GetAsync(missionDefinitionsUrl); + var missionDefinitionsResponse = await Client.GetAsync(missionDefinitionsUrl); var missionDefinitions = await missionDefinitionsResponse.Content.ReadFromJsonAsync< List - >(_serializerOptions); + >(SerializerOptions); Assert.NotNull(missionDefinitions); Assert.Single(missionDefinitions.Where(m => m.Id == missionId1)); } @@ -379,15 +368,15 @@ public async Task ScheduleDuplicateCustomMissionDefinitions() public async Task GetNextRun() { // Arrange - Initialise area - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.ReadOrNewInstallation(); + var plant = await DatabaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.ReadOrNewInspectionArea( installation.InstallationCode, plant.PlantCode ); // Arrange - Robot - var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, installation); + var robot = await DatabaseUtilities.NewRobot(RobotStatus.Available, installation); string robotId = robot.Id; // Arrange - Schedule custom mission - create mission definition @@ -421,10 +410,10 @@ public async Task GetNextRun() ); string customMissionsUrl = "/missions/custom"; - var response = await _client.PostAsync(customMissionsUrl, content); + var response = await Client.PostAsync(customMissionsUrl, content); Assert.True(response.IsSuccessStatusCode); var missionRun = await response.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); Assert.NotNull(missionRun); Assert.NotNull(missionRun.MissionId); @@ -463,36 +452,27 @@ public async Task GetNextRun() "application/json" ); string scheduleMissionsUrl = $"/missions/schedule/{missionRun.MissionId}"; - var missionRun1Response = await _client.PostAsync( - scheduleMissionsUrl, - scheduleContent1 - ); - var missionRun2Response = await _client.PostAsync( - scheduleMissionsUrl, - scheduleContent2 - ); - var missionRun3Response = await _client.PostAsync( - scheduleMissionsUrl, - scheduleContent3 - ); + var missionRun1Response = await Client.PostAsync(scheduleMissionsUrl, scheduleContent1); + var missionRun2Response = await Client.PostAsync(scheduleMissionsUrl, scheduleContent2); + var missionRun3Response = await Client.PostAsync(scheduleMissionsUrl, scheduleContent3); var missionRun1 = await missionRun1Response.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); var missionRun2 = await missionRun2Response.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); var missionRun3 = await missionRun3Response.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); // Act string nextMissionUrl = $"missions/definitions/{missionRun.MissionId}/next-run"; - var nextMissionResponse = await _client.GetAsync(nextMissionUrl); + var nextMissionResponse = await Client.GetAsync(nextMissionUrl); // Assert Assert.True(nextMissionResponse.IsSuccessStatusCode); var nextMissionRun = await nextMissionResponse.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); Assert.NotNull(nextMissionRun); Assert.NotNull(missionRun1); @@ -508,24 +488,24 @@ public async Task GetNextRun() public async Task ScheduleDuplicatMissionDefinitions() { // Arrange - Initialise area - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.ReadOrNewInstallation(); + var plant = await DatabaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.ReadOrNewInspectionArea( installation.InstallationCode, plant.PlantCode ); - var area = await _databaseUtilities.ReadOrNewArea( + var area = await DatabaseUtilities.ReadOrNewArea( installation.InstallationCode, plant.PlantCode, inspectionArea.Name ); // Arrange - Robot - var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, installation); + var robot = await DatabaseUtilities.NewRobot(RobotStatus.Available, installation); string robotId = robot.Id; string missionSourceId = "986"; - var source = await _databaseUtilities.NewSource(missionSourceId); + var source = await DatabaseUtilities.NewSource(missionSourceId); var query = new ScheduledMissionQuery { @@ -542,17 +522,17 @@ public async Task ScheduleDuplicatMissionDefinitions() // Act string missionsUrl = "/missions"; - var response1 = await _client.PostAsync(missionsUrl, content); - var response2 = await _client.PostAsync(missionsUrl, content); + var response1 = await Client.PostAsync(missionsUrl, content); + var response2 = await Client.PostAsync(missionsUrl, content); // Assert Assert.True(response1.IsSuccessStatusCode); Assert.True(response2.IsSuccessStatusCode); var missionRun1 = await response1.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); var missionRun2 = await response2.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); Assert.NotNull(missionRun1); Assert.NotNull(missionRun2); @@ -560,10 +540,10 @@ public async Task ScheduleDuplicatMissionDefinitions() string? missionId2 = missionRun2.MissionId; Assert.Equal(missionId1, missionId2); string missionDefinitionsUrl = "/missions/definitions?pageSize=50"; - var missionDefinitionsResponse = await _client.GetAsync(missionDefinitionsUrl); + var missionDefinitionsResponse = await Client.GetAsync(missionDefinitionsUrl); var missionDefinitions = await missionDefinitionsResponse.Content.ReadFromJsonAsync< List - >(_serializerOptions); + >(SerializerOptions); Assert.NotNull(missionDefinitions); Assert.NotNull(missionDefinitions.Find(m => m.Id == missionId1)); } @@ -572,9 +552,9 @@ public async Task ScheduleDuplicatMissionDefinitions() public async Task MissionDoesNotStartIfRobotIsNotInSameInstallationAsMission() { // Arrange - Initialise area - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.ReadOrNewInstallation(); + var plant = await DatabaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.ReadOrNewInspectionArea( installation.InstallationCode, plant.PlantCode ); @@ -585,10 +565,10 @@ public async Task MissionDoesNotStartIfRobotIsNotInSameInstallationAsMission() // Arrange - Get different installation string otherInstallationCode = "installationMissionDoesNotStartIfRobotIsNotInSameInstallationAsMission_Other"; - var otherInstallation = await _databaseUtilities.NewInstallation(otherInstallationCode); + var otherInstallation = await DatabaseUtilities.NewInstallation(otherInstallationCode); // Arrange - Robot - var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, otherInstallation); + var robot = await DatabaseUtilities.NewRobot(RobotStatus.Available, otherInstallation); string robotId = robot.Id; // Arrange - Create custom mission definition @@ -632,7 +612,7 @@ public async Task MissionDoesNotStartIfRobotIsNotInSameInstallationAsMission() // Act string customMissionsUrl = "/missions/custom"; - var response = await _client.PostAsync(customMissionsUrl, content); + var response = await Client.PostAsync(customMissionsUrl, content); Assert.Equal(HttpStatusCode.Conflict, response.StatusCode); } @@ -640,12 +620,12 @@ public async Task MissionDoesNotStartIfRobotIsNotInSameInstallationAsMission() public async Task MissionFailsIfRobotIsNotInSameInspectionAreaAsMission() { // Arrange - Initialise area - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var installation = await DatabaseUtilities.ReadOrNewInstallation(); + var plant = await DatabaseUtilities.ReadOrNewPlant(installation.InstallationCode); string inspectionAreaName1 = "inspectionAreaMissionFailsIfRobotIsNotInSameInspectionAreaAsMission1"; - var inspectionArea1 = await _databaseUtilities.NewInspectionArea( + var inspectionArea1 = await DatabaseUtilities.NewInspectionArea( installation.InstallationCode, plant.PlantCode, inspectionAreaName1 @@ -653,7 +633,7 @@ public async Task MissionFailsIfRobotIsNotInSameInspectionAreaAsMission() string inspectionAreaName2 = "inspectionAreaMissionFailsIfRobotIsNotInSameInspectionAreaAsMission2"; - var inspectionArea2 = await _databaseUtilities.NewInspectionArea( + var inspectionArea2 = await DatabaseUtilities.NewInspectionArea( installation.InstallationCode, plant.PlantCode, inspectionAreaName2 @@ -662,7 +642,7 @@ public async Task MissionFailsIfRobotIsNotInSameInspectionAreaAsMission() string testMissionName = "testMissionFailsIfRobotIsNotInSameInspectionAreaAsMission"; // Arrange - Robot - var robot = await _databaseUtilities.NewRobot( + var robot = await DatabaseUtilities.NewRobot( RobotStatus.Available, installation, inspectionArea1 @@ -710,7 +690,7 @@ public async Task MissionFailsIfRobotIsNotInSameInspectionAreaAsMission() // Act string customMissionsUrl = "/missions/custom"; - var missionResponse = await _client.PostAsync(customMissionsUrl, content); + var missionResponse = await Client.PostAsync(customMissionsUrl, content); Assert.Equal(HttpStatusCode.Conflict, missionResponse.StatusCode); } } diff --git a/backend/api.test/Client/RobotTests.cs b/backend/api.test/Client/RobotTests.cs index 3945cf91..1a002935 100644 --- a/backend/api.test/Client/RobotTests.cs +++ b/backend/api.test/Client/RobotTests.cs @@ -2,58 +2,48 @@ using System.Collections.Generic; using System.Net; using System.Net.Http; -using System.Net.Http.Headers; using System.Net.Http.Json; using System.Text.Json; -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.Client { - [Collection("Database collection")] - public class RobotTests : IClassFixture> + public class RobotTests : IAsyncLifetime { - private readonly HttpClient _client; - private readonly DatabaseUtilities _databaseUtilities; - private readonly JsonSerializerOptions _serializerOptions = - new() - { - Converters = { new JsonStringEnumConverter() }, - PropertyNameCaseInsensitive = true, - }; + public required DatabaseUtilities DatabaseUtilities; + public required HttpClient Client; + public required JsonSerializerOptions SerializerOptions; - public RobotTests(TestWebApplicationFactory factory) + public async Task InitializeAsync() { - _client = factory.CreateClient( - new WebApplicationFactoryClientOptions - { - AllowAutoRedirect = false, - BaseAddress = new Uri("https://localhost:8000"), - } + string databaseName = Guid.NewGuid().ToString(); + (string connectionString, var connection) = await TestSetupHelpers.ConfigureDatabase( + databaseName ); - _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( - TestAuthHandler.AuthenticationScheme + var factory = TestSetupHelpers.ConfigureWebApplicationFactory(databaseName); + + Client = TestSetupHelpers.ConfigureHttpClient(factory); + SerializerOptions = TestSetupHelpers.ConfigureJsonSerializerOptions(); + + DatabaseUtilities = new DatabaseUtilities( + TestSetupHelpers.ConfigureFlotillaDbContext(connectionString) ); - object? context = - factory.Services.GetService(typeof(FlotillaDbContext)) as FlotillaDbContext - ?? throw new ArgumentNullException(nameof(factory)); - _databaseUtilities = new DatabaseUtilities((FlotillaDbContext)context); } + public Task DisposeAsync() => Task.CompletedTask; + [Fact] public async Task RobotsTest() { string url = "/robots"; - var response = await _client.GetAsync(url); + var response = await Client.GetAsync(url); var robots = await response.Content.ReadFromJsonAsync>( - _serializerOptions + SerializerOptions ); Assert.True(response.IsSuccessStatusCode); Assert.NotNull(robots); @@ -64,28 +54,28 @@ public async Task GetRobotById_ShouldReturnNotFound() { string robotId = "RandomString"; string url = "/robots/" + robotId; - var response = await _client.GetAsync(url); + var response = await Client.GetAsync(url); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } [Fact] public async Task GetRobotById_ShouldReturnRobot() { - var installation = await _databaseUtilities.ReadOrNewInstallation(); - _ = await _databaseUtilities.NewRobot(RobotStatus.Available, installation); + var installation = await DatabaseUtilities.ReadOrNewInstallation(); + _ = await DatabaseUtilities.NewRobot(RobotStatus.Available, installation); string url = "/robots"; - var response = await _client.GetAsync(url); + var response = await Client.GetAsync(url); var robots = await response.Content.ReadFromJsonAsync>( - _serializerOptions + SerializerOptions ); Assert.NotNull(robots); string robotId = robots[0].Id; - var robotResponse = await _client.GetAsync("/robots/" + robotId); + var robotResponse = await Client.GetAsync("/robots/" + robotId); var robot = await robotResponse.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); Assert.Equal(HttpStatusCode.OK, robotResponse.StatusCode); Assert.NotNull(robot); @@ -100,13 +90,13 @@ public async Task GetRobotById_ShouldReturnRobot() public async Task RobotIsNotCreatedWithAreaNotInInstallation() { // Arrange - Area - var installation = await _databaseUtilities.ReadOrNewInstallation(); + var installation = await DatabaseUtilities.ReadOrNewInstallation(); - var wrongInstallation = await _databaseUtilities.NewInstallation("wrongInstallation"); - var wrongPlant = await _databaseUtilities.ReadOrNewPlant( + var wrongInstallation = await DatabaseUtilities.NewInstallation("wrongInstallation"); + var wrongPlant = await DatabaseUtilities.ReadOrNewPlant( wrongInstallation.InstallationCode ); - var wrongInspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var wrongInspectionArea = await DatabaseUtilities.ReadOrNewInspectionArea( wrongInstallation.InstallationCode, wrongPlant.PlantCode ); @@ -134,7 +124,7 @@ public async Task RobotIsNotCreatedWithAreaNotInInstallation() try { - var response = await _client.PostAsync(robotUrl, content); + var response = await Client.PostAsync(robotUrl, content); } catch (DbUpdateException ex) { diff --git a/backend/api.test/Client/RoleAccessTests.cs b/backend/api.test/Client/RoleAccessTests.cs index 5f46d489..44fbbd1c 100644 --- a/backend/api.test/Client/RoleAccessTests.cs +++ b/backend/api.test/Client/RoleAccessTests.cs @@ -1,50 +1,40 @@ using System; using System.Net.Http; -using System.Net.Http.Headers; using System.Net.Http.Json; using System.Text.Json; -using System.Text.Json.Serialization; using System.Threading.Tasks; using Api.Controllers.Models; using Api.Database.Models; using Api.Test.Mocks; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.DependencyInjection; using Xunit; -namespace Api.Test +namespace Api.Test.Client { - [Collection("Database collection")] - public class RoleAccessTests : IClassFixture> + public class RoleAccessTests : IAsyncLifetime { - private readonly HttpClient _client; - private readonly MockHttpContextAccessor _httpContextAccessor; - private readonly JsonSerializerOptions _serializerOptions = - new() - { - Converters = { new JsonStringEnumConverter() }, - PropertyNameCaseInsensitive = true, - }; + public required HttpClient Client; + public required JsonSerializerOptions SerializerOptions; + public required MockHttpContextAccessor HttpContextAccessor; - public RoleAccessTests(TestWebApplicationFactory factory) + public async Task InitializeAsync() { - _httpContextAccessor = (MockHttpContextAccessor) - factory.Services.GetService()!; - _httpContextAccessor.SetHttpContextRoles(["Role.Admin"]); - //var x = new HttpContextAccessor(); - _client = factory.CreateClient( - new WebApplicationFactoryClientOptions - { - AllowAutoRedirect = false, - BaseAddress = new Uri("https://localhost:8000"), - } - ); - _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( - TestAuthHandler.AuthenticationScheme + string databaseName = Guid.NewGuid().ToString(); + (string connectionString, var connection) = await TestSetupHelpers.ConfigureDatabase( + databaseName ); + var factory = TestSetupHelpers.ConfigureWebApplicationFactory(databaseName); + var serviceProvider = TestSetupHelpers.ConfigureServiceProvider(factory); + + Client = TestSetupHelpers.ConfigureHttpClient(factory); + SerializerOptions = TestSetupHelpers.ConfigureJsonSerializerOptions(); + HttpContextAccessor = (MockHttpContextAccessor) + serviceProvider.GetService()!; } + public Task DisposeAsync() => Task.CompletedTask; + [Fact] public async Task AuthorisedGetPlantTest_NotFound() { @@ -90,29 +80,26 @@ public async Task AuthorisedGetPlantTest_NotFound() // Act string installationUrl = "/installations"; - var installationResponse = await _client.PostAsync( - installationUrl, - installationContent - ); + var installationResponse = await Client.PostAsync(installationUrl, installationContent); string accessRoleUrl = "/access-roles"; - var accessRoleResponse = await _client.PostAsync(accessRoleUrl, accessRoleContent); + var accessRoleResponse = await Client.PostAsync(accessRoleUrl, accessRoleContent); string plantUrl = "/plants"; - var plantResponse = await _client.PostAsync(plantUrl, plantContent); + var plantResponse = await Client.PostAsync(plantUrl, plantContent); // Only restrict ourselves to non-admin role after doing POSTs - _httpContextAccessor.SetHttpContextRoles(["User.TestInstallationAreaTest_Wrong"]); + HttpContextAccessor.SetHttpContextRoles(["User.TestInstallationAreaTest_Wrong"]); // Assert Assert.True(accessRoleResponse.IsSuccessStatusCode); Assert.True(installationResponse.IsSuccessStatusCode); Assert.True(plantResponse.IsSuccessStatusCode); - var plant = await plantResponse.Content.ReadFromJsonAsync(_serializerOptions); + var plant = await plantResponse.Content.ReadFromJsonAsync(SerializerOptions); Assert.NotNull(plant); // Act string getPlantUrl = $"/plants/{plant.Id}"; - var samePlantResponse = await _client.GetAsync(getPlantUrl); + var samePlantResponse = await Client.GetAsync(getPlantUrl); // Assert Assert.False(samePlantResponse.IsSuccessStatusCode); @@ -217,24 +204,21 @@ public async Task ExplicitlyAuthorisedPostInstallationPlantInspectionAreaAndArea // Act string installationUrl = "/installations"; - var installationResponse = await _client.PostAsync( - installationUrl, - installationContent - ); + var installationResponse = await Client.PostAsync(installationUrl, installationContent); string accessRoleUrl = "/access-roles"; - var accessRoleResponse = await _client.PostAsync(accessRoleUrl, accessRoleContent); + var accessRoleResponse = await Client.PostAsync(accessRoleUrl, accessRoleContent); string plantUrl = "/plants"; - var plantResponse = await _client.PostAsync(plantUrl, plantContent); + var plantResponse = await Client.PostAsync(plantUrl, plantContent); string inspectionAreaUrl = "/inspectionAreas"; - var inspectionAreaResponse = await _client.PostAsync( + var inspectionAreaResponse = await Client.PostAsync( inspectionAreaUrl, inspectionAreaContent ); string areaUrl = "/areas"; - var areaResponse = await _client.PostAsync(areaUrl, areaContent); + var areaResponse = await Client.PostAsync(areaUrl, areaContent); // Only restrict ourselves to non-admin role after doing POSTs - _httpContextAccessor.SetHttpContextRoles( + HttpContextAccessor.SetHttpContextRoles( [ "User.ExplicitlyAuthorisedPostInstallationPlantInspectionAreaAndAreaTestInstallation", ] @@ -247,18 +231,18 @@ public async Task ExplicitlyAuthorisedPostInstallationPlantInspectionAreaAndArea Assert.True(inspectionAreaResponse.IsSuccessStatusCode); Assert.True(areaResponse.IsSuccessStatusCode); var area = await areaResponse.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); Assert.NotNull(area); // Act string getAreaUrl = $"/areas/{area.Id}"; - var sameAreaResponse = await _client.GetAsync(getAreaUrl); + var sameAreaResponse = await Client.GetAsync(getAreaUrl); // Assert Assert.True(sameAreaResponse.IsSuccessStatusCode); var sameArea = await sameAreaResponse.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); Assert.NotNull(sameArea); Assert.Equal(sameArea.Id, area.Id); @@ -346,19 +330,16 @@ public async Task AdminAuthorisedPostInstallationPlantInspectionAreaAndAreaTest( // Act string installationUrl = "/installations"; - var installationResponse = await _client.PostAsync( - installationUrl, - installationContent - ); + var installationResponse = await Client.PostAsync(installationUrl, installationContent); string plantUrl = "/plants"; - var plantResponse = await _client.PostAsync(plantUrl, plantContent); + var plantResponse = await Client.PostAsync(plantUrl, plantContent); string inspectionAreaUrl = "/inspectionAreas"; - var inspectionAreaResponse = await _client.PostAsync( + var inspectionAreaResponse = await Client.PostAsync( inspectionAreaUrl, inspectionAreaContent ); string areaUrl = "/areas"; - var areaResponse = await _client.PostAsync(areaUrl, areaContent); + var areaResponse = await Client.PostAsync(areaUrl, areaContent); // Assert Assert.True(installationResponse.IsSuccessStatusCode); @@ -366,7 +347,7 @@ public async Task AdminAuthorisedPostInstallationPlantInspectionAreaAndAreaTest( Assert.True(inspectionAreaResponse.IsSuccessStatusCode); Assert.True(areaResponse.IsSuccessStatusCode); var area = await areaResponse.Content.ReadFromJsonAsync( - _serializerOptions + SerializerOptions ); Assert.NotNull(area); } diff --git a/backend/api.test/DbContextTestSetup.cs b/backend/api.test/DbContextTestSetup.cs index 4dcf5a97..606993c6 100644 --- a/backend/api.test/DbContextTestSetup.cs +++ b/backend/api.test/DbContextTestSetup.cs @@ -1,65 +1,12 @@ -using System; -using System.Security.Claims; +using System.Security.Claims; using System.Text.Encodings.Web; using System.Threading.Tasks; -using Api.Database.Context; using Microsoft.AspNetCore.Authentication; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Xunit; namespace Api.Test { - // Class for building and disposing dbcontext - public class DatabaseFixture : IDisposable - { - public FlotillaDbContext NewContext => CreateContext(); - private SqliteConnection? _connection; - - private DbContextOptions CreateOptions() - { - string connectionString = new SqliteConnectionStringBuilder - { - DataSource = ":memory:", - Cache = SqliteCacheMode.Shared, - }.ToString(); - _connection = new SqliteConnection(connectionString); - _connection.Open(); - var builder = new DbContextOptionsBuilder(); - builder.EnableSensitiveDataLogging(); - builder.UseSqlite(_connection); - return builder.Options; - } - - public FlotillaDbContext CreateContext() - { - var options = CreateOptions(); - var context = new FlotillaDbContext(options); - context.Database.EnsureCreated(); - return context; - } - - public void Dispose() - { - if (_connection != null) - { - _connection.Dispose(); - _connection = null; - } - GC.SuppressFinalize(this); - } - } - - [CollectionDefinition("Database collection")] - public class DatabaseCollection : ICollectionFixture - { - // This class has no code, and is never created. Its purpose is simply - // to be the place to apply [CollectionDefinition] and all the - // ICollectionFixture<> interfaces. - } - // Class for mocking authentication options public class TestAuthHandlerOptions : AuthenticationSchemeOptions { diff --git a/backend/api.test/EventHandlers/TestMissionEventHandler.cs b/backend/api.test/EventHandlers/TestMissionEventHandler.cs index 0a7365ec..23876e4b 100644 --- a/backend/api.test/EventHandlers/TestMissionEventHandler.cs +++ b/backend/api.test/EventHandlers/TestMissionEventHandler.cs @@ -5,247 +5,97 @@ using Api.Controllers.Models; using Api.Database.Context; using Api.Database.Models; -using Api.EventHandlers; using Api.Mqtt; using Api.Mqtt.Events; using Api.Mqtt.MessageModels; -using Api.Options; using Api.Services; -using Api.Services.ActionServices; using Api.Services.Events; using Api.Test.Database; -using Api.Test.Mocks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using Moq; using Xunit; namespace Api.Test.EventHandlers { - [Collection("Database collection")] - public class TestMissionEventHandler : IDisposable + public class TestMissionEventHandler : IAsyncLifetime, IAsyncDisposable { - private readonly MissionEventHandler _missionEventHandler; - private readonly MissionRunService _missionRunService; - private readonly MqttEventHandler _mqttEventHandler; - private readonly MqttService _mqttService; - private readonly DatabaseUtilities _databaseUtilities; - private readonly RobotService _robotService; - private readonly LocalizationService _localizationService; - private readonly EmergencyActionService _emergencyActionService; - private readonly MissionSchedulingService _missionSchedulingService; - - public TestMissionEventHandler(DatabaseFixture fixture) + private FlotillaDbContext Context => CreateContext(); + public required TestWebApplicationFactory Factory; + public required IServiceProvider ServiceProvider; + + public required string ConnectionString; + + public required DatabaseUtilities DatabaseUtilities; + + public required IMissionRunService MissionRunService; + public required IRobotService RobotService; + public required IMissionSchedulingService MissionSchedulingService; + + public required MqttService MqttService; + + public async Task InitializeAsync() { - var missionEventHandlerLogger = new Mock>().Object; + string databaseName = Guid.NewGuid().ToString(); + (ConnectionString, _) = await TestSetupHelpers.ConfigureDatabase(databaseName); + + DatabaseUtilities = new DatabaseUtilities(Context); + + Factory = TestSetupHelpers.ConfigureWebApplicationFactory(databaseName); + ServiceProvider = TestSetupHelpers.ConfigureServiceProvider(Factory); + + MissionRunService = ServiceProvider.GetRequiredService(); + RobotService = ServiceProvider.GetRequiredService(); + MissionSchedulingService = + ServiceProvider.GetRequiredService(); + var mqttServiceLogger = new Mock>().Object; - var mqttEventHandlerLogger = new Mock>().Object; - var missionLogger = new Mock>().Object; - var missionSchedulingServiceLogger = new Mock< - ILogger - >().Object; - var robotServiceLogger = new Mock>().Object; - var localizationServiceLogger = new Mock>().Object; - var mapServiceLogger = new Mock>().Object; - var mapBlobOptions = new Mock>().Object; - var returnToHomeServiceLogger = new Mock>().Object; - var missionDefinitionServiceLogger = new Mock< - ILogger - >().Object; - var lastMissionRunServiceLogger = new Mock>().Object; - var sourceServiceLogger = new Mock>().Object; - var errorHandlingServiceLogger = new Mock>().Object; - var missionTaskServiceLogger = new Mock>().Object; - - var configuration = WebApplication.CreateBuilder().Configuration; - - var context = fixture.NewContext; - - var signalRService = new MockSignalRService(); - var accessRoleService = new AccessRoleService(context, new HttpContextAccessor()); - var userInfoService = new UserInfoService( - context, - new HttpContextAccessor(), - new Mock>().Object - ); - - _mqttService = new MqttService(mqttServiceLogger, configuration); - - var missionTaskService = new MissionTaskService(context, missionTaskServiceLogger); - - var missionLoader = new MockMissionLoader(); - var stidServiceMock = new MockStidService(context); - var sourceService = new SourceService(context, sourceServiceLogger); - var robotModelService = new RobotModelService(context); - var taskDurationServiceMock = new MockTaskDurationService(); - var isarServiceMock = new MockIsarService(); - var installationService = new InstallationService(context, accessRoleService); - var defaultLocalizationPoseService = new DefaultLocalizationPoseService(context); - var plantService = new PlantService(context, installationService, accessRoleService); - var inspectionAreaService = new InspectionAreaService( - context, - defaultLocalizationPoseService, - installationService, - plantService, - accessRoleService, - signalRService - ); - var areaService = new AreaService( - context, - installationService, - plantService, - inspectionAreaService, - defaultLocalizationPoseService, - accessRoleService - ); - var mapServiceMock = new MockMapService(); - _robotService = new RobotService( - context, - robotServiceLogger, - robotModelService, - signalRService, - accessRoleService, - installationService, - inspectionAreaService - ); - _missionRunService = new MissionRunService( - context, - signalRService, - missionLogger, - accessRoleService, - missionTaskService, - inspectionAreaService, - _robotService, - userInfoService - ); - var missionDefinitionService = new MissionDefinitionService( - context, - missionLoader, - signalRService, - accessRoleService, - missionDefinitionServiceLogger, - _missionRunService, - sourceService - ); - _localizationService = new LocalizationService( - localizationServiceLogger, - _robotService, - installationService, - inspectionAreaService - ); - var errorHandlingService = new ErrorHandlingService( - errorHandlingServiceLogger, - _robotService, - _missionRunService - ); - var returnToHomeService = new ReturnToHomeService( - returnToHomeServiceLogger, - _robotService, - _missionRunService - ); - _missionSchedulingService = new MissionSchedulingService( - missionSchedulingServiceLogger, - _missionRunService, - _robotService, - isarServiceMock, - _localizationService, - returnToHomeService, - signalRService, - errorHandlingService - ); - var lastMissionRunService = new LastMissionRunService(missionDefinitionService); - - _databaseUtilities = new DatabaseUtilities(context); - _emergencyActionService = new EmergencyActionService(); - - var mockServiceProvider = new Mock(); - - // Mock services and controllers that are passed through the mocked service injector - mockServiceProvider - .Setup(p => p.GetService(typeof(IMissionRunService))) - .Returns(_missionRunService); - mockServiceProvider - .Setup(p => p.GetService(typeof(IRobotService))) - .Returns(_robotService); - mockServiceProvider - .Setup(p => p.GetService(typeof(IMissionSchedulingService))) - .Returns(_missionSchedulingService); - mockServiceProvider - .Setup(p => p.GetService(typeof(FlotillaDbContext))) - .Returns(context); - mockServiceProvider - .Setup(p => p.GetService(typeof(ILocalizationService))) - .Returns(_localizationService); - mockServiceProvider - .Setup(p => p.GetService(typeof(IReturnToHomeService))) - .Returns(returnToHomeService); - mockServiceProvider - .Setup(p => p.GetService(typeof(IMapService))) - .Returns(mapServiceMock); - mockServiceProvider - .Setup(p => p.GetService(typeof(ITaskDurationService))) - .Returns(taskDurationServiceMock); - mockServiceProvider - .Setup(p => p.GetService(typeof(ILastMissionRunService))) - .Returns(lastMissionRunService); - mockServiceProvider.Setup(p => p.GetService(typeof(IAreaService))).Returns(areaService); - mockServiceProvider - .Setup(p => p.GetService(typeof(ISignalRService))) - .Returns(signalRService); - mockServiceProvider - .Setup(p => p.GetService(typeof(IEmergencyActionService))) - .Returns(_emergencyActionService); - - // Mock service injector - var mockScope = new Mock(); - mockScope.Setup(scope => scope.ServiceProvider).Returns(mockServiceProvider.Object); - var mockFactory = new Mock(); - mockFactory.Setup(f => f.CreateScope()).Returns(mockScope.Object); - - // Instantiating the event handlers are required for the event subscribers to be activated - _missionEventHandler = new MissionEventHandler( - missionEventHandlerLogger, - mockFactory.Object - ); - _mqttEventHandler = new MqttEventHandler(mqttEventHandlerLogger, mockFactory.Object); + MqttService = new MqttService(mqttServiceLogger, Factory.Configuration!); + } + + public async Task DisposeAsync() + { + await Context.Database.EnsureDeletedAsync(); + await Context.Database.EnsureCreatedAsync(); } - public void Dispose() + async ValueTask IAsyncDisposable.DisposeAsync() { - _missionEventHandler.Dispose(); - GC.SuppressFinalize(this); + await Task.CompletedTask; + } + + private FlotillaDbContext CreateContext() + { + return TestSetupHelpers.ConfigureFlotillaDbContext(ConnectionString); } [Fact] public async Task ScheduledMissionStartedWhenSystemIsAvailable() { // Arrange - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.NewInstallation(); + var plant = await DatabaseUtilities.NewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.NewInspectionArea( installation.InstallationCode, plant.PlantCode ); - var robot = await _databaseUtilities.NewRobot( + var robot = await DatabaseUtilities.NewRobot( RobotStatus.Available, installation, inspectionArea ); - var missionRun = await _databaseUtilities.NewMissionRun( + var missionRun = await DatabaseUtilities.NewMissionRun( installation.InstallationCode, robot, inspectionArea ); // Act - await _missionRunService.Create(missionRun); + await MissionRunService.Create(missionRun); Thread.Sleep(100); // Assert - var postTestMissionRun = await _missionRunService.ReadById( + var postTestMissionRun = await MissionRunService.ReadById( missionRun.Id, readOnly: true ); @@ -256,39 +106,39 @@ public async Task ScheduledMissionStartedWhenSystemIsAvailable() public async Task SecondScheduledMissionQueuedIfRobotIsBusy() { // Arrange - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.NewInstallation(); + var plant = await DatabaseUtilities.NewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.NewInspectionArea( installation.InstallationCode, plant.PlantCode ); - var robot = await _databaseUtilities.NewRobot( + var robot = await DatabaseUtilities.NewRobot( RobotStatus.Available, installation, inspectionArea ); - var missionRunOne = await _databaseUtilities.NewMissionRun( + var missionRunOne = await DatabaseUtilities.NewMissionRun( installation.InstallationCode, robot, inspectionArea ); - var missionRunTwo = await _databaseUtilities.NewMissionRun( + var missionRunTwo = await DatabaseUtilities.NewMissionRun( installation.InstallationCode, robot, inspectionArea ); // Act - await _missionRunService.Create(missionRunOne); + await MissionRunService.Create(missionRunOne); Thread.Sleep(100); - await _missionRunService.Create(missionRunTwo); + await MissionRunService.Create(missionRunTwo); // Assert - var postTestMissionRunOne = await _missionRunService.ReadById( + var postTestMissionRunOne = await MissionRunService.ReadById( missionRunOne.Id, readOnly: true ); - var postTestMissionRunTwo = await _missionRunService.ReadById( + var postTestMissionRunTwo = await MissionRunService.ReadById( missionRunTwo.Id, readOnly: true ); @@ -300,24 +150,24 @@ public async Task SecondScheduledMissionQueuedIfRobotIsBusy() public async Task NewMissionIsStartedWhenRobotBecomesAvailable() { // Arrange - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.NewInstallation(); + var plant = await DatabaseUtilities.NewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.NewInspectionArea( installation.InstallationCode, plant.PlantCode ); - var robot = await _databaseUtilities.NewRobot( + var robot = await DatabaseUtilities.NewRobot( RobotStatus.Busy, installation, inspectionArea ); - var missionRun = await _databaseUtilities.NewMissionRun( + var missionRun = await DatabaseUtilities.NewMissionRun( installation.InstallationCode, robot, inspectionArea ); - await _missionRunService.Create(missionRun); + await MissionRunService.Create(missionRun); Thread.Sleep(100); var mqttEventArgs = new MqttReceivedArgs( @@ -331,11 +181,11 @@ public async Task NewMissionIsStartedWhenRobotBecomesAvailable() ); // Act - _mqttService.RaiseEvent(nameof(MqttService.MqttIsarStatusReceived), mqttEventArgs); + MqttService.RaiseEvent(nameof(MqttService.MqttIsarStatusReceived), mqttEventArgs); Thread.Sleep(500); // Assert - var postTestMissionRun = await _missionRunService.ReadById( + var postTestMissionRun = await MissionRunService.ReadById( missionRun.Id, readOnly: true ); @@ -346,13 +196,13 @@ public async Task NewMissionIsStartedWhenRobotBecomesAvailable() public async Task ReturnToHomeMissionIsStartedIfQueueIsEmptyWhenRobotBecomesAvailable() { // Arrange - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.NewInstallation(); + var plant = await DatabaseUtilities.NewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.NewInspectionArea( installation.InstallationCode, plant.PlantCode ); - var robot = await _databaseUtilities.NewRobot( + var robot = await DatabaseUtilities.NewRobot( RobotStatus.Busy, installation, inspectionArea @@ -369,11 +219,11 @@ public async Task ReturnToHomeMissionIsStartedIfQueueIsEmptyWhenRobotBecomesAvai ); // Act - _mqttService.RaiseEvent(nameof(MqttService.MqttIsarStatusReceived), mqttEventArgs); + MqttService.RaiseEvent(nameof(MqttService.MqttIsarStatusReceived), mqttEventArgs); // Assert Thread.Sleep(1000); - var ongoingMission = await _missionRunService.ReadAll( + var ongoingMission = await MissionRunService.ReadAll( new MissionRunQueryStringParameters { Statuses = [MissionStatus.Ongoing], @@ -389,19 +239,19 @@ public async Task ReturnToHomeMissionIsStartedIfQueueIsEmptyWhenRobotBecomesAvai public async Task ReturnToHomeMissionIsNotStartedIfReturnToHomeIsNotSupported() { // Arrange - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.NewInstallation(); + var plant = await DatabaseUtilities.NewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.NewInspectionArea( installation.InstallationCode, plant.PlantCode ); - var robot = await _databaseUtilities.NewRobot( + var robot = await DatabaseUtilities.NewRobot( RobotStatus.Busy, installation, inspectionArea ); robot.RobotCapabilities!.Remove(RobotCapabilitiesEnum.return_to_home); - await _robotService.Update(robot); + await RobotService.Update(robot); var mqttEventArgs = new MqttReceivedArgs( new IsarStatusMessage @@ -414,11 +264,11 @@ public async Task ReturnToHomeMissionIsNotStartedIfReturnToHomeIsNotSupported() ); // Act - _mqttService.RaiseEvent(nameof(MqttService.MqttIsarStatusReceived), mqttEventArgs); + MqttService.RaiseEvent(nameof(MqttService.MqttIsarStatusReceived), mqttEventArgs); // Assert Thread.Sleep(1000); - var ongoingMission = await _missionRunService.ReadAll( + var ongoingMission = await MissionRunService.ReadAll( new MissionRunQueryStringParameters { Statuses = [MissionStatus.Ongoing], @@ -434,39 +284,39 @@ public async Task ReturnToHomeMissionIsNotStartedIfReturnToHomeIsNotSupported() public async Task MissionRunIsStartedForOtherAvailableRobotIfOneRobotHasAnOngoingMissionRun() { // Arrange - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.NewInstallation(); + var plant = await DatabaseUtilities.NewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.NewInspectionArea( installation.InstallationCode, plant.PlantCode ); - var robotOne = await _databaseUtilities.NewRobot( + var robotOne = await DatabaseUtilities.NewRobot( RobotStatus.Available, installation, inspectionArea ); - var robotTwo = await _databaseUtilities.NewRobot( + var robotTwo = await DatabaseUtilities.NewRobot( RobotStatus.Available, installation, inspectionArea ); - var missionRunOne = await _databaseUtilities.NewMissionRun( + var missionRunOne = await DatabaseUtilities.NewMissionRun( installation.InstallationCode, robotOne, inspectionArea ); - var missionRunTwo = await _databaseUtilities.NewMissionRun( + var missionRunTwo = await DatabaseUtilities.NewMissionRun( installation.InstallationCode, robotTwo, inspectionArea ); // Act (Ensure first mission is started) - await _missionRunService.Create(missionRunOne); + await MissionRunService.Create(missionRunOne); Thread.Sleep(100); // Assert - var postStartMissionRunOne = await _missionRunService.ReadById( + var postStartMissionRunOne = await MissionRunService.ReadById( missionRunOne.Id, readOnly: true ); @@ -474,11 +324,11 @@ public async Task MissionRunIsStartedForOtherAvailableRobotIfOneRobotHasAnOngoin Assert.Equal(MissionStatus.Ongoing, postStartMissionRunOne.Status); // Act (Ensure second mission is started for second robot) - await _missionRunService.Create(missionRunTwo); + await MissionRunService.Create(missionRunTwo); Thread.Sleep(100); // Assert - var postStartMissionRunTwo = await _missionRunService.ReadById( + var postStartMissionRunTwo = await MissionRunService.ReadById( missionRunTwo.Id, readOnly: true ); @@ -490,24 +340,20 @@ public async Task MissionRunIsStartedForOtherAvailableRobotIfOneRobotHasAnOngoin public async Task QueuedMissionsAreNotAbortedWhenRobotAvailableHappensAtTheSameTimeAsOnIsarMissionCompleted() { // Arrange - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.NewInstallation(); + var plant = await DatabaseUtilities.NewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.NewInspectionArea( installation.InstallationCode, plant.PlantCode ); - var robot = await _databaseUtilities.NewRobot( - RobotStatus.Available, - installation, - null - ); - var missionRun1 = await _databaseUtilities.NewMissionRun( + var robot = await DatabaseUtilities.NewRobot(RobotStatus.Available, installation, null); + var missionRun1 = await DatabaseUtilities.NewMissionRun( installation.InstallationCode, robot, inspectionArea, true ); - var missionRun2 = await _databaseUtilities.NewMissionRun( + var missionRun2 = await DatabaseUtilities.NewMissionRun( installation.InstallationCode, robot, inspectionArea, @@ -515,13 +361,13 @@ public async Task QueuedMissionsAreNotAbortedWhenRobotAvailableHappensAtTheSameT ); var missionRunCreatedEventArgs = new MissionRunCreatedEventArgs(missionRun1); - _missionRunService.RaiseEvent( - nameof(MissionRunService.MissionRunCreated), + MissionRunService.RaiseEvent( + nameof(Api.Services.MissionRunService.MissionRunCreated), missionRunCreatedEventArgs ); - Thread.Sleep(100); + Thread.Sleep(1000); - var missionRun1PostCreation = await _missionRunService.ReadById( + var missionRun1PostCreation = await MissionRunService.ReadById( missionRun1.Id, readOnly: true ); @@ -541,22 +387,22 @@ public async Task QueuedMissionsAreNotAbortedWhenRobotAvailableHappensAtTheSameT var robotAvailableEventArgs = new RobotAvailableEventArgs(robot); - _mqttService.RaiseEvent( + MqttService.RaiseEvent( nameof(MqttService.MqttIsarMissionReceived), mqttIsarMissionEventArgs ); - _missionSchedulingService.RaiseEvent( - nameof(MissionSchedulingService.RobotAvailable), + MissionSchedulingService.RaiseEvent( + nameof(Api.Services.MissionSchedulingService.RobotAvailable), robotAvailableEventArgs ); // Assert - var postTestMissionRun1 = await _missionRunService.ReadById( + var postTestMissionRun1 = await MissionRunService.ReadById( missionRun1.Id, readOnly: true ); Assert.Equal(MissionStatus.Successful, postTestMissionRun1!.Status); - var postTestMissionRun2 = await _missionRunService.ReadById( + var postTestMissionRun2 = await MissionRunService.ReadById( missionRun2.Id, readOnly: true ); @@ -569,18 +415,18 @@ public async Task QueuedMissionsAreNotAbortedWhenRobotAvailableHappensAtTheSameT public async Task QueuedContinuesWhenOnIsarStatusHappensAtTheSameTimeAsOnIsarMissionCompleted() { // Arrange - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.ReadOrNewInstallation(); + var plant = await DatabaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.ReadOrNewInspectionArea( installation.InstallationCode, plant.PlantCode ); - var robot = await _databaseUtilities.NewRobot( + var robot = await DatabaseUtilities.NewRobot( RobotStatus.Available, installation, inspectionArea ); - var missionRun1 = await _databaseUtilities.NewMissionRun( + var missionRun1 = await DatabaseUtilities.NewMissionRun( installation.InstallationCode, robot, inspectionArea, @@ -589,7 +435,7 @@ public async Task QueuedContinuesWhenOnIsarStatusHappensAtTheSameTimeAsOnIsarMis MissionStatus.Ongoing, Guid.NewGuid().ToString() ); - var missionRun2 = await _databaseUtilities.NewMissionRun( + var missionRun2 = await DatabaseUtilities.NewMissionRun( installation.InstallationCode, robot, inspectionArea, @@ -598,8 +444,8 @@ public async Task QueuedContinuesWhenOnIsarStatusHappensAtTheSameTimeAsOnIsarMis Thread.Sleep(100); var missionRunCreatedEventArgs = new MissionRunCreatedEventArgs(missionRun1); - _missionRunService.RaiseEvent( - nameof(MissionRunService.MissionRunCreated), + MissionRunService.RaiseEvent( + nameof(Api.Services.MissionRunService.MissionRunCreated), missionRunCreatedEventArgs ); Thread.Sleep(100); @@ -626,18 +472,18 @@ public async Task QueuedContinuesWhenOnIsarStatusHappensAtTheSameTimeAsOnIsarMis } ); - _mqttService.RaiseEvent( + MqttService.RaiseEvent( nameof(MqttService.MqttIsarMissionReceived), mqttIsarMissionEventArgs ); - _mqttService.RaiseEvent( + MqttService.RaiseEvent( nameof(MqttService.MqttIsarStatusReceived), mqttIsarStatusEventArgs ); Thread.Sleep(2500); // Accommodate for sleep in OnIsarStatus // Assert - var postTestMissionRun1 = await _missionRunService.ReadById( + var postTestMissionRun1 = await MissionRunService.ReadById( missionRun1.Id, readOnly: true ); @@ -645,7 +491,7 @@ public async Task QueuedContinuesWhenOnIsarStatusHappensAtTheSameTimeAsOnIsarMis Api.Database.Models.TaskStatus.Successful, postTestMissionRun1!.Tasks[0].Status ); - var postTestMissionRun2 = await _missionRunService.ReadById( + var postTestMissionRun2 = await MissionRunService.ReadById( missionRun2.Id, readOnly: true ); @@ -656,18 +502,18 @@ public async Task QueuedContinuesWhenOnIsarStatusHappensAtTheSameTimeAsOnIsarMis public async Task ReturnHomeMissionAbortedIfNewMissionScheduled() { // Arrange - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.NewInstallation(); + var plant = await DatabaseUtilities.NewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.NewInspectionArea( installation.InstallationCode, plant.PlantCode ); - var robot = await _databaseUtilities.NewRobot( + var robot = await DatabaseUtilities.NewRobot( RobotStatus.Busy, installation, inspectionArea ); - var returnToHomeMission = await _databaseUtilities.NewMissionRun( + var returnToHomeMission = await DatabaseUtilities.NewMissionRun( installation.InstallationCode, robot, inspectionArea, @@ -676,7 +522,7 @@ public async Task ReturnHomeMissionAbortedIfNewMissionScheduled() MissionStatus.Ongoing, Guid.NewGuid().ToString() ); - var missionRun = await _databaseUtilities.NewMissionRun( + var missionRun = await DatabaseUtilities.NewMissionRun( installation.InstallationCode, robot, inspectionArea, @@ -690,11 +536,14 @@ public async Task ReturnHomeMissionAbortedIfNewMissionScheduled() // Act var eventArgs = new MissionRunCreatedEventArgs(missionRun); - _missionRunService.RaiseEvent(nameof(MissionRunService.MissionRunCreated), eventArgs); + MissionRunService.RaiseEvent( + nameof(Api.Services.MissionRunService.MissionRunCreated), + eventArgs + ); Thread.Sleep(500); // Assert - var updatedReturnHomeMission = await _missionRunService.ReadById( + var updatedReturnHomeMission = await MissionRunService.ReadById( returnToHomeMission.Id, readOnly: true ); @@ -722,20 +571,17 @@ public async Task ReturnHomeMissionAbortedIfNewMissionScheduled() } ); - _mqttService.RaiseEvent( + MqttService.RaiseEvent( nameof(MqttService.MqttIsarMissionReceived), mqttIsarMissionEventArgs ); - _mqttService.RaiseEvent( + MqttService.RaiseEvent( nameof(MqttService.MqttIsarStatusReceived), mqttIsarStatusEventArgs ); Thread.Sleep(500); - var updatedMissionRun = await _missionRunService.ReadById( - missionRun.Id, - readOnly: true - ); + var updatedMissionRun = await MissionRunService.ReadById(missionRun.Id, readOnly: true); Assert.True(updatedMissionRun?.Status.Equals(MissionStatus.Ongoing)); } } diff --git a/backend/api.test/Services/MissionService.cs b/backend/api.test/Services/MissionService.cs index 9c623511..133d74ad 100644 --- a/backend/api.test/Services/MissionService.cs +++ b/backend/api.test/Services/MissionService.cs @@ -1,93 +1,40 @@ using System; 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; +using Microsoft.Extensions.DependencyInjection; using Xunit; namespace Api.Test.Services { - [Collection("Database collection")] - public class MissionServiceTest : IDisposable + public class MissionServiceTest : IAsyncLifetime { - private readonly FlotillaDbContext _context; - private readonly DatabaseUtilities _databaseUtilities; - private readonly ILogger _logger; - private readonly MissionRunService _missionRunService; - private readonly ISignalRService _signalRService; - private readonly IAccessRoleService _accessRoleService; - private readonly UserInfoService _userInfoService; - private readonly IMissionTaskService _missionTaskService; - private readonly IInspectionAreaService _inspectionAreaService; - private readonly IInstallationService _installationService; - private readonly IPlantService _plantService; - private readonly IRobotModelService _robotModelService; - private readonly IRobotService _robotService; + public required DatabaseUtilities DatabaseUtilities; + public required IMissionRunService MissionRunService; - public MissionServiceTest(DatabaseFixture fixture) + public async Task InitializeAsync() { - _context = fixture.NewContext; - var defaultLocalizationPoseService = new DefaultLocalizationPoseService(_context); - _logger = new Mock>().Object; - _signalRService = new MockSignalRService(); - _accessRoleService = new AccessRoleService(_context, new HttpContextAccessor()); - _userInfoService = new UserInfoService( - _context, - new HttpContextAccessor(), - new Mock>().Object + string databaseName = Guid.NewGuid().ToString(); + (string connectionString, var connection) = await TestSetupHelpers.ConfigureDatabase( + databaseName ); - _missionTaskService = new MissionTaskService( - _context, - new Mock>().Object - ); - _installationService = new InstallationService(_context, _accessRoleService); - _plantService = new PlantService(_context, _installationService, _accessRoleService); - _inspectionAreaService = new InspectionAreaService( - _context, - defaultLocalizationPoseService, - _installationService, - _plantService, - _accessRoleService, - new MockSignalRService() - ); - _robotModelService = new RobotModelService(_context); - _robotService = new RobotService( - _context, - new Mock>().Object, - _robotModelService, - new MockSignalRService(), - _accessRoleService, - _installationService, - _inspectionAreaService - ); - _missionRunService = new MissionRunService( - _context, - _signalRService, - _logger, - _accessRoleService, - _missionTaskService, - _inspectionAreaService, - _robotService, - _userInfoService + var factory = TestSetupHelpers.ConfigureWebApplicationFactory(databaseName); + var serviceProvider = TestSetupHelpers.ConfigureServiceProvider(factory); + + DatabaseUtilities = new DatabaseUtilities( + TestSetupHelpers.ConfigureFlotillaDbContext(connectionString) ); - _databaseUtilities = new DatabaseUtilities(_context); + MissionRunService = serviceProvider.GetRequiredService(); } - public void Dispose() - { - _context.Dispose(); - GC.SuppressFinalize(this); - } + public Task DisposeAsync() => Task.CompletedTask; [Fact] public async Task ReadIdDoesNotExist() { - var missionRun = await _missionRunService.ReadById( + var missionRun = await MissionRunService.ReadById( "some_id_that_does_not_exist", readOnly: true ); @@ -97,28 +44,28 @@ public async Task ReadIdDoesNotExist() [Fact] public async Task Create() { - var reportsBefore = await _missionRunService.ReadAll( + var reportsBefore = await MissionRunService.ReadAll( new MissionRunQueryStringParameters(), readOnly: true ); int nReportsBefore = reportsBefore.Count; - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var plant = await _databaseUtilities.ReadOrNewPlant(installation.InstallationCode); - var inspectionArea = await _databaseUtilities.ReadOrNewInspectionArea( + var installation = await DatabaseUtilities.ReadOrNewInstallation(); + var plant = await DatabaseUtilities.ReadOrNewPlant(installation.InstallationCode); + var inspectionArea = await DatabaseUtilities.ReadOrNewInspectionArea( installation.InstallationCode, plant.PlantCode ); - var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, installation); - var missionRun = await _databaseUtilities.NewMissionRun( + var robot = await DatabaseUtilities.NewRobot(RobotStatus.Available, installation); + var missionRun = await DatabaseUtilities.NewMissionRun( installation.InstallationCode, robot, inspectionArea ); - await _missionRunService.Create(missionRun); + await MissionRunService.Create(missionRun); - var reportsAfter = await _missionRunService.ReadAll( + var reportsAfter = await MissionRunService.ReadAll( new MissionRunQueryStringParameters() ); int nReportsAfter = reportsAfter.Count; diff --git a/backend/api.test/Services/RobotService.cs b/backend/api.test/Services/RobotService.cs index 32025805..b58ddca9 100644 --- a/backend/api.test/Services/RobotService.cs +++ b/backend/api.test/Services/RobotService.cs @@ -2,82 +2,45 @@ 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; +using Microsoft.Extensions.DependencyInjection; using Xunit; namespace Api.Test.Services { - [Collection("Database collection")] - public class RobotServiceTest : IDisposable + public class RobotServiceTest : IAsyncLifetime { - private readonly FlotillaDbContext _context; - private readonly ILogger _logger; - private readonly RobotModelService _robotModelService; - private readonly ISignalRService _signalRService; - private readonly IAccessRoleService _accessRoleService; - private readonly IInstallationService _installationService; - private readonly IPlantService _plantService; - private readonly IDefaultLocalizationPoseService _defaultLocalizationPoseService; - private readonly IInspectionAreaService _inspectionAreaService; - private readonly IAreaService _areaService; - private readonly DatabaseUtilities _databaseUtilities; + public required DatabaseUtilities DatabaseUtilities; + public required IRobotService RobotService; + public required IInstallationService InstallationService; - public RobotServiceTest(DatabaseFixture fixture) + public async Task InitializeAsync() { - _context = fixture.NewContext; - _databaseUtilities = new DatabaseUtilities(_context); - _logger = new Mock>().Object; - _robotModelService = new RobotModelService(_context); - _signalRService = new MockSignalRService(); - _accessRoleService = new AccessRoleService(_context, new HttpContextAccessor()); - _installationService = new InstallationService(_context, _accessRoleService); - _plantService = new PlantService(_context, _installationService, _accessRoleService); - _defaultLocalizationPoseService = new DefaultLocalizationPoseService(_context); - _inspectionAreaService = new InspectionAreaService( - _context, - _defaultLocalizationPoseService, - _installationService, - _plantService, - _accessRoleService, - _signalRService + string databaseName = Guid.NewGuid().ToString(); + (string connectionString, var connection) = await TestSetupHelpers.ConfigureDatabase( + databaseName ); - _areaService = new AreaService( - _context, - _installationService, - _plantService, - _inspectionAreaService, - _defaultLocalizationPoseService, - _accessRoleService + var factory = TestSetupHelpers.ConfigureWebApplicationFactory(databaseName); + var serviceProvider = TestSetupHelpers.ConfigureServiceProvider(factory); + + DatabaseUtilities = new DatabaseUtilities( + TestSetupHelpers.ConfigureFlotillaDbContext(connectionString) ); - } - public void Dispose() - { - _context.Dispose(); - GC.SuppressFinalize(this); + RobotService = serviceProvider.GetRequiredService(); + InstallationService = serviceProvider.GetRequiredService(); } + public Task DisposeAsync() => Task.CompletedTask; + [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, - _inspectionAreaService - ); - var robots = await robotService.ReadAll(); + var installation = await DatabaseUtilities.NewInstallation(); + _ = await DatabaseUtilities.NewRobot(RobotStatus.Available, installation); + var robots = await RobotService.ReadAll(); Assert.True(robots.Any()); } @@ -85,18 +48,9 @@ public async Task ReadAll() [Fact] public async Task Read() { - var robotService = new RobotService( - _context, - _logger, - _robotModelService, - _signalRService, - _accessRoleService, - _installationService, - _inspectionAreaService - ); - var installation = await _databaseUtilities.ReadOrNewInstallation(); - var robot = await _databaseUtilities.NewRobot(RobotStatus.Available, installation); - var robotById = await robotService.ReadById(robot.Id, readOnly: true); + var installation = await DatabaseUtilities.NewInstallation(); + 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); } @@ -104,62 +58,23 @@ public async Task Read() [Fact] public async Task ReadIdDoesNotExist() { - var robotService = new RobotService( - _context, - _logger, - _robotModelService, - _signalRService, - _accessRoleService, - _installationService, - _inspectionAreaService - ); - var robot = await robotService.ReadById("some_id_that_does_not_exist", readOnly: true); + var robot = await RobotService.ReadById("some_id_that_does_not_exist", readOnly: true); Assert.Null(robot); } [Fact] public async Task Create() { - var robotService = new RobotService( - _context, - _logger, - _robotModelService, - _signalRService, - _accessRoleService, - _installationService, - _inspectionAreaService - ); - var installationService = new InstallationService(_context, _accessRoleService); - - var installation = await installationService.Create( + var installation = await InstallationService.Create( new CreateInstallationQuery { Name = "Johan Sverdrup", InstallationCode = "JSV" } ); - var robotsBefore = await robotService.ReadAll(readOnly: true); + var robotsBefore = await RobotService.ReadAll(readOnly: true); int nRobotsBefore = robotsBefore.Count(); - var documentationQuery = new CreateDocumentationQuery - { - Name = "Some document", - Url = "someURL", - }; - var robotQuery = new CreateRobotQuery - { - Name = "", - IsarId = "", - SerialNumber = "", - Documentation = [documentationQuery], - CurrentInstallationCode = installation.InstallationCode, - RobotType = RobotType.Robot, - Host = "", - Port = 1, - Status = RobotStatus.Available, - }; - var robotModel = _context.RobotModels.First(); - var robot = new Robot(robotQuery, installation, robotModel); + _ = await DatabaseUtilities.NewRobot(RobotStatus.Available, installation); - await robotService.Create(robot); - var robotsAfter = await robotService.ReadAll(readOnly: true); + var robotsAfter = await RobotService.ReadAll(readOnly: true); int nRobotsAfter = robotsAfter.Count(); Assert.Equal(nRobotsBefore + 1, nRobotsAfter); diff --git a/backend/api.test/TestSetupHelpers.cs b/backend/api.test/TestSetupHelpers.cs new file mode 100644 index 00000000..8c8af5a3 --- /dev/null +++ b/backend/api.test/TestSetupHelpers.cs @@ -0,0 +1,82 @@ +using System; +using System.Data.Common; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using Api.Database.Context; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; + +namespace Api.Test; + +public static class TestSetupHelpers +{ + public static async Task<(string, DbConnection)> ConfigureDatabase(string databaseName) + { + string connectionString = new SqliteConnectionStringBuilder + { + DataSource = $"file:{databaseName}?mode=memory", + Cache = SqliteCacheMode.Shared, + }.ToString(); + + var context = ConfigureFlotillaDbContext(connectionString); + await context.Database.EnsureCreatedAsync(); + + var connection = context.Database.GetDbConnection(); + await connection.OpenAsync(); + + return (connectionString, connection); + } + + public static JsonSerializerOptions ConfigureJsonSerializerOptions() + { + return new JsonSerializerOptions + { + Converters = { new JsonStringEnumConverter() }, + PropertyNameCaseInsensitive = true, + }; + } + + public static IServiceProvider ConfigureServiceProvider( + TestWebApplicationFactory factory + ) + { + return factory.Services; + } + + public static FlotillaDbContext ConfigureFlotillaDbContext(string connectionString) + { + var optionsBuilder = new DbContextOptionsBuilder(); + optionsBuilder.EnableSensitiveDataLogging(); + optionsBuilder.UseSqlite(connectionString); + + var context = new FlotillaDbContext(optionsBuilder.Options); + return context; + } + + public static TestWebApplicationFactory ConfigureWebApplicationFactory( + string databaseName + ) + { + return new TestWebApplicationFactory(databaseName); + } + + public static HttpClient ConfigureHttpClient(TestWebApplicationFactory factory) + { + var client = factory.CreateClient( + new WebApplicationFactoryClientOptions + { + AllowAutoRedirect = false, + BaseAddress = new Uri("http://localhost:8000"), + } + ); + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( + TestAuthHandler.AuthenticationScheme + ); + + return client; + } +} diff --git a/backend/api.test/TestWebApplicationFactory.cs b/backend/api.test/TestWebApplicationFactory.cs index 53587c71..1a69e57f 100644 --- a/backend/api.test/TestWebApplicationFactory.cs +++ b/backend/api.test/TestWebApplicationFactory.cs @@ -1,4 +1,5 @@ using System.IO; +using Api.Database.Context; using Api.Services; using Api.Services.MissionLoaders; using Api.Test.Mocks; @@ -7,19 +8,24 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.TestHost; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace Api.Test { - public class TestWebApplicationFactory : WebApplicationFactory + public class TestWebApplicationFactory(string databaseName) + : WebApplicationFactory where TProgram : class { + public IConfiguration? Configuration; + protected override void ConfigureWebHost(IWebHostBuilder builder) { string projectDir = Directory.GetCurrentDirectory(); string configPath = Path.Combine(projectDir, "appsettings.Test.json"); - var configuration = new ConfigurationBuilder().AddJsonFile(configPath).Build(); + Configuration = new ConfigurationBuilder().AddJsonFile(configPath).Build(); builder.UseEnvironment("Test"); builder.ConfigureAppConfiguration( (context, config) => @@ -29,6 +35,19 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) ); builder.ConfigureTestServices(services => { + string sqlLiteConnectionString = new SqliteConnectionStringBuilder + { + DataSource = $"file:{databaseName}?mode=memory", + Cache = SqliteCacheMode.Shared, + }.ToString(); + + services.AddDbContext(options => + options.UseSqlite( + sqlLiteConnectionString, + o => o.UseQuerySplittingBehavior(QuerySplittingBehavior.SingleQuery) + ) + ); + services.AddScoped(); services.AddScoped(); services.AddSingleton(); diff --git a/backend/api/Configurations/CustomServiceConfigurations.cs b/backend/api/Configurations/CustomServiceConfigurations.cs index 2e9c7155..e4a3e929 100644 --- a/backend/api/Configurations/CustomServiceConfigurations.cs +++ b/backend/api/Configurations/CustomServiceConfigurations.cs @@ -11,14 +11,20 @@ public static class CustomServiceConfigurations { public static IServiceCollection ConfigureDatabase( this IServiceCollection services, - IConfiguration configuration + IConfiguration configuration, + string environmentName ) { bool useInMemoryDatabase = configuration .GetSection("Database") .GetValue("UseInMemoryDatabase"); - if (useInMemoryDatabase) + if (environmentName.Equals("Test", StringComparison.Ordinal)) + { + Console.WriteLine("Using TEST"); + // The application is running in a test state and database will be configured there + } + else if (useInMemoryDatabase) { DbContextOptionsBuilder dbBuilder = new DbContextOptionsBuilder(); diff --git a/backend/api/EventHandlers/MqttEventHandler.cs b/backend/api/EventHandlers/MqttEventHandler.cs index 78de91df..880e20b8 100644 --- a/backend/api/EventHandlers/MqttEventHandler.cs +++ b/backend/api/EventHandlers/MqttEventHandler.cs @@ -390,7 +390,7 @@ private async void OnIsarMissionUpdate(object? sender, MqttReceivedArgs mqttArgs if (flotillaMissionRun is null) { string errorMessage = - $"Mission with isar mission Id {isarMission.IsarId} was not found"; + $"Mission with isar mission Id {isarMission.MissionId} was not found"; _logger.LogError("{Message}", errorMessage); return; } diff --git a/backend/api/Program.cs b/backend/api/Program.cs index cc6230b4..ef0182c7 100644 --- a/backend/api/Program.cs +++ b/backend/api/Program.cs @@ -45,7 +45,7 @@ builder.ConfigureLogger(); -builder.Services.ConfigureDatabase(builder.Configuration); +builder.Services.ConfigureDatabase(builder.Configuration, builder.Environment.EnvironmentName); builder.Services.ConfigureMissionLoader(builder.Configuration);