diff --git a/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/ConnectionStringDialogTests.cs b/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/ConnectionStringDialogTests.cs new file mode 100644 index 000000000..0e41904c7 --- /dev/null +++ b/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/ConnectionStringDialogTests.cs @@ -0,0 +1,160 @@ +// 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.Tests.Unit.Pages.Edge_Devices +{ + using System; + using System.Net.Http; + using System.Threading.Tasks; + using AzureIoTHub.Portal.Client.Pages.Edge_Devices; + using Models.v10; + using Bunit; + using Client.Exceptions; + using Client.Models; + using Client.Services; + using FluentAssertions; + using Helpers; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.JSInterop; + using Moq; + using MudBlazor; + using MudBlazor.Interop; + using MudBlazor.Services; + using NUnit.Framework; + using RichardSzalay.MockHttp; + + [TestFixture] + public class ConnectionStringDialogTests : TestContextWrapper, IDisposable + { + private MockHttpMessageHandler mockHttpClient; + private DialogService dialogService; + private MockRepository mockRepository; + private Mock mockJSRuntime; + + [SetUp] + public void Setup() + { + TestContext = new Bunit.TestContext(); + _ = TestContext.Services.AddMudServices(); + this.mockHttpClient = TestContext.Services.AddMockHttpClient(); + _ = TestContext.Services.AddSingleton(new PortalSettings { IsLoRaSupported = false }); + + this.mockRepository = new MockRepository(MockBehavior.Strict); + this.mockJSRuntime = this.mockRepository.Create(); + _ = TestContext.Services.AddSingleton(new ClipboardService(this.mockJSRuntime.Object)); + + this.mockHttpClient.AutoFlush = true; + + _ = TestContext.JSInterop.Setup("mudElementRef.getBoundingClientRect", _ => true); + _ = TestContext.JSInterop.SetupVoid("mudPopover.connect", _ => true); + _ = TestContext.JSInterop.SetupVoid("mudElementRef.saveFocus", _ => true); + + this.dialogService = TestContext.Services.GetService() as DialogService; + } + + [TearDown] + public void TearDown() => TestContext?.Dispose(); + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + } + + [Test] + public async Task ConnectionStringDialogMustShowEnrollmentCredentials() + { + // Arrange + var deviceId = Guid.NewGuid().ToString(); + + _ = this.mockHttpClient + .When(HttpMethod.Get, $"/api/edge/devices/{deviceId}/credentials") + .RespondJson(new EnrollmentCredentials()); + + var cut = RenderComponent(); + + var parameters = new DialogParameters + { + { + "deviceId", deviceId + } + }; + + // Act + await cut.InvokeAsync(() => this.dialogService?.Show(string.Empty, parameters)); + _ = cut.WaitForElement("div.mud-paper"); + + // Assert + _ = cut.FindAll("div.mud-grid-item").Count.Should().Be(4); + this.mockHttpClient.VerifyNoOutstandingRequest(); + this.mockHttpClient.VerifyNoOutstandingExpectation(); + } + + [Test] + public async Task ConnectionStringDialogMustBeCancelledWhenProblemDetailsOccurs() + { + // Arrange + var deviceId = Guid.NewGuid().ToString(); + + _ = this.mockHttpClient + .When(HttpMethod.Get, $"/api/edge/devices/{deviceId}/credentials") + .Throw(new ProblemDetailsException(new ProblemDetailsWithExceptionDetails())); + + var cut = RenderComponent(); + + var parameters = new DialogParameters + { + { + "deviceId", deviceId + } + }; + + IDialogReference dialogReference = null; + + // Act + await cut.InvokeAsync(() => dialogReference = this.dialogService?.Show(string.Empty, parameters)); + var result = await dialogReference.Result; + + // Assert + _ = result.Cancelled.Should().BeTrue(); + this.mockHttpClient.VerifyNoOutstandingRequest(); + this.mockHttpClient.VerifyNoOutstandingExpectation(); + } + + [Test] + public async Task ConnectionStringDialogMustBeCancelledOnClickOnCancel() + { + // Arrange + var deviceId = Guid.NewGuid().ToString(); + + _ = this.mockHttpClient + .When(HttpMethod.Get, $"api/devices/{deviceId}/credentials") + .RespondJson(new EnrollmentCredentials()); + + var cut = RenderComponent(); + + var parameters = new DialogParameters + { + { + "deviceId", deviceId + } + }; + + IDialogReference dialogReference = null; + + // Act + await cut.InvokeAsync(() => dialogReference = this.dialogService?.Show(string.Empty, parameters)); + cut.Find("#cancel").Click(); + var result = await dialogReference.Result; + + // Assert + _ = result.Cancelled.Should().BeTrue(); + this.mockHttpClient.VerifyNoOutstandingRequest(); + this.mockHttpClient.VerifyNoOutstandingExpectation(); + } + } +} diff --git a/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/CreateEdgeDeviceDialogTests.cs b/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/CreateEdgeDeviceDialogTests.cs new file mode 100644 index 000000000..6b7ec7cea --- /dev/null +++ b/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/CreateEdgeDeviceDialogTests.cs @@ -0,0 +1,106 @@ +// 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.Tests.Unit.Pages.Edge_Devices +{ + using System; + using System.Threading.Tasks; + using AzureIoTHub.Portal.Client.Pages.Edge_Devices; + using Models.v10; + using Bunit; + using Client.Services; + using FluentAssertions; + using Helpers; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.JSInterop; + using Moq; + using MudBlazor; + using MudBlazor.Interop; + using MudBlazor.Services; + using NUnit.Framework; + using RichardSzalay.MockHttp; + + [TestFixture] + public class CreateEdgeDeviceDialogTests : TestContextWrapper, IDisposable + { + private MockHttpMessageHandler mockHttpClient; + private MockRepository mockRepository; + private Mock mockJsRuntime; + private DialogService dialogService; + + [SetUp] + public void Setup() + { + TestContext = new Bunit.TestContext(); + _ = TestContext.Services.AddMudServices(); + this.mockHttpClient = TestContext.Services.AddMockHttpClient(); + _ = TestContext.Services.AddSingleton(new PortalSettings { IsLoRaSupported = false }); + + this.mockRepository = new MockRepository(MockBehavior.Strict); + this.mockJsRuntime = this.mockRepository.Create(); + _ = TestContext.Services.AddSingleton(new ClipboardService(this.mockJsRuntime.Object)); + + this.mockHttpClient.AutoFlush = true; + + _ = TestContext.JSInterop.Setup("mudElementRef.getBoundingClientRect", _ => true); + _ = TestContext.JSInterop.SetupVoid("mudKeyInterceptor.connect", _ => true); + _ = TestContext.JSInterop.SetupVoid("mudPopover.connect", _ => true); + _ = TestContext.JSInterop.SetupVoid("mudElementRef.saveFocus", _ => true); + + this.dialogService = TestContext.Services.GetService() as DialogService; + } + + [TearDown] + public void TearDown() => TestContext?.Dispose(); + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + } + + [Test] + public async Task CreateEdgeDeviceDialogMustRenderCorrectly() + { + // Arrange + var cut = RenderComponent(); + + var parameters = new DialogParameters(); + + // Act + await cut.InvokeAsync(() => this.dialogService?.Show(string.Empty, parameters)); + _ = cut.WaitForElement("div.mud-paper"); + + // Assert + _ = cut.FindAll("#name").Count.Should().Be(1); + _ = cut.FindAll("#type").Count.Should().Be(1); + _ = cut.FindAll("#environment").Count.Should().Be(1); + _ = cut.FindAll("#cancel").Count.Should().Be(1); + _ = cut.FindAll("#create").Count.Should().Be(1); + } + + [Test] + public async Task CreateEdgeDeviceDialogMustBeCancelledOnClickOnCancel() + { + // Arrange + var cut = RenderComponent(); + + var parameters = new DialogParameters(); + + IDialogReference dialogReference = null; + + // Act + await cut.InvokeAsync(() => dialogReference = this.dialogService?.Show(string.Empty, parameters)); + _ = cut.WaitForElement("div.mud-paper"); + cut.Find("#cancel").Click(); + var result = await dialogReference.Result; + + // Assert + _ = result.Cancelled.Should().BeTrue(); + } + } +} diff --git a/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/EdgeDeviceDeleteConfirmationDialogTests.cs b/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/EdgeDeviceDeleteConfirmationDialogTests.cs new file mode 100644 index 000000000..ee939c5d6 --- /dev/null +++ b/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/EdgeDeviceDeleteConfirmationDialogTests.cs @@ -0,0 +1,146 @@ +// 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.Tests.Unit.Pages.Edge_Devices +{ + using System; + using System.Net; + using System.Net.Http; + using System.Threading.Tasks; + using AzureIoTHub.Portal.Client.Pages.Edge_Devices; + using Models.v10; + using Bunit; + using Client.Exceptions; + using Client.Models; + using FluentAssertions; + using Helpers; + using Microsoft.Extensions.DependencyInjection; + using MudBlazor; + using MudBlazor.Interop; + using MudBlazor.Services; + using NUnit.Framework; + using RichardSzalay.MockHttp; + + [TestFixture] + public class EdgeDeviceDeleteConfirmationDialogTests : TestContextWrapper, IDisposable + { + private MockHttpMessageHandler mockHttpClient; + private DialogService dialogService; + + [SetUp] + public void Setup() + { + TestContext = new Bunit.TestContext(); + _ = TestContext.Services.AddMudServices(); + this.mockHttpClient = TestContext.Services.AddMockHttpClient(); + _ = TestContext.Services.AddSingleton(new PortalSettings { IsLoRaSupported = false }); + + this.mockHttpClient.AutoFlush = true; + + _ = TestContext.JSInterop.Setup("mudElementRef.getBoundingClientRect", _ => true); + _ = TestContext.JSInterop.SetupVoid("mudPopover.connect", _ => true); + + this.dialogService = TestContext.Services.GetService() as DialogService; + } + + [TearDown] + public void TearDown() => TestContext?.Dispose(); + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + } + + [Test] + public async Task EdgeDeviceDeleteConfirmationDialogMustDeleteDevice() + { + // Arrange + var deviceId = Guid.NewGuid().ToString(); + + _ = this.mockHttpClient + .When(HttpMethod.Delete, $"/api/edge/devices/{deviceId}") + .Respond(HttpStatusCode.NoContent); + + var cut = RenderComponent(); + + var parameters = new DialogParameters + { + { + "DeviceId", deviceId + } + }; + + IDialogReference dialogReference = null; + + // Act + await cut.InvokeAsync(() => dialogReference = this.dialogService?.Show(string.Empty, parameters)); + cut.Find("#delete").Click(); + var result = await dialogReference.GetReturnValueAsync(); + + // Assert + _ = result.Should().BeTrue(); + } + + [Test] + public async Task EdgeDeviceDeleteConfirmationDialogShouldProcessProblemDetailsExceptionWhenIssueOccursWhenDeletingDevice() + { + // Arrange + var deviceId = Guid.NewGuid().ToString(); + + _ = this.mockHttpClient + .When(HttpMethod.Delete, $"/api/edge/devices/{deviceId}") + .Throw(new ProblemDetailsException(new ProblemDetailsWithExceptionDetails())); + + var cut = RenderComponent(); + + var parameters = new DialogParameters + { + { + "DeviceId", deviceId + } + }; + + // Act + await cut.InvokeAsync(() => this.dialogService?.Show(string.Empty, parameters)); + cut.Find("#delete").Click(); + + // Assert + _ = cut.Find("#delete").TextContent.Should().Be("Delete"); + } + + [Test] + public async Task EdgeDeviceDeleteConfirmationDialogMustBeCanceledOnClickOnCancel() + { + // Arrange + var deviceId = Guid.NewGuid().ToString(); + + _ = this.mockHttpClient + .When(HttpMethod.Delete, $"/api/edge/devices/{deviceId}") + .Respond(HttpStatusCode.NoContent); + + var cut = RenderComponent(); + + var parameters = new DialogParameters + { + { + "DeviceId", deviceId + } + }; + + IDialogReference dialogReference = null; + + // Act + await cut.InvokeAsync(() => dialogReference = this.dialogService?.Show(string.Empty, parameters)); + cut.Find("#cancel").Click(); + var result = await dialogReference.Result; + + // Assert + _ = result.Cancelled.Should().BeTrue(); + } + } +} diff --git a/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/EdgeDeviceDetailPageTests.cs b/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/EdgeDeviceDetailPageTests.cs index c7865ed32..13b5835a6 100644 --- a/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/EdgeDeviceDetailPageTests.cs +++ b/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/EdgeDeviceDetailPageTests.cs @@ -13,6 +13,9 @@ namespace AzureIoTHub.Portal.Server.Tests.Unit.Pages using AzureIoTHub.Portal.Client.Shared; using Bunit; using Bunit.TestDoubles; + using Client.Exceptions; + using Client.Models; + using FluentAssertions; using Helpers; using Microsoft.AspNetCore.Components; using Microsoft.Extensions.DependencyInjection; @@ -147,8 +150,26 @@ public void ClickOnSaveShouldPutEdgeDeviceDetails() } [Test] - public void ClickOnSaveShouldDisplaySnackbarIfValidationError() + public void EdgeDeviceDetailPageShouldProcessProblemDetailsExceptionWhenIssueOccursOnLoadDevice() { + // Arrange + _ = this.mockHttpClient + .When(HttpMethod.Get, $"/api/edge/devices/{this.mockdeviceId}") + .Throw(new ProblemDetailsException(new ProblemDetailsWithExceptionDetails())); + + // Act + var cut = RenderComponent(ComponentParameter.CreateParameter("deviceId", this.mockdeviceId)); + + // Assert + cut.WaitForAssertion(() => cut.Find("form").Should().NotBeNull()); + this.mockHttpClient.VerifyNoOutstandingRequest(); + this.mockHttpClient.VerifyNoOutstandingExpectation(); + } + + [Test] + public void EdgeDeviceDetailPageShouldProcessProblemDetailsExceptionWhenIssueOccursOnUpdateDevice() + { + // Arrange var mockIoTEdgeDevice = new IoTEdgeDevice() { DeviceId = mockdeviceId, @@ -156,6 +177,60 @@ public void ClickOnSaveShouldDisplaySnackbarIfValidationError() Type = "Other" }; + _ = this.mockHttpClient + .When(HttpMethod.Get, $"/api/edge/devices/{this.mockdeviceId}") + .RespondJson(mockIoTEdgeDevice); + + _ = this.mockHttpClient + .When(HttpMethod.Put, $"/api/edge/devices/{this.mockdeviceId}") + .With(m => + { + Assert.IsAssignableFrom>(m.Content); + var objectContent = m.Content as ObjectContent; + Assert.IsNotNull(objectContent); + + Assert.IsAssignableFrom(objectContent.Value); + var edgeDevice = objectContent.Value as IoTEdgeDevice; + Assert.IsNotNull(edgeDevice); + + Assert.AreEqual(mockIoTEdgeDevice.DeviceId, edgeDevice.DeviceId); + Assert.AreEqual(mockIoTEdgeDevice.ConnectionState, edgeDevice.ConnectionState); + Assert.AreEqual(mockIoTEdgeDevice.Type, edgeDevice.Type); + + return true; + }) + .Throw(new ProblemDetailsException(new ProblemDetailsWithExceptionDetails())); + + var mockDialogReference = new DialogReference(Guid.NewGuid(), this.mockDialogService.Object); + + _ = this.mockDialogService.Setup(c => c.Show("Processing", It.IsAny())) + .Returns(mockDialogReference); + + _ = this.mockDialogService.Setup(c => c.Close(It.Is(x => x == mockDialogReference))); + + var cut = RenderComponent( + ComponentParameter.CreateParameter("deviceId", this.mockdeviceId)); + cut.WaitForAssertion(() => cut.Find("form").Should().NotBeNull()); + + // Act + cut.Find("#saveButton").Click(); + + // Assert + cut.WaitForAssertion(() => this.mockRepository.VerifyAll()); + this.mockHttpClient.VerifyNoOutstandingRequest(); + this.mockHttpClient.VerifyNoOutstandingExpectation(); + } + + [Test] + public void ClickOnSaveShouldDisplaySnackbarIfValidationError() + { + var mockIoTEdgeDevice = new IoTEdgeDevice + { + DeviceId = mockdeviceId, + ConnectionState = "Connected", + Type = "Other" + }; + _ = this.mockHttpClient .When(HttpMethod.Get, $"/api/edge/devices/{this.mockdeviceId}") .RespondJson(mockIoTEdgeDevice); @@ -192,8 +267,6 @@ public void ClickOnSaveShouldDisplaySnackbarIfValidationError() _ = this.mockDialogService.Setup(c => c.Close(It.Is(x => x == mockDialogReference))); - _ = this.mockSnackbarService.Setup(c => c.Add("One or more validation errors occurred", Severity.Error, null)).Returns((Snackbar)null); - // Act saveButton.Click(); Thread.Sleep(2500); @@ -249,8 +322,6 @@ public void ClickOnSaveShouldDisplaySnackbarIfUnexpectedError() _ = this.mockDialogService.Setup(c => c.Close(It.Is(x => x == mockDialogReference))); - _ = this.mockSnackbarService.Setup(c => c.Add("Something unexpected occurred", Severity.Warning, null)).Returns((Snackbar)null); - // Act saveButton.Click(); Thread.Sleep(2500); @@ -398,6 +469,65 @@ public void ClickOnRebootShouldDisplaySnackbarIfError() this.mockRepository.VerifyAll(); } + [Test] + public void EdgeDeviceDetailPageShouldProcessProblemDetailsExceptionWhenIssueOccursOnClickOnReboot() + { + // Arrange + var mockIoTEdgeModule = new IoTEdgeModule() + { + ModuleName = Guid.NewGuid().ToString() + }; + + var mockIoTEdgeDevice = new IoTEdgeDevice() + { + DeviceId = mockdeviceId, + ConnectionState = "Connected", + Type = "Other", + Modules= new List(){mockIoTEdgeModule} + }; + + + _ = this.mockHttpClient + .When(HttpMethod.Get, $"/api/edge/devices/{this.mockdeviceId}") + .RespondJson(mockIoTEdgeDevice); + + _ = this.mockHttpClient + .When(HttpMethod.Post, $"/api/edge/devices/{mockIoTEdgeDevice.DeviceId}/{mockIoTEdgeModule.ModuleName}/RestartModule") + .With(m => + { + Assert.IsAssignableFrom>(m.Content); + var objectContent = m.Content as ObjectContent; + Assert.IsNotNull(objectContent); + + Assert.IsAssignableFrom(objectContent.Value); + var edgeModule = objectContent.Value as IoTEdgeModule; + Assert.IsNotNull(edgeModule); + + Assert.AreEqual(mockIoTEdgeModule.ModuleName, edgeModule.ModuleName); + + return true; + }) + .Throw(new ProblemDetailsException(new ProblemDetailsWithExceptionDetails())); + + var mockDialogReference = new DialogReference(Guid.NewGuid(), this.mockDialogService.Object); + + _ = this.mockDialogService.Setup(c => c.Show("Processing", It.IsAny())) + .Returns(mockDialogReference); + + _ = this.mockDialogService.Setup(c => c.Close(It.Is(x => x == mockDialogReference))); + + var cut = RenderComponent(ComponentParameter.CreateParameter("deviceId", this.mockdeviceId)); + cut.WaitForAssertion(() => cut.Find("form").Should().NotBeNull()); + + // Act + cut.Find("#rebootModule").Click(); + + // Assert + cut.WaitForAssertion(() => this.mockRepository.VerifyAll()); + this.mockHttpClient.VerifyNoOutstandingRequest(); + this.mockHttpClient.VerifyNoOutstandingExpectation(); + } + [Test] public void ClickOnLogsShouldDisplayLogs() { diff --git a/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/EdgeDeviceListPageTests.cs b/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/EdgeDeviceListPageTests.cs new file mode 100644 index 000000000..57565b0b1 --- /dev/null +++ b/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/EdgeDeviceListPageTests.cs @@ -0,0 +1,155 @@ +// 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.Tests.Unit.Pages.Edge_Devices +{ + using System; + using System.Collections.Generic; + using System.Net.Http; + using AzureIoTHub.Portal.Client.Pages.Edge_Devices; + using Models.v10; + using Bunit; + using Client.Exceptions; + using Client.Models; + using Client.Services; + using FluentAssertions; + using Helpers; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.JSInterop; + using Moq; + using MudBlazor.Interop; + using MudBlazor.Services; + using NUnit.Framework; + using RichardSzalay.MockHttp; + + [TestFixture] + public class EdgeDeviceListPageTests : TestContextWrapper, IDisposable + { + private MockHttpMessageHandler mockHttpClient; + private MockRepository mockRepository; + private Mock mockJsRuntime; + + [SetUp] + public void Setup() + { + TestContext = new Bunit.TestContext(); + _ = TestContext.Services.AddMudServices(); + this.mockHttpClient = TestContext.Services.AddMockHttpClient(); + _ = TestContext.Services.AddSingleton(new PortalSettings { IsLoRaSupported = false }); + + this.mockRepository = new MockRepository(MockBehavior.Strict); + this.mockJsRuntime = this.mockRepository.Create(); + _ = TestContext.Services.AddSingleton(new ClipboardService(this.mockJsRuntime.Object)); + + this.mockHttpClient.AutoFlush = true; + + _ = TestContext.JSInterop.Setup("mudElementRef.getBoundingClientRect", _ => true); + _ = TestContext.JSInterop.SetupVoid("mudKeyInterceptor.connect", _ => true); + _ = TestContext.JSInterop.SetupVoid("mudPopover.connect", _ => true); + } + + [TearDown] + public void TearDown() => TestContext?.Dispose(); + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + } + + [Test] + public void EdgeDeviceListPageShouldShowEdgeDevices() + { + // Arrange + _ = this.mockHttpClient + .When(HttpMethod.Get, "/api/edge/devices?pageSize=10&searchText=&searchStatus=&searchType=") + .RespondJson(new PaginationResult + { + Items = new List + { + new(), + new(), + new() + } + }); + + // Act + var cut = RenderComponent(); + + // Assert + cut.WaitForAssertion(() => cut.Markup.Should().NotContain("Loading...")); + _ = cut.FindAll("tr").Count.Should().Be(4); + this.mockHttpClient.VerifyNoOutstandingRequest(); + this.mockHttpClient.VerifyNoOutstandingExpectation(); + } + + [Test] + public void EdgeDeviceListPageShouldShowNoContentWhenNoEdgeDevices() + { + // Arrange + _ = this.mockHttpClient + .When(HttpMethod.Get, "/api/edge/devices?pageSize=10&searchText=&searchStatus=&searchType=") + .RespondJson(new PaginationResult()); + + // Act + var cut = RenderComponent(); + + // Assert + cut.WaitForAssertion(() => cut.Markup.Should().NotContain("Loading...")); + _ = cut.FindAll("tr").Count.Should().Be(2); + _ = cut.Markup.Should().Contain("No matching records found"); + this.mockHttpClient.VerifyNoOutstandingRequest(); + this.mockHttpClient.VerifyNoOutstandingExpectation(); + } + + [Test] + public void EdgeDeviceListPageShouldShowNoContentWhenProblemDetailsExceptionOccurs() + { + // Arrange + _ = this.mockHttpClient + .When(HttpMethod.Get, "/api/edge/devices?pageSize=10&searchText=&searchStatus=&searchType=") + .Throw(new ProblemDetailsException(new ProblemDetailsWithExceptionDetails())); + + // Act + var cut = RenderComponent(); + + // Assert + cut.WaitForAssertion(() => cut.Markup.Should().NotContain("Loading...")); + _ = cut.FindAll("tr").Count.Should().Be(2); + _ = cut.Markup.Should().Contain("No matching records found"); + this.mockHttpClient.VerifyNoOutstandingRequest(); + this.mockHttpClient.VerifyNoOutstandingExpectation(); + } + + [Test] + public void EdgeDeviceListPageShouldResetOnClickOnReset() + { + // Arrange + _ = this.mockHttpClient + .When(HttpMethod.Get, "/api/edge/devices?pageSize=10&searchText=&searchStatus=&searchType=") + .RespondJson(new PaginationResult + { + Items = new List + { + new(), + new(), + new() + } + }); + + // Act + var cut = RenderComponent(); + cut.Find("#reset").Click(); + + // Assert + cut.WaitForAssertion(() => cut.Markup.Should().NotContain("Loading...")); + _ = cut.FindAll("tr").Count.Should().Be(4); + this.mockHttpClient.VerifyNoOutstandingRequest(); + this.mockHttpClient.VerifyNoOutstandingExpectation(); + } + } +} diff --git a/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/ModuleLogsDialogTests.cs b/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/ModuleLogsDialogTests.cs index 56b6ecd2a..819855ff9 100644 --- a/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/ModuleLogsDialogTests.cs +++ b/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Edge_Devices/ModuleLogsDialogTests.cs @@ -5,10 +5,13 @@ namespace AzureIoTHub.Portal.Server.Tests.Unit.Pages.Edge_Devices { using System; using System.Collections.Generic; + using System.Threading.Tasks; using AzureIoTHub.Portal.Client.Pages.Edge_Devices; using AzureIoTHub.Portal.Client.Services; using AzureIoTHub.Portal.Models.v10; using Bunit; + using Client.Exceptions; + using Client.Models; using FluentAssertions; using Microsoft.AspNetCore.Components; using Microsoft.Extensions.DependencyInjection; @@ -28,7 +31,6 @@ public class ModuleLogsDialogTests private MockRepository mockRepository; private Mock edgeDeviceClientServiceMock; - private Mock mockDialogService; [SetUp] public void SetUp() @@ -37,14 +39,11 @@ public void SetUp() this.mockRepository = new MockRepository(MockBehavior.Strict); this.edgeDeviceClientServiceMock = this.mockRepository.Create(); - this.mockDialogService = this.mockRepository.Create(); _ = this.testContext.Services.AddMudServices(); _ = this.testContext.Services.AddSingleton(this.edgeDeviceClientServiceMock.Object); - _ = this.testContext.Services.AddSingleton(this.mockDialogService.Object); - _ = this.testContext.JSInterop.Setup("mudElementRef.getBoundingClientRect", _ => true); _ = this.testContext.JSInterop.SetupVoid("mudPopover.connect", _ => true); } @@ -58,7 +57,49 @@ private IRenderedComponent RenderComponent(params Compon } [Test] - public void ModuleLogsDialogParametersMustBeCorrect() + public async Task ModuleLogsDialogParametersMustBeCorrect() + { + // Arrange + var deviceId = Guid.NewGuid().ToString(); + + var edgeModule = new IoTEdgeModule + { + Version = "1.0", + ModuleName = Guid.NewGuid().ToString() + }; + + var expectedLogs = new List() + { + new(), + new(), + new() + }; + + _ = this.edgeDeviceClientServiceMock.Setup(c => c.GetEdgeDeviceLogs(It.Is(x => x.Equals(deviceId, StringComparison.Ordinal)), It.Is(x => x.Equals(edgeModule)))) + .ReturnsAsync(expectedLogs); + + var cut = RenderComponent(); + var service = this.testContext.Services.GetService() as DialogService; + + var parameters = new DialogParameters + { + { + "deviceId", deviceId + }, + { + "edgeModule", edgeModule + } + }; + + // Act + await cut.InvokeAsync(() => service?.Show(string.Empty, parameters)); + + // Assert + _ = cut.FindAll("tr").Count.Should().Be(4); + } + + [Test] + public async Task ModuleLogsShouldProcessProblemDetailsExceptionWhenIssueOccursOnGettingLogs() { // Arrange var deviceId = Guid.NewGuid().ToString(); @@ -69,28 +110,71 @@ public void ModuleLogsDialogParametersMustBeCorrect() ModuleName = Guid.NewGuid().ToString() }; - var expectedLog = new IoTEdgeDeviceLog + _ = this.edgeDeviceClientServiceMock.Setup(c => c.GetEdgeDeviceLogs(It.Is(x => x.Equals(deviceId, StringComparison.Ordinal)), It.Is(x => x.Equals(edgeModule)))) + .ThrowsAsync(new ProblemDetailsException(new ProblemDetailsWithExceptionDetails())); + + var cut = RenderComponent(); + var service = this.testContext.Services.GetService() as DialogService; + + var parameters = new DialogParameters { - Id = deviceId, - Text = Guid.NewGuid().ToString(), - LogLevel = 1, - TimeStamp = DateTime.UtcNow + { + "deviceId", deviceId + }, + { + "edgeModule", edgeModule + } + }; + + // Act + await cut.InvokeAsync(() => service?.Show(string.Empty, parameters)); + + // Assert + _ = cut.FindAll("tr").Count.Should().Be(2); + } + + [Test] + public async Task ModuleLogsMustCloseOnCLickOnCloseButton() + { + // Arrange + var deviceId = Guid.NewGuid().ToString(); + + var edgeModule = new IoTEdgeModule + { + Version = "1.0", + ModuleName = Guid.NewGuid().ToString() }; var expectedLogs = new List() { - expectedLog + new() }; - _ = edgeDeviceClientServiceMock.Setup(c => c.GetEdgeDeviceLogs(It.Is(x => x.Equals(deviceId, StringComparison.Ordinal)), It.Is(x => x.Equals(edgeModule)))) + _ = this.edgeDeviceClientServiceMock.Setup(c => c.GetEdgeDeviceLogs(It.Is(x => x.Equals(deviceId, StringComparison.Ordinal)), It.Is(x => x.Equals(edgeModule)))) .ReturnsAsync(expectedLogs); + var cut = RenderComponent(); + var service = this.testContext.Services.GetService() as DialogService; + + var parameters = new DialogParameters + { + { + "deviceId", deviceId + }, + { + "edgeModule", edgeModule + } + }; + + IDialogReference dialogReference = null; + // Act - var cut = RenderComponent(ComponentParameter.CreateParameter("deviceId", deviceId), ComponentParameter.CreateParameter("edgeModule", edgeModule)); + await cut.InvokeAsync(() => dialogReference = service?.Show(string.Empty, parameters)); + cut.Find("#close").Click(); + var result = await dialogReference.Result; // Assert - _ = cut.Instance.deviceId.Should().Be(deviceId); - _ = cut.Instance.edgeModule.Should().Be(edgeModule); + _ = result.Cancelled.Should().BeTrue(); } } } diff --git a/src/AzureIoTHub.Portal.Server.Tests.Unit/Services/EdgeDeviceClientServiceTests.cs b/src/AzureIoTHub.Portal.Server.Tests.Unit/Services/EdgeDeviceClientServiceTests.cs index 736a38355..3b15bc9b8 100644 --- a/src/AzureIoTHub.Portal.Server.Tests.Unit/Services/EdgeDeviceClientServiceTests.cs +++ b/src/AzureIoTHub.Portal.Server.Tests.Unit/Services/EdgeDeviceClientServiceTests.cs @@ -8,7 +8,9 @@ namespace AzureIoTHub.Portal.Server.Tests.Unit.Services using System.Net.Http; using System.Threading.Tasks; using AzureIoTHub.Portal.Client.Services; - using AzureIoTHub.Portal.Models.v10; + using Models.v10; + using Client.Exceptions; + using Client.Models; using FluentAssertions; using Newtonsoft.Json; using NUnit.Framework; @@ -66,7 +68,7 @@ public async Task GetEdgeDeviceLogsMustReturnLogsWhenNoError() } [Test] - public async Task GetEdgeDeviceLogsMustThowHttpRequestExceptionWhenError() + public async Task GetEdgeDeviceLogsMustThrowProblemDetailsExceptionWhenErrorOccurs() { // Arrange var deviceId = Guid.NewGuid().ToString(); @@ -80,7 +82,7 @@ public async Task GetEdgeDeviceLogsMustThowHttpRequestExceptionWhenError() using var mockHttp = new MockHttpMessageHandler(); _ = mockHttp.When(HttpMethod.Post, $"http://localhost/api/edge/devices/{deviceId}/logs") - .Respond(System.Net.HttpStatusCode.BadRequest); + .Throw(new ProblemDetailsException(new ProblemDetailsWithExceptionDetails())); using var client = new HttpClient(mockHttp) { @@ -93,7 +95,7 @@ public async Task GetEdgeDeviceLogsMustThowHttpRequestExceptionWhenError() var act = () => edgeDeviceClientService.GetEdgeDeviceLogs(deviceId, edgeModule); // Assert - _ = await act.Should().ThrowAsync(); + _ = await act.Should().ThrowAsync(); } } } diff --git a/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/ConnectionStringDialog.razor b/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/ConnectionStringDialog.razor index afab810e8..0d2653b0b 100644 --- a/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/ConnectionStringDialog.razor +++ b/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/ConnectionStringDialog.razor @@ -1,13 +1,9 @@ -@using AzureIoTHub.Portal.Client.Services -@using Microsoft.AspNetCore.Authorization -@using AzureIoTHub.Portal.Models.v10 +@using AzureIoTHub.Portal.Models.v10 @inject HttpClient Http -@inject ISnackbar Snackbar @inject ClipboardService ClipboardService -
- + @if (loading) { @@ -42,12 +38,14 @@ } - Cancel + Cancel -
@code { + [CascadingParameter] + public Error Error {get; set;} + [CascadingParameter] MudDialogInstance MudDialog { get; set; } [Parameter] public string deviceId { get; set; } private EnrollmentCredentials Credentials; @@ -59,22 +57,16 @@ { await base.OnInitializedAsync(); - Credentials = await this.Http.GetFromJsonAsync($"api/edge/devices/{deviceId}/credentials"); - loading = false; - + Credentials = await Http.GetFromJsonAsync($"api/edge/devices/{deviceId}/credentials"); } - catch (HttpRequestException e) + catch (ProblemDetailsException exception) { - if (e.StatusCode == System.Net.HttpStatusCode.NotFound) - { - Snackbar.Add("Cannot obtain the connection string
because the enrollment group does not exist.", Severity.Error); - } - else - { - Snackbar.Add($"Something went wrong.", Severity.Error); - } - - MudDialog.Close(); + Error?.ProcessProblemDetails(exception); + Cancel(); + } + finally + { + loading = false; } } diff --git a/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/CreateEdgeDeviceDialog.razor b/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/CreateEdgeDeviceDialog.razor index 505b4c373..f4bfb2e02 100644 --- a/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/CreateEdgeDeviceDialog.razor +++ b/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/CreateEdgeDeviceDialog.razor @@ -1,5 +1,4 @@ @page "/edge/devices/add" -@using Microsoft.AspNetCore.Authorization @using AzureIoTHub.Portal.Models.v10; @inject HttpClient Http @@ -13,6 +12,7 @@ - Cancel + Cancel @if (processingSave) { @@ -54,7 +56,7 @@ } else { - Create + Create } @@ -63,28 +65,33 @@ @code { + [CascadingParameter] + public Error Error {get; set;} + [CascadingParameter] MudDialogInstance MudDialog { get; set; } - private IoTEdgeDevice gateway = new IoTEdgeDevice(); - private bool processingSave = false; + private readonly IoTEdgeDevice gateway = new(); + private bool processingSave; void Cancel() => MudDialog.Cancel(); private async Task OnValidation() { - processingSave = true; - var result = await Http.PostAsJsonAsync("api/edge/devices", gateway); - processingSave = false; - - if (result.IsSuccessStatusCode) + try { - Snackbar.Add($"Device has been successfully created !", Severity.Success); + processingSave = true; + await Http.PostAsJsonAsync("api/edge/devices", gateway); + + Snackbar.Add("Device has been successfully created !", Severity.Success); MudDialog.Close(DialogResult.Ok(true)); } - else + catch (ProblemDetailsException exception) + { + Error?.ProcessProblemDetails(exception); + } + finally { - Snackbar.Add($"Something went wrong while creating device ... ", Severity.Error); - return; + processingSave = false; } } } diff --git a/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/EdgeDeviceDeleteConfirmationDialog.razor b/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/EdgeDeviceDeleteConfirmationDialog.razor index 9567f1439..873abfc02 100644 --- a/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/EdgeDeviceDeleteConfirmationDialog.razor +++ b/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/EdgeDeviceDeleteConfirmationDialog.razor @@ -1,8 +1,5 @@ -@using AzureIoTHub.Portal.Models.v10 -@inject HttpClient Http -@inject IJSRuntime JS +@inject HttpClient Http @inject ISnackbar Snackbar -@inject NavigationManager NavigationManager @@ -18,12 +15,15 @@ - Cancel - Delete + Cancel + Delete @code { + [CascadingParameter] + public Error Error {get; set;} + [CascadingParameter] MudDialogInstance MudDialog { get; set; } [Parameter] public string DeviceId { get; set; } @@ -31,14 +31,16 @@ private async Task DeleteDevice() { - var result = await Http.DeleteAsync($"api/edge/devices/{DeviceId}"); + try + { + await Http.DeleteAsync($"api/edge/devices/{DeviceId}"); - if (!result.IsSuccessStatusCode) + Snackbar.Add($"Device {DeviceId} has been successfully deleted!", Severity.Success); + MudDialog.Close(DialogResult.Ok(true)); + } + catch (ProblemDetailsException exception) { - Snackbar.Add($"Oh oh, something went wrong while deleting device {DeviceId}... ", Severity.Error); + Error?.ProcessProblemDetails(exception); } - - Snackbar.Add($"Device {DeviceId} has been successfully deleted!", Severity.Success); - MudDialog.Close(DialogResult.Ok(true)); } } diff --git a/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/EdgeDeviceDetailPage.razor b/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/EdgeDeviceDetailPage.razor index 4c999bbb6..79ef49694 100644 --- a/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/EdgeDeviceDetailPage.razor +++ b/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/EdgeDeviceDetailPage.razor @@ -1,8 +1,6 @@ @page "/edge/devices/{deviceId}" @using Microsoft.AspNetCore.Authorization -@using Microsoft.AspNetCore.Components.WebAssembly.Authentication @using AzureIoTHub.Portal.Models.v10 -@using System.Net.Http.Json @attribute [Authorize] @inject HttpClient Http @@ -176,6 +174,9 @@ else } @code { + [CascadingParameter] + public Error Error {get; set;} + [Parameter] public string deviceId { get; set; } private bool loading = true; @@ -192,36 +193,45 @@ else public async Task LoadDevice() { - Gateway = await Http.GetFromJsonAsync($"api/edge/devices/{deviceId}"); + try + { + Gateway = await Http.GetFromJsonAsync($"api/edge/devices/{deviceId}"); + - if (Gateway.ConnectionState == "Disconnected") + if (Gateway.ConnectionState == "Disconnected") + { + btn_disable = true; + } + } + catch (ProblemDetailsException exception) { - btn_disable = true; + Error?.ProcessProblemDetails(exception); + } + finally + { + loading = false; } - loading = false; } public async Task UpdateDevice() { var parameters = new DialogParameters{{ "ContentText", "Processing" }}; - MudBlazor.DialogReference processingDialog = DialogService.Show("Processing", parameters) as MudBlazor.DialogReference; - - var result = await Http.PutAsJsonAsync($"api/edge/devices/{Gateway.DeviceId}", Gateway); - - DialogService.Close(processingDialog); + var processingDialog = DialogService.Show("Processing", parameters) as DialogReference; - if (result.IsSuccessStatusCode) + try { + await Http.PutAsJsonAsync($"api/edge/devices/{Gateway.DeviceId}", Gateway); + Snackbar.Add($"Device {Gateway.DeviceId} has been successfully updated!", Severity.Success); } - else if (result.StatusCode == System.Net.HttpStatusCode.BadRequest) + catch (ProblemDetailsException exception) { - Snackbar.Add("One or more validation errors occurred", Severity.Error); + Error?.ProcessProblemDetails(exception); } - else + finally { - Snackbar.Add("Something unexpected occurred", Severity.Warning); + DialogService.Close(processingDialog); } } @@ -229,33 +239,44 @@ else { var parameters = new DialogParameters{{ "ContentText", "Processing" }}; - MudBlazor.DialogReference processingDialog = DialogService.Show("Processing", parameters) as MudBlazor.DialogReference; - - var result = await Http.PostAsJsonAsync($"api/edge/devices/{Gateway.DeviceId}/{module.ModuleName}/{methodName}", module); + var processingDialog = DialogService.Show("Processing", parameters) as DialogReference; - DialogService.Close(processingDialog); + try + { + var result = await Http.PostAsJsonAsync($"api/edge/devices/{Gateway.DeviceId}/{module.ModuleName}/{methodName}", module); - var c2dResult = result.Content.ReadFromJsonAsync().Result; + var c2dResult = result.Content.ReadFromJsonAsync().Result; - if (c2dResult.Status == 200) + if (c2dResult.Status == 200) + { + Snackbar.Add("Command successfully executed.", Severity.Success); + } + else + { + Snackbar.Add($"Error
Status : {c2dResult.Status};
Payload : {c2dResult.Payload};", Severity.Error, + (option) => + { + option.VisibleStateDuration = 10000; + }); + } + } + catch (ProblemDetailsException exception) { - Snackbar.Add("Command successfully executed.", Severity.Success); + Error?.ProcessProblemDetails(exception); } - else + finally { - Snackbar.Add($"Error
Status : {c2dResult.Status};
Payload : {c2dResult.Payload};", Severity.Error, - (option) => - { - option.VisibleStateDuration = 10000; - }); + DialogService.Close(processingDialog); } } public async Task ShowEdgeDeviceLogs(IoTEdgeModule module) { - var parameter = new DialogParameters(); - parameter.Add("deviceId", deviceId); - parameter.Add("edgeModule", module); + var parameter = new DialogParameters + { + {"deviceId", deviceId}, + {"edgeModule", module} + }; _ = await DialogService.Show("Edge device log", parameter).Result; @@ -263,17 +284,14 @@ else public void ShowConnectionString() { - var parameters = new DialogParameters(); - parameters.Add(nameof(ConnectionStringDialog.deviceId), this.deviceId); + var parameters = new DialogParameters {{nameof(ConnectionStringDialog.deviceId), this.deviceId}}; DialogService.Show("Edge Device Connection String", parameters); } public async Task ShowDeleteModal() { - var parameter = new DialogParameters(); - - parameter.Add(nameof(Gateway.DeviceId), Gateway.DeviceId); + var parameter = new DialogParameters {{nameof(Gateway.DeviceId), Gateway.DeviceId}}; var result = await DialogService.Show("Edge device deletion confirmation", parameter).Result; diff --git a/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/EdgeDeviceListPage.razor b/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/EdgeDeviceListPage.razor index 8edf8e88c..d9a339149 100644 --- a/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/EdgeDeviceListPage.razor +++ b/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/EdgeDeviceListPage.razor @@ -1,17 +1,11 @@ @page "/edge/devices" @using AzureIoTHub.Portal @using Microsoft.AspNetCore.Authorization -@using Microsoft.AspNetCore.Components.WebAssembly.Authentication @using AzureIoTHub.Portal.Models.v10 -@using System.Net.Http.Json -@using Blazored.Modal -@using Blazored.Modal.Services @using System.Web @attribute [Authorize] @inject HttpClient Http -@inject NavigationManager NavigationManager -@inject ISnackbar Snackbar @inject IDialogService DialogService @@ -46,7 +40,7 @@ Search - Reset + Reset @@ -128,10 +122,13 @@ @code { + [CascadingParameter] + public Error Error {get; set;} + private MudTable table; - private SearchModel searchModel = new SearchModel(); + private SearchModel searchModel = new(); - DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true }; + readonly DialogOptions maxWidth = new() { MaxWidth = MaxWidth.Medium, FullWidth = true }; private Dictionary Pages { get; set; } = new(); private bool IsLoading { get; set; } = true; @@ -145,44 +142,50 @@ private async Task> LoadItems(TableState state) { - PaginationResult result; - - if (Pages.Keys.Contains(state.Page)) - { - result = await Http.GetFromJsonAsync>(Pages[state.Page]); - } - else + try { - var uri = $"api/edge/devices?pageSize={state.PageSize}&searchText={HttpUtility.UrlEncode(searchModel.DeviceId)}&searchStatus={searchModel.Status}&searchType={searchModel.Type}"; + PaginationResult result; - _ = Pages.TryAdd(state.Page, uri); + if (Pages.Keys.Contains(state.Page)) + { + result = await Http.GetFromJsonAsync>(Pages[state.Page]); + } + else + { + var uri = $"api/edge/devices?pageSize={state.PageSize}&searchText={HttpUtility.UrlEncode(searchModel.DeviceId)}&searchStatus={searchModel.Status}&searchType={searchModel.Type}"; - result = await Http.GetFromJsonAsync>(uri); - } + _ = Pages.TryAdd(state.Page, uri); - _ = Pages.TryAdd(state.Page + 1, result.NextPage); + result = await Http.GetFromJsonAsync>(uri); + } - IsLoading = false; + _ = Pages.TryAdd(state.Page + 1, result.NextPage); - return new TableData + return new TableData { Items = result.Items, TotalItems = result.TotalItems }; + } + catch (ProblemDetailsException exception) + { + Error?.ProcessProblemDetails(exception); + + return new TableData(); + } + finally + { + IsLoading = false; + } } - private void ResetFiltre() + private void ResetFilter() { - this.searchModel = new SearchModel(); + searchModel = new SearchModel(); Search(); } - private void RedirectToDetail(string id) - { - NavigationManager.NavigateTo($"/edge-device/detail/{id}"); - } - private async Task ShowAddDialog() { var result = await DialogService.Show("Add IoT Edge", maxWidth).Result; @@ -197,8 +200,7 @@ public async Task ShowDeleteDialog(IoTEdgeListItem gateway) { - var parameters = new DialogParameters(); - parameters.Add(nameof(IoTEdgeDevice.DeviceId), gateway.DeviceId); + var parameters = new DialogParameters {{nameof(IoTEdgeDevice.DeviceId), gateway.DeviceId}}; var result = await DialogService.Show("Confirm Deletion", parameters).Result; if (result.Cancelled) diff --git a/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/ModuleLogsDialog.razor b/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/ModuleLogsDialog.razor index 90463e043..5326a5d66 100644 --- a/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/ModuleLogsDialog.razor +++ b/src/AzureIoTHub.Portal/Client/Pages/Edge_Devices/ModuleLogsDialog.razor @@ -10,7 +10,7 @@ - @@ -48,17 +48,20 @@ - Cancel + Cancel @code { + [CascadingParameter] + public Error Error {get; set;} + [CascadingParameter] MudDialogInstance MudDialog { get; set; } [Parameter] public string deviceId { get; set; } [Parameter] public IoTEdgeModule edgeModule { get; set; } private int[] pageSizeOptions = new int[] { 3, 5 , 10}; - private List Logs; + private List logs = new(); void Cancel() => MudDialog.Cancel(); @@ -71,6 +74,13 @@ public async Task LoadEdgeDeviceLogs() { - Logs = await EdgeDeviceService.GetEdgeDeviceLogs(deviceId, edgeModule); + try + { + logs = await EdgeDeviceService.GetEdgeDeviceLogs(deviceId, edgeModule); + } + catch (ProblemDetailsException exception) + { + Error?.ProcessProblemDetails(exception); + } } } diff --git a/src/AzureIoTHub.Portal/Client/Services/EdgeDeviceClientService.cs b/src/AzureIoTHub.Portal/Client/Services/EdgeDeviceClientService.cs index 0587631e5..c821441b7 100644 --- a/src/AzureIoTHub.Portal/Client/Services/EdgeDeviceClientService.cs +++ b/src/AzureIoTHub.Portal/Client/Services/EdgeDeviceClientService.cs @@ -27,14 +27,7 @@ public async Task> GetEdgeDeviceLogs(string deviceId, IoT Encoding.UTF8, Application.Json)); - if (response.IsSuccessStatusCode) - { - return JsonConvert.DeserializeObject>(await response.Content.ReadAsStringAsync()); - } - else - { - throw new HttpRequestException(response.ReasonPhrase); - } + return JsonConvert.DeserializeObject>(await response.Content.ReadAsStringAsync()); } } }