From 83b5aca310de41a01a470aac0535ec4f397417bb Mon Sep 17 00:00:00 2001 From: GuillaumeM Date: Fri, 17 Feb 2023 16:58:00 +0100 Subject: [PATCH 01/11] enable search on device models --- .../Services/IDeviceModelService.cs | 6 +- .../DeviceModels/DeviceModelSearch.razor | 39 +++++++++ .../Models/DeviceModelSearchInfo.cs | 10 +++ .../CreateDeviceConfigurationsPage.razor | 3 +- .../DeviceModels/DeviceModelListPage.razor | 87 ++++++++++++++++--- .../Pages/Devices/CreateDevicePage.razor | 3 +- .../Pages/Devices/DeviceListPage.razor | 2 +- .../Services/DeviceModelsClientService.cs | 17 +++- .../Services/IDeviceModelsClientService.cs | 3 +- .../v1.0/DeviceModelControllerBase.cs | 32 ++++++- .../v1.0/DeviceModelsController.cs | 6 +- .../LoRaWAN/LoRaWANDeviceModelsController.cs | 18 +++- .../Services/DeviceModelService.cs | 38 +++++--- .../Models/v1.0/Filters/DeviceModelFilter.cs | 11 +++ src/AzureIoTHub.Portal.sln | 5 +- 15 files changed, 236 insertions(+), 44 deletions(-) create mode 100644 src/AzureIoTHub.Portal.Client/Components/DeviceModels/DeviceModelSearch.razor create mode 100644 src/AzureIoTHub.Portal.Client/Models/DeviceModelSearchInfo.cs create mode 100644 src/AzureIoTHub.Portal.Shared/Models/v1.0/Filters/DeviceModelFilter.cs diff --git a/src/AzureIoTHub.Portal.Application/Services/IDeviceModelService.cs b/src/AzureIoTHub.Portal.Application/Services/IDeviceModelService.cs index 13f6a3f96..bb8366c03 100644 --- a/src/AzureIoTHub.Portal.Application/Services/IDeviceModelService.cs +++ b/src/AzureIoTHub.Portal.Application/Services/IDeviceModelService.cs @@ -3,16 +3,18 @@ namespace AzureIoTHub.Portal.Application.Services { - using System.Collections.Generic; using System.Threading.Tasks; + using AzureIoTHub.Portal.Models.v10; using AzureIoTHub.Portal.Shared.Models; + using AzureIoTHub.Portal.Shared.Models.v1._0; + using AzureIoTHub.Portal.Shared.Models.v10.Filters; using Microsoft.AspNetCore.Http; public interface IDeviceModelService where TListItem : class, IDeviceModel where TModel : class, IDeviceModel { - Task> GetDeviceModels(); + Task> GetDeviceModels(DeviceModelFilter deviceModelFilter); Task GetDeviceModel(string deviceModelId); diff --git a/src/AzureIoTHub.Portal.Client/Components/DeviceModels/DeviceModelSearch.razor b/src/AzureIoTHub.Portal.Client/Components/DeviceModels/DeviceModelSearch.razor new file mode 100644 index 000000000..255ba1d97 --- /dev/null +++ b/src/AzureIoTHub.Portal.Client/Components/DeviceModels/DeviceModelSearch.razor @@ -0,0 +1,39 @@ + + + + + + + + + Search + Reset + + + + + + + +@code { + [Parameter] + public EventCallback OnSearch { get; set; } + + private string? searchText = string.Empty; + + private async Task Search() + { + var searchInfo = new DeviceModelSearchInfo + { + SearchText = searchText + }; + await OnSearch.InvokeAsync(searchInfo); + } + + private async Task Reset() + { + searchText = string.Empty; + + await Search(); + } +} diff --git a/src/AzureIoTHub.Portal.Client/Models/DeviceModelSearchInfo.cs b/src/AzureIoTHub.Portal.Client/Models/DeviceModelSearchInfo.cs new file mode 100644 index 000000000..8d42cfd2c --- /dev/null +++ b/src/AzureIoTHub.Portal.Client/Models/DeviceModelSearchInfo.cs @@ -0,0 +1,10 @@ +// 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.Client.Models +{ + public class DeviceModelSearchInfo + { + public string? SearchText { get; set; } + } +} diff --git a/src/AzureIoTHub.Portal.Client/Pages/DeviceConfigurations/CreateDeviceConfigurationsPage.razor b/src/AzureIoTHub.Portal.Client/Pages/DeviceConfigurations/CreateDeviceConfigurationsPage.razor index 6eebbd63f..b3002cbf2 100644 --- a/src/AzureIoTHub.Portal.Client/Pages/DeviceConfigurations/CreateDeviceConfigurationsPage.razor +++ b/src/AzureIoTHub.Portal.Client/Pages/DeviceConfigurations/CreateDeviceConfigurationsPage.razor @@ -243,7 +243,8 @@ isProcessing = true; var models = await DeviceModelsClientService.GetDeviceModels(); - AvailableModels = models.Where(c => !c.SupportLoRaFeatures).ToArray(); + + AvailableModels = models.Items.Where(c => !c.SupportLoRaFeatures).ToArray(); AvailableTags = await DeviceTagSettingsClientService.GetDeviceTags(); } diff --git a/src/AzureIoTHub.Portal.Client/Pages/DeviceModels/DeviceModelListPage.razor b/src/AzureIoTHub.Portal.Client/Pages/DeviceModels/DeviceModelListPage.razor index d77b406f8..03c8fd786 100644 --- a/src/AzureIoTHub.Portal.Client/Pages/DeviceModels/DeviceModelListPage.razor +++ b/src/AzureIoTHub.Portal.Client/Pages/DeviceModels/DeviceModelListPage.razor @@ -1,5 +1,6 @@ @page "/device-models" @using AzureIoTHub.Portal.Models.v10 +@using AzureIoTHub.Portal.Shared.Models.v10.Filters; @attribute [Authorize] @inject NavigationManager navigationManager @@ -9,7 +10,10 @@ - + await Search(args)) /> + + + @@ -21,7 +25,7 @@ Device Models - + @@ -63,7 +67,7 @@ - + No matching records found @@ -80,15 +84,20 @@ [CascadingParameter] public Error Error { get; set; } - private int[] pageSizeOptions = new int[] { 2, 5, 10 }; - private List result = new(); + private MudTable table; + + private readonly Dictionary pages = new(); + + //private List DeviceModelList = new List(); + private bool IsLoading = true; - protected override async Task OnInitializedAsync() - { - await LoadDeviceModels(); - IsLoading = false; - } + private DeviceModelSearchInfo deviceModelSearchInfo = new(); + + //protected override async Task OnInitializedAsync() + //{ + // table.ReloadServerData(); + //} private void AddDeviceModel() { @@ -99,16 +108,46 @@ /// Sends a GET request to the DeviceModelsController, to retrieve all device models from the database /// /// - private async Task LoadDeviceModels() + private async Task> LoadDeviceModels(TableState state) { try { - result.Clear(); - result.AddRange(await DeviceModelsClientService.GetDeviceModels()); + IsLoading = true; + + string orderBy = null; + + switch (state.SortDirection) + { + case SortDirection.Ascending: + orderBy = $"{state.SortLabel} asc"; + break; + case SortDirection.Descending: + orderBy = $"{state.SortLabel} desc"; + break; + } + + var result = await DeviceModelsClientService.GetDeviceModels(new DeviceModelFilter + { + SearchText = this.deviceModelSearchInfo.SearchText, + PageNumber = state.Page, + PageSize = state.PageSize, + OrderBy = new string[] { orderBy } + }); + + return new TableData + { + Items = result.Items, + TotalItems = result.TotalItems + }; } catch (ProblemDetailsException exception) { Error?.ProcessProblemDetails(exception); + return new TableData(); + } + finally + { + IsLoading = false; } } @@ -125,11 +164,31 @@ } // Update the list of devices after the deletion - await LoadDeviceModels(); + // await LoadDeviceModels(); + await Search(); } private void GoToDetails(DeviceModelDto item) { navigationManager.NavigateTo($"/device-models/{item.ModelId}{((item.SupportLoRaFeatures && Portal.IsLoRaSupported) ? "?isLora=true" : "")}"); } + + private async Task Search(DeviceModelSearchInfo deviceModelSearchInfo = null) + { + if (deviceModelSearchInfo == null) + { + this.deviceModelSearchInfo = new(); + } + else + { + this.deviceModelSearchInfo = deviceModelSearchInfo; + } + + await table.ReloadServerData(); + } + + private async void Refresh() + { + await table.ReloadServerData(); + } } diff --git a/src/AzureIoTHub.Portal.Client/Pages/Devices/CreateDevicePage.razor b/src/AzureIoTHub.Portal.Client/Pages/Devices/CreateDevicePage.razor index fda5e70be..2df4a52f7 100644 --- a/src/AzureIoTHub.Portal.Client/Pages/Devices/CreateDevicePage.razor +++ b/src/AzureIoTHub.Portal.Client/Pages/Devices/CreateDevicePage.razor @@ -317,7 +317,8 @@ Device.IsEnabled = true; // Gets a list of device model previously registered to Azure to allow autocomplete field in the form - DeviceModelList = await DeviceModelsClientService.GetDeviceModels(); + var result = await DeviceModelsClientService.GetDeviceModels(); + DeviceModelList = result.Items.ToList(); // Gets the custom tags that can be set when creating a device TagList = await DeviceTagSettingsClientService.GetDeviceTags(); diff --git a/src/AzureIoTHub.Portal.Client/Pages/Devices/DeviceListPage.razor b/src/AzureIoTHub.Portal.Client/Pages/Devices/DeviceListPage.razor index b0967c365..861145994 100644 --- a/src/AzureIoTHub.Portal.Client/Pages/Devices/DeviceListPage.razor +++ b/src/AzureIoTHub.Portal.Client/Pages/Devices/DeviceListPage.razor @@ -286,7 +286,7 @@ { try { - this.ModelList = (await DeviceModelsClientService.GetDeviceModels()).ToList(); + this.ModelList = (await DeviceModelsClientService.GetDeviceModels()).Items.ToList(); // Gets the custom tags that can be searched via the panel TagList = await DeviceTagSettingsClientService.GetDeviceTags(); foreach (var tag in TagList) diff --git a/src/AzureIoTHub.Portal.Client/Services/DeviceModelsClientService.cs b/src/AzureIoTHub.Portal.Client/Services/DeviceModelsClientService.cs index 10ef6db79..e5d26f69b 100644 --- a/src/AzureIoTHub.Portal.Client/Services/DeviceModelsClientService.cs +++ b/src/AzureIoTHub.Portal.Client/Services/DeviceModelsClientService.cs @@ -7,20 +7,33 @@ namespace AzureIoTHub.Portal.Client.Services using System.Net.Http; using System.Net.Http.Json; using System.Threading.Tasks; + using AzureIoTHub.Portal.Shared.Models.v10.Filters; + using Microsoft.AspNetCore.WebUtilities; using Portal.Models.v10; public class DeviceModelsClientService : IDeviceModelsClientService { private readonly HttpClient http; + private readonly string apiUrlBase = "api/models"; public DeviceModelsClientService(HttpClient http) { this.http = http; } - public async Task> GetDeviceModels() + public async Task> GetDeviceModels(DeviceModelFilter? deviceModelFilter = null) { - return await this.http.GetFromJsonAsync>("api/models"); + var query = new Dictionary + { + { nameof(DeviceModelFilter.SearchText), deviceModelFilter?.SearchText ?? string.Empty }, + { nameof(DeviceModelFilter.PageNumber), deviceModelFilter?.PageNumber.ToString() ?? string.Empty }, + { nameof(DeviceModelFilter.PageSize), deviceModelFilter?.PageSize.ToString() ?? string.Empty }, + { nameof(DeviceModelFilter.OrderBy), deviceModelFilter?.OrderBy.ToString() ?? string.Empty } + }; + + var uri = QueryHelpers.AddQueryString(this.apiUrlBase, query); + + return await this.http.GetFromJsonAsync>(uri); } public Task GetDeviceModel(string deviceModelId) diff --git a/src/AzureIoTHub.Portal.Client/Services/IDeviceModelsClientService.cs b/src/AzureIoTHub.Portal.Client/Services/IDeviceModelsClientService.cs index 939242b3f..cf67142ae 100644 --- a/src/AzureIoTHub.Portal.Client/Services/IDeviceModelsClientService.cs +++ b/src/AzureIoTHub.Portal.Client/Services/IDeviceModelsClientService.cs @@ -6,11 +6,12 @@ namespace AzureIoTHub.Portal.Client.Services using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; + using AzureIoTHub.Portal.Shared.Models.v10.Filters; using Portal.Models.v10; public interface IDeviceModelsClientService { - Task> GetDeviceModels(); + Task> GetDeviceModels(DeviceModelFilter? deviceModelFilter = null); Task GetDeviceModel(string deviceModelId); diff --git a/src/AzureIoTHub.Portal.Server/Controllers/v1.0/DeviceModelControllerBase.cs b/src/AzureIoTHub.Portal.Server/Controllers/v1.0/DeviceModelControllerBase.cs index a90b2e2ec..aff1542df 100644 --- a/src/AzureIoTHub.Portal.Server/Controllers/v1.0/DeviceModelControllerBase.cs +++ b/src/AzureIoTHub.Portal.Server/Controllers/v1.0/DeviceModelControllerBase.cs @@ -6,9 +6,13 @@ namespace AzureIoTHub.Portal.Server.Controllers.V10 using System.Collections.Generic; using System.Threading.Tasks; using AzureIoTHub.Portal.Application.Services; + using AzureIoTHub.Portal.Models.v10; using AzureIoTHub.Portal.Shared.Models; + using AzureIoTHub.Portal.Shared.Models.v1._0; + using AzureIoTHub.Portal.Shared.Models.v10.Filters; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Routing; public abstract class DeviceModelsControllerBase : ControllerBase where TListItemModel : class, IDeviceModel @@ -36,9 +40,33 @@ protected DeviceModelsControllerBase(IDeviceModelService /// Gets the device models. /// /// The list of device models. - public virtual async Task>> GetItems() + public virtual async Task>> GetItems(DeviceModelFilter deviceModelFilter) { - return Ok(await this.deviceModelService.GetDeviceModels()); + var paginatedDevices = await this.deviceModelService.GetDeviceModels(deviceModelFilter); + + var nextPage = string.Empty; + + if (paginatedDevices.HasNextPage) + { + nextPage = Url.RouteUrl(new UrlRouteContext + { + RouteName = "GET Device Model list", + Values = new + { + deviceModelFilter.SearchText, + deviceModelFilter.PageSize, + pageNumber = deviceModelFilter.PageNumber + 1, + deviceModelFilter.OrderBy + } + }); + } + + return new PaginationResult + { + Items = paginatedDevices.Data, + TotalItems = paginatedDevices.TotalCount, + NextPage = nextPage + }; } /// diff --git a/src/AzureIoTHub.Portal.Server/Controllers/v1.0/DeviceModelsController.cs b/src/AzureIoTHub.Portal.Server/Controllers/v1.0/DeviceModelsController.cs index ade0b676c..31b696ce3 100644 --- a/src/AzureIoTHub.Portal.Server/Controllers/v1.0/DeviceModelsController.cs +++ b/src/AzureIoTHub.Portal.Server/Controllers/v1.0/DeviceModelsController.cs @@ -3,13 +3,13 @@ namespace AzureIoTHub.Portal.Server.Controllers.V10 { - using System.Collections.Generic; using System.Threading.Tasks; using AzureIoTHub.Portal.Models.v10; using AzureIoTHub.Portal.Application.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; + using AzureIoTHub.Portal.Shared.Models.v10.Filters; [Authorize] [ApiController] @@ -33,9 +33,9 @@ public DeviceModelsController(IDeviceModelServiceAn array representing the device models. [HttpGet(Name = "GET Device model list")] [ProducesResponseType(StatusCodes.Status200OK)] - public override Task>> GetItems() + public override async Task>> GetItems([FromQuery] DeviceModelFilter deviceModelFilter) { - return base.GetItems(); + return await base.GetItems(deviceModelFilter); } /// diff --git a/src/AzureIoTHub.Portal.Server/Controllers/v1.0/LoRaWAN/LoRaWANDeviceModelsController.cs b/src/AzureIoTHub.Portal.Server/Controllers/v1.0/LoRaWAN/LoRaWANDeviceModelsController.cs index aefc83c0c..c0c0d21dc 100644 --- a/src/AzureIoTHub.Portal.Server/Controllers/v1.0/LoRaWAN/LoRaWANDeviceModelsController.cs +++ b/src/AzureIoTHub.Portal.Server/Controllers/v1.0/LoRaWAN/LoRaWANDeviceModelsController.cs @@ -4,11 +4,11 @@ namespace AzureIoTHub.Portal.Server.Controllers.V10.LoRaWAN { using System.Collections.Generic; - using System.Linq; using System.Threading.Tasks; using AzureIoTHub.Portal.Application.Services; using AzureIoTHub.Portal.Models.v10; using AzureIoTHub.Portal.Models.v10.LoRaWAN; + using AzureIoTHub.Portal.Shared.Models.v10.Filters; using Filters; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -40,10 +40,20 @@ public LoRaWANDeviceModelsController(IDeviceModelServiceAn array representing the device models. [HttpGet(Name = "GET LoRaWAN device model list")] [ProducesResponseType(StatusCodes.Status200OK)] - public override async Task>> GetItems() + public override async Task>> GetItems([FromQuery] DeviceModelFilter deviceModelFilter) { - var devices = await this.deviceModelService.GetDeviceModels(); - return Ok(devices.Where(device => device.SupportLoRaFeatures)); + var devices = await this.deviceModelService.GetDeviceModels(deviceModelFilter); + + var lorawamDevices = new List(); + foreach (var device in devices.Data) + { + if (device.SupportLoRaFeatures) + { + lorawamDevices.Add(device); + } + } + + return Ok(lorawamDevices); } /// diff --git a/src/AzureIoTHub.Portal.Server/Services/DeviceModelService.cs b/src/AzureIoTHub.Portal.Server/Services/DeviceModelService.cs index 5f5380d97..b051fdfa9 100644 --- a/src/AzureIoTHub.Portal.Server/Services/DeviceModelService.cs +++ b/src/AzureIoTHub.Portal.Server/Services/DeviceModelService.cs @@ -4,8 +4,9 @@ namespace AzureIoTHub.Portal.Server.Services { using System; - using System.Collections.Generic; using System.Linq; + using System.Linq.Dynamic.Core; + using System.Linq.Expressions; using System.Threading.Tasks; using AutoMapper; using AzureIoTHub.Portal.Application.Helpers; @@ -13,13 +14,18 @@ namespace AzureIoTHub.Portal.Server.Services using AzureIoTHub.Portal.Application.Providers; using AzureIoTHub.Portal.Application.Services; using AzureIoTHub.Portal.Infrastructure.Mappers; + using AzureIoTHub.Portal.Infrastructure.Repositories; + using AzureIoTHub.Portal.Models.v10; using AzureIoTHub.Portal.Shared.Models; + using AzureIoTHub.Portal.Shared.Models.v1._0; + using AzureIoTHub.Portal.Shared.Models.v10.Filters; using Domain; using Domain.Entities; using Domain.Exceptions; using Domain.Repositories; using Microsoft.AspNetCore.Http; using Microsoft.Azure.Devices.Shared; + using Microsoft.EntityFrameworkCore; public class DeviceModelService : IDeviceModelService where TListItem : class, IDeviceModel @@ -60,17 +66,29 @@ public DeviceModelService(IMapper mapper, this.externalDeviceService = externalDeviceService; } - public async Task> GetDeviceModels() + public async Task> GetDeviceModels(DeviceModelFilter deviceModelFilter) { - return await Task.Run(() => this.deviceModelRepository - .GetAll(c => c.Labels) - .Select(model => + var deviceModelPredicate = PredicateBuilder.True(); + + if (!string.IsNullOrWhiteSpace(deviceModelFilter.SearchText)) + { + deviceModelPredicate = deviceModelPredicate.And(model => model.Name.ToLower().Contains(deviceModelFilter.SearchText.ToLower()) || model.Description.ToLower().Contains(deviceModelFilter.SearchText.ToLower())); + } + + var paginatedDeviceModels = await this.deviceModelRepository.GetPaginatedListAsync(deviceModelFilter.PageNumber, deviceModelFilter.PageSize, deviceModelFilter.OrderBy, deviceModelPredicate, includes: new Expression>[] { d => d.Labels }); + + var paginateDeviceModelsDto = new PaginatedResult + { + Data = paginatedDeviceModels.Data.Select(x => this.mapper.Map(x, opts => { - var deviceModelDto = this.mapper.Map(model); - deviceModelDto.ImageUrl = this.deviceModelImageManager.ComputeImageUri(deviceModelDto.ModelId); - return deviceModelDto; - }) - .ToList()); + opts.AfterMap((src, dest) => dest.ImageUrl = this.deviceModelImageManager.ComputeImageUri(x.Id)); + })).ToList(), + TotalCount = paginatedDeviceModels.TotalCount, + CurrentPage = paginatedDeviceModels.CurrentPage, + PageSize = deviceModelFilter.PageSize + }; + + return new PaginatedResult(paginateDeviceModelsDto.Data, paginateDeviceModelsDto.TotalCount); } public async Task GetDeviceModel(string deviceModelId) diff --git a/src/AzureIoTHub.Portal.Shared/Models/v1.0/Filters/DeviceModelFilter.cs b/src/AzureIoTHub.Portal.Shared/Models/v1.0/Filters/DeviceModelFilter.cs new file mode 100644 index 000000000..847457751 --- /dev/null +++ b/src/AzureIoTHub.Portal.Shared/Models/v1.0/Filters/DeviceModelFilter.cs @@ -0,0 +1,11 @@ +// 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.Shared.Models.v10.Filters +{ + + public class DeviceModelFilter : PaginationFilter + { + public string SearchText { get; set; } + } +} diff --git a/src/AzureIoTHub.Portal.sln b/src/AzureIoTHub.Portal.sln index e21414688..5a0decd51 100644 --- a/src/AzureIoTHub.Portal.sln +++ b/src/AzureIoTHub.Portal.sln @@ -1,4 +1,3 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.1.31911.260 @@ -69,9 +68,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureIoTHub.Portal.Applicat EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureIoTHub.Portal.Crosscutting", "AzureIoTHub.Portal.Crosscutting\AzureIoTHub.Portal.Crosscutting.csproj", "{3523EAFD-81F3-4FC3-BC49-65D3ECE94E4D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureIoTHub.Portal.MySql", "AzureIoTHub.Portal.MySql\AzureIoTHub.Portal.MySql.csproj", "{6F4A8F36-51C5-405C-B701-F3DC7A7B8436}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureIoTHub.Portal.MySql", "AzureIoTHub.Portal.MySql\AzureIoTHub.Portal.MySql.csproj", "{6F4A8F36-51C5-405C-B701-F3DC7A7B8436}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureIoTHub.Portal.Postgres", "AzureIoTHub.Portal.Postgres\AzureIoTHub.Portal.Postgres.csproj", "{3195668B-D3D9-4E5A-894C-A56C9F913E99}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureIoTHub.Portal.Postgres", "AzureIoTHub.Portal.Postgres\AzureIoTHub.Portal.Postgres.csproj", "{3195668B-D3D9-4E5A-894C-A56C9F913E99}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From 9b36c677b352670ba8f2f96332be0d6dfd5b3f81 Mon Sep 17 00:00:00 2001 From: GuillaumeM Date: Mon, 20 Feb 2023 09:11:01 +0100 Subject: [PATCH 02/11] enable sort on device models --- .../Services/DeviceModelsClientService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AzureIoTHub.Portal.Client/Services/DeviceModelsClientService.cs b/src/AzureIoTHub.Portal.Client/Services/DeviceModelsClientService.cs index e5d26f69b..2d3960bc9 100644 --- a/src/AzureIoTHub.Portal.Client/Services/DeviceModelsClientService.cs +++ b/src/AzureIoTHub.Portal.Client/Services/DeviceModelsClientService.cs @@ -28,7 +28,7 @@ public async Task> GetDeviceModels(DeviceModelF { nameof(DeviceModelFilter.SearchText), deviceModelFilter?.SearchText ?? string.Empty }, { nameof(DeviceModelFilter.PageNumber), deviceModelFilter?.PageNumber.ToString() ?? string.Empty }, { nameof(DeviceModelFilter.PageSize), deviceModelFilter?.PageSize.ToString() ?? string.Empty }, - { nameof(DeviceModelFilter.OrderBy), deviceModelFilter?.OrderBy.ToString() ?? string.Empty } + { nameof(DeviceModelFilter.OrderBy), string.Join(",", deviceModelFilter?.OrderBy) ?? string.Empty } }; var uri = QueryHelpers.AddQueryString(this.apiUrlBase, query); From 520e7b40722c4f605620ca28a28152e8e56d4122 Mon Sep 17 00:00:00 2001 From: GuillaumeM Date: Mon, 20 Feb 2023 09:51:16 +0100 Subject: [PATCH 03/11] update sort on device models --- .../Services/DeviceModelsClientService.cs | 2 +- .../Controllers/v1.0/DeviceModelControllerBase.cs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/AzureIoTHub.Portal.Client/Services/DeviceModelsClientService.cs b/src/AzureIoTHub.Portal.Client/Services/DeviceModelsClientService.cs index 2d3960bc9..4005ce7ff 100644 --- a/src/AzureIoTHub.Portal.Client/Services/DeviceModelsClientService.cs +++ b/src/AzureIoTHub.Portal.Client/Services/DeviceModelsClientService.cs @@ -28,7 +28,7 @@ public async Task> GetDeviceModels(DeviceModelF { nameof(DeviceModelFilter.SearchText), deviceModelFilter?.SearchText ?? string.Empty }, { nameof(DeviceModelFilter.PageNumber), deviceModelFilter?.PageNumber.ToString() ?? string.Empty }, { nameof(DeviceModelFilter.PageSize), deviceModelFilter?.PageSize.ToString() ?? string.Empty }, - { nameof(DeviceModelFilter.OrderBy), string.Join(",", deviceModelFilter?.OrderBy) ?? string.Empty } + { nameof(DeviceModelFilter.OrderBy), string.Join("", deviceModelFilter?.OrderBy) ?? string.Empty } }; var uri = QueryHelpers.AddQueryString(this.apiUrlBase, query); diff --git a/src/AzureIoTHub.Portal.Server/Controllers/v1.0/DeviceModelControllerBase.cs b/src/AzureIoTHub.Portal.Server/Controllers/v1.0/DeviceModelControllerBase.cs index aff1542df..4fb4baafd 100644 --- a/src/AzureIoTHub.Portal.Server/Controllers/v1.0/DeviceModelControllerBase.cs +++ b/src/AzureIoTHub.Portal.Server/Controllers/v1.0/DeviceModelControllerBase.cs @@ -3,12 +3,10 @@ namespace AzureIoTHub.Portal.Server.Controllers.V10 { - using System.Collections.Generic; using System.Threading.Tasks; using AzureIoTHub.Portal.Application.Services; using AzureIoTHub.Portal.Models.v10; using AzureIoTHub.Portal.Shared.Models; - using AzureIoTHub.Portal.Shared.Models.v1._0; using AzureIoTHub.Portal.Shared.Models.v10.Filters; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; From a779b60306018a921dba6d86ba1b2f1208d27b5f Mon Sep 17 00:00:00 2001 From: GuillaumeM Date: Wed, 22 Feb 2023 09:27:50 +0100 Subject: [PATCH 04/11] update unit tests --- .../Services/DeviceModelService.cs | 2 +- .../CreateDeviceConfigurationsPageTests.cs | 35 ++--- .../Pages/Devices/CreateDevicePageTests.cs | 52 +++++--- .../Pages/Devices/DevicesListPageTests.cs | 123 +++++++++++++----- .../DevicesModels/DeviceModelListPageTests.cs | 39 +++--- .../DeviceModelsClientServiceTests.cs | 21 ++- .../v1.0/DeviceModelsControllerTests.cs | 10 +- .../LoRaWANDeviceModelsControllerTest.cs | 10 +- .../Services/DeviceModelServiceTests.cs | 31 ++++- 9 files changed, 220 insertions(+), 103 deletions(-) diff --git a/src/AzureIoTHub.Portal.Server/Services/DeviceModelService.cs b/src/AzureIoTHub.Portal.Server/Services/DeviceModelService.cs index b051fdfa9..39f43cfb5 100644 --- a/src/AzureIoTHub.Portal.Server/Services/DeviceModelService.cs +++ b/src/AzureIoTHub.Portal.Server/Services/DeviceModelService.cs @@ -88,7 +88,7 @@ public async Task> GetDeviceModels(DeviceModelFi PageSize = deviceModelFilter.PageSize }; - return new PaginatedResult(paginateDeviceModelsDto.Data, paginateDeviceModelsDto.TotalCount); + return new PaginatedResult(paginateDeviceModelsDto.Data, paginateDeviceModelsDto.TotalCount, paginateDeviceModelsDto.CurrentPage, paginateDeviceModelsDto.PageSize); } public async Task GetDeviceModel(string deviceModelId) diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DeviceConfigurations/CreateDeviceConfigurationsPageTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DeviceConfigurations/CreateDeviceConfigurationsPageTests.cs index 3ceecb2bb..73701d3db 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DeviceConfigurations/CreateDeviceConfigurationsPageTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DeviceConfigurations/CreateDeviceConfigurationsPageTests.cs @@ -21,6 +21,7 @@ namespace AzureIoTHub.Portal.Tests.Unit.Client.Pages.DeviceConfigurations using MudBlazor; using NUnit.Framework; using RichardSzalay.MockHttp; + using AzureIoTHub.Portal.Shared.Models.v10.Filters; [TestFixture] public class CreateDeviceConfigurationsPageTests : BlazorUnitTest @@ -49,10 +50,9 @@ public override void Setup() public void DeviceConfigurationDetailPageShouldRenderCorrectly() { // Arrange - _ = this.mockDeviceModelsClientService.Setup(service => - service.GetDeviceModels()) - .ReturnsAsync(new List()); + service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult { Items = new List() }); _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) @@ -79,8 +79,8 @@ public void DeviceConfigurationDetailShouldCreateConfiguration() }; _ = this.mockDeviceModelsClientService.Setup(service => - service.GetDeviceModels()) - .ReturnsAsync(new List()); + service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult { Items = new List() }); _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) @@ -115,8 +115,8 @@ public void DeviceConfigurationDetailShouldProcessProblemDetailsExceptionWhenIss }; _ = this.mockDeviceModelsClientService.Setup(service => - service.GetDeviceModels()) - .ReturnsAsync(new List()); + service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult { Items = new List() }); _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) @@ -142,7 +142,7 @@ public void DeviceConfigurationDetailPageShouldProcessProblemDetailsExceptionWhe { // Arrange _ = this.mockDeviceModelsClientService.Setup(service => - service.GetDeviceModels()) + service.GetDeviceModels(It.IsAny())) .ThrowsAsync(new ProblemDetailsException(new ProblemDetailsWithExceptionDetails())); // Act @@ -157,8 +157,8 @@ public void DeviceConfigurationDetailPageShouldProcessProblemDetailsExceptionWhe { // Arrange _ = this.mockDeviceModelsClientService.Setup(service => - service.GetDeviceModels()) - .ReturnsAsync(new List()); + service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult { Items = new List() }); _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) @@ -176,8 +176,8 @@ public void WhenClickToDeleteTagShouldRemoveTheSelectedTag() { // Arrange _ = this.mockDeviceModelsClientService.Setup(service => - service.GetDeviceModels()) - .ReturnsAsync(new List()); + service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult { Items = new List() }); _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) @@ -212,15 +212,8 @@ public void WhenClickToAddTagShouldAddTheSelectedTag() var modelId = Guid.NewGuid().ToString(); _ = this.mockDeviceModelsClientService.Setup(service => - service.GetDeviceModels()) - .ReturnsAsync(new List - { - new () - { - ModelId = modelId, - Name = Guid.NewGuid().ToString() - } - }); + service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult { Items = new[] { new DeviceModelDto { ModelId = modelId, Name = Guid.NewGuid().ToString() } } }); _ = MockHttpClient .When(HttpMethod.Get, $"/api/models/{modelId}/properties") diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/Devices/CreateDevicePageTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/Devices/CreateDevicePageTests.cs index 5be3f94e8..adde5602f 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/Devices/CreateDevicePageTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/Devices/CreateDevicePageTests.cs @@ -21,6 +21,7 @@ namespace AzureIoTHub.Portal.Tests.Unit.Client.Pages.Devices using MudBlazor.Services; using NUnit.Framework; using UnitTests.Mocks; + using AzureIoTHub.Portal.Shared.Models.v10.Filters; [TestFixture] public class CreateDevicePageTests : BlazorUnitTest @@ -80,10 +81,13 @@ public async Task ClickOnSaveShouldPostDeviceDetailsAsync() _ = this.mockDeviceClientService.Setup(service => service.CreateDevice(It.Is(details => expectedDeviceDetails.DeviceID.Equals(details.DeviceID, StringComparison.Ordinal)))) .Returns(Task.CompletedTask); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List { mockDeviceModel + } }); _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) @@ -132,10 +136,13 @@ public async Task DeviceShouldNotBeCreatedWhenModelIsNotValid() Name = Guid.NewGuid().ToString() }; - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List { mockDeviceModel + } }); _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) @@ -179,10 +186,13 @@ public void OnInitializedAsyncShouldProcessProblemDetailsExceptionWhenIssueOccur Name = Guid.NewGuid().ToString() }; - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List { mockDeviceModel + } }); _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) @@ -199,7 +209,7 @@ public void OnInitializedAsyncShouldProcessProblemDetailsExceptionWhenIssueOccur [Test] public void OnInitializedAsyncShouldProcessProblemDetailsExceptionWhenIssueOccursOnGettingDeviceModels() { - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) .ThrowsAsync(new ProblemDetailsException(new ProblemDetailsWithExceptionDetails())); // Act @@ -231,10 +241,13 @@ public async Task SaveShouldProcessProblemDetailsExceptionWhenIssueOccursOnCreat _ = this.mockDeviceClientService.Setup(service => service.CreateDevice(It.Is(details => expectedDeviceDetails.DeviceID.Equals(details.DeviceID, StringComparison.Ordinal)))) .ThrowsAsync(new ProblemDetailsException(new ProblemDetailsWithExceptionDetails())); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List { mockDeviceModel + } }); _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) @@ -286,10 +299,13 @@ public async Task ChangeModelShouldProcessProblemDetailsExceptionWhenIssueOccurs DeviceID = Guid.NewGuid().ToString(), }; - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List { mockDeviceModel + } }); _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) @@ -340,10 +356,13 @@ public async Task ClickOnSaveAndAddNewShouldCreateDeviceAndResetCreateDevicePage _ = this.mockDeviceClientService.Setup(service => service.CreateDevice(It.Is(details => expectedDeviceDetails.DeviceID.Equals(details.DeviceID, StringComparison.Ordinal)))) .Returns(Task.CompletedTask); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List { mockDeviceModel + } }); _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) @@ -416,10 +435,13 @@ public async Task ClickOnSaveAndDuplicateShouldCreateDeviceAndDuplicateDeviceDet _ = this.mockDeviceClientService.Setup(service => service.CreateDevice(It.Is(details => expectedDeviceDetails.DeviceID.Equals(details.DeviceID, StringComparison.Ordinal)))) .Returns(Task.CompletedTask); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List { mockDeviceModel + } }); _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/Devices/DevicesListPageTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/Devices/DevicesListPageTests.cs index 787382cf1..62556d1e7 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/Devices/DevicesListPageTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/Devices/DevicesListPageTests.cs @@ -24,6 +24,7 @@ namespace AzureIoTHub.Portal.Tests.Unit.Client.Pages.Devices using UnitTests.Bases; using AutoFixture; using Microsoft.AspNetCore.Components.Forms; + using AzureIoTHub.Portal.Shared.Models.v10.Filters; [TestFixture] public class DevicesListPageTests : BlazorUnitTest @@ -60,8 +61,11 @@ public void DeviceListPageRendersCorrectly() _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) .ReturnsAsync(new List()); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List()); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); _ = this.mockDeviceClientService.Setup(service => service.GetAvailableLabels()) .ReturnsAsync(Array.Empty()); @@ -105,8 +109,11 @@ public async Task WhenResetFilterButtonClickShouldClearFilters() _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) .ReturnsAsync(new List()); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List()); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); // Act @@ -143,8 +150,11 @@ public void WhenAddNewDeviceClickShouldNavigateToNewDevicePage() _ = this.mockDeviceClientService.Setup(service => service.GetAvailableLabels()) .ReturnsAsync(Array.Empty()); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List()); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); _ = Services.AddSingleton(new PortalSettings { IsLoRaSupported = true }); @@ -183,8 +193,11 @@ public void ClickOnRefreshShouldReloadDevices() _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) .ReturnsAsync(new List()); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List()); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); var cut = RenderComponent(); @@ -216,8 +229,11 @@ public void WhenLoraFeatureDisableClickToItemShouldRedirectToDeviceDetailsPage() _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) .ReturnsAsync(new List()); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List()); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); var cut = RenderComponent(); cut.WaitForAssertion(() => cut.Markup.Should().NotContain("Loading...")); @@ -250,8 +266,11 @@ public void WhenLoraFeatureEnableClickToItemShouldRedirectToLoRaDeviceDetailsPag _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) .ReturnsAsync(new List()); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List()); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); var cut = RenderComponent(); cut.WaitForAssertion(() => cut.Markup.Should().NotContain("Loading...")); @@ -279,8 +298,11 @@ public void OnInitializedAsyncShouldProcessProblemDetailsExceptionWhenIssueOccur _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) .ThrowsAsync(new ProblemDetailsException(new ProblemDetailsWithExceptionDetails())); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List()); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); // Act var cut = RenderComponent(); @@ -307,8 +329,12 @@ public void LoadItemsShouldProcessProblemDetailsExceptionWhenIssueOccursOnGettin _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) .ReturnsAsync(new List()); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List()); + + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); // Act var cut = RenderComponent(); @@ -348,19 +374,20 @@ public async Task TypingSomeCharactersInTheAutocompleteShouldFilterTheDeviceMode _ = this.mockDeviceClientService.Setup(service => service.GetAvailableLabels()) .ReturnsAsync(Array.Empty()); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List() + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult { - new DeviceModelDto() + Items = new List { new DeviceModelDto { Name = "model_01", Description = Guid.NewGuid().ToString(), }, - new DeviceModelDto() + new DeviceModelDto { Name = "model_02", Description = Guid.NewGuid().ToString(), }, + } }); // Act @@ -400,8 +427,11 @@ public void ShowDeviceTelemetry_Clicked_LoRaDeviceTelemetryDialogIsShown() _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) .ReturnsAsync(new List()); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List()); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); var mockDialogReference = MockRepository.Create(); _ = mockDialogReference.Setup(c => c.Result).ReturnsAsync(DialogResult.Ok("Ok")); @@ -439,8 +469,11 @@ public void DeleteDevice_Clicked_DeleteDeviceDialogIsShown() _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) .ReturnsAsync(new List()); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List()); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); var mockDialogReference = MockRepository.Create(); _ = mockDialogReference.Setup(c => c.Result).ReturnsAsync(DialogResult.Ok("Ok")); @@ -478,8 +511,11 @@ public async Task ExportDevicesClickedShouldDownloadTheFile() _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) .ReturnsAsync(new List()); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List()); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); var popoverProvider = RenderComponent(); var cut = RenderComponent(); @@ -518,8 +554,11 @@ public async Task ExportTemplateClickedShouldDownloadTheFile() _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) .ReturnsAsync(new List()); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List()); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); var popoverProvider = RenderComponent(); var cut = RenderComponent(); @@ -561,8 +600,11 @@ public void SearchDeviceModels_InputExisingDeviceModelName_DeviceModelReturned() _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) .ReturnsAsync(new List()); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(deviceModels); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = deviceModels + }); var popoverProvider = RenderComponent(); @@ -609,8 +651,11 @@ public async Task ImportDevices_FileAdded_DevicesExported() _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) .ReturnsAsync(new List()); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List()); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); _ = this.mockDeviceClientService.Setup(service => service.GetAvailableLabels()) .ReturnsAsync(Array.Empty()); @@ -661,8 +706,11 @@ public void Sort_ClickOnSortIdAsc_DevicesSorted() _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) .ReturnsAsync(new List()); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List()); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); var cut = RenderComponent(); @@ -704,8 +752,11 @@ public void Sort_ClickOnSortIdDesc_DevicesSorted() _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) .ReturnsAsync(new List()); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new List()); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); var cut = RenderComponent(); diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs index 797b13cd8..4c665805d 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs @@ -19,6 +19,7 @@ namespace AzureIoTHub.Portal.Tests.Unit.Client.Pages.DevicesModels using Moq; using MudBlazor; using NUnit.Framework; + using AzureIoTHub.Portal.Shared.Models.v10.Filters; [TestFixture] public class DeviceModelListPageTests : BlazorUnitTest @@ -43,8 +44,8 @@ public void WhenLoraFeatureDisableClickToItemShouldRedirectToDeviceDetailsPage() // Arrange var modelId = Fixture.Create(); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new[] { new DeviceModelDto { ModelId = modelId, SupportLoRaFeatures = false } }); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult { Items = new[] { new DeviceModelDto { ModelId = modelId, SupportLoRaFeatures = false } } }); _ = Services.AddSingleton(new PortalSettings { IsLoRaSupported = true }); @@ -65,8 +66,8 @@ public void WhenLoraFeatureEnableClickToItemShouldRedirectToLoRaDeviceDetailsPag // Arrange var modelId = Guid.NewGuid().ToString(); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new[] { new DeviceModelDto { ModelId = modelId, SupportLoRaFeatures = true } }); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult { Items = new[] { new DeviceModelDto { ModelId = modelId, SupportLoRaFeatures = true } } }); _ = Services.AddSingleton(new PortalSettings { IsLoRaSupported = true }); @@ -85,10 +86,13 @@ public void WhenLoraFeatureEnableClickToItemShouldRedirectToLoRaDeviceDetailsPag public void DeviceModelListPageRendersCorrectly() { // Arrange - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new[] { + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new[] { new DeviceModelDto { ModelId = Guid.NewGuid().ToString() }, new DeviceModelDto{ ModelId = Guid.NewGuid().ToString() } + } }); _ = Services.AddSingleton(new PortalSettings { IsLoRaSupported = true }); @@ -113,8 +117,8 @@ public void WhenAddNewDeviceModelClickShouldNavigateToNewDeviceModelPage() // Arrange var deviceId = Guid.NewGuid().ToString(); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new[] { new DeviceModelDto { ModelId = deviceId, SupportLoRaFeatures = true } }); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult { Items = new[] { new DeviceModelDto { ModelId = deviceId, SupportLoRaFeatures = true } } }); _ = Services.AddSingleton(new PortalSettings { IsLoRaSupported = true }); @@ -131,7 +135,7 @@ public void WhenAddNewDeviceModelClickShouldNavigateToNewDeviceModelPage() public void LoadDeviceModelsShouldProcessProblemDetailsExceptionWhenIssueOccursOnGettingDeviceModels() { // Arrange - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) .ThrowsAsync(new ProblemDetailsException(new ProblemDetailsWithExceptionDetails())); _ = Services.AddSingleton(new PortalSettings { IsLoRaSupported = true }); @@ -150,8 +154,8 @@ public async Task WhenRefreshClickShouldReloadFromApi() // Arrange var deviceId = Guid.NewGuid().ToString(); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new[] { new DeviceModelDto { ModelId = deviceId, SupportLoRaFeatures = true } }); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult { Items = new[] { new DeviceModelDto { ModelId = deviceId, SupportLoRaFeatures = true } } }); _ = Services.AddSingleton(new PortalSettings { IsLoRaSupported = true }); @@ -166,7 +170,7 @@ public async Task WhenRefreshClickShouldReloadFromApi() } // Assert - cut.WaitForAssertion(() => this.mockDeviceModelsClientService.Verify(service => service.GetDeviceModels(), Times.Exactly(4))); + cut.WaitForAssertion(() => this.mockDeviceModelsClientService.Verify(service => service.GetDeviceModels(It.IsAny()), Times.Exactly(4))); cut.WaitForAssertion(() => MockRepository.VerifyAll()); } @@ -176,8 +180,8 @@ public void ClickOnDeleteShouldDisplayConfirmationDialogAndReturnIfAborted() // Arrange var deviceId = Guid.NewGuid().ToString(); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new[] { new DeviceModelDto { ModelId = deviceId, SupportLoRaFeatures = true } }); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult { Items = new[] { new DeviceModelDto { ModelId = deviceId, SupportLoRaFeatures = true } } }); _ = Services.AddSingleton(new PortalSettings { IsLoRaSupported = true }); @@ -199,10 +203,11 @@ public void ClickOnDeleteShouldDisplayConfirmationDialogAndReturnIfAborted() [Test] public void ClickOnDeleteShouldDisplayConfirmationDialogAndReloadDeviceModelIfConfirmed() { + // Arrange var deviceId = Guid.NewGuid().ToString(); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(new[] { new DeviceModelDto { ModelId = deviceId, SupportLoRaFeatures = true } }); + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult { Items = new[] { new DeviceModelDto { ModelId = deviceId, SupportLoRaFeatures = true } } }); _ = Services.AddSingleton(new PortalSettings { IsLoRaSupported = true }); @@ -218,7 +223,7 @@ public void ClickOnDeleteShouldDisplayConfirmationDialogAndReloadDeviceModelIfCo deleteButton.Click(); // Assert - cut.WaitForAssertion(() => this.mockDeviceModelsClientService.Verify(service => service.GetDeviceModels(), Times.Exactly(2))); + cut.WaitForAssertion(() => this.mockDeviceModelsClientService.Verify(service => service.GetDeviceModels(It.IsAny()), Times.Exactly(2))); cut.WaitForAssertion(() => MockRepository.VerifyAll()); } } diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Client/Services/DeviceModelsClientServiceTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Client/Services/DeviceModelsClientServiceTests.cs index 492eec089..534b71bd4 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Client/Services/DeviceModelsClientServiceTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Client/Services/DeviceModelsClientServiceTests.cs @@ -17,6 +17,7 @@ namespace AzureIoTHub.Portal.Tests.Unit.Client.Services using Models.v10; using NUnit.Framework; using RichardSzalay.MockHttp; + using AzureIoTHub.Portal.Shared.Models.v10.Filters; [TestFixture] public class DeviceModelsClientServiceTests : BlazorUnitTest @@ -36,13 +37,27 @@ public override void Setup() public async Task GetDeviceModelsShouldReturnDeviceModels() { // Arrange - var expectedDeviceModels = Fixture.Build().CreateMany(3).ToList(); + var expectedDeviceModels = new PaginationResult() + { + Items = Fixture.Build().CreateMany(3).ToList() + }; - _ = MockHttpClient.When(HttpMethod.Get, "/api/models") + _ = MockHttpClient.When(HttpMethod.Get, "/api/models?SearchText=&PageNumber=1&PageSize=10&OrderBy=") .RespondJson(expectedDeviceModels); + var filter = new DeviceModelFilter + { + SearchText = string.Empty, + PageNumber = 1, + PageSize = 10, + OrderBy = new string[] + { + null + } + }; + // Act - var result = await this.deviceModelsClientService.GetDeviceModels(); + var result = await this.deviceModelsClientService.GetDeviceModels(filter); // Assert _ = result.Should().BeEquivalentTo(expectedDeviceModels); diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/DeviceModelsControllerTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/DeviceModelsControllerTests.cs index e732d07f4..76aef8936 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/DeviceModelsControllerTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/DeviceModelsControllerTests.cs @@ -8,6 +8,8 @@ namespace AzureIoTHub.Portal.Tests.Unit.Server.Controllers.v1._0 using AutoFixture; using AzureIoTHub.Portal.Application.Services; using AzureIoTHub.Portal.Server.Controllers.V10; + using AzureIoTHub.Portal.Shared.Models.v1._0; + using AzureIoTHub.Portal.Shared.Models.v10.Filters; using FluentAssertions; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -43,11 +45,13 @@ public async Task GetListShouldReturnAList() // Arrange var expectedDeviceModels = Fixture.CreateMany(3).ToList(); - _ = this.mockDeviceModelService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(expectedDeviceModels); + var filter = new DeviceModelFilter(); + + _ = this.mockDeviceModelService.Setup(service => service.GetDeviceModels(filter)) + .ReturnsAsync(new PaginatedResult { Data = expectedDeviceModels }); // Act - var response = await this.deviceModelsController.GetItems(); + var response = await this.deviceModelsController.GetItems(filter); // Assert _ = ((OkObjectResult)response.Result)?.Value.Should().BeEquivalentTo(expectedDeviceModels); diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/LoRaWAN/LoRaWANDeviceModelsControllerTest.cs b/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/LoRaWAN/LoRaWANDeviceModelsControllerTest.cs index 24c9902b3..caf5d9c2d 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/LoRaWAN/LoRaWANDeviceModelsControllerTest.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/LoRaWAN/LoRaWANDeviceModelsControllerTest.cs @@ -7,6 +7,8 @@ namespace AzureIoTHub.Portal.Tests.Unit.Server.Controllers.v1._0.LoRaWAN using System.Threading.Tasks; using AutoFixture; using AzureIoTHub.Portal.Application.Services; + using AzureIoTHub.Portal.Shared.Models.v1._0; + using AzureIoTHub.Portal.Shared.Models.v10.Filters; using FluentAssertions; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -48,11 +50,13 @@ public async Task GetListShouldReturnAList() return dto; }) .ToList(); - _ = this.mockDeviceModelService.Setup(service => service.GetDeviceModels()) - .ReturnsAsync(expectedDeviceModels); + var filter = new DeviceModelFilter(); + + _ = this.mockDeviceModelService.Setup(service => service.GetDeviceModels(filter)) + .ReturnsAsync(new PaginatedResult { Data = expectedDeviceModels }); // Act - var response = await this.deviceModelsController.GetItems(); + var response = await this.deviceModelsController.GetItems(filter); // Assert _ = ((OkObjectResult)response.Result)?.Value.Should().BeEquivalentTo(expectedDeviceModels); diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/DeviceModelServiceTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/DeviceModelServiceTests.cs index 6d7d9e5cc..17d8f07ec 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/DeviceModelServiceTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/DeviceModelServiceTests.cs @@ -8,6 +8,7 @@ namespace AzureIoTHub.Portal.Tests.Unit.Server.Services using System.IO; using System.Linq; using System.Linq.Expressions; + using System.Threading; using System.Threading.Tasks; using AutoFixture; using AutoMapper; @@ -17,6 +18,8 @@ namespace AzureIoTHub.Portal.Tests.Unit.Server.Services using AzureIoTHub.Portal.Domain; using AzureIoTHub.Portal.Infrastructure.Mappers; using AzureIoTHub.Portal.Server.Services; + using AzureIoTHub.Portal.Shared.Models.v1._0; + using AzureIoTHub.Portal.Shared.Models.v10.Filters; using EntityFramework.Exceptions.Common; using FluentAssertions; using Microsoft.AspNetCore.Http; @@ -91,17 +94,37 @@ public async Task GetDeviceModelsShouldReturnExpectedDeviceModels() return deviceModelDto; }).ToList(); - _ = this.mockDeviceModelRepository.Setup(repository => repository.GetAll(It.IsAny>[]>())) - .Returns(expectedDeviceModels); + var filter = new DeviceModelFilter + { + SearchText = string.Empty, + PageNumber = 1, + PageSize = 10, + OrderBy = new string[] + { + null + } + }; + + _ = this.mockDeviceModelRepository.Setup(repository => repository.GetPaginatedListAsync(filter.PageNumber, filter.PageSize, filter.OrderBy, It.IsAny>>(), It.IsAny(), It.IsAny>[]>())) + .ReturnsAsync(new PaginatedResult + { + Data = expectedDeviceModels, + PageSize = filter.PageSize, + CurrentPage = filter.PageNumber, + TotalCount = 10 + }); _ = this.mockDeviceModelImageManager.Setup(manager => manager.ComputeImageUri(It.IsAny())) .Returns(expectedImageUri); // Act - var result = await this.deviceModelService.GetDeviceModels(); + var result = await this.deviceModelService.GetDeviceModels(filter); // Assert - _ = result.Should().BeEquivalentTo(expectedDeviceModelsDto); + _ = result.Data.Should().BeEquivalentTo(expectedDeviceModelsDto); + _ = result.CurrentPage.Should().Be(filter.PageNumber); + _ = result.PageSize.Should().Be(filter.PageSize); + _ = result.TotalCount.Should().Be(10); MockRepository.VerifyAll(); } From 3c9c716eb6ca9231fa81e43bd08771f757e6f8b3 Mon Sep 17 00:00:00 2001 From: GuillaumeM Date: Wed, 22 Feb 2023 09:52:56 +0100 Subject: [PATCH 05/11] update lorawan controller --- .../v1.0/LoRaWAN/LoRaWANDeviceModelsController.cs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/AzureIoTHub.Portal.Server/Controllers/v1.0/LoRaWAN/LoRaWANDeviceModelsController.cs b/src/AzureIoTHub.Portal.Server/Controllers/v1.0/LoRaWAN/LoRaWANDeviceModelsController.cs index c0c0d21dc..6c2564ca6 100644 --- a/src/AzureIoTHub.Portal.Server/Controllers/v1.0/LoRaWAN/LoRaWANDeviceModelsController.cs +++ b/src/AzureIoTHub.Portal.Server/Controllers/v1.0/LoRaWAN/LoRaWANDeviceModelsController.cs @@ -4,6 +4,7 @@ namespace AzureIoTHub.Portal.Server.Controllers.V10.LoRaWAN { using System.Collections.Generic; + using System.Linq; using System.Threading.Tasks; using AzureIoTHub.Portal.Application.Services; using AzureIoTHub.Portal.Models.v10; @@ -44,16 +45,7 @@ public override async Task>> GetIt { var devices = await this.deviceModelService.GetDeviceModels(deviceModelFilter); - var lorawamDevices = new List(); - foreach (var device in devices.Data) - { - if (device.SupportLoRaFeatures) - { - lorawamDevices.Add(device); - } - } - - return Ok(lorawamDevices); + return Ok(devices.Data.Where(d => d.SupportLoRaFeatures)); } /// From 7161085efa1a756c9344ec6e60267f5ea99b2209 Mon Sep 17 00:00:00 2001 From: GuillaumeM Date: Wed, 22 Feb 2023 09:59:31 +0100 Subject: [PATCH 06/11] update lorawan controller --- .../Controllers/v1.0/LoRaWAN/LoRaWANDeviceModelsController.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/AzureIoTHub.Portal.Server/Controllers/v1.0/LoRaWAN/LoRaWANDeviceModelsController.cs b/src/AzureIoTHub.Portal.Server/Controllers/v1.0/LoRaWAN/LoRaWANDeviceModelsController.cs index 6c2564ca6..2d283abd7 100644 --- a/src/AzureIoTHub.Portal.Server/Controllers/v1.0/LoRaWAN/LoRaWANDeviceModelsController.cs +++ b/src/AzureIoTHub.Portal.Server/Controllers/v1.0/LoRaWAN/LoRaWANDeviceModelsController.cs @@ -3,7 +3,6 @@ namespace AzureIoTHub.Portal.Server.Controllers.V10.LoRaWAN { - using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using AzureIoTHub.Portal.Application.Services; From e1cf1c5e8644003cb2bbb579611c1fbeccc6fbc4 Mon Sep 17 00:00:00 2001 From: GuillaumeM Date: Wed, 22 Feb 2023 11:10:18 +0100 Subject: [PATCH 07/11] update unit tests DeviceModelSearch component + list page --- .../DevicesModels/DeviceModelSearchTests.cs | 79 +++++++++++++++++++ .../DevicesModels/DeviceModelListPageTests.cs | 62 +++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 src/AzureIoTHub.Portal.Tests.Unit/Client/Components/DevicesModels/DeviceModelSearchTests.cs diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Client/Components/DevicesModels/DeviceModelSearchTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Client/Components/DevicesModels/DeviceModelSearchTests.cs new file mode 100644 index 000000000..e839f2a62 --- /dev/null +++ b/src/AzureIoTHub.Portal.Tests.Unit/Client/Components/DevicesModels/DeviceModelSearchTests.cs @@ -0,0 +1,79 @@ +// 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.Client.Components.DevicesModels +{ + using AutoFixture; + using AzureIoTHub.Portal.Client.Models; + using System.Collections.Generic; + using AzureIoTHub.Portal.Tests.Unit.UnitTests.Bases; + using Bunit; + using NUnit.Framework; + using AzureIoTHub.Portal.Client.Components.DeviceModels; + using FluentAssertions; + using System.Linq; + + [TestFixture] + public class DeviceModelSearchTests : BlazorUnitTest + { + public override void Setup() + { + base.Setup(); + } + + [Test] + public void SearchDeviceModels_ClickOnSearch_SearchIsFired() + { + // Arrange + var searchText = Fixture.Create(); + var receivedEvents = new List(); + var expectedDeviceModelSearchInfo = new DeviceModelSearchInfo + { + SearchText = searchText + }; + + var cut = RenderComponent(parameters => parameters.Add(p => p.OnSearch, (searchInfo) => + { + receivedEvents.Add(searchInfo); + })); + + cut.WaitForElement("#searchText").Change(searchText); + + // Act + cut.WaitForElement("#searchButton").Click(); + + // Assert + cut.WaitForAssertion(() => receivedEvents.Count.Should().Be(1)); + _ = receivedEvents.First().Should().BeEquivalentTo(expectedDeviceModelSearchInfo); + cut.WaitForAssertion(() => MockRepository.VerifyAll()); + } + + [Test] + public void SearchDeviceModels_ClickOnReset_SearchTextIsSetToEmptyAndSearchIsFired() + { + // Arrange + var searchText = Fixture.Create(); + var receivedEvents = new List(); + var expectedDeviceModelSearchInfo = new DeviceModelSearchInfo + { + SearchText = string.Empty + }; + + var cut = RenderComponent(parameters => parameters.Add(p => p.OnSearch, (searchInfo) => + { + receivedEvents.Add(searchInfo); + })); + + cut.WaitForElement("#searchText").Input(searchText); + + // Act + cut.WaitForElement("#resetSearch").Click(); + + // Assert + cut.WaitForAssertion(() => receivedEvents.Count.Should().Be(1)); + _ = receivedEvents.First().Should().BeEquivalentTo(expectedDeviceModelSearchInfo); + _ = cut.Find("#searchText").TextContent.Should().Be(string.Empty); + cut.WaitForAssertion(() => MockRepository.VerifyAll()); + } + } +} diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs index 4c665805d..16776ded6 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs @@ -20,6 +20,7 @@ namespace AzureIoTHub.Portal.Tests.Unit.Client.Pages.DevicesModels using MudBlazor; using NUnit.Framework; using AzureIoTHub.Portal.Shared.Models.v10.Filters; + using System.Collections.Generic; [TestFixture] public class DeviceModelListPageTests : BlazorUnitTest @@ -226,5 +227,66 @@ public void ClickOnDeleteShouldDisplayConfirmationDialogAndReloadDeviceModelIfCo cut.WaitForAssertion(() => this.mockDeviceModelsClientService.Verify(service => service.GetDeviceModels(It.IsAny()), Times.Exactly(2))); cut.WaitForAssertion(() => MockRepository.VerifyAll()); } + + public void ClickOnSearchShouldSearchDeviceModels() + { + // Arrange + var searchText = Fixture.Create(); + var deviceModelSearchInfo = new DeviceModelSearchInfo + { + SearchText = searchText + }; + var expectedFilter = new DeviceModelFilter + { + SearchText = string.Empty, + PageNumber = 1, + PageSize = 10, + OrderBy = new string[] + { + null + } + }; + var expectedFilterWithParam = new DeviceModelFilter + { + SearchText = deviceModelSearchInfo.SearchText, + PageNumber = 1, + PageSize = 10, + OrderBy = new string[] + { + null + } + }; + + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(expectedFilter)).ReturnsAsync(new PaginationResult + { + Items = new List() + { + new(), + new() + } + }); + + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(expectedFilterWithParam)).ReturnsAsync(new PaginationResult + { + Items = new List() + { + new() + } + }); + + var cut = RenderComponent(); + + cut.WaitForAssertion(() => cut.Markup.Should().NotContain("Loading...")); + cut.WaitForAssertion(() => cut.FindAll("table tbody tr").Count.Should().Be(2)); + cut.WaitForElement("#searchText").Change(searchText); + + // Act + cut.WaitForElement("#searchButton").Click(); + + // Assert + cut.WaitForAssertion(() => cut.Markup.Should().NotContain("Loading...")); + cut.WaitForAssertion(() => cut.FindAll("table tbody tr").Count.Should().Be(1)); + cut.WaitForAssertion(() => MockRepository.VerifyAll()); + } } } From 3a7fdb4d70f79f8e1cf1a16a0ddd3b27c538df39 Mon Sep 17 00:00:00 2001 From: GuillaumeM Date: Wed, 22 Feb 2023 14:48:44 +0100 Subject: [PATCH 08/11] update unit tests list page --- .../DevicesModels/DeviceModelListPageTests.cs | 35 ++++--------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs index 16776ded6..e8816897e 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs @@ -228,36 +228,15 @@ public void ClickOnDeleteShouldDisplayConfirmationDialogAndReloadDeviceModelIfCo cut.WaitForAssertion(() => MockRepository.VerifyAll()); } + [Test] public void ClickOnSearchShouldSearchDeviceModels() { // Arrange - var searchText = Fixture.Create(); - var deviceModelSearchInfo = new DeviceModelSearchInfo - { - SearchText = searchText - }; - var expectedFilter = new DeviceModelFilter - { - SearchText = string.Empty, - PageNumber = 1, - PageSize = 10, - OrderBy = new string[] - { - null - } - }; - var expectedFilterWithParam = new DeviceModelFilter - { - SearchText = deviceModelSearchInfo.SearchText, - PageNumber = 1, - PageSize = 10, - OrderBy = new string[] - { - null - } - }; + var expectedSearchText = Fixture.Create(); + + _ = Services.AddSingleton(new PortalSettings { IsLoRaSupported = true }); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(expectedFilter)).ReturnsAsync(new PaginationResult + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.Is(x => string.IsNullOrEmpty(x.SearchText)))).ReturnsAsync(new PaginationResult { Items = new List() { @@ -266,7 +245,7 @@ public void ClickOnSearchShouldSearchDeviceModels() } }); - _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(expectedFilterWithParam)).ReturnsAsync(new PaginationResult + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.Is(x => expectedSearchText.Equals(x.SearchText)))).ReturnsAsync(new PaginationResult { Items = new List() { @@ -278,7 +257,7 @@ public void ClickOnSearchShouldSearchDeviceModels() cut.WaitForAssertion(() => cut.Markup.Should().NotContain("Loading...")); cut.WaitForAssertion(() => cut.FindAll("table tbody tr").Count.Should().Be(2)); - cut.WaitForElement("#searchText").Change(searchText); + cut.WaitForElement("#searchText").Change(expectedSearchText); // Act cut.WaitForElement("#searchButton").Click(); From 33caf2668511623e3893f4f8ccbacc05f4abc045 Mon Sep 17 00:00:00 2001 From: GuillaumeM Date: Wed, 22 Feb 2023 16:25:05 +0100 Subject: [PATCH 09/11] update unit tests list page + controller base --- .../DeviceModels/DeviceModelListPage.razor | 4 +- .../DevicesModels/DeviceModelListPageTests.cs | 33 +++++++++ .../v1.0/DeviceModelControllerBaseTests.cs | 69 +++++++++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/DeviceModelControllerBaseTests.cs diff --git a/src/AzureIoTHub.Portal.Client/Pages/DeviceModels/DeviceModelListPage.razor b/src/AzureIoTHub.Portal.Client/Pages/DeviceModels/DeviceModelListPage.razor index 03c8fd786..ffb6e4263 100644 --- a/src/AzureIoTHub.Portal.Client/Pages/DeviceModels/DeviceModelListPage.razor +++ b/src/AzureIoTHub.Portal.Client/Pages/DeviceModels/DeviceModelListPage.razor @@ -33,8 +33,8 @@ - Name - Description + Name + Description Details Delete diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs index e8816897e..51821dcce 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs @@ -21,6 +21,7 @@ namespace AzureIoTHub.Portal.Tests.Unit.Client.Pages.DevicesModels using NUnit.Framework; using AzureIoTHub.Portal.Shared.Models.v10.Filters; using System.Collections.Generic; + using AzureIoTHub.Portal.Client.Pages.EdgeModels; [TestFixture] public class DeviceModelListPageTests : BlazorUnitTest @@ -267,5 +268,37 @@ public void ClickOnSearchShouldSearchDeviceModels() cut.WaitForAssertion(() => cut.FindAll("table tbody tr").Count.Should().Be(1)); cut.WaitForAssertion(() => MockRepository.VerifyAll()); } + + [Test] + public void ClickOnSortLabel() + { + // Arrange + _ = Services.AddSingleton(new PortalSettings { IsLoRaSupported = true }); + + _ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModels(It.IsAny())) + .ReturnsAsync(new PaginationResult + { + Items = new List() + { + new (), + new () + } + }); + + // Act + var cut = RenderComponent(); + + cut.WaitForAssertion(() => cut.WaitForElement("#NameLabel").Should().NotBeNull()); + var sortNameButtons = cut.WaitForElement("#NameLabel"); + sortNameButtons.Click(); + + cut.WaitForAssertion(() => cut.WaitForElement("#DescriptionLabel").Should().NotBeNull()); + var sortDescriptionButtons = cut.WaitForElement("#DescriptionLabel"); + sortDescriptionButtons.Click(); + + // Assert + cut.WaitForAssertion(() => Assert.AreEqual(3, cut.FindAll("tr").Count)); + cut.WaitForAssertion(() => MockRepository.VerifyAll()); + } } } diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/DeviceModelControllerBaseTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/DeviceModelControllerBaseTests.cs new file mode 100644 index 000000000..46463278a --- /dev/null +++ b/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/DeviceModelControllerBaseTests.cs @@ -0,0 +1,69 @@ +// 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.Controllers.v1._0 +{ + using AutoFixture; + using AzureIoTHub.Portal.Models.v10; + using AzureIoTHub.Portal.Shared.Models.v1._0; + using AzureIoTHub.Portal.Shared.Models.v10.Filters; + using System.Threading.Tasks; + using AzureIoTHub.Portal.Tests.Unit.UnitTests.Bases; + using Microsoft.AspNetCore.Mvc; + using NUnit.Framework; + using AzureIoTHub.Portal.Application.Services; + using Moq; + using Microsoft.Extensions.DependencyInjection; + using System.Linq; + using AzureIoTHub.Portal.Server.Controllers.V10; + using FluentAssertions; + + [TestFixture] + public class DeviceModelControllerBaseTests : BackendUnitTest + { + private Mock> mockDeviceModelService; + + private DeviceModelsController deviceModelsController; + + public override void Setup() + { + base.Setup(); + + this.mockDeviceModelService = MockRepository.Create>(); + + _ = ServiceCollection.AddSingleton(this.mockDeviceModelService.Object); + + Services = ServiceCollection.BuildServiceProvider(); + + this.deviceModelsController = new DeviceModelsController(Services.GetRequiredService>()); + } + + [Test] + public async Task GetListGreaterThan10ShouldReturnAListAndNextPage() + { + // Arrange + var expectedDeviceModels = Fixture.CreateMany(12).ToList(); + + var filter = new DeviceModelFilter + { + SearchText = string.Empty, + PageNumber = 1, + PageSize = 10, + OrderBy = new string[] + { + null + } + }; + + _ = this.mockDeviceModelService.Setup(service => service.GetDeviceModels(filter)) + .ReturnsAsync(new PaginatedResult { Data = expectedDeviceModels }); + + // Act + var response = await this.deviceModelsController.GetItems(filter); + + // Assert + _ = ((OkObjectResult)response.Result)?.Value.Should().BeEquivalentTo(expectedDeviceModels); + MockRepository.VerifyAll(); + } + } +} From 656c378aaea7d60fc0e9b50fb4c45be8a6c604b1 Mon Sep 17 00:00:00 2001 From: GuillaumeM Date: Thu, 23 Feb 2023 10:48:26 +0100 Subject: [PATCH 10/11] update unit tests list page + controller base --- .../DevicesModels/DeviceModelListPageTests.cs | 7 ++++- .../v1.0/DeviceModelControllerBaseTests.cs | 30 +++++++++++++++---- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs index 51821dcce..805540237 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs @@ -21,7 +21,6 @@ namespace AzureIoTHub.Portal.Tests.Unit.Client.Pages.DevicesModels using NUnit.Framework; using AzureIoTHub.Portal.Shared.Models.v10.Filters; using System.Collections.Generic; - using AzureIoTHub.Portal.Client.Pages.EdgeModels; [TestFixture] public class DeviceModelListPageTests : BlazorUnitTest @@ -299,6 +298,12 @@ public void ClickOnSortLabel() // Assert cut.WaitForAssertion(() => Assert.AreEqual(3, cut.FindAll("tr").Count)); cut.WaitForAssertion(() => MockRepository.VerifyAll()); + + sortNameButtons.Click(); + sortDescriptionButtons.Click(); + + cut.WaitForAssertion(() => Assert.AreEqual(3, cut.FindAll("tr").Count)); + cut.WaitForAssertion(() => MockRepository.VerifyAll()); } } } diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/DeviceModelControllerBaseTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/DeviceModelControllerBaseTests.cs index 46463278a..a38472b84 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/DeviceModelControllerBaseTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/DeviceModelControllerBaseTests.cs @@ -17,37 +17,45 @@ namespace AzureIoTHub.Portal.Tests.Unit.Server.Controllers.v1._0 using System.Linq; using AzureIoTHub.Portal.Server.Controllers.V10; using FluentAssertions; + using System.Collections.Generic; + using Microsoft.AspNetCore.Mvc.Routing; [TestFixture] public class DeviceModelControllerBaseTests : BackendUnitTest { private Mock> mockDeviceModelService; + private Mock mockUrlHelper; private DeviceModelsController deviceModelsController; + [SetUp] public override void Setup() { base.Setup(); this.mockDeviceModelService = MockRepository.Create>(); + this.mockUrlHelper = MockRepository.Create(); _ = ServiceCollection.AddSingleton(this.mockDeviceModelService.Object); Services = ServiceCollection.BuildServiceProvider(); - this.deviceModelsController = new DeviceModelsController(Services.GetRequiredService>()); + this.deviceModelsController = new DeviceModelsController(Services.GetRequiredService>()) + { + Url = this.mockUrlHelper.Object + }; } [Test] public async Task GetListGreaterThan10ShouldReturnAListAndNextPage() { // Arrange - var expectedDeviceModels = Fixture.CreateMany(12).ToList(); + var expectedDeviceModels = Fixture.CreateMany(24).ToList(); var filter = new DeviceModelFilter { SearchText = string.Empty, - PageNumber = 1, + PageNumber = 0, PageSize = 10, OrderBy = new string[] { @@ -56,13 +64,25 @@ public async Task GetListGreaterThan10ShouldReturnAListAndNextPage() }; _ = this.mockDeviceModelService.Setup(service => service.GetDeviceModels(filter)) - .ReturnsAsync(new PaginatedResult { Data = expectedDeviceModels }); + .ReturnsAsync((DeviceModelFilter filter) => new PaginatedResult + { + Data = expectedDeviceModels.Skip(filter.PageSize * filter.PageNumber).Take(filter.PageSize).ToList(), + TotalCount = expectedDeviceModels.Count + }); + + var locationUrl = "http://location/models"; + + _ = this.mockUrlHelper + .Setup(x => x.RouteUrl(It.IsAny())) + .Returns(locationUrl); // Act var response = await this.deviceModelsController.GetItems(filter); // Assert - _ = ((OkObjectResult)response.Result)?.Value.Should().BeEquivalentTo(expectedDeviceModels); + _ = ((OkObjectResult)response.Result)?.Value.Should().BeAssignableTo>(); + var results = (response.Value)?.TotalItems; + _ = results.Should().HaveValue("10"); MockRepository.VerifyAll(); } } From 385e9a5762cd27f4c6d71ed1c98284608e768410 Mon Sep 17 00:00:00 2001 From: GuillaumeM Date: Thu, 23 Feb 2023 13:42:34 +0100 Subject: [PATCH 11/11] update unit tests list page + service --- .../DevicesModels/DeviceModelListPageTests.cs | 36 +++++++++++++++++-- .../Services/DeviceModelServiceTests.cs | 2 +- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs index 805540237..ccc384d46 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Client/Pages/DevicesModels/DeviceModelListPageTests.cs @@ -21,6 +21,7 @@ namespace AzureIoTHub.Portal.Tests.Unit.Client.Pages.DevicesModels using NUnit.Framework; using AzureIoTHub.Portal.Shared.Models.v10.Filters; using System.Collections.Generic; + using System.Linq; [TestFixture] public class DeviceModelListPageTests : BlazorUnitTest @@ -298,11 +299,40 @@ public void ClickOnSortLabel() // Assert cut.WaitForAssertion(() => Assert.AreEqual(3, cut.FindAll("tr").Count)); cut.WaitForAssertion(() => MockRepository.VerifyAll()); + } - sortNameButtons.Click(); - sortDescriptionButtons.Click(); + [Test] + public void SortClickOnSortNameDescDeviceModelsSorted() + { + // Arrange + _ = Services.AddSingleton(new PortalSettings { IsLoRaSupported = true }); - cut.WaitForAssertion(() => Assert.AreEqual(3, cut.FindAll("tr").Count)); + _ = this.mockDeviceModelsClientService.Setup(service => + service.GetDeviceModels(It.Is(x => string.IsNullOrEmpty(x.OrderBy.First())))) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); + _ = this.mockDeviceModelsClientService.Setup(service => + service.GetDeviceModels(It.Is(x => "Name asc".Equals(x.OrderBy.First())))) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); + _ = this.mockDeviceModelsClientService.Setup(service => + service.GetDeviceModels(It.Is(x => "Name desc".Equals(x.OrderBy.First())))) + .ReturnsAsync(new PaginationResult + { + Items = new List() + }); + + var cut = RenderComponent(); + + // Act + cut.WaitForElement("#NameLabel").Click(); + cut.WaitForElement("#NameLabel").Click(); + + // Assert cut.WaitForAssertion(() => MockRepository.VerifyAll()); } } diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/DeviceModelServiceTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/DeviceModelServiceTests.cs index 17d8f07ec..4ff2c54f7 100644 --- a/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/DeviceModelServiceTests.cs +++ b/src/AzureIoTHub.Portal.Tests.Unit/Server/Services/DeviceModelServiceTests.cs @@ -96,7 +96,7 @@ public async Task GetDeviceModelsShouldReturnExpectedDeviceModels() var filter = new DeviceModelFilter { - SearchText = string.Empty, + SearchText = Fixture.Create(), PageNumber = 1, PageSize = 10, OrderBy = new string[]