diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/EdgeModels/CreateEdgeModelsPageTest.cs b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/EdgeModels/CreateEdgeModelsPageTest.cs index fb3cdd6eb..af9dd9f86 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/EdgeModels/CreateEdgeModelsPageTest.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/EdgeModels/CreateEdgeModelsPageTest.cs @@ -100,7 +100,7 @@ public void WhenModulesRequiredFieldEmptyClickOnSaveShouldProssessValidationErro _ = this.mockSnackbarService .Setup(c => c.Add(It.IsAny(), Severity.Error, It.IsAny>())) - .Returns((Snackbar)null); + .Returns(value: null); // Act var cut = RenderComponent(); diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/DevicesControllerTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/DevicesControllerTests.cs index 9127fc2e3..735b41e1f 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/DevicesControllerTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/DevicesControllerTests.cs @@ -247,7 +247,7 @@ public async Task UpdateDeviceAsyncStateUnderTestExpectedBehavior() .ReturnsAsync(twin); _ = this.mockDeviceService.Setup(c => c.UpdateDevice(It.Is(x => x.Id == item.Id))) .ReturnsAsync(item); - _ = this.mockDeviceService.Setup(c => c.UpdateDeviceTwin(It.Is(x => x == device.DeviceID), It.Is(x => x.DeviceId == device.DeviceID))) + _ = this.mockDeviceService.Setup(c => c.UpdateDeviceTwin(It.Is(x => x.DeviceId == device.DeviceID))) .ReturnsAsync(twin); _ = this.mockDeviceTwinMapper.Setup(x => x.UpdateTwin(It.Is(x => x == twin), It.Is(x => x == device))); @@ -580,7 +580,6 @@ public async Task SetPropertiesShouldUpdateDesiredProperties() .ReturnsAsync(twin); _ = this.mockDeviceService.Setup(c => c.UpdateDeviceTwin( - It.Is(c => c == "aaa"), It.Is(c => c == twin))) .ReturnsAsync(twin); @@ -680,7 +679,6 @@ public async Task WhenPropertyNotWrittableSetPropertiesShouldNotUpdateDesiredPro .ReturnsAsync(twin); _ = this.mockDeviceService.Setup(c => c.UpdateDeviceTwin( - It.Is(c => c == "aaa"), It.Is(c => c == twin))) .ReturnsAsync(twin); @@ -741,7 +739,6 @@ public async Task WhenPropertyNotInModelSetPropertiesShouldNotUpdateDesiredPrope .ReturnsAsync(twin); _ = this.mockDeviceService.Setup(c => c.UpdateDeviceTwin( - It.Is(c => c == "aaa"), It.Is(c => c == twin))) .ReturnsAsync(twin); diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/EdgeDevicesControllerTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/EdgeDevicesControllerTests.cs index 1099cb15e..1c13c08f0 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/EdgeDevicesControllerTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/EdgeDevicesControllerTests.cs @@ -9,29 +9,25 @@ namespace AzureIoTHub.Portal.Tests.Unit.Server.Controllers.v1._0 using System.Threading.Tasks; using Models.v10; using AzureIoTHub.Portal.Server.Controllers.V10; - using AzureIoTHub.Portal.Server.Managers; using AzureIoTHub.Portal.Server.Services; using FluentAssertions; using Microsoft.AspNetCore.Mvc; - using Microsoft.AspNetCore.Mvc.Routing; - using Microsoft.Azure.Devices; - using Microsoft.Azure.Devices.Common.Exceptions; - using Microsoft.Azure.Devices.Shared; - using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; + using Microsoft.Azure.Devices.Shared; + using Microsoft.Azure.Devices; + using Microsoft.Azure.Devices.Common.Exceptions; + using AzureIoTHub.Portal.Server.Exceptions; [TestFixture] public class EdgeDevicesControllerTests { private MockRepository mockRepository; - private Mock mockProvisioningServiceManager; - private Mock mockConfiguration; private Mock> mockLogger; - private Mock mockRegistryManager; private Mock mockDeviceService; + private Mock mockEdgeDeviceService; private Mock mockUrlHelper; [SetUp] @@ -39,59 +35,52 @@ public void SetUp() { this.mockRepository = new MockRepository(MockBehavior.Strict); - this.mockProvisioningServiceManager = this.mockRepository.Create(); - this.mockConfiguration = this.mockRepository.Create(); this.mockLogger = this.mockRepository.Create>(); - this.mockRegistryManager = this.mockRepository.Create(); this.mockDeviceService = this.mockRepository.Create(); + this.mockEdgeDeviceService = this.mockRepository.Create(); this.mockUrlHelper = this.mockRepository.Create(); } private EdgeDevicesController CreateEdgeDevicesController() { return new EdgeDevicesController( - this.mockConfiguration.Object, this.mockLogger.Object, - this.mockRegistryManager.Object, this.mockDeviceService.Object, - this.mockProvisioningServiceManager.Object) + this.mockEdgeDeviceService.Object) { Url = this.mockUrlHelper.Object }; } [Test] - public async Task GetAllDevicesShouldReturnListOfEdgeDevices() + public async Task GetAllDeviceShouldReturnOkResult() { // Arrange - const int count = 100; - var paginationResultSimul = new PaginationResult - { - Items = Enumerable.Range(0, 100).Select(x => new Twin - { - DeviceId = FormattableString.Invariant($"{x}"), - }), - TotalItems = 1000, - NextPage = Guid.NewGuid().ToString() - - }; + var edgeDeviceController = CreateEdgeDevicesController(); - _ = this.mockDeviceService.Setup(x => x.GetAllEdgeDevice( - It.Is(x => x == "aaa"), - It.Is(x => x == "bbb"), - It.Is(x => x == true), - It.IsAny(), - It.Is(x => x == 2))) - .ReturnsAsync(paginationResultSimul); + var deviceTwinListPage = new PaginationResult(); - var edgeDevicesController = CreateEdgeDevicesController(); + _ = this.mockDeviceService + .Setup(x => x.GetAllEdgeDevice(It.Is(c => c.Equals("aaa", StringComparison.Ordinal)), + It.Is(c => c.Equals("bbb", StringComparison.Ordinal)), + It.Is(c => c.Equals(true)), It.IsAny(), It.IsAny())) + .ReturnsAsync(deviceTwinListPage); - _ = this.mockUrlHelper.Setup(c => c.RouteUrl(It.IsAny())) - .Returns(Guid.NewGuid().ToString()); + _ = this.mockEdgeDeviceService + .Setup(x => x.GetEdgeDevicesPage(deviceTwinListPage, It.IsAny(), + It.Is(c => c.Equals("bbb", StringComparison.Ordinal)), It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(new PaginationResult() + { + Items = Enumerable.Range(0, 10).Select(x => new IoTEdgeListItem() + { + DeviceId = FormattableString.Invariant($"{x}"), + }), + NextPage = Guid.NewGuid().ToString(), + TotalItems = 100 + }); // Act - var result = await edgeDevicesController.Get( - continuationToken: "aaa", + var result = await edgeDeviceController.Get(continuationToken: "aaa", searchText: "bbb", searchStatus: true, pageSize: 2); @@ -99,6 +88,7 @@ public async Task GetAllDevicesShouldReturnListOfEdgeDevices() // Assert Assert.IsNotNull(result); Assert.IsAssignableFrom(result); + var okObjectResult = result as ObjectResult; Assert.IsNotNull(okObjectResult); @@ -106,12 +96,11 @@ public async Task GetAllDevicesShouldReturnListOfEdgeDevices() Assert.IsNotNull(okObjectResult.Value); Assert.IsAssignableFrom>(okObjectResult.Value); + var paginationResult = okObjectResult.Value as PaginationResult; Assert.IsNotNull(paginationResult); - Assert.AreEqual(count, paginationResult.Items.Count()); - Assert.AreEqual(1000, paginationResult.TotalItems); - Assert.IsNotNull(paginationResult.NextPage); + Assert.AreEqual(10, paginationResult.Items.Count()); this.mockRepository.VerifyAll(); } @@ -120,44 +109,30 @@ public async Task GetAllDevicesShouldReturnListOfEdgeDevices() public async Task WhenSpecifyingIdGetShouldReturnTheEdgeDevice() { // Arrange - var edgeDevicesController = CreateEdgeDevicesController(); - var deviceId = Guid.NewGuid().ToString(); - - var twin = new Twin(deviceId); - twin.Tags[nameof(IoTEdgeDevice.Type)] = "bbb"; - twin.Tags["env"] = "fake"; - - _ = this.mockDeviceService.Setup(c => c.GetDeviceTwin(It.Is(x => x == deviceId))) - .ReturnsAsync(twin); - - _ = this.mockDeviceService.Setup(c => c.GetDeviceTwinWithModule(It.Is(x => x == deviceId))) - .ReturnsAsync(twin); - - var edgeHubTwin = new Twin("edgeHub"); - edgeHubTwin.Properties.Reported["clients"] = new[] - { - 1, 2 - }; + var edgeDeviceController = CreateEdgeDevicesController(); - var mockQuery = this.mockRepository.Create(); - _ = mockQuery.Setup(c => c.GetNextAsTwinAsync()) - .ReturnsAsync(new[] { edgeHubTwin }); + var deviceId = Guid.NewGuid().ToString(); - _ = this.mockRegistryManager.Setup(c => c.CreateQuery( - It.Is(x => x == $"SELECT * FROM devices.modules WHERE devices.modules.moduleId = '$edgeHub' AND deviceId in ['{deviceId}']"), - It.Is(x => x == 1))) - .Returns(mockQuery.Object); + _ = this.mockEdgeDeviceService + .Setup(x => x.GetEdgeDevice(It.IsAny())) + .ReturnsAsync(new IoTEdgeDevice() + { + DeviceId = deviceId, + }); // Act - var result = await edgeDevicesController.Get(deviceId); + var result = await edgeDeviceController.Get(deviceId); // Assert Assert.IsNotNull(result); Assert.IsAssignableFrom(result); + var okObjectResult = result as ObjectResult; Assert.IsAssignableFrom(okObjectResult.Value); + var iotEdge = okObjectResult.Value as IoTEdgeDevice; + Assert.IsNotNull(iotEdge); Assert.AreEqual(deviceId, iotEdge.DeviceId); @@ -165,17 +140,19 @@ public async Task WhenSpecifyingIdGetShouldReturnTheEdgeDevice() } [Test] - public async Task WhenNotFoundShouldReturnNotFound() + public async Task WhenDeviceDoesNotExistGetEdgeDeviceSpecifyingIdShouldThrowAnException() { // Arrange - var edgeDevicesController = CreateEdgeDevicesController(); + var edgeDeviceController = CreateEdgeDevicesController(); + var deviceId = Guid.NewGuid().ToString(); - _ = this.mockDeviceService.Setup(c => c.GetDeviceTwin(It.Is(x => x == deviceId))) - .Throws(new DeviceNotFoundException(deviceId)); + _ = this.mockEdgeDeviceService + .Setup(x => x.GetEdgeDevice(It.IsAny())) + .ThrowsAsync(new DeviceNotFoundException("")); // Act - var result = await edgeDevicesController.Get(deviceId); + var result = await edgeDeviceController.Get(deviceId); // Assert Assert.IsNotNull(result); @@ -185,173 +162,79 @@ public async Task WhenNotFoundShouldReturnNotFound() } [Test] - public async Task GetEnrollmentCredentialsShouldReturnEnrollmentCredentials() - { - // Arrange - var edgeDevicesController = CreateEdgeDevicesController(); - var mockRegistrationCredentials = new EnrollmentCredentials - { - RegistrationID = "aaa", - SymmetricKey = "dfhjkfdgh" - }; - - var mockTwin = new Twin("aaa"); - mockTwin.Tags["type"] = "bbb"; - - _ = this.mockProvisioningServiceManager.Setup(c => c.GetEnrollmentCredentialsAsync("aaa", "bbb")) - .ReturnsAsync(mockRegistrationCredentials); - - _ = this.mockDeviceService.Setup(c => c.GetDeviceTwin("aaa")) - .ReturnsAsync(mockTwin); - - // Act - var response = await edgeDevicesController.GetCredentials("aaa"); - - // Assert - Assert.IsNotNull(response); - Assert.IsAssignableFrom(response.Result); - - var okObjectResult = (OkObjectResult)response.Result; - Assert.IsNotNull(okObjectResult); - Assert.AreEqual(mockRegistrationCredentials, okObjectResult.Value); - - this.mockRepository.VerifyAll(); - } - - [Test] - public async Task WhenDeviceNotExistGetEnrollmentCredentialsShouldReturnNotFound() + public async Task CreateEdgeDeviceAsyncShouldReturnOk() { // Arrange - var devicesController = CreateEdgeDevicesController(); - - _ = this.mockDeviceService.Setup(c => c.GetDeviceTwin("aaa")) - .ReturnsAsync((Twin)null); - - // Act - var response = await devicesController.GetCredentials("aaa"); - - // Assert - Assert.IsNotNull(response); - Assert.IsAssignableFrom(response.Result); - - this.mockRepository.VerifyAll(); - } + var edgeDeviceController = CreateEdgeDevicesController(); - [Test] - public async Task CreateGatewayAsyncStateUnderTestExpectedBehavior() - { - // Arrange - var edgeDevicesController = CreateEdgeDevicesController(); - var gateway = new IoTEdgeDevice() - { - DeviceId = "aaa", - Type = "lora" - }; - var mockResult = new BulkRegistryOperationResult + var edgeDevice = new IoTEdgeDevice() { - IsSuccessful = true + DeviceId = Guid.NewGuid().ToString() }; - _ = this.mockDeviceService.Setup(c => c.CreateDeviceWithTwin( - It.Is(x => x == gateway.DeviceId), - It.Is(x => x), - It.Is(x => x.DeviceId == gateway.DeviceId), - It.Is(x => x == DeviceStatus.Enabled))) - .ReturnsAsync(mockResult); - - _ = this.mockLogger.Setup(x => x.Log(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>())); + _ = this.mockEdgeDeviceService + .Setup(x => x.CreateEdgeDevice(It.Is(c => c.DeviceId.Equals(edgeDevice.DeviceId, StringComparison.Ordinal)))) + .ReturnsAsync(new BulkRegistryOperationResult() { IsSuccessful = true }); // Act - var result = await edgeDevicesController.CreateGatewayAsync(gateway); + var result = await edgeDeviceController.CreateEdgeDeviceAsync(edgeDevice); // Assert Assert.IsNotNull(result); Assert.IsAssignableFrom(result); + var okObjectResult = result as ObjectResult; + Assert.IsNotNull(okObjectResult); Assert.AreEqual(200, okObjectResult.StatusCode); + Assert.IsNotNull(okObjectResult.Value); Assert.IsAssignableFrom(okObjectResult.Value); - Assert.AreEqual(mockResult, okObjectResult.Value); - } - [Test] - public async Task WhenDeviceAlreadyExistsPostShouldReturnBadRequest() - { - // Arrange - var edgeDevicesController = CreateEdgeDevicesController(); - var gateway = new IoTEdgeDevice() - { - DeviceId = "aaa", - Type = "lora" - }; + var bulkOperationResult = okObjectResult.Value as BulkRegistryOperationResult; + Assert.IsNotNull(bulkOperationResult); + Assert.AreEqual(true, bulkOperationResult.IsSuccessful); - _ = this.mockDeviceService.Setup(c => c.CreateDeviceWithTwin( - It.Is(x => x == gateway.DeviceId), - It.Is(x => x), - It.Is(x => x.DeviceId == gateway.DeviceId), - It.Is(x => x == DeviceStatus.Enabled))) - .Throws(new DeviceAlreadyExistsException(gateway.DeviceId)); - - _ = this.mockLogger.Setup(x => x.Log(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>())); - - // Act - var result = await edgeDevicesController.CreateGatewayAsync(gateway); - - // Assert - Assert.IsNotNull(result); - Assert.IsAssignableFrom(result); + this.mockRepository.VerifyAll(); } [Test] - public async Task UpdateDeviceAsyncStateUnderTestExpectedBehavior() + public async Task UpdateDeviceAsyncShouldReturnOkResult() { // Arrange - var edgeDevicesController = CreateEdgeDevicesController(); - var gateway = new IoTEdgeDevice() + var edgeDeviceController = CreateEdgeDevicesController(); + + var edgeDevice = new IoTEdgeDevice() { - DeviceId = "aaa", - Type = "lora", - Environment = "prod", - Status = nameof(DeviceStatus.Enabled) + DeviceId = Guid.NewGuid().ToString(), + Environment = "fake" }; - var mockTwin = new Twin(gateway.DeviceId); - mockTwin.Tags["env"] = "dev"; - - _ = this.mockDeviceService.Setup(c => c.GetDevice(It.Is(x => x == gateway.DeviceId))) - .ReturnsAsync(new Device(gateway.DeviceId) - { - Status = DeviceStatus.Disabled - }); - - _ = this.mockDeviceService.Setup(c => c.UpdateDevice(It.Is(x => x.Id == gateway.DeviceId && x.Status == DeviceStatus.Enabled))) - .ReturnsAsync(new Device(gateway.DeviceId) - { - Status = DeviceStatus.Enabled - }); - - _ = this.mockDeviceService.Setup(c => c.GetDeviceTwin(It.Is(x => x == gateway.DeviceId))) - .ReturnsAsync(mockTwin); - - _ = this.mockDeviceService.Setup(c => c.UpdateDeviceTwin(It.Is(x => x == gateway.DeviceId), It.Is(x => x == mockTwin))) - .ReturnsAsync(mockTwin); + var deviceTwin = new Twin(edgeDevice.DeviceId); + deviceTwin.Tags["env"] = "dev"; - _ = this.mockLogger.Setup(x => x.Log(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>())); + _ = this.mockEdgeDeviceService + .Setup(x => x.UpdateEdgeDevice(It.Is(c => c.DeviceId.Equals(edgeDevice.DeviceId, StringComparison.Ordinal)))) + .ReturnsAsync(deviceTwin); // Act - var result = await edgeDevicesController.UpdateDeviceAsync(gateway.DeviceId, gateway); + var result = await edgeDeviceController.UpdateDeviceAsync(edgeDevice); // Assert Assert.IsNotNull(result); Assert.IsAssignableFrom(result); + var okObjectResult = result as ObjectResult; + Assert.IsNotNull(okObjectResult); Assert.AreEqual(200, okObjectResult.StatusCode); + Assert.IsNotNull(okObjectResult.Value); + Assert.IsAssignableFrom(okObjectResult.Value); - Assert.AreEqual(mockTwin, okObjectResult.Value); - Assert.AreEqual("prod", mockTwin.Tags["env"].ToString()); + Assert.AreEqual(deviceTwin, okObjectResult.Value); + + this.mockRepository.VerifyAll(); } [Test] @@ -381,46 +264,6 @@ public async Task DeleteDeviceAsyncStateUnderTestExpectedBehavior() this.mockRepository.VerifyAll(); } - [TestCase("RestartModule", /*lang=json,strict*/ "{\"id\":\"aaa\",\"schemaVersion\":null}")] - public async Task ExecuteMethodShouldExecuteC2DMethod(string methodName, string expected) - { - // Arrange - var edgeDevicesController = CreateEdgeDevicesController(); - var module = new IoTEdgeModule - { - ModuleName = "aaa", - }; - - var deviceId = Guid.NewGuid().ToString(); - - _ = 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.ExecuteC2DMethod( - It.Is(x => x == deviceId), - It.Is(x => - x.MethodName == methodName - && x.GetPayloadAsJson() == expected - ))) - .ReturnsAsync(new CloudToDeviceMethodResult - { - Status = 200 - }); - - // Act - _ = await edgeDevicesController.ExecuteModuleMethod( - module, - deviceId, - methodName); - - // Assert - this.mockRepository.VerifyAll(); - } - [Test] public async Task GetEdgeDeviceLogsMustReturnLogsWhenNoErrorIsReturned() { @@ -476,5 +319,88 @@ public async Task GetEdgeDeviceLogsThrowsArgumentNullExceptionWhenModelIsNull() // Assert _ = await act.Should().ThrowAsync(); } + + [Test] + public async Task GetEnrollmentCredentialsShouldReturnEnrollmentCredentials() + { + // Arrange + var edgeDevicesController = CreateEdgeDevicesController(); + + var deviceId = Guid.NewGuid().ToString(); + + _ = this.mockEdgeDeviceService + .Setup(x => x.GetEdgeDeviceCredentials(It.Is(c => c.Equals(deviceId, StringComparison.Ordinal)))) + .ReturnsAsync(new EnrollmentCredentials()); + + // Act + var result = await edgeDevicesController.GetCredentials(deviceId); + + // Assert + Assert.IsNotNull(result); + + var okObjectResult = result.Result as ObjectResult; + + Assert.IsNotNull(okObjectResult); + Assert.AreEqual(200, okObjectResult.StatusCode); + + Assert.IsNotNull(okObjectResult.Value); + Assert.IsAssignableFrom(okObjectResult.Value); + + this.mockRepository.VerifyAll(); + } + + [Test] + public async Task WhenDeviceDoesNotExistGetEnrollmentCredentialsShouldThrowAnException() + { + // Arrange + var edgeDevicesController = CreateEdgeDevicesController(); + + var deviceId = Guid.NewGuid().ToString(); + + _ = this.mockEdgeDeviceService + .Setup(x => x.GetEdgeDeviceCredentials(It.Is(c => c.Equals(deviceId, StringComparison.Ordinal)))) + .ThrowsAsync(new ResourceNotFoundException("")); + + // Act + var result = await edgeDevicesController.GetCredentials(deviceId); + + // Assert + Assert.IsNotNull(result); + + var objectResult = result.Result as ObjectResult; + + Assert.IsNotNull(objectResult); + Assert.AreEqual(404, objectResult.StatusCode); + + this.mockRepository.VerifyAll(); + } + + [TestCase("RestartModule")] + public async Task ExecuteMethodShouldExecuteC2DMethod(string methodName) + { + // Arrange + var edgeDeviceController = CreateEdgeDevicesController(); + + var module = new IoTEdgeModule + { + ModuleName = "aaa", + }; + + var deviceId = Guid.NewGuid().ToString(); + + _ = this.mockEdgeDeviceService + .Setup(x => x.ExecuteModuleMethod(It.IsAny(), + It.Is(c => c.Equals(deviceId, StringComparison.Ordinal)), + It.Is(c => c.Equals(methodName, StringComparison.Ordinal)))) + .ReturnsAsync(new C2Dresult()); + + // Act + var result = await edgeDeviceController.ExecuteModuleMethod(module, deviceId, methodName); + + // Assert + Assert.IsNotNull(result); + + this.mockRepository.VerifyAll(); + } } } diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/LoRaWAN/LoRaWANConcentratorsControllerTest.cs b/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/LoRaWAN/LoRaWANConcentratorsControllerTest.cs index e1d1d9c7b..0acfb3d96 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/LoRaWAN/LoRaWANConcentratorsControllerTest.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/LoRaWAN/LoRaWANConcentratorsControllerTest.cs @@ -364,7 +364,7 @@ public async Task UpdateDeviceAsyncWithValidArgumentShouldReturnOkResult() .ReturnsAsync(device); _ = this.mockDeviceService.Setup(x => x.GetDeviceTwin(It.Is(c => c == concentrator.DeviceId))) .ReturnsAsync(twin); - _ = this.mockDeviceService.Setup(x => x.UpdateDeviceTwin(It.Is(c => c == concentrator.DeviceId), It.Is(c => c.DeviceId == concentrator.DeviceId))) + _ = this.mockDeviceService.Setup(x => x.UpdateDeviceTwin(It.Is(c => c.DeviceId == concentrator.DeviceId))) .ReturnsAsync(twin); // Act @@ -463,7 +463,7 @@ public async Task WhenUpdateDeviceTwinThrowAnErrorUpdateDeviceAsyncWithValidArgu .ReturnsAsync(device); _ = this.mockDeviceService.Setup(x => x.GetDeviceTwin(It.Is(c => c == concentrator.DeviceId))) .ReturnsAsync(twin); - _ = this.mockDeviceService.Setup(x => x.UpdateDeviceTwin(It.Is(c => c == concentrator.DeviceId), It.Is(c => c.DeviceId == concentrator.DeviceId))) + _ = this.mockDeviceService.Setup(x => x.UpdateDeviceTwin(It.Is(c => c.DeviceId == concentrator.DeviceId))) .ThrowsAsync(new InternalServerErrorException("")); // Act 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 7cb6ce908..caa85df67 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 @@ -453,7 +453,7 @@ public async Task UpdateDeviceAsyncStateUnderTestExpectedBehavior() .ReturnsAsync(twin); _ = this.mockDeviceService.Setup(c => c.UpdateDevice(It.Is(x => x.Id == item.Id))) .ReturnsAsync(item); - _ = this.mockDeviceService.Setup(c => c.UpdateDeviceTwin(It.Is(x => x == device.DeviceID), It.Is(x => x.DeviceId == device.DeviceID))) + _ = this.mockDeviceService.Setup(c => c.UpdateDeviceTwin(It.Is(x => x.DeviceId == device.DeviceID))) .ReturnsAsync(twin); _ = this.mockDeviceTwinMapper.Setup(x => x.UpdateTwin(It.Is(x => x == twin), It.Is(x => x == device))); diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Server/Mappers/EdgeDeviceMapperTest.cs b/src/AzureIoTHub.Portal.Tests.Unit/Server/Mappers/EdgeDeviceMapperTest.cs new file mode 100644 index 000000000..28770f396 --- /dev/null +++ b/src/AzureIoTHub.Portal.Tests.Unit/Server/Mappers/EdgeDeviceMapperTest.cs @@ -0,0 +1,83 @@ +// 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.Mappers +{ + using System; + using System.Collections.Generic; + using AzureIoTHub.Portal.Models.v10; + using AzureIoTHub.Portal.Server.Mappers; + using Microsoft.Azure.Devices.Shared; + using Newtonsoft.Json; + using NUnit.Framework; + + [TestFixture] + public class EdgeDeviceMapperTest + { + + [Test] + public void CreateEdgeDeviceListItemShouldReturnValue() + { + // Arrange + var edgeDeviceMapper = new EdgeDeviceMapper(); + + var deviceTwin = new Twin(Guid.NewGuid().ToString()); + deviceTwin.Tags["type"] = "lora"; + deviceTwin.Properties.Reported["clients"] = new object[12]; + + // Act + var result = edgeDeviceMapper.CreateEdgeDeviceListItem(deviceTwin); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual("lora", result.Type); + Assert.AreEqual(12, result.NbDevices); + } + + [Test] + public void CreateEdgeDeviceShouldReturnValue() + { + // Arrange + var edgeDeviceMapper = new EdgeDeviceMapper(); + + var deviceId = Guid.NewGuid().ToString(); + + var deviceTwin = new Twin(deviceId); + deviceTwin.Tags["type"] = "fake"; + deviceTwin.Tags["env"] = "fake"; + + var deviceTwinWithModules = new Twin(deviceId); + var reportedProperties = new Dictionary() + { + { + "systemModules", new Dictionary() + { + { + "edgeAgent", new Dictionary() + { + { + "runtimeStatus", "running" + } + } + } + } + } + }; + + deviceTwinWithModules.Properties.Desired["modules"] = new object[2]; + deviceTwinWithModules.Properties.Reported = new TwinCollection(JsonConvert.SerializeObject(reportedProperties)); + + var lastDeployment = new ConfigItem(); + + // Act + var result = edgeDeviceMapper.CreateEdgeDevice(deviceTwin, deviceTwinWithModules, 5, lastDeployment); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(deviceTwin.DeviceId, result.DeviceId); + Assert.AreEqual(5, result.NbDevices); + Assert.AreEqual("running", result.RuntimeResponse); + Assert.AreEqual("fake", result.Type); + } + } +} diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/DeviceServiceTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/DeviceServiceTests.cs index 61c848f46..433833ecf 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/DeviceServiceTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/DeviceServiceTests.cs @@ -951,7 +951,7 @@ public async Task UpdateDeviceTwinStateUnderTestExpectedBehavior() var service = CreateService(); var deviceId = Guid.NewGuid().ToString(); - var twin = new Twin() + var twin = new Twin(deviceId) { ETag = Guid.NewGuid().ToString(), }; @@ -963,7 +963,7 @@ public async Task UpdateDeviceTwinStateUnderTestExpectedBehavior() .ReturnsAsync(new Twin()); // Act - var result = await service.UpdateDeviceTwin(deviceId, twin); + var result = await service.UpdateDeviceTwin(twin); // Assert Assert.IsNotNull(result); @@ -978,7 +978,7 @@ public async Task UpdateDeviceTwinShouldThrowInternalServerErrorExceptionWhenIss var service = CreateService(); var deviceId = Guid.NewGuid().ToString(); - var twin = new Twin() + var twin = new Twin(deviceId) { ETag = Guid.NewGuid().ToString(), }; @@ -990,7 +990,7 @@ public async Task UpdateDeviceTwinShouldThrowInternalServerErrorExceptionWhenIss .ThrowsAsync(new Exception("test")); // Act - var act = () => service.UpdateDeviceTwin(deviceId, twin); + var act = () => service.UpdateDeviceTwin(twin); // Assert _ = await act.Should().ThrowAsync(); diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/EdgeDeviceServiceTest.cs b/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/EdgeDeviceServiceTest.cs new file mode 100644 index 000000000..a3a0625cd --- /dev/null +++ b/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/EdgeDeviceServiceTest.cs @@ -0,0 +1,360 @@ +// 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.Linq; + using System; + using AzureIoTHub.Portal.Server.Managers; + using AzureIoTHub.Portal.Server.Mappers; + using AzureIoTHub.Portal.Server.Services; + using Microsoft.Azure.Devices; + using Microsoft.Azure.Devices.Shared; + using Moq; + using NUnit.Framework; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Routing; + using AzureIoTHub.Portal.Models.v10; + using System.Threading.Tasks; + using System.Collections.Generic; + using AzureIoTHub.Portal.Server.Exceptions; + + [TestFixture] + public class EdgeDeviceServiceTest + { + private MockRepository mockRepository; + + private Mock mockRegistryManager; + private Mock mockEdgeDeviceMapper; + private Mock mockDeviceService; + private Mock mockProvisioningServiceManager; + + [SetUp] + public void SetUp() + { + this.mockRepository = new MockRepository(MockBehavior.Strict); + + this.mockProvisioningServiceManager = this.mockRepository.Create(); + this.mockRegistryManager = this.mockRepository.Create(); + this.mockDeviceService = this.mockRepository.Create(); + this.mockEdgeDeviceMapper = this.mockRepository.Create(); + } + + private EdgeDevicesService CreateEdgeDeviceService() + { + return new EdgeDevicesService( + this.mockRegistryManager.Object, + this.mockDeviceService.Object, + this.mockEdgeDeviceMapper.Object, + this.mockProvisioningServiceManager.Object); + } + + [Test] + public void GetEdgeDevicesPageShouldReturnList() + { + // Arrange + var edgeDeviceService = CreateEdgeDeviceService(); + + const int count = 100; + var paginationResultSimul = new PaginationResult + { + Items = Enumerable.Range(0, 100).Select(x => new Twin + { + DeviceId = FormattableString.Invariant($"{x}"), + }), + TotalItems = 1000, + NextPage = Guid.NewGuid().ToString() + + }; + + _ = this.mockEdgeDeviceMapper + .Setup(x => x.CreateEdgeDeviceListItem(It.IsAny())) + .Returns(new IoTEdgeListItem()); + + var mockUrlHelper = this.mockRepository.Create(); + _ = mockUrlHelper.Setup(x => x.RouteUrl(It.IsAny())) + .Returns(Guid.NewGuid().ToString()); + + // Act + var result = edgeDeviceService.GetEdgeDevicesPage(paginationResultSimul, + mockUrlHelper.Object, + searchText: "bbb", + searchStatus: true, + pageSize: 2); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(count, result.Items.Count()); + Assert.AreEqual(1000, result.TotalItems); + Assert.IsNotNull(result.NextPage); + + this.mockRepository.VerifyAll(); + } + + [Test] + public async Task GetEdgeDeviceShouldReturnValue() + { + // Arrange + var edgeDeviceService = CreateEdgeDeviceService(); + + var expectedDevice = new IoTEdgeDevice() + { + DeviceId = Guid.NewGuid().ToString(), + Status = DeviceStatus.Enabled.ToString(), + NbDevices = 2, + NbModules = 1, + LastDeployment = new ConfigItem(), + Modules = new List() + { + new IoTEdgeModule() + } + }; + + _ = this.mockDeviceService + .Setup(x => x.GetDeviceTwin(It.Is(c => c.Equals(expectedDevice.DeviceId, StringComparison.Ordinal)))) + .ReturnsAsync(new Twin(expectedDevice.DeviceId)); + + _ = this.mockDeviceService + .Setup(x => x.GetDeviceTwinWithModule(It.Is(c => c.Equals(expectedDevice.DeviceId, StringComparison.Ordinal)))) + .ReturnsAsync(new Twin(expectedDevice.DeviceId)); + + var edgeHubTwin = new Twin("edgeHub"); + edgeHubTwin.Properties.Reported["clients"] = new[] + { + 1, 2 + }; + + var mockQuery = this.mockRepository.Create(); + _ = mockQuery.Setup(c => c.GetNextAsTwinAsync()) + .ReturnsAsync(new[] { edgeHubTwin }); + + _ = this.mockRegistryManager.Setup(c => c.CreateQuery( + It.Is(x => x == $"SELECT * FROM devices.modules WHERE devices.modules.moduleId = '$edgeHub' AND deviceId in ['{expectedDevice.DeviceId}']"), + It.Is(x => x == 1))) + .Returns(mockQuery.Object); + + _ = this.mockEdgeDeviceMapper + .Setup(x => x.CreateEdgeDevice(It.Is(c => c.DeviceId.Equals(expectedDevice.DeviceId, StringComparison.Ordinal)), + It.Is(c => c.DeviceId.Equals(expectedDevice.DeviceId, StringComparison.Ordinal)), + It.Is(c => c.Equals(2)), It.IsAny())) + .Returns(expectedDevice); + + // Act + var result = await edgeDeviceService.GetEdgeDevice(expectedDevice.DeviceId); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(expectedDevice, result); + + this.mockRepository.VerifyAll(); + } + + [Test] + public void WhenDeviceTwinIsNullGetEdgeDeviceShouldResourceNotFoundException() + { + // Arrange + var edgeDeviceService = CreateEdgeDeviceService(); + + var deviceId = Guid.NewGuid().ToString(); + + _ = this.mockDeviceService + .Setup(x => x.GetDeviceTwin(It.Is(c => c.Equals(deviceId, StringComparison.Ordinal)))) + .ReturnsAsync(value: null); + + // Act + _ = Assert.ThrowsAsync(() => edgeDeviceService.GetEdgeDevice(deviceId)); + + this.mockRepository.VerifyAll(); + } + + [Test] + public async Task CreateEdgeDeviceShouldReturnvalue() + { + // Arrange + var edgeDeviceService = CreateEdgeDeviceService(); + + var mockResult = new BulkRegistryOperationResult + { + IsSuccessful = true + }; + + var edgeDevice = new IoTEdgeDevice() + { + DeviceId = "aaa", + Type = "lora", + Environment = "test" + }; + + _ = this.mockDeviceService.Setup(c => c.CreateDeviceWithTwin( + It.Is(x => x == edgeDevice.DeviceId), + It.Is(x => x), + It.Is(x => x.DeviceId == edgeDevice.DeviceId), + It.Is(x => x == DeviceStatus.Enabled))) + .ReturnsAsync(mockResult); + + // Act + var result = await edgeDeviceService.CreateEdgeDevice(edgeDevice); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(mockResult.IsSuccessful, result.IsSuccessful); + + this.mockRepository.VerifyAll(); + } + + [Test] + public void WhenEdgeDeviceIsNullCreateEdgeDeviceShouldThrowArgumentNullException() + { + // Arrange + var edgeDeviceService = CreateEdgeDeviceService(); + + // Act + + // Assert + _ = Assert.ThrowsAsync(() => edgeDeviceService.CreateEdgeDevice(null)); + } + + [Test] + public async Task UpdateEdgeDeviceShouldReturnUpdatedTwin() + { + // Arrange + var edgeDeviceService = CreateEdgeDeviceService(); + + var edgeDevice = new IoTEdgeDevice() + { + DeviceId = Guid.NewGuid().ToString(), + Status = DeviceStatus.Enabled.ToString(), + Environment = "fake" + }; + + var mockTwin = new Twin(edgeDevice.DeviceId); + mockTwin.Tags["env"] = "dev"; + + _ = this.mockDeviceService + .Setup(x => x.GetDevice(It.Is(c => c.Equals(edgeDevice.DeviceId, StringComparison.Ordinal)))) + .ReturnsAsync(new Device(edgeDevice.DeviceId)); + + _ = this.mockDeviceService + .Setup(x => x.UpdateDevice(It.Is(c => c.Id.Equals(edgeDevice.DeviceId, StringComparison.Ordinal)))) + .ReturnsAsync(new Device(edgeDevice.DeviceId)); + + _ = this.mockDeviceService + .Setup(x => x.GetDeviceTwin(It.Is(c => c.Equals(edgeDevice.DeviceId, StringComparison.Ordinal)))) + .ReturnsAsync(mockTwin); + + _ = this.mockDeviceService + .Setup(x => x.UpdateDeviceTwin(It.Is(c => c.DeviceId.Equals(edgeDevice.DeviceId, StringComparison.Ordinal)))) + .ReturnsAsync(mockTwin); + + // Act + var result = await edgeDeviceService.UpdateEdgeDevice(edgeDevice); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(edgeDevice.Environment, mockTwin.Tags["env"].ToString()); + + this.mockRepository.VerifyAll(); + } + + [Test] + public void WhenEdgeDeviceIsNullUpdateEdgeDeviceShouldThrowArgumentNullException() + { + // Arrange + var edgeDeviceService = CreateEdgeDeviceService(); + + // Assert + _ = Assert.ThrowsAsync(() => edgeDeviceService.UpdateEdgeDevice(null)); + } + + [TestCase("RestartModule", /*lang=json,strict*/ "{\"id\":\"aaa\",\"schemaVersion\":null}")] + public async Task ExecuteMethodShouldExecuteC2DMethod(string methodName, string expected) + { + // Arrange + var edgeDeviceService = CreateEdgeDeviceService(); + + var edgeModule = new IoTEdgeModule + { + ModuleName = "aaa", + }; + + var deviceId = Guid.NewGuid().ToString(); + + _ = this.mockDeviceService.Setup(c => c.ExecuteC2DMethod( + It.Is(x => x == deviceId), + It.Is(x => + x.MethodName == methodName + && x.GetPayloadAsJson() == expected + ))) + .ReturnsAsync(new CloudToDeviceMethodResult + { + Status = 200 + }); + + // Act + _ = await edgeDeviceService.ExecuteModuleMethod(edgeModule, deviceId, methodName); + + // Assert + this.mockRepository.VerifyAll(); + } + + [TestCase("RestartModule")] + public void WhenEdgeModuleIsNullExecuteMethodShouldThrowArgumentNullException(string methodName) + { + // Arrange + var edgeDeviceService = CreateEdgeDeviceService(); + + var deviceId = Guid.NewGuid().ToString(); + + // Assert + _ = Assert.ThrowsAsync(() => edgeDeviceService.ExecuteModuleMethod(null, deviceId, methodName)); + } + + [Test] + public async Task GetEdgeDeviceCredentialsShouldReturnEnrollmentCredentials() + { + // Arrange + var edgeDeviceService = CreateEdgeDeviceService(); + + var mockRegistrationCredentials = new EnrollmentCredentials + { + RegistrationID = "aaa", + SymmetricKey = "dfhjkfdgh" + }; + + var mockTwin = new Twin("aaa"); + mockTwin.Tags["type"] = "bbb"; + + _ = this.mockProvisioningServiceManager.Setup(c => c.GetEnrollmentCredentialsAsync("aaa", "bbb")) + .ReturnsAsync(mockRegistrationCredentials); + + _ = this.mockDeviceService.Setup(c => c.GetDeviceTwin("aaa")) + .ReturnsAsync(mockTwin); + + // Act + var result = await edgeDeviceService.GetEdgeDeviceCredentials("aaa"); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(mockRegistrationCredentials, result); + + this.mockRepository.VerifyAll(); + } + + [Test] + public void WhenDeviceTwinIsNullGetEdgeDeviceCredentialsShouldThrowResourceNotFoundException() + { + // Arrange + var edgeDeviceService = CreateEdgeDeviceService(); + + _ = this.mockDeviceService.Setup(c => c.GetDeviceTwin("aaa")) + .ReturnsAsync(value: null); + + // Act + + // Assert + _ = Assert.ThrowsAsync(() => edgeDeviceService.GetEdgeDeviceCredentials("aaa")); + + this.mockRepository.VerifyAll(); + } + } +} diff --git a/src/AzureIoTHub.Portal/Client/Pages/EdgeDevices/EdgeDeviceDetailPage.razor b/src/AzureIoTHub.Portal/Client/Pages/EdgeDevices/EdgeDeviceDetailPage.razor index 16a4ba078..6285be8a7 100644 --- a/src/AzureIoTHub.Portal/Client/Pages/EdgeDevices/EdgeDeviceDetailPage.razor +++ b/src/AzureIoTHub.Portal/Client/Pages/EdgeDevices/EdgeDeviceDetailPage.razor @@ -14,13 +14,13 @@ Edge Device Details - + - @Gateway.DeviceId + @edgeDevice.DeviceId @@ -43,10 +43,10 @@ - + - + @@ -56,7 +56,7 @@ Status - + Enabled The device can connect to the platform. @@ -72,7 +72,7 @@ Runtime response - @if (Gateway.RuntimeResponse == "running") + @if (edgeDevice.RuntimeResponse == "running") { @@ -88,10 +88,10 @@ } - + - + @@ -103,16 +103,16 @@ Last deployment - @if (Gateway.LastDeployment != null){ + @if (edgeDevice.LastDeployment != null){ - + - + - + } @@ -125,7 +125,7 @@ Modules - + @@ -168,13 +168,13 @@ private bool btn_disable = false; private void Return() => NavigationManager.NavigateTo("edge/devices"); - private IoTEdgeDevice Gateway; + private IoTEdgeDevice edgeDevice; private bool isProcessing; protected override async Task OnInitializedAsync() { - Gateway = new IoTEdgeDevice(); + edgeDevice = new IoTEdgeDevice(); await LoadDevice(); } @@ -184,9 +184,9 @@ { isProcessing = true; - Gateway = await EdgeDeviceClientService.GetDevice(deviceId); + edgeDevice = await EdgeDeviceClientService.GetDevice(deviceId); - if (Gateway.ConnectionState == "Disconnected") + if (edgeDevice.ConnectionState == "Disconnected") { btn_disable = true; } @@ -207,9 +207,9 @@ try { - await EdgeDeviceClientService.UpdateDevice(Gateway); + await EdgeDeviceClientService.UpdateDevice(edgeDevice); - Snackbar.Add($"Device {Gateway.DeviceId} has been successfully updated!", Severity.Success); + Snackbar.Add($"Device {edgeDevice.DeviceId} has been successfully updated!", Severity.Success); } catch (ProblemDetailsException exception) { @@ -227,9 +227,9 @@ try { - //var result = await Http.PostAsJsonAsync($"api/edge/devices/{Gateway.DeviceId}/{module.ModuleName}/{methodName}", module); + //var result = await Http.PostAsJsonAsync($"api/edge/devices/{edgeDevice.DeviceId}/{module.ModuleName}/{methodName}", module); - var c2dResult = await EdgeDeviceClientService.ExecuteModuleMethod(Gateway.DeviceId, module, methodName); + var c2dResult = await EdgeDeviceClientService.ExecuteModuleMethod(edgeDevice.DeviceId, module, methodName); if (c2dResult.Status == 200) { @@ -277,7 +277,7 @@ { isProcessing = true; - var parameter = new DialogParameters {{nameof(Gateway.DeviceId), Gateway.DeviceId}}; + var parameter = new DialogParameters {{nameof(edgeDevice.DeviceId), edgeDevice.DeviceId}}; var result = await DialogService.Show("Edge device deletion confirmation", parameter).Result; diff --git a/src/AzureIoTHub.Portal/Server/Controllers/v1.0/DevicesController.cs b/src/AzureIoTHub.Portal/Server/Controllers/v1.0/DevicesController.cs index 8467addfd..7f3e03ed9 100644 --- a/src/AzureIoTHub.Portal/Server/Controllers/v1.0/DevicesController.cs +++ b/src/AzureIoTHub.Portal/Server/Controllers/v1.0/DevicesController.cs @@ -243,7 +243,7 @@ public async Task>> SetProperties( device.Properties.Desired = DeviceHelper.PropertiesWithDotNotationToTwinCollection(desiredProperties); - _ = await this.devicesService.UpdateDeviceTwin(deviceID, device); + _ = await this.devicesService.UpdateDeviceTwin(device); return Ok(); } diff --git a/src/AzureIoTHub.Portal/Server/Controllers/v1.0/DevicesControllerBase.cs b/src/AzureIoTHub.Portal/Server/Controllers/v1.0/DevicesControllerBase.cs index e98263372..2760b2df3 100644 --- a/src/AzureIoTHub.Portal/Server/Controllers/v1.0/DevicesControllerBase.cs +++ b/src/AzureIoTHub.Portal/Server/Controllers/v1.0/DevicesControllerBase.cs @@ -205,7 +205,7 @@ public virtual async Task UpdateDeviceAsync(TModel device) // Update the twin properties this.deviceTwinMapper.UpdateTwin(currentTwin, device); - _ = await this.devicesService.UpdateDeviceTwin(device.DeviceID, currentTwin); + _ = await this.devicesService.UpdateDeviceTwin(currentTwin); return Ok(); } diff --git a/src/AzureIoTHub.Portal/Server/Controllers/v1.0/EdgeDevicesController.cs b/src/AzureIoTHub.Portal/Server/Controllers/v1.0/EdgeDevicesController.cs index 517271f1a..4c6588c3c 100644 --- a/src/AzureIoTHub.Portal/Server/Controllers/v1.0/EdgeDevicesController.cs +++ b/src/AzureIoTHub.Portal/Server/Controllers/v1.0/EdgeDevicesController.cs @@ -5,23 +5,15 @@ namespace AzureIoTHub.Portal.Server.Controllers.V10 { using System; using System.Collections.Generic; - using System.Linq; using System.Threading.Tasks; using AzureIoTHub.Portal.Models.v10; - using AzureIoTHub.Portal.Server.Helpers; - using AzureIoTHub.Portal.Server.Managers; + using AzureIoTHub.Portal.Server.Exceptions; using AzureIoTHub.Portal.Server.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; - using Microsoft.AspNetCore.Mvc.Routing; - using Microsoft.Azure.Devices; using Microsoft.Azure.Devices.Common.Exceptions; - using Microsoft.Azure.Devices.Shared; - using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; - using Newtonsoft.Json; - using Newtonsoft.Json.Linq; [Authorize] [ApiController] @@ -35,46 +27,30 @@ public class EdgeDevicesController : ControllerBase /// private readonly ILogger logger; - /// - /// The device registry manager. - /// - private readonly RegistryManager registryManager; - - /// - /// The device iconfiguration. - /// - private readonly IConfiguration configuration; - /// /// The device idevice service. /// private readonly IDeviceService devicesService; /// - /// The device provisioning srevice manager. + /// The edge device service. /// - private readonly IDeviceProvisioningServiceManager deviceProvisioningServiceManager; + private readonly IEdgeDevicesService edgeDevicesService; /// /// Initializes a new instance of the class. /// - /// The configuration. /// The logger. - /// The registry manager. - /// The service. - /// The device provisioning service manager. + /// The device service. + /// The edge deviceservice. public EdgeDevicesController( - IConfiguration configuration, ILogger logger, - RegistryManager registryManager, IDeviceService service, - IDeviceProvisioningServiceManager deviceProvisioningServiceManager) + IEdgeDevicesService edgeDevicesService) { + this.edgeDevicesService = edgeDevicesService; this.logger = logger; - this.registryManager = registryManager; - this.configuration = configuration; this.devicesService = service; - this.deviceProvisioningServiceManager = deviceProvisioningServiceManager; } /// @@ -94,50 +70,15 @@ public async Task Get( string searchType = null, int pageSize = 10) { - var result = await this.devicesService.GetAllEdgeDevice( + var edgeDevicesTwin = await this.devicesService.GetAllEdgeDevice( continuationToken: continuationToken, searchText: searchText, searchStatus: searchStatus, searchType: searchType, pageSize: pageSize); - var newGatewayList = new List(); - - foreach (var deviceTwin in result.Items) - { - newGatewayList.Add(new IoTEdgeListItem - { - DeviceId = deviceTwin.DeviceId, - Status = deviceTwin.Status?.ToString(), - Type = DeviceHelper.RetrieveTagValue(deviceTwin, nameof(IoTEdgeDevice.Type)) ?? "Undefined", - NbDevices = DeviceHelper.RetrieveConnectedDeviceCount(deviceTwin) - }); - } - - var nextPage = string.Empty; - - if (!string.IsNullOrEmpty(result.NextPage)) - { - nextPage = Url.RouteUrl(new UrlRouteContext - { - RouteName = "GET IoT Edge devices", - Values = new - { - continuationToken = result.NextPage, - searchText, - searchType, - searchStatus, - pageSize - } - }); - } - - return Ok(new PaginationResult - { - Items = newGatewayList, - TotalItems = result.TotalItems, - NextPage = nextPage - }); + return Ok(this.edgeDevicesService.GetEdgeDevicesPage( + edgeDevicesTwin, Url, searchText, searchStatus, searchType, pageSize)); } /// @@ -150,29 +91,7 @@ public async Task Get(string deviceId) { try { - var deviceTwin = await this.devicesService.GetDeviceTwin(deviceId); - var deviceWithModules = await this.devicesService.GetDeviceTwinWithModule(deviceId); - - var gateway = new IoTEdgeDevice() - { - DeviceId = deviceTwin.DeviceId, - Status = deviceTwin.Status?.ToString(), - Scope = deviceTwin.DeviceScope, - ConnectionState = deviceTwin.ConnectionState?.ToString(), - // We retrieve the values of tags - Type = DeviceHelper.RetrieveTagValue(deviceTwin, nameof(IoTEdgeDevice.Type)) ?? "Undefined", - Environment = DeviceHelper.RetrieveTagValue(deviceTwin, "env"), - // We retrieve the number of connected device - NbDevices = await RetrieveNbConnectedDevice(deviceTwin.DeviceId), - // récupération des informations sur le modules de la gateways² - NbModules = DeviceHelper.RetrieveNbModuleCount(deviceWithModules, deviceId), - RuntimeResponse = DeviceHelper.RetrieveRuntimeResponse(deviceWithModules), - Modules = DeviceHelper.RetrieveModuleList(deviceWithModules), - // recup du dernier deployment - LastDeployment = await RetrieveLastConfiguration(deviceWithModules) - }; - - return Ok(gateway); + return Ok(await this.edgeDevicesService.GetEdgeDevice(deviceId)); } catch (DeviceNotFoundException e) { @@ -180,84 +99,27 @@ public async Task Get(string deviceId) } } - /// - /// Gets the IoT Edge device enrollement credentials. - /// - /// The device identifier. - [HttpGet("{deviceId}/credentials", Name = "GET Device enrollment credentials")] - [ProducesResponseType(StatusCodes.Status200OK)] - public async Task> GetCredentials(string deviceId) - { - var deviceTwin = await this.devicesService.GetDeviceTwin(deviceId); - - if (deviceTwin == null) - { - return NotFound($"IoT Edge {deviceId} doesn't exist."); - } - - var deviceType = DeviceHelper.RetrieveTagValue(deviceTwin, nameof(IoTEdgeDevice.Type)); - - var credentials = await this.deviceProvisioningServiceManager.GetEnrollmentCredentialsAsync(deviceId, deviceType); - - return Ok(credentials); - } - /// /// Creates the IoT Edge device. /// - /// The IoT Edge device. + /// The IoT Edge device. [HttpPost(Name = "POST Create IoT Edge")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] - public async Task CreateGatewayAsync(IoTEdgeDevice gateway) + public async Task CreateEdgeDeviceAsync(IoTEdgeDevice edgeDevice) { - ArgumentNullException.ThrowIfNull(gateway, nameof(gateway)); - - try - { - var deviceTwin = new Twin(gateway.DeviceId); - - deviceTwin.Tags["env"] = gateway.Environment; - deviceTwin.Tags["type"] = gateway.Type; - - var result = await this.devicesService.CreateDeviceWithTwin(gateway.DeviceId, true, deviceTwin, DeviceStatus.Enabled); - this.logger.LogInformation($"Created edge device {gateway.DeviceId}"); - - return Ok(result); - } - catch (DeviceAlreadyExistsException e) - { - this.logger.LogInformation(e.Message); - return StatusCode(StatusCodes.Status400BadRequest, e.Message); - } + return Ok(await this.edgeDevicesService.CreateEdgeDevice(edgeDevice)); } /// /// Updates the device. /// - /// - /// The IoT Edge device. + /// The IoT Edge device. [HttpPut("{deviceId}", Name = "PUT Update IoT Edge")] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task UpdateDeviceAsync(string deviceId, IoTEdgeDevice gateway) + public async Task UpdateDeviceAsync(IoTEdgeDevice edgeDevice) { - ArgumentNullException.ThrowIfNull(gateway, nameof(gateway)); - - var device = await this.devicesService.GetDevice(deviceId); - - if (Enum.TryParse(gateway.Status, out DeviceStatus status)) - { - device.Status = status; - } - - device = await this.devicesService.UpdateDevice(device); - - var deviceTwin = await this.devicesService.GetDeviceTwin(gateway.DeviceId); - deviceTwin.Tags["env"] = gateway.Environment; - deviceTwin = await this.devicesService.UpdateDeviceTwin(gateway.DeviceId, deviceTwin); - - this.logger.LogInformation($"iot hub device was updated {device.Id}"); - return Ok(deviceTwin); + return Ok(await this.edgeDevicesService.UpdateEdgeDevice(edgeDevice)); } /// @@ -275,38 +137,33 @@ public async Task DeleteDeviceAsync(string deviceId) } /// - /// Executes the module method on the IoT Edge device. + /// Gets the IoT Edge device enrollement credentials. /// - /// The module. /// The device identifier. - /// Name of the method. - [HttpPost("{deviceId}/{moduleId}/{methodName}", Name = "POST Execute module command")] - public async Task ExecuteModuleMethod(IoTEdgeModule module, string deviceId, string methodName) + [HttpGet("{deviceId}/credentials", Name = "GET Device enrollment credentials")] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task> GetCredentials(string deviceId) { - ArgumentNullException.ThrowIfNull(module, nameof(module)); - - var method = new CloudToDeviceMethod(methodName); - var payload = string.Empty; - - if (methodName == "RestartModule") + try { - payload = JsonConvert.SerializeObject(new - { - id = module.ModuleName, - schemaVersion = module.Version - }); + return Ok(await this.edgeDevicesService.GetEdgeDeviceCredentials(deviceId)); } - - _ = method.SetPayloadJson(payload); - - var result = await this.devicesService.ExecuteC2DMethod(deviceId, method); - this.logger.LogInformation($"iot hub device : {deviceId} module : {module.ModuleName} execute methode {methodName}."); - - return new C2Dresult() + catch (ResourceNotFoundException e) { - Payload = result.GetPayloadAsJson(), - Status = result.Status - }; + return NotFound(e); + } + } + + /// + /// Executes the module method on the IoT Edge device. + /// + /// The edge module. + /// The device identifier. + /// Name of the method. + [HttpPost("{deviceId}/{moduleId}/{methodName}", Name = "POST Execute module command")] + public async Task ExecuteModuleMethod(IoTEdgeModule edgeModule, string deviceId, string methodName) + { + return await this.edgeDevicesService.ExecuteModuleMethod(edgeModule, deviceId, methodName); } /// @@ -322,48 +179,5 @@ public async Task> GetEdgeDeviceLogs(string device return await this.devicesService.GetEdgeDeviceLogs(deviceId, edgeModule); } - - /// - /// Retrieves the connected devices number on the IoT Edge. - /// - /// The device identifier. - private async Task RetrieveNbConnectedDevice(string deviceId) - { - var query = this.registryManager.CreateQuery($"SELECT * FROM devices.modules WHERE devices.modules.moduleId = '$edgeHub' AND deviceId in ['{deviceId}']", 1); - var deviceWithClient = (await query.GetNextAsTwinAsync()).SingleOrDefault(); - var reportedProperties = JObject.Parse(deviceWithClient.Properties.Reported.ToJson()); - - if (reportedProperties.TryGetValue("clients", out var clients)) - { - return clients.Count(); - } - - return 0; - } - - /// - /// Retrieves the last configuration of the IoT Edge. - /// - /// The twin. - private async Task RetrieveLastConfiguration(Twin twin) - { - var item = new ConfigItem(); - - if (twin.Configurations?.Count > 0) - { - foreach (var config in twin.Configurations) - { - var confObj = await this.registryManager.GetConfigurationAsync(config.Key); - if (item.DateCreation < confObj.CreatedTimeUtc && config.Value.Status == ConfigurationStatus.Applied) - { - item.Name = config.Key; - item.DateCreation = confObj.CreatedTimeUtc; - item.Status = nameof(ConfigurationStatus.Applied); - } - } - return item; - } - return null; - } } } diff --git a/src/AzureIoTHub.Portal/Server/Controllers/v1.0/LoRaWAN/LoRaWANConcentratorsController.cs b/src/AzureIoTHub.Portal/Server/Controllers/v1.0/LoRaWAN/LoRaWANConcentratorsController.cs index 034d5f983..8df280def 100644 --- a/src/AzureIoTHub.Portal/Server/Controllers/v1.0/LoRaWAN/LoRaWANConcentratorsController.cs +++ b/src/AzureIoTHub.Portal/Server/Controllers/v1.0/LoRaWAN/LoRaWANConcentratorsController.cs @@ -192,7 +192,7 @@ public async Task UpdateDeviceAsync(Concentrator device) // Update the twin properties this.concentratorTwinMapper.UpdateTwin(currentTwin, device); - _ = await this.devicesService.UpdateDeviceTwin(device.DeviceId, currentTwin); + _ = await this.devicesService.UpdateDeviceTwin(currentTwin); return Ok("Device updated."); } diff --git a/src/AzureIoTHub.Portal/Server/Mappers/EdgeDeviceMapper.cs b/src/AzureIoTHub.Portal/Server/Mappers/EdgeDeviceMapper.cs new file mode 100644 index 000000000..f6ccd036c --- /dev/null +++ b/src/AzureIoTHub.Portal/Server/Mappers/EdgeDeviceMapper.cs @@ -0,0 +1,50 @@ +// 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.Mappers +{ + using AzureIoTHub.Portal.Models.v10; + using AzureIoTHub.Portal.Server.Helpers; + using Microsoft.Azure.Devices.Shared; + + public class EdgeDeviceMapper : IEdgeDeviceMapper + { + + public IoTEdgeListItem CreateEdgeDeviceListItem(Twin deviceTwin) + { + return new IoTEdgeListItem() + { + DeviceId = deviceTwin?.DeviceId, + Status = deviceTwin?.Status.ToString(), + Type = DeviceHelper.RetrieveTagValue(deviceTwin, nameof(IoTEdgeDevice.Type)) ?? "Undefined", + NbDevices = DeviceHelper.RetrieveConnectedDeviceCount(deviceTwin) + }; + } + + /// + /// + /// + /// + /// + /// + /// + /// + public IoTEdgeDevice CreateEdgeDevice(Twin deviceTwin, Twin deviceTwinWithModules, int nbConnectedDevice, ConfigItem lastConfiguration) + { + return new IoTEdgeDevice() + { + DeviceId = deviceTwin?.DeviceId, + Status = deviceTwin?.Status?.ToString(), + Scope = deviceTwin?.DeviceScope, + ConnectionState = deviceTwin?.ConnectionState?.ToString(), + Type = DeviceHelper.RetrieveTagValue(deviceTwin, nameof(IoTEdgeDevice.Type)) ?? "Undefined", + Environment = DeviceHelper.RetrieveTagValue(deviceTwin, "env"), + NbDevices = nbConnectedDevice, + NbModules = DeviceHelper.RetrieveNbModuleCount(deviceTwinWithModules, deviceTwin?.DeviceId), + RuntimeResponse = DeviceHelper.RetrieveRuntimeResponse(deviceTwinWithModules), + Modules = DeviceHelper.RetrieveModuleList(deviceTwinWithModules), + LastDeployment = lastConfiguration + }; + } + } +} diff --git a/src/AzureIoTHub.Portal/Server/Mappers/EdgeModelMapper.cs b/src/AzureIoTHub.Portal/Server/Mappers/EdgeModelMapper.cs index 92e5066bc..4ef2819dc 100644 --- a/src/AzureIoTHub.Portal/Server/Mappers/EdgeModelMapper.cs +++ b/src/AzureIoTHub.Portal/Server/Mappers/EdgeModelMapper.cs @@ -18,6 +18,11 @@ public EdgeModelMapper(IDeviceModelImageManager deviceModelImageManager) this.deviceModelImageManager = deviceModelImageManager; } + /// + /// Create IoT edge model list item. + /// + /// Table entity. + /// IoTEdgeModelListItem. public IoTEdgeModelListItem CreateEdgeDeviceModelListItem(TableEntity entity) { ArgumentNullException.ThrowIfNull(entity, nameof(entity)); diff --git a/src/AzureIoTHub.Portal/Server/Mappers/IEdgeDeviceMapper.cs b/src/AzureIoTHub.Portal/Server/Mappers/IEdgeDeviceMapper.cs new file mode 100644 index 000000000..43de09851 --- /dev/null +++ b/src/AzureIoTHub.Portal/Server/Mappers/IEdgeDeviceMapper.cs @@ -0,0 +1,15 @@ +// 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.Mappers +{ + using AzureIoTHub.Portal.Models.v10; + using Microsoft.Azure.Devices.Shared; + + public interface IEdgeDeviceMapper + { + IoTEdgeListItem CreateEdgeDeviceListItem(Twin deviceTwin); + + IoTEdgeDevice CreateEdgeDevice(Twin deviceTwin, Twin deviceTwinWithModules, int nbConnectedDevice, ConfigItem lastConfiguration); + } +} diff --git a/src/AzureIoTHub.Portal/Server/Services/DeviceService.cs b/src/AzureIoTHub.Portal/Server/Services/DeviceService.cs index 671330567..b145d8d4b 100644 --- a/src/AzureIoTHub.Portal/Server/Services/DeviceService.cs +++ b/src/AzureIoTHub.Portal/Server/Services/DeviceService.cs @@ -369,20 +369,19 @@ public async Task UpdateDevice(Device device) /// /// This function update the twin of the device. /// - /// the device id. /// the new twin. /// the updated twin. - public async Task UpdateDeviceTwin(string deviceId, Twin twin) + public async Task UpdateDeviceTwin(Twin twin) { ArgumentNullException.ThrowIfNull(twin, nameof(twin)); try { - return await this.registryManager.UpdateTwinAsync(deviceId, twin, twin.ETag); + return await this.registryManager.UpdateTwinAsync(twin.DeviceId, twin, twin.ETag); } catch (Exception e) { - throw new InternalServerErrorException($"Unable to update the device twin with id {deviceId}", e); + throw new InternalServerErrorException($"Unable to update the device twin with id {twin.DeviceId}", e); } } diff --git a/src/AzureIoTHub.Portal/Server/Services/EdgeDevicesService.cs b/src/AzureIoTHub.Portal/Server/Services/EdgeDevicesService.cs new file mode 100644 index 000000000..0ce655429 --- /dev/null +++ b/src/AzureIoTHub.Portal/Server/Services/EdgeDevicesService.cs @@ -0,0 +1,249 @@ +// 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 AzureIoTHub.Portal.Models.v10; + using System.Threading.Tasks; + using AzureIoTHub.Portal.Server.Managers; + using Microsoft.Azure.Devices; + using System.Collections.Generic; + using AzureIoTHub.Portal.Server.Mappers; + using Microsoft.Azure.Devices.Shared; + using Newtonsoft.Json.Linq; + using System.Linq; + using System; + using Newtonsoft.Json; + using AzureIoTHub.Portal.Server.Helpers; + using AzureIoTHub.Portal.Server.Exceptions; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Routing; + + public class EdgeDevicesService : IEdgeDevicesService + { + /// + /// The device registry manager. + /// + private readonly RegistryManager registryManager; + + /// + /// The device idevice service. + /// + private readonly IDeviceService devicesService; + + /// + /// The edge device mapper. + /// + private readonly IEdgeDeviceMapper edgeDeviceMapper; + + /// + /// The device provisioning srevice manager. + /// + private readonly IDeviceProvisioningServiceManager deviceProvisioningServiceManager; + + public EdgeDevicesService(RegistryManager registryManager, IDeviceService devicesService, + IEdgeDeviceMapper edgeDeviceMapper, + IDeviceProvisioningServiceManager deviceProvisioningServiceManager) + { + this.registryManager = registryManager; + this.devicesService = devicesService; + this.edgeDeviceMapper = edgeDeviceMapper; + this.deviceProvisioningServiceManager = deviceProvisioningServiceManager; + } + + public PaginationResult GetEdgeDevicesPage(PaginationResult edgeDevicesTwin, + IUrlHelper urlHelper, + string searchText = null, + bool? searchStatus = null, + string searchType = null, + int pageSize = 10) + { + var newEdgeDevicesList = new List(); + + foreach (var deviceTwin in edgeDevicesTwin.Items) + { + newEdgeDevicesList.Add(this.edgeDeviceMapper.CreateEdgeDeviceListItem(deviceTwin)); + } + + var nextPage = string.Empty; + + if (!string.IsNullOrEmpty(edgeDevicesTwin.NextPage)) + { + nextPage = urlHelper.RouteUrl(new UrlRouteContext + { + RouteName = "GET IoT Edge devices", + Values = new + { + continuationToken = edgeDevicesTwin.NextPage, + searchText, + searchType, + searchStatus, + pageSize + } + }); + } + + return new PaginationResult + { + Items = newEdgeDevicesList, + TotalItems = edgeDevicesTwin.TotalItems, + NextPage = nextPage + }; + } + + /// + /// Get edge device with its modules. + /// + /// device id. + /// IoTEdgeDevice object. + public async Task GetEdgeDevice(string edgeDeviceId) + { + var deviceTwin = await this.devicesService.GetDeviceTwin(edgeDeviceId); + + if (deviceTwin is null) + { + throw new ResourceNotFoundException($"Device {edgeDeviceId} not found."); + } + + var deviceTwinWithModules = await this.devicesService.GetDeviceTwinWithModule(edgeDeviceId); + + var edgeDeviceLastConfiguration = await RetrieveLastConfiguration(deviceTwinWithModules); + var edgeDeviceNbConnectedDevice = await RetrieveNbConnectedDevice(edgeDeviceId); + + return this.edgeDeviceMapper.CreateEdgeDevice(deviceTwin, deviceTwinWithModules, edgeDeviceNbConnectedDevice, edgeDeviceLastConfiguration); + } + + /// + /// Create a new edge device. + /// + /// the new edge device. + /// the result of the operation. + public async Task CreateEdgeDevice(IoTEdgeDevice edgeDevice) + { + ArgumentNullException.ThrowIfNull(edgeDevice, nameof(edgeDevice)); + + var deviceTwin = new Twin(edgeDevice.DeviceId); + + deviceTwin.Tags["env"] = edgeDevice.Environment; + deviceTwin.Tags["type"] = edgeDevice.Type; + + return await this.devicesService.CreateDeviceWithTwin(edgeDevice.DeviceId, true, deviceTwin, DeviceStatus.Enabled); + } + + /// + /// Update the edge device ant the twin. + /// + /// edge device object update. + /// device twin updated. + public async Task UpdateEdgeDevice(IoTEdgeDevice edgeDevice) + { + ArgumentNullException.ThrowIfNull(edgeDevice, nameof(edgeDevice)); + + var device = await this.devicesService.GetDevice(edgeDevice.DeviceId); + + if (Enum.TryParse(edgeDevice.Status, out DeviceStatus status)) + { + device.Status = status; + } + + _ = await this.devicesService.UpdateDevice(device); + + var deviceTwin = await this.devicesService.GetDeviceTwin(edgeDevice.DeviceId); + deviceTwin.Tags["env"] = edgeDevice.Environment; + + return await this.devicesService.UpdateDeviceTwin(deviceTwin); + } + + /// + /// Executes the module method on the IoT Edge device. + /// + /// + /// + /// + /// + public async Task ExecuteModuleMethod(IoTEdgeModule edgeModule, string deviceId, string methodName) + { + ArgumentNullException.ThrowIfNull(edgeModule, nameof(edgeModule)); + + var method = new CloudToDeviceMethod(methodName); + var payload = string.Empty; + + if (methodName == "RestartModule") + { + payload = JsonConvert.SerializeObject(new + { + id = edgeModule.ModuleName, + schemaVersion = edgeModule.Version + }); + } + + _ = method.SetPayloadJson(payload); + + var result = await this.devicesService.ExecuteC2DMethod(deviceId, method); + + return new C2Dresult() + { + Payload = result.GetPayloadAsJson(), + Status = result.Status + }; + } + + /// + /// Gets the IoT Edge device enrollement credentials. + /// + /// the edge device id. + /// Enrollment credentials. + /// + public async Task GetEdgeDeviceCredentials(string edgeDeviceId) + { + var deviceTwin = await this.devicesService.GetDeviceTwin(edgeDeviceId); + + if (deviceTwin == null) + { + throw new ResourceNotFoundException($"IoT Edge {edgeDeviceId} doesn't exist."); + } + + var deviceType = DeviceHelper.RetrieveTagValue(deviceTwin, nameof(IoTEdgeDevice.Type)); + + return await this.deviceProvisioningServiceManager.GetEnrollmentCredentialsAsync(edgeDeviceId, deviceType); + } + + /// + /// Retrieves the connected devices number on the IoT Edge. + /// + /// The device identifier. + private async Task RetrieveNbConnectedDevice(string deviceId) + { + var query = this.registryManager.CreateQuery($"SELECT * FROM devices.modules WHERE devices.modules.moduleId = '$edgeHub' AND deviceId in ['{deviceId}']", 1); + var deviceWithClient = (await query.GetNextAsTwinAsync()).SingleOrDefault(); + var reportedProperties = JObject.Parse(deviceWithClient.Properties.Reported.ToJson()); + + return reportedProperties.TryGetValue("clients", out var clients) ? clients.Count() : 0; + } + + /// + /// Retrieves the last configuration of the IoT Edge. + /// + /// The twin. + private async Task RetrieveLastConfiguration(Twin twin) + { + var item = new ConfigItem(); + + if (twin.Configurations?.Count > 0) + { + foreach (var config in twin.Configurations) + { + var confObj = await this.registryManager.GetConfigurationAsync(config.Key); + if (item.DateCreation < confObj.CreatedTimeUtc && config.Value.Status == ConfigurationStatus.Applied) + { + item.Name = config.Key; + item.DateCreation = confObj.CreatedTimeUtc; + item.Status = nameof(ConfigurationStatus.Applied); + } + } + return item; + } + return null; + } + } +} diff --git a/src/AzureIoTHub.Portal/Server/Services/EdgeModelService.cs b/src/AzureIoTHub.Portal/Server/Services/EdgeModelService.cs index ecd00be01..d05e2fa99 100644 --- a/src/AzureIoTHub.Portal/Server/Services/EdgeModelService.cs +++ b/src/AzureIoTHub.Portal/Server/Services/EdgeModelService.cs @@ -54,6 +54,11 @@ public EdgeModelService(IConfigService configService, this.deviceModelImageManager = deviceModelImageManager; } + /// + /// Return the edge model template list. + /// + /// IEnumerable IoTEdgeModelListItem. + /// public IEnumerable GetEdgeModels() { try @@ -69,6 +74,13 @@ public IEnumerable GetEdgeModels() } } + /// + /// Get the edge model template and it's configuration by the edge model id. + /// + /// The model identifier. + /// An edge model object. + /// Resource not found if template does not exist. + /// Internal server error exception. public async Task GetEdgeModel(string modelId) { try @@ -92,6 +104,14 @@ public async Task GetEdgeModel(string modelId) } } + /// + /// Create a new edge model template and roll out + /// the edge model configuration. + /// + /// the new edge modle object. + /// nothing. + /// If edge model template already exist return ResourceAlreadyExistsException. + /// public async Task CreateEdgeModel(IoTEdgeModel edgeModel) { if (!string.IsNullOrEmpty(edgeModel?.ModelId)) @@ -122,6 +142,13 @@ public async Task CreateEdgeModel(IoTEdgeModel edgeModel) await SaveEntity(entity, edgeModel); } + /// + /// Update the edge model template and the configuration. + /// + /// The edge model. + /// nothing. + /// + /// public async Task UpdateEdgeModel(IoTEdgeModel edgeModel) { if (string.IsNullOrEmpty(edgeModel?.ModelId)) @@ -147,6 +174,12 @@ public async Task UpdateEdgeModel(IoTEdgeModel edgeModel) } } + /// + /// Delete edge model template and it's configuration. + /// + /// The edge model indentifier. + /// + /// public async Task DeleteEdgeModel(string edgeModelId) { try @@ -168,6 +201,13 @@ public async Task DeleteEdgeModel(string edgeModelId) } } + /// + /// Get the edge model avatar. + /// + /// The edge model indentifier. + /// + /// + /// public async Task GetEdgeModelAvatar(string edgeModelId) { try @@ -189,6 +229,14 @@ public async Task GetEdgeModelAvatar(string edgeModelId) } } + /// + /// Update the edge model avatar. + /// + /// The edge model indentifier + /// The image. + /// + /// + /// public async Task UpdateEdgeModelAvatar(string edgeModelId, IFormFile file) { try @@ -210,6 +258,13 @@ public async Task UpdateEdgeModelAvatar(string edgeModelId, IFormFile fi } } + /// + /// Delete the edge model avatar. + /// + /// The edge model indentifier + /// + /// + /// public async Task DeleteEdgeModelAvatar(string edgeModelId) { try @@ -232,7 +287,7 @@ public async Task DeleteEdgeModelAvatar(string edgeModelId) } /// - /// Saves the entity. + /// Saves the entity and roll out the configuration. /// /// The entity. /// The device model object. diff --git a/src/AzureIoTHub.Portal/Server/Services/IDeviceService.cs b/src/AzureIoTHub.Portal/Server/Services/IDeviceService.cs index 31faf035b..2d748613a 100644 --- a/src/AzureIoTHub.Portal/Server/Services/IDeviceService.cs +++ b/src/AzureIoTHub.Portal/Server/Services/IDeviceService.cs @@ -21,7 +21,7 @@ public interface IDeviceService Task UpdateDevice(Device device); - Task UpdateDeviceTwin(string deviceId, Twin twin); + Task UpdateDeviceTwin(Twin twin); Task ExecuteC2DMethod(string deviceId, CloudToDeviceMethod method); diff --git a/src/AzureIoTHub.Portal/Server/Services/IEdgeDevicesService.cs b/src/AzureIoTHub.Portal/Server/Services/IEdgeDevicesService.cs new file mode 100644 index 000000000..16222e921 --- /dev/null +++ b/src/AzureIoTHub.Portal/Server/Services/IEdgeDevicesService.cs @@ -0,0 +1,31 @@ +// 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; + using AzureIoTHub.Portal.Models.v10; + using Microsoft.AspNetCore.Mvc; + using Microsoft.Azure.Devices; + using Microsoft.Azure.Devices.Shared; + + public interface IEdgeDevicesService + { + PaginationResult GetEdgeDevicesPage(PaginationResult edgeDevicesTwin, + IUrlHelper urlHelper, + string searchText = null, + bool? searchStatus = null, + string searchType = null, + int pageSize = 10); + + Task GetEdgeDevice(string edgeDeviceId); + + Task CreateEdgeDevice(IoTEdgeDevice edgeDevice); + + Task UpdateEdgeDevice(IoTEdgeDevice edgeDevice); + + Task ExecuteModuleMethod(IoTEdgeModule edgeModule, string deviceId, string methodName); + + Task GetEdgeDeviceCredentials(string edgeDeviceId); + } +} diff --git a/src/AzureIoTHub.Portal/Server/Startup.cs b/src/AzureIoTHub.Portal/Server/Startup.cs index 4d587a7bb..93ab512cb 100644 --- a/src/AzureIoTHub.Portal/Server/Startup.cs +++ b/src/AzureIoTHub.Portal/Server/Startup.cs @@ -123,11 +123,13 @@ public void ConfigureServices(IServiceCollection services) _ = services.AddTransient, LoRaDeviceModelMapper>(); _ = services.AddTransient(); _ = services.AddTransient(); + _ = services.AddTransient(); _ = services.AddTransient(); _ = services.AddTransient(); _ = services.AddTransient(); _ = services.AddTransient(); + _ = services.AddTransient(); _ = services.AddMudServices(); diff --git a/src/AzureIoTHub.Portal/Shared/Models/v1.0/IoTEdgeModule.cs b/src/AzureIoTHub.Portal/Shared/Models/v1.0/IoTEdgeModule.cs index 94d03412b..1c226709e 100644 --- a/src/AzureIoTHub.Portal/Shared/Models/v1.0/IoTEdgeModule.cs +++ b/src/AzureIoTHub.Portal/Shared/Models/v1.0/IoTEdgeModule.cs @@ -23,6 +23,9 @@ public class IoTEdgeModule /// public string Version { get; set; } + /// + /// the device image URI. + /// [Required(ErrorMessage = "The device image uri is required.")] public string ImageURI { get; set; }