From bb1816f696ee53095bfd431e4f944abe73c6a289 Mon Sep 17 00:00:00 2001 From: aestene Date: Wed, 5 Feb 2025 15:12:32 +0100 Subject: [PATCH 1/6] Add test for list all robot models --- .../Controllers/RobotModelControllerTests.cs | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 backend/api.test/Controllers/RobotModelControllerTests.cs diff --git a/backend/api.test/Controllers/RobotModelControllerTests.cs b/backend/api.test/Controllers/RobotModelControllerTests.cs new file mode 100644 index 00000000..4a50b0fb --- /dev/null +++ b/backend/api.test/Controllers/RobotModelControllerTests.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Json; +using System.Text.Json; +using System.Threading.Tasks; +using Api.Database.Models; +using Api.Test.Database; +using Testcontainers.PostgreSql; +using Xunit; + +namespace Api.Test.Controllers; + +public class RobotModelControllerTests : IAsyncLifetime +{ + public required DatabaseUtilities DatabaseUtilities; + public required PostgreSqlContainer Container; + public required HttpClient Client; + public required JsonSerializerOptions SerializerOptions; + + public async Task InitializeAsync() + { + (Container, var connectionString, var connection) = + await TestSetupHelpers.ConfigurePostgreSqlDatabase(); + var factory = TestSetupHelpers.ConfigureWebApplicationFactory( + postgreSqlConnectionString: connectionString + ); + Client = TestSetupHelpers.ConfigureHttpClient(factory); + SerializerOptions = TestSetupHelpers.ConfigureJsonSerializerOptions(); + + DatabaseUtilities = new DatabaseUtilities( + TestSetupHelpers.ConfigurePostgreSqlContext(connectionString) + ); + } + + public Task DisposeAsync() => Task.CompletedTask; + + [Fact] + public async Task CheckThatListAllRobotModelsReturnsSuccess() + { + var response = await Client.GetAsync("/robot-models"); + var robotModels = await response.Content.ReadFromJsonAsync>( + SerializerOptions + ); + + // Seven models are added by default to the database + // This number must be changed if new robots are introduced + Assert.Equal(7, robotModels!.Count); + } +} From c29521b5cd6f1b830535c92f7923e59f93d890b7 Mon Sep 17 00:00:00 2001 From: aestene Date: Wed, 5 Feb 2025 15:27:47 +0100 Subject: [PATCH 2/6] Add test for looking up robot model by type --- .../Controllers/RobotModelControllerTests.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/backend/api.test/Controllers/RobotModelControllerTests.cs b/backend/api.test/Controllers/RobotModelControllerTests.cs index 4a50b0fb..f92b42dd 100644 --- a/backend/api.test/Controllers/RobotModelControllerTests.cs +++ b/backend/api.test/Controllers/RobotModelControllerTests.cs @@ -4,7 +4,9 @@ using System.Text.Json; using System.Threading.Tasks; using Api.Database.Models; +using Api.Services; using Api.Test.Database; +using Microsoft.Extensions.DependencyInjection; using Testcontainers.PostgreSql; using Xunit; @@ -17,6 +19,8 @@ public class RobotModelControllerTests : IAsyncLifetime public required HttpClient Client; public required JsonSerializerOptions SerializerOptions; + public required IRobotModelService RobotModelService; + public async Task InitializeAsync() { (Container, var connectionString, var connection) = @@ -24,12 +28,16 @@ public async Task InitializeAsync() var factory = TestSetupHelpers.ConfigureWebApplicationFactory( postgreSqlConnectionString: connectionString ); + var serviceProvider = TestSetupHelpers.ConfigureServiceProvider(factory); + Client = TestSetupHelpers.ConfigureHttpClient(factory); SerializerOptions = TestSetupHelpers.ConfigureJsonSerializerOptions(); DatabaseUtilities = new DatabaseUtilities( TestSetupHelpers.ConfigurePostgreSqlContext(connectionString) ); + + RobotModelService = serviceProvider.GetRequiredService(); } public Task DisposeAsync() => Task.CompletedTask; @@ -46,4 +54,15 @@ public async Task CheckThatListAllRobotModelsReturnsSuccess() // This number must be changed if new robots are introduced Assert.Equal(7, robotModels!.Count); } + + [Fact] + public async Task CheckThatLookupRobotModelByRobotTypeReturnsSuccess() + { + const RobotType RobotType = RobotType.Robot; + + var response = await Client.GetAsync("/robot-models/type/" + RobotType); + var robotModel = await response.Content.ReadFromJsonAsync(SerializerOptions); + + Assert.Equal(RobotType, robotModel!.Type); + } } From 581842308a8b2b7cb5128e0b36f8a239477bdca4 Mon Sep 17 00:00:00 2001 From: aestene Date: Wed, 5 Feb 2025 15:35:04 +0100 Subject: [PATCH 3/6] Add test for reading robot model by id --- .../Controllers/RobotModelControllerTests.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/backend/api.test/Controllers/RobotModelControllerTests.cs b/backend/api.test/Controllers/RobotModelControllerTests.cs index f92b42dd..7779b54a 100644 --- a/backend/api.test/Controllers/RobotModelControllerTests.cs +++ b/backend/api.test/Controllers/RobotModelControllerTests.cs @@ -65,4 +65,18 @@ public async Task CheckThatLookupRobotModelByRobotTypeReturnsSuccess() Assert.Equal(RobotType, robotModel!.Type); } + + [Fact] + public async Task CheckThatLookupRobotModelByIdReturnsSuccess() + { + var robotModel = await RobotModelService.ReadByRobotType(RobotType.Robot); + + var response = await Client.GetAsync("/robot-models/" + robotModel!.Id); + var robotModelFromResponse = await response.Content.ReadFromJsonAsync( + SerializerOptions + ); + + Assert.Equal(robotModel.Id, robotModelFromResponse!.Id); + Assert.Equal(robotModel.Type, robotModelFromResponse!.Type); + } } From aa7556d7df1f8be74acafa2f4470b3f6ae9c47a1 Mon Sep 17 00:00:00 2001 From: aestene Date: Fri, 7 Feb 2025 09:10:15 +0100 Subject: [PATCH 4/6] Remove the endpoint for deleting a robot model This endpoint is never used and it should not be possible to make this destructive action. If deleting a RobotModel should be considered it would require some care and thought to the decision. --- .../api/Controllers/RobotModelController.cs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/backend/api/Controllers/RobotModelController.cs b/backend/api/Controllers/RobotModelController.cs index 86a51912..67b6e3f7 100644 --- a/backend/api/Controllers/RobotModelController.cs +++ b/backend/api/Controllers/RobotModelController.cs @@ -188,25 +188,6 @@ [FromBody] UpdateRobotModelQuery robotModelQuery return await UpdateModel(robotModel, robotModelQuery); } - /// - /// Deletes the robot model with the specified id from the database. - /// - [HttpDelete] - [Authorize(Roles = Role.Admin)] - [Route("{id}")] - [ProducesResponseType(typeof(RobotModel), StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(StatusCodes.Status403Forbidden)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task> DeleteRobotModel([FromRoute] string id) - { - var robotModel = await robotModelService.Delete(id); - if (robotModel is null) - return NotFound($"Area with id {id} not found"); - return Ok(robotModel); - } - private async Task> UpdateModel( RobotModel robotModel, UpdateRobotModelQuery robotModelQuery From 508591cdc5d064feb325e7354e4502f9ff53f425 Mon Sep 17 00:00:00 2001 From: aestene Date: Wed, 12 Feb 2025 11:27:40 +0100 Subject: [PATCH 5/6] Add tests for updating of robot models --- .../Controllers/RobotModelControllerTests.cs | 56 +++++++++++++++++++ .../Models/UpdateRobotModelQuery.cs | 8 ++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/backend/api.test/Controllers/RobotModelControllerTests.cs b/backend/api.test/Controllers/RobotModelControllerTests.cs index 7779b54a..51b71d76 100644 --- a/backend/api.test/Controllers/RobotModelControllerTests.cs +++ b/backend/api.test/Controllers/RobotModelControllerTests.cs @@ -3,6 +3,7 @@ using System.Net.Http.Json; using System.Text.Json; using System.Threading.Tasks; +using Api.Controllers.Models; using Api.Database.Models; using Api.Services; using Api.Test.Database; @@ -79,4 +80,59 @@ public async Task CheckThatLookupRobotModelByIdReturnsSuccess() Assert.Equal(robotModel.Id, robotModelFromResponse!.Id); Assert.Equal(robotModel.Type, robotModelFromResponse!.Type); } + + [Theory] + [InlineData(10, 90, 10, 50, true)] + [InlineData(-1, -10, 10, 50, false)] + [InlineData(110, 1000, 10, 900, false)] + [InlineData(0, 9000, 0, 100, true)] + public async Task CheckThatUpdatingRobotBasedOnIdIsSuccessful( + int batteryWarningThreshold, + int upperPressureWarningThreshold, + int lowerPressureWarningThreshold, + int batteryMissionStartThreshold, + bool valuesShouldHaveBeenChanged + ) + { + // Arrange + var modelBefore = await RobotModelService.ReadByRobotType(RobotType.Robot); + + var query = new UpdateRobotModelQuery + { + BatteryWarningThreshold = batteryWarningThreshold, + UpperPressureWarningThreshold = upperPressureWarningThreshold, + LowerPressureWarningThreshold = lowerPressureWarningThreshold, + BatteryMissionStartThreshold = batteryMissionStartThreshold, + }; + var content = new StringContent(JsonSerializer.Serialize(query), null, "application/json"); + + // Act + _ = await Client.PutAsync("/robot-models/" + modelBefore!.Id, content); + + // Assert + var modelAfter = await RobotModelService.ReadByRobotType(RobotType.Robot); + if (valuesShouldHaveBeenChanged) + { + Assert.Equal(modelAfter!.BatteryWarningThreshold, batteryWarningThreshold); + Assert.Equal(modelAfter!.UpperPressureWarningThreshold, upperPressureWarningThreshold); + Assert.Equal(modelAfter!.LowerPressureWarningThreshold, lowerPressureWarningThreshold); + Assert.Equal(modelAfter!.BatteryMissionStartThreshold, batteryMissionStartThreshold); + } + else + { + Assert.Equal(modelAfter!.BatteryWarningThreshold, modelBefore!.BatteryWarningThreshold); + Assert.Equal( + modelAfter!.UpperPressureWarningThreshold, + modelBefore!.UpperPressureWarningThreshold + ); + Assert.Equal( + modelAfter!.LowerPressureWarningThreshold, + modelBefore!.LowerPressureWarningThreshold + ); + Assert.Equal( + modelAfter!.BatteryMissionStartThreshold, + modelBefore!.BatteryMissionStartThreshold + ); + } + } } diff --git a/backend/api/Controllers/Models/UpdateRobotModelQuery.cs b/backend/api/Controllers/Models/UpdateRobotModelQuery.cs index ef2ce7ee..cfa51168 100644 --- a/backend/api/Controllers/Models/UpdateRobotModelQuery.cs +++ b/backend/api/Controllers/Models/UpdateRobotModelQuery.cs @@ -1,25 +1,31 @@ -namespace Api.Controllers.Models +using System.ComponentModel.DataAnnotations; + +namespace Api.Controllers.Models { public struct UpdateRobotModelQuery { /// /// Lower battery warning threshold in percentage /// + [Range(0, 100, ErrorMessage = "Value must be between 0 and 100")] public float? BatteryWarningThreshold { get; set; } /// /// Upper pressure warning threshold in Bar /// + [Range(0, float.MaxValue, ErrorMessage = "Value must be a non-negative number")] public float? UpperPressureWarningThreshold { get; set; } /// /// Lower pressure warning threshold in Bar /// + [Range(0, float.MaxValue, ErrorMessage = "Value must be a non-negative number")] public float? LowerPressureWarningThreshold { get; set; } /// /// Lower battery threshold at which to allow missions to be scheduled, in percentage /// + [Range(0, 100, ErrorMessage = "Value must be between 0 and 100")] public float? BatteryMissionStartThreshold { get; set; } } } From ba93dbe8dda53381baa75eced2dca0027806a1d3 Mon Sep 17 00:00:00 2001 From: aestene Date: Wed, 12 Feb 2025 14:22:06 +0100 Subject: [PATCH 6/6] Add test for create robot model endpoint --- .../Controllers/RobotModelControllerTests.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/backend/api.test/Controllers/RobotModelControllerTests.cs b/backend/api.test/Controllers/RobotModelControllerTests.cs index 51b71d76..49df4c3d 100644 --- a/backend/api.test/Controllers/RobotModelControllerTests.cs +++ b/backend/api.test/Controllers/RobotModelControllerTests.cs @@ -81,6 +81,26 @@ public async Task CheckThatLookupRobotModelByIdReturnsSuccess() Assert.Equal(robotModel.Type, robotModelFromResponse!.Type); } + [Fact] + public async Task CheckThatCreateRobotModelReturnsSuccess() + { + // Arrange + var modelBefore = await RobotModelService.ReadByRobotType(RobotType.Robot); + _ = await RobotModelService.Delete(modelBefore!.Id); + + var query = new CreateRobotModelQuery { RobotType = RobotType.Robot }; + var content = new StringContent(JsonSerializer.Serialize(query), null, "application/json"); + + // Act + var response = await Client.PostAsync("/robot-models", content); + + // Assert + var modelAfter = await RobotModelService.ReadByRobotType(RobotType.Robot); + + Assert.True(response.IsSuccessStatusCode); + Assert.NotEqual(modelBefore!.Id, modelAfter!.Id); + } + [Theory] [InlineData(10, 90, 10, 50, true)] [InlineData(-1, -10, 10, 50, false)]