diff --git a/src/AzureIoTHub.Portal.Infrastructure/Services/AWS/AWSExternalDeviceService.cs b/src/AzureIoTHub.Portal.Infrastructure/Services/AWS/AWSExternalDeviceService.cs index f6a67d76e..59d69df36 100644 --- a/src/AzureIoTHub.Portal.Infrastructure/Services/AWS/AWSExternalDeviceService.cs +++ b/src/AzureIoTHub.Portal.Infrastructure/Services/AWS/AWSExternalDeviceService.cs @@ -69,6 +69,35 @@ public async Task UpdateDevice(UpdateThingRequest device) public async Task DeleteDevice(DeleteThingRequest device) { + //Retreive all thing princpals and detach it before deleting the thing + var principals = await this.amazonIotClient.ListThingPrincipalsAsync(new ListThingPrincipalsRequest + { + NextToken = string.Empty, + ThingName = device.ThingName + }); + + if (principals.HttpStatusCode != System.Net.HttpStatusCode.OK) + { + throw new InternalServerErrorException($"Unable to retreive Thing {device.ThingName} principals due to an error in the Amazon IoT API : {principals.HttpStatusCode}"); + + } + + foreach (var principal in principals.Principals) + { + var detachPrincipal = await this.amazonIotClient.DetachThingPrincipalAsync(new DetachThingPrincipalRequest + { + Principal = principal, + ThingName = device.ThingName + }); + + if (detachPrincipal.HttpStatusCode != System.Net.HttpStatusCode.OK) + { + throw new InternalServerErrorException($"Unable to detach Thing {device.ThingName} principal due to an error in the Amazon IoT API : {detachPrincipal.HttpStatusCode}"); + + } + } + + //Delete the thing type before detaching the princiapl var deleteResponse = await this.amazonIotClient.DeleteThingAsync(device); if (deleteResponse.HttpStatusCode != System.Net.HttpStatusCode.OK) diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Services/AWSExternalDeviceServiceTest.cs b/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Services/AWSExternalDeviceServiceTest.cs index b83e9dfbd..1dbc33daa 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Services/AWSExternalDeviceServiceTest.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Services/AWSExternalDeviceServiceTest.cs @@ -3,6 +3,7 @@ namespace AzureIoTHub.Portal.Tests.Unit.Infrastructure.Services { + using System.Collections.Generic; using System.Net; using System.Threading; using System.Threading.Tasks; @@ -253,6 +254,19 @@ public async Task DeleteDeviceShouldReturnAValue() HttpStatusCode = HttpStatusCode.OK }; + _ = this.mockAmazonIotClient.Setup(iotClient => iotClient.ListThingPrincipalsAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new ListThingPrincipalsResponse + { + HttpStatusCode = HttpStatusCode.OK, + Principals = Fixture.Create>() + }); + + _ = this.mockAmazonIotClient.Setup(iotClient => iotClient.DetachThingPrincipalAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new DetachThingPrincipalResponse + { + HttpStatusCode = HttpStatusCode.OK + }); + _ = this.mockAmazonIotClient.Setup(iotClient => iotClient.DeleteThingAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(expected); @@ -272,9 +286,8 @@ public Task DeleteDeviceShouldThrowInternalServerErrorIfHttpStatusCodeIsNotOK() { ThingName = Fixture.Create(), }; - - _ = this.mockAmazonIotClient.Setup(iotClient => iotClient.DeleteThingAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(new DeleteThingResponse + _ = this.mockAmazonIotClient.Setup(iotClient => iotClient.ListThingPrincipalsAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new ListThingPrincipalsResponse { HttpStatusCode = HttpStatusCode.BadRequest }); diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Services/AwsExternalDeviceServiceTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Services/AwsExternalDeviceServiceTests.cs index 7f6570623..418ab9550 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Services/AwsExternalDeviceServiceTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Infrastructure/Services/AwsExternalDeviceServiceTests.cs @@ -4,6 +4,7 @@ namespace AzureIoTHub.Portal.Tests.Unit.Infrastructure.Services { using System; + using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Amazon.GreengrassV2; @@ -11,6 +12,7 @@ namespace AzureIoTHub.Portal.Tests.Unit.Infrastructure.Services using Amazon.IoT; using Amazon.IoT.Model; using Amazon.SecretsManager; + using Amazon.SecretsManager.Model; using AutoFixture; using AutoMapper; using AzureIoTHub.Portal.Application.Services; @@ -378,6 +380,19 @@ public async Task UpdateDeviceShouldThrowNotImplementedException() _ = await act.Should().ThrowAsync(); } + [Test] + public async Task CreateEdgeDeviceShouldThrowNotImplementedException() + { + // Arrange + var deviceId = Fixture.Create(); + + // Act + var act = () => this.externalDeviceService.CreateEdgeDevice(deviceId); + + // Assert + _ = await act.Should().ThrowAsync(); + } + [Test] public async Task UpdateDeviceTwinShouldThrowNotImplementedException() { @@ -387,5 +402,149 @@ public async Task UpdateDeviceTwinShouldThrowNotImplementedException() // Assert _ = await act.Should().ThrowAsync(); } + + [Test] + public async Task GetEdgeDeviceCredentialsShouldReturnExisitingDeviceCredentials() + { + // Arrange + var device = Fixture.Create(); + + _ = this.mockSecretsManager.Setup(c => c.GetSecretValueAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new GetSecretValueResponse()); + + // Act + var result = this.externalDeviceService.GetEdgeDeviceCredentials(device); + + // Assert + _ = result.Should().NotBeNull(); + + } + + [Test] + public async Task GetEdgeDeviceCredentialsShouldCreateAndReturnDeviceCredentials() + { + // Arrange + var device = Fixture.Create(); + + _ = this.mockSecretsManager.Setup(c => c.GetSecretValueAsync(It.IsAny(), It.IsAny())) + .ThrowsAsync(new Amazon.SecretsManager.Model.ResourceNotFoundException("Resource Not found")); + + + _ = this.mockAmazonIot.Setup(c => c.AttachPolicyAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new AttachPolicyResponse()); + + _ = this.mockAmazonIot.Setup(c => c.CreateKeysAndCertificateAsync(true, It.IsAny())) + .ReturnsAsync(new CreateKeysAndCertificateResponse()); + + _ = this.mockAmazonIot.Setup(c => c.AttachThingPrincipalAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new AttachThingPrincipalResponse()); + + _ = this.mockSecretsManager.Setup(c => c.CreateSecretAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new CreateSecretResponse()); + + // Act + var result = this.externalDeviceService.GetEdgeDeviceCredentials(device); + + // Assert + _ = result.Should().NotBeNull(); + + } + + [Test] + public async Task GetDeviceCredentialsShouldReturnExisitingDeviceCredentials() + { + // Arrange + var deviceName = Fixture.Create(); + + _ = this.mockSecretsManager.Setup(c => c.GetSecretValueAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new GetSecretValueResponse()); + + // Act + var result = this.externalDeviceService.GetDeviceCredentials(deviceName); + + // Assert + _ = result.Should().NotBeNull(); + + } + + [Test] + public async Task GetDeviceCredentialsShouldCreateAndReturnDeviceCredentials() + { + // Arrange + var deviceName = Fixture.Create(); + + _ = this.mockSecretsManager.Setup(c => c.GetSecretValueAsync(It.IsAny(), It.IsAny())) + .ThrowsAsync(new Amazon.SecretsManager.Model.ResourceNotFoundException("Resource Not found")); + + + _ = this.mockAmazonIot.Setup(c => c.AttachPolicyAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new AttachPolicyResponse()); + + _ = this.mockAmazonIot.Setup(c => c.CreateKeysAndCertificateAsync(true, It.IsAny())) + .ReturnsAsync(new CreateKeysAndCertificateResponse()); + + _ = this.mockAmazonIot.Setup(c => c.AttachThingPrincipalAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new AttachThingPrincipalResponse()); + + _ = this.mockSecretsManager.Setup(c => c.CreateSecretAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new CreateSecretResponse()); + + // Act + var result = this.externalDeviceService.GetDeviceCredentials(deviceName); + + // Assert + _ = result.Should().NotBeNull(); + } + + [Test] + public async Task RetriveEdgeDeviceLastDeploymentShouldRetuenLastDeployment() + { + //Arrange + var device = Fixture.Create(); + + _ = this.mockGreengrassV2.Setup(c => c.GetCoreDeviceAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new GetCoreDeviceResponse()); + + // Act + var result = this.externalDeviceService.RetrieveLastConfiguration(device); + + // Assert + _ = result.Should().NotBeNull(); + } + + [Test] + public async Task RemoveDeviceCredentialsShouldRemoveDeviceCredentials() + { + // Arrange + var device = Fixture.Create(); + + _ = this.mockAmazonIot.Setup(c => c.ListThingPrincipalsAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new ListThingPrincipalsResponse + { + Principals = Fixture.Create>() + }); + + _ = this.mockAmazonIot.Setup(c => c.DetachPolicyAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new DetachPolicyResponse()); + + _ = this.mockAmazonIot.Setup(c => c.DetachThingPrincipalAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new DetachThingPrincipalResponse()); + + _ = this.mockSecretsManager.Setup(c => c.DeleteSecretAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new DeleteSecretResponse()); + + _ = this.mockAmazonIot.Setup(c => c.UpdateCertificateAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new UpdateCertificateResponse()); + + _ = this.mockAmazonIot.Setup(c => c.DeleteCertificateAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new DeleteCertificateResponse()); + + // Act + var result = this.externalDeviceService.RemoveDeviceCredentials(device); + + // Assert + _ = result.Should().NotBeNull(); + } + } }