diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/LoRaWAN/LoRaWANDevicesControllerTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/LoRaWAN/LoRaWANDevicesControllerTests.cs index caa85df67..26025e77b 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/LoRaWAN/LoRaWANDevicesControllerTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/LoRaWAN/LoRaWANDevicesControllerTests.cs @@ -6,16 +6,14 @@ namespace AzureIoTHub.Portal.Tests.Unit.Server.Controllers.v1._0.LoRaWAN using System; using System.Collections.Generic; using System.Linq; - using System.Net; using System.Net.Http; + using System.Net; using System.Threading; using System.Threading.Tasks; using Azure; using Azure.Data.Tables; - using Models.v10; using AzureIoTHub.Portal.Models.v10.LoRaWAN; using AzureIoTHub.Portal.Server.Controllers.V10; - using AzureIoTHub.Portal.Server.Exceptions; using AzureIoTHub.Portal.Server.Factories; using AzureIoTHub.Portal.Server.Managers; using AzureIoTHub.Portal.Server.Mappers; @@ -26,6 +24,7 @@ namespace AzureIoTHub.Portal.Tests.Unit.Server.Controllers.v1._0.LoRaWAN using Microsoft.Azure.Devices; using Microsoft.Azure.Devices.Shared; using Microsoft.Extensions.Logging; + using Models.v10; using Moq; using NUnit.Framework; @@ -44,6 +43,7 @@ public class LoRaWANDevicesControllerTests private Mock mockDeviceModelCommandMapper; private Mock mockUrlHelper; private Mock mockCommandsTableClient; + private Mock mockLoRaWANDeviceService; [SetUp] public void SetUp() @@ -60,6 +60,7 @@ public void SetUp() this.mockDeviceModelCommandMapper = this.mockRepository.Create(); this.mockCommandsTableClient = this.mockRepository.Create(); this.mockUrlHelper = this.mockRepository.Create(); + this.mockLoRaWANDeviceService = this.mockRepository.Create(); } private LoRaWANDevicesController CreateLoRaWANDevicesController() @@ -70,8 +71,7 @@ private LoRaWANDevicesController CreateLoRaWANDevicesController() this.mockDeviceTagService.Object, this.mockDeviceTwinMapper.Object, this.mockTableClientFactory.Object, - this.mockLoraDeviceMethodManager.Object, - this.mockDeviceModelCommandMapper.Object, + this.mockLoRaWANDeviceService.Object, this.mockProvisioningServiceManager.Object); } @@ -84,59 +84,9 @@ public async Task ExecuteCommandStateUnderTestExpectedBehavior() var deviceId = Guid.NewGuid().ToString(); var commandId = Guid.NewGuid().ToString(); - var mockResponse = this.mockRepository.Create(); - _ = this.mockDeviceModelCommandMapper - .Setup(c => c.GetDeviceModelCommand(It.Is(x => x.RowKey == commandId && x.PartitionKey == modelId))) - .Returns(new DeviceModelCommand - { - Name = commandId, - Frame = Guid.NewGuid().ToString(), - Port = 125 - }); - - _ = this.mockCommandsTableClient.Setup(c => c.Query( - It.Is(x => x == $"RowKey eq '{commandId}' and PartitionKey eq '{modelId}'"), - It.IsAny(), - It.IsAny>(), - It.IsAny())) - .Returns(Pageable.FromPages(new[] - { - Page.FromValues(new[] - { - new TableEntity(modelId, commandId) - }, null, mockResponse.Object) - })); - - _ = this.mockTableClientFactory.Setup(c => c.GetDeviceCommands()) - .Returns(this.mockCommandsTableClient.Object); - - using var success = new HttpResponseMessage(HttpStatusCode.Accepted); - - _ = this.mockLoraDeviceMethodManager.Setup(c => c.ExecuteLoRaDeviceMessage( - It.Is(x => x == deviceId), - It.Is(x => x.Name == commandId))) - .ReturnsAsync(success); - - _ = this.mockLogger.Setup(c => c.Log( - It.Is(x => x == LogLevel.Information), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny>())); - - _ = this.mockDeviceService.Setup(c => c.GetDeviceTwin(It.Is(x => x == deviceId))) - .ReturnsAsync(new Twin() - { - DeviceId = deviceId, - ModelId = modelId, - }); - - _ = this.mockDeviceTwinMapper.Setup(c => c.CreateDeviceDetails(It.IsAny(), It.IsAny>())) - .Returns>((_, _) => new LoRaDeviceDetails - { - DeviceID = deviceId, - ModelId = modelId, - }); + this.mockLoRaWANDeviceService.Setup(c => c.ExecuteLoRaWANCommand(deviceId, commandId)) + .Returns(Task.CompletedTask) + .Verifiable(); // Act var result = await loRaWANDevicesController.ExecuteCommand(deviceId, commandId); @@ -148,166 +98,6 @@ public async Task ExecuteCommandStateUnderTestExpectedBehavior() this.mockRepository.VerifyAll(); } - [Test] - public async Task ExecuteCommandShouldThrowInternalServerErrorExceptionWheIssueOccursWhenQueryingCommands() - { - // Arrange - var loRaWANDevicesController = CreateLoRaWANDevicesController(); - var modelId = Guid.NewGuid().ToString(); - var deviceId = Guid.NewGuid().ToString(); - var commandId = Guid.NewGuid().ToString(); - - _ = this.mockCommandsTableClient.Setup(c => c.Query( - It.Is(x => x == $"RowKey eq '{commandId}' and PartitionKey eq '{modelId}'"), - It.IsAny(), - It.IsAny>(), - It.IsAny())) - .Throws(new RequestFailedException("test")); - - _ = this.mockTableClientFactory.Setup(c => c.GetDeviceCommands()) - .Returns(this.mockCommandsTableClient.Object); - - _ = this.mockDeviceService.Setup(c => c.GetDeviceTwin(It.Is(x => x == deviceId))) - .ReturnsAsync(new Twin() - { - DeviceId = deviceId, - ModelId = modelId, - }); - - _ = this.mockDeviceTwinMapper.Setup(c => c.CreateDeviceDetails(It.IsAny(), It.IsAny>())) - .Returns>((_, _) => new LoRaDeviceDetails - { - DeviceID = deviceId, - ModelId = modelId, - }); - - // Act - var act = () => loRaWANDevicesController.ExecuteCommand(deviceId, commandId); - - // Assert - _ = await act.Should().ThrowAsync(); - this.mockRepository.VerifyAll(); - } - - [Test] - public async Task ExecuteCommandShouldReturnNotFoundWhenCommandIsNotFound() - { - // Arrange - var loRaWANDevicesController = CreateLoRaWANDevicesController(); - var modelId = Guid.NewGuid().ToString(); - var deviceId = Guid.NewGuid().ToString(); - var commandId = Guid.NewGuid().ToString(); - - var mockResponse = this.mockRepository.Create(); - - _ = this.mockCommandsTableClient.Setup(c => c.Query( - It.Is(x => x == $"RowKey eq '{commandId}' and PartitionKey eq '{modelId}'"), - It.IsAny(), - It.IsAny>(), - It.IsAny())) - .Returns(Pageable.FromPages(new[] - { - Page.FromValues(Array.Empty(), null, mockResponse.Object) - })); - - _ = this.mockTableClientFactory.Setup(c => c.GetDeviceCommands()) - .Returns(this.mockCommandsTableClient.Object); - - _ = this.mockDeviceService.Setup(c => c.GetDeviceTwin(It.Is(x => x == deviceId))) - .ReturnsAsync(new Twin() - { - DeviceId = deviceId, - ModelId = modelId, - }); - - _ = this.mockDeviceTwinMapper.Setup(c => c.CreateDeviceDetails(It.IsAny(), It.IsAny>())) - .Returns>((_, _) => new LoRaDeviceDetails - { - DeviceID = deviceId, - ModelId = modelId, - }); - - // Act - var result = await loRaWANDevicesController.ExecuteCommand(deviceId, commandId); - - // Assert - Assert.IsNotNull(result); - Assert.IsAssignableFrom(result); - this.mockRepository.VerifyAll(); - } - - [Test] - public async Task ExecuteCommandFailedShouldReturnHttp400() - { - // Arrange - var loRaWANDevicesController = CreateLoRaWANDevicesController(); - var modelId = Guid.NewGuid().ToString(); - var deviceId = Guid.NewGuid().ToString(); - var commandId = Guid.NewGuid().ToString(); - - var mockResponse = this.mockRepository.Create(); - _ = this.mockDeviceModelCommandMapper - .Setup(c => c.GetDeviceModelCommand(It.Is(x => x.RowKey == commandId && x.PartitionKey == modelId))) - .Returns(new DeviceModelCommand - { - Name = commandId, - Frame = Guid.NewGuid().ToString(), - Port = 125 - }); - - _ = this.mockCommandsTableClient.Setup(c => c.Query( - It.Is(x => x == $"RowKey eq '{commandId}' and PartitionKey eq '{modelId}'"), - It.IsAny(), - It.IsAny>(), - It.IsAny())) - .Returns(Pageable.FromPages(new[] - { - Page.FromValues(new[] - { - new TableEntity(modelId, commandId) - }, null, mockResponse.Object) - })); - - _ = this.mockTableClientFactory.Setup(c => c.GetDeviceCommands()) - .Returns(this.mockCommandsTableClient.Object); - - using var internalServerError = new HttpResponseMessage(HttpStatusCode.InternalServerError); - - _ = this.mockLoraDeviceMethodManager.Setup(c => c.ExecuteLoRaDeviceMessage( - It.Is(x => x == deviceId), - It.Is(x => x.Name == commandId))) - .ReturnsAsync(internalServerError); - - _ = this.mockLogger.Setup(c => c.Log( - It.Is(x => x == LogLevel.Error), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny>())); - - _ = this.mockDeviceService.Setup(c => c.GetDeviceTwin(It.Is(x => x == deviceId))) - .ReturnsAsync(new Twin() - { - DeviceId = deviceId, - ModelId = modelId, - }); - - _ = this.mockDeviceTwinMapper.Setup(c => c.CreateDeviceDetails(It.IsAny(), It.IsAny>())) - .Returns>((_, _) => new LoRaDeviceDetails - { - DeviceID = deviceId, - ModelId = modelId, - }); - - // Act - var result = await loRaWANDevicesController.ExecuteCommand(deviceId, commandId); - - // Assert - Assert.IsNotNull(result); - Assert.IsAssignableFrom(result); - this.mockRepository.VerifyAll(); - } - [Test] public async Task GetListStateUnderTestExpectedBehavior() { diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/LoRaWANDeviceServiceTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/LoRaWANDeviceServiceTests.cs new file mode 100644 index 000000000..bd0419c8e --- /dev/null +++ b/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/LoRaWANDeviceServiceTests.cs @@ -0,0 +1,297 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace AzureIoTHub.Portal.Tests.Unit.Server.Services +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + using Azure.Data.Tables; + using AzureIoTHub.Portal.Models.v10.LoRaWAN; + using AzureIoTHub.Portal.Models.v10; + using AzureIoTHub.Portal.Server.Controllers.V10; + using AzureIoTHub.Portal.Server.Factories; + using AzureIoTHub.Portal.Server.Managers; + using AzureIoTHub.Portal.Server.Mappers; + using AzureIoTHub.Portal.Server.Services; + using Microsoft.AspNetCore.Mvc; + using Microsoft.Extensions.Logging; + using Moq; + using NUnit.Framework; + using Azure; + using System.Threading; + using System.Net.Http; + using System.Net; + using Microsoft.Azure.Devices.Shared; + using AzureIoTHub.Portal.Server.Exceptions; + using FluentAssertions; + + [TestFixture] + public class LoRaWANDeviceServiceTests + { + private MockRepository mockRepository; + + private Mock> mockLogger; + private Mock mockDeviceService; + private Mock mockDeviceTagService; + private Mock> mockDeviceTwinMapper; + private Mock mockTableClientFactory; + private Mock mockLoraDeviceMethodManager; + private Mock mockDeviceModelCommandMapper; + private Mock mockCommandsTableClient; + + [SetUp] + public void SetUp() + { + this.mockRepository = new MockRepository(MockBehavior.Strict); + + this.mockLogger = this.mockRepository.Create>(); + this.mockDeviceService = this.mockRepository.Create(); + this.mockDeviceTagService = this.mockRepository.Create(); + this.mockDeviceTwinMapper = this.mockRepository.Create>(); + this.mockTableClientFactory = this.mockRepository.Create(); + this.mockLoraDeviceMethodManager = this.mockRepository.Create(); + this.mockDeviceModelCommandMapper = this.mockRepository.Create(); + this.mockCommandsTableClient = this.mockRepository.Create(); + + } + + private LoRaWANDeviceService CreateLoRaWANDeviceService() + { + return new LoRaWANDeviceService( + this.mockTableClientFactory.Object, + this.mockDeviceService.Object, + this.mockDeviceTwinMapper.Object, + this.mockLoraDeviceMethodManager.Object, + this.mockDeviceModelCommandMapper.Object, + this.mockLogger.Object); + } + + [Test] + public async Task ExecuteCommandStateUnderTestExpectedBehavior() + { + // Arrange + var loRaWANDevicesService = CreateLoRaWANDeviceService(); + var modelId = Guid.NewGuid().ToString(); + var deviceId = Guid.NewGuid().ToString(); + var commandId = Guid.NewGuid().ToString(); + + var mockResponse = this.mockRepository.Create(); + _ = this.mockDeviceModelCommandMapper + .Setup(c => c.GetDeviceModelCommand(It.Is(x => x.RowKey == commandId && x.PartitionKey == modelId))) + .Returns(new DeviceModelCommand + { + Name = commandId, + Frame = Guid.NewGuid().ToString(), + Port = 125 + }); + + _ = this.mockCommandsTableClient.Setup(c => c.Query( + It.Is(x => x == $"RowKey eq '{commandId}' and PartitionKey eq '{modelId}'"), + It.IsAny(), + It.IsAny>(), + It.IsAny())) + .Returns(Pageable.FromPages(new[] + { + Page.FromValues(new[] + { + new TableEntity(modelId, commandId) + }, null, mockResponse.Object) + })); + + _ = this.mockTableClientFactory.Setup(c => c.GetDeviceCommands()) + .Returns(this.mockCommandsTableClient.Object); + + using var success = new HttpResponseMessage(HttpStatusCode.Accepted); + + _ = this.mockLoraDeviceMethodManager.Setup(c => c.ExecuteLoRaDeviceMessage( + It.Is(x => x == deviceId), + It.Is(x => x.Name == commandId))) + .ReturnsAsync(success); + + _ = this.mockLogger.Setup(c => c.Log( + It.Is(x => x == LogLevel.Information), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny>())); + + _ = this.mockDeviceService.Setup(c => c.GetDeviceTwin(It.Is(x => x == deviceId))) + .ReturnsAsync(new Twin() + { + DeviceId = deviceId, + ModelId = modelId, + }); + + _ = this.mockDeviceTwinMapper.Setup(c => c.CreateDeviceDetails(It.IsAny(), It.IsAny>())) + .Returns>((_, _) => new LoRaDeviceDetails + { + DeviceID = deviceId, + ModelId = modelId, + }); + + // Act + await loRaWANDevicesService.ExecuteLoRaWANCommand(deviceId, commandId); + + // Assert + this.mockRepository.VerifyAll(); + } + + [Test] + public async Task ExecuteCommandShouldThrowInternalServerErrorExceptionWheIssueOccursWhenQueryingCommands() + { + // Arrange + var loRaWANDevicesService= CreateLoRaWANDeviceService(); + var modelId = Guid.NewGuid().ToString(); + var deviceId = Guid.NewGuid().ToString(); + var commandId = Guid.NewGuid().ToString(); + + _ = this.mockCommandsTableClient.Setup(c => c.Query( + It.Is(x => x == $"RowKey eq '{commandId}' and PartitionKey eq '{modelId}'"), + It.IsAny(), + It.IsAny>(), + It.IsAny())) + .Throws(new RequestFailedException("test")); + + _ = this.mockTableClientFactory.Setup(c => c.GetDeviceCommands()) + .Returns(this.mockCommandsTableClient.Object); + + _ = this.mockDeviceService.Setup(c => c.GetDeviceTwin(It.Is(x => x == deviceId))) + .ReturnsAsync(new Twin() + { + DeviceId = deviceId, + ModelId = modelId, + }); + + _ = this.mockDeviceTwinMapper.Setup(c => c.CreateDeviceDetails(It.IsAny(), It.IsAny>())) + .Returns>((_, _) => new LoRaDeviceDetails + { + DeviceID = deviceId, + ModelId = modelId, + }); + + // Act + var act = () => loRaWANDevicesService.ExecuteLoRaWANCommand(deviceId, commandId); + + // Assert + _ = await act.Should().ThrowAsync(); + this.mockRepository.VerifyAll(); + } + + [Test] + public void ExecuteCommandShouldReturnNotFoundWhenCommandIsNotFound() + { + // Arrange + var loRaWANDevicesService = CreateLoRaWANDeviceService(); + var modelId = Guid.NewGuid().ToString(); + var deviceId = Guid.NewGuid().ToString(); + var commandId = Guid.NewGuid().ToString(); + + var mockResponse = this.mockRepository.Create(); + + _ = this.mockCommandsTableClient.Setup(c => c.Query( + It.Is(x => x == $"RowKey eq '{commandId}' and PartitionKey eq '{modelId}'"), + It.IsAny(), + It.IsAny>(), + It.IsAny())) + .Returns(Pageable.FromPages(new[] + { + Page.FromValues(Array.Empty(), null, mockResponse.Object) + })); + + _ = this.mockTableClientFactory.Setup(c => c.GetDeviceCommands()) + .Returns(this.mockCommandsTableClient.Object); + + _ = this.mockDeviceService.Setup(c => c.GetDeviceTwin(It.Is(x => x == deviceId))) + .ReturnsAsync(new Twin() + { + DeviceId = deviceId, + ModelId = modelId, + }); + + _ = this.mockDeviceTwinMapper.Setup(c => c.CreateDeviceDetails(It.IsAny(), It.IsAny>())) + .Returns>((_, _) => new LoRaDeviceDetails + { + DeviceID = deviceId, + ModelId = modelId, + }); + + // Act + _ = Assert.ThrowsAsync(async () => await loRaWANDevicesService.ExecuteLoRaWANCommand(deviceId, commandId)); + + // Assert + this.mockRepository.VerifyAll(); + } + + [Test] + public void ExecuteCommandFailedShouldThrowInternalServerErrorException() + { + // Arrange + var loRaWANDevicesService = CreateLoRaWANDeviceService(); + var modelId = Guid.NewGuid().ToString(); + var deviceId = Guid.NewGuid().ToString(); + var commandId = Guid.NewGuid().ToString(); + + var mockResponse = this.mockRepository.Create(); + _ = this.mockDeviceModelCommandMapper + .Setup(c => c.GetDeviceModelCommand(It.Is(x => x.RowKey == commandId && x.PartitionKey == modelId))) + .Returns(new DeviceModelCommand + { + Name = commandId, + Frame = Guid.NewGuid().ToString(), + Port = 125 + }); + + _ = this.mockCommandsTableClient.Setup(c => c.Query( + It.Is(x => x == $"RowKey eq '{commandId}' and PartitionKey eq '{modelId}'"), + It.IsAny(), + It.IsAny>(), + It.IsAny())) + .Returns(Pageable.FromPages(new[] + { + Page.FromValues(new[] + { + new TableEntity(modelId, commandId) + }, null, mockResponse.Object) + })); + + _ = this.mockTableClientFactory.Setup(c => c.GetDeviceCommands()) + .Returns(this.mockCommandsTableClient.Object); + + using var internalServerError = new HttpResponseMessage(HttpStatusCode.InternalServerError); + + _ = this.mockLoraDeviceMethodManager.Setup(c => c.ExecuteLoRaDeviceMessage( + It.Is(x => x == deviceId), + It.Is(x => x.Name == commandId))) + .ReturnsAsync(internalServerError); + + _ = this.mockLogger.Setup(c => c.Log( + It.Is(x => x == LogLevel.Error), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny>())); + + _ = this.mockDeviceService.Setup(c => c.GetDeviceTwin(It.Is(x => x == deviceId))) + .ReturnsAsync(new Twin() + { + DeviceId = deviceId, + ModelId = modelId, + }); + + _ = this.mockDeviceTwinMapper.Setup(c => c.CreateDeviceDetails(It.IsAny(), It.IsAny>())) + .Returns>((_, _) => new LoRaDeviceDetails + { + DeviceID = deviceId, + ModelId = modelId, + }); + + // Assert + _ = Assert.ThrowsAsync(async () => await loRaWANDevicesService.ExecuteLoRaWANCommand(deviceId, commandId)); + + this.mockRepository.VerifyAll(); + } + } +} diff --git a/src/AzureIoTHub.Portal/Server/Controllers/v1.0/LoRaWAN/LoRaWANDevicesController.cs b/src/AzureIoTHub.Portal/Server/Controllers/v1.0/LoRaWAN/LoRaWANDevicesController.cs index c4bbf797a..c487cea1b 100644 --- a/src/AzureIoTHub.Portal/Server/Controllers/v1.0/LoRaWAN/LoRaWANDevicesController.cs +++ b/src/AzureIoTHub.Portal/Server/Controllers/v1.0/LoRaWAN/LoRaWANDevicesController.cs @@ -3,10 +3,7 @@ namespace AzureIoTHub.Portal.Server.Controllers.V10 { - using System.Linq; using System.Threading.Tasks; - using Azure; - using Azure.Data.Tables; using AzureIoTHub.Portal.Models.v10; using AzureIoTHub.Portal.Models.v10.LoRaWAN; using AzureIoTHub.Portal.Server.Factories; @@ -14,7 +11,6 @@ namespace AzureIoTHub.Portal.Server.Controllers.V10 using AzureIoTHub.Portal.Server.Managers; using AzureIoTHub.Portal.Server.Mappers; using AzureIoTHub.Portal.Server.Services; - using Exceptions; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; @@ -27,11 +23,7 @@ namespace AzureIoTHub.Portal.Server.Controllers.V10 [LoRaFeatureActiveFilter] public class LoRaWANDevicesController : DevicesControllerBase { - private readonly ITableClientFactory tableClientFactory; - private readonly ILoraDeviceMethodManager loraDeviceMethodManager; - private readonly IDeviceModelCommandMapper deviceModelCommandMapper; - private readonly IDeviceService deviceService; - private readonly IDeviceTwinMapper deviceTwinMapper; + private readonly ILoRaWANDeviceService loRaWANDeviceService; public LoRaWANDevicesController( ILogger logger, @@ -39,16 +31,11 @@ public LoRaWANDevicesController( IDeviceTagService deviceTagService, IDeviceTwinMapper deviceTwinMapper, ITableClientFactory tableClientFactory, - ILoraDeviceMethodManager loraDeviceMethodManager, - IDeviceModelCommandMapper deviceModelCommandMapper, + ILoRaWANDeviceService loRaWANDeviceService, IDeviceProvisioningServiceManager deviceProvisioningServiceManager) : base(logger, devicesService, deviceTagService, deviceTwinMapper, deviceProvisioningServiceManager, tableClientFactory) { - this.tableClientFactory = tableClientFactory; - this.loraDeviceMethodManager = loraDeviceMethodManager; - this.deviceModelCommandMapper = deviceModelCommandMapper; - this.deviceService = devicesService; - this.deviceTwinMapper = deviceTwinMapper; + this.loRaWANDeviceService = loRaWANDeviceService; } /// @@ -119,42 +106,9 @@ public override Task Delete(string deviceID) [HttpPost("{deviceId}/_command/{commandId}", Name = "POST Execute LoRaWAN command")] public async Task ExecuteCommand(string deviceId, string commandId) { - var twin = await this.deviceService.GetDeviceTwin(deviceId); - var modelId = this.deviceTwinMapper.CreateDeviceDetails(twin, null).ModelId; + await this.loRaWANDeviceService.ExecuteLoRaWANCommand(deviceId, commandId); - TableEntity commandEntity; - - try - { - commandEntity = this.tableClientFactory - .GetDeviceCommands() - .Query(filter: $"RowKey eq '{commandId}' and PartitionKey eq '{modelId}'") - .FirstOrDefault(); - - if (commandEntity == null) - { - return NotFound($"The LoRaWAN command {commandId} for the device {deviceId} cannot be found"); - } - } - catch (RequestFailedException e) - { - throw new InternalServerErrorException($"Unable to get the LoRaWAN command {commandId} for the device {deviceId}", e); - } - - var deviceModelCommand = this.deviceModelCommandMapper.GetDeviceModelCommand(commandEntity); - - var result = await this.loraDeviceMethodManager.ExecuteLoRaDeviceMessage(deviceId, deviceModelCommand); - - if (!result.IsSuccessStatusCode) - { - Logger.LogError($"{deviceId} - Execute command on device failed \n{(int)result.StatusCode} - {result.ReasonPhrase}\n{await result.Content.ReadAsStringAsync()}"); - - return BadRequest($"Something went wrong when executing the command {deviceModelCommand.Name}."); - } - - Logger.LogInformation($"{deviceId} - Execute command: \n{(int)result.StatusCode} - {result.ReasonPhrase}\n{await result.Content.ReadAsStringAsync()}"); - - return Ok(); + return this.Ok(); } [ApiExplorerSettings(IgnoreApi = true)] diff --git a/src/AzureIoTHub.Portal/Server/Services/ILoRaWANDeviceService.cs b/src/AzureIoTHub.Portal/Server/Services/ILoRaWANDeviceService.cs new file mode 100644 index 000000000..2c3f9578b --- /dev/null +++ b/src/AzureIoTHub.Portal/Server/Services/ILoRaWANDeviceService.cs @@ -0,0 +1,12 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace AzureIoTHub.Portal.Server.Services +{ + using System.Threading.Tasks; + + public interface ILoRaWANDeviceService + { + Task ExecuteLoRaWANCommand(string deviceId, string commandId); + } +} diff --git a/src/AzureIoTHub.Portal/Server/Services/LoRaWANDeviceService.cs b/src/AzureIoTHub.Portal/Server/Services/LoRaWANDeviceService.cs new file mode 100644 index 000000000..bed3038cf --- /dev/null +++ b/src/AzureIoTHub.Portal/Server/Services/LoRaWANDeviceService.cs @@ -0,0 +1,74 @@ +// Copyright (c) CGI France. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace AzureIoTHub.Portal.Server.Services +{ + using System.Linq; + using System.Threading.Tasks; + using Azure; + using Azure.Data.Tables; + using AzureIoTHub.Portal.Models.v10; + using AzureIoTHub.Portal.Models.v10.LoRaWAN; + using AzureIoTHub.Portal.Server.Exceptions; + using AzureIoTHub.Portal.Server.Factories; + using AzureIoTHub.Portal.Server.Managers; + using AzureIoTHub.Portal.Server.Mappers; + using Microsoft.Extensions.Logging; + + public class LoRaWANDeviceService : ILoRaWANDeviceService + { + private readonly ITableClientFactory tableClientFactory; + private readonly IDeviceService deviceService; + private readonly IDeviceTwinMapper deviceTwinMapper; + private readonly ILoraDeviceMethodManager loraDeviceMethodManager; + private readonly IDeviceModelCommandMapper deviceModelCommandMapper; + private readonly ILogger logger; + + public LoRaWANDeviceService(ITableClientFactory tableClientFactory, IDeviceService deviceService, IDeviceTwinMapper deviceTwinMapper, ILoraDeviceMethodManager loraDeviceMethodManager, IDeviceModelCommandMapper deviceModelCommandMapper, ILogger logger) + { + this.tableClientFactory = tableClientFactory; + this.deviceService = deviceService; + this.deviceTwinMapper = deviceTwinMapper; + this.loraDeviceMethodManager = loraDeviceMethodManager; + this.deviceModelCommandMapper = deviceModelCommandMapper; + this.logger = logger; + } + + public async Task ExecuteLoRaWANCommand(string deviceId, string commandId) + { + var twin = await this.deviceService.GetDeviceTwin(deviceId); + var modelId = this.deviceTwinMapper.CreateDeviceDetails(twin, null).ModelId; + TableEntity commandEntity; + + try + { + commandEntity = this.tableClientFactory + .GetDeviceCommands() + .Query(filter: $"RowKey eq '{commandId}' and PartitionKey eq '{modelId}'") + .FirstOrDefault(); + + if (commandEntity == null) + { + throw new ResourceNotFoundException($"The LoRaWAN command {commandId} for the device {deviceId} cannot be found"); + } + } + catch (RequestFailedException e) + { + throw new InternalServerErrorException($"Unable to get the LoRaWAN command {commandId} for the device {deviceId}", e); + } + + var deviceModelCommand = this.deviceModelCommandMapper.GetDeviceModelCommand(commandEntity); + + var result = await this.loraDeviceMethodManager.ExecuteLoRaDeviceMessage(deviceId, deviceModelCommand); + + if (!result.IsSuccessStatusCode) + { + logger.LogError($"{deviceId} - Execute command on device failed \n{(int)result.StatusCode} - {result.ReasonPhrase}\n{await result.Content.ReadAsStringAsync()}"); + + throw new InternalServerErrorException($"Something went wrong when executing the command {deviceModelCommand.Name}."); + } + + logger.LogInformation($"{deviceId} - Execute command: \n{(int)result.StatusCode} - {result.ReasonPhrase}\n{await result.Content.ReadAsStringAsync()}"); + } + } +}