Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #969 - Refactor LoRa Device model and LoRaDevice classes #1056

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ namespace AzureIoTHub.Portal.Tests.Unit.Client.Pages.Devices
using MudBlazor.Services;
using NUnit.Framework;
using UnitTests.Mocks;
using AzureIoTHub.Portal.Models.v10.LoRaWAN;
using AzureIoTHub.Portal.Client.Pages.DeviceModels;

[TestFixture]
public class DeviceDetailPageTests : BlazorUnitTest
Expand All @@ -42,10 +44,10 @@ public override void Setup()

this.mockDialogService = MockRepository.Create<IDialogService>();
this.mockSnackbarService = MockRepository.Create<ISnackbar>();
this.mockDeviceModelsClientService = MockRepository.Create<IDeviceModelsClientService>();
this.mockLoRaWanDeviceModelsClientService = MockRepository.Create<ILoRaWanDeviceModelsClientService>();
this.mockDeviceTagSettingsClientService = MockRepository.Create<IDeviceTagSettingsClientService>();
this.mockDeviceClientService = MockRepository.Create<IDeviceClientService>();
this.mockDeviceModelsClientService = MockRepository.Create<IDeviceModelsClientService>();
this.mockLoRaWanDeviceModelsClientService = MockRepository.Create<ILoRaWanDeviceModelsClientService>();
this.mockLoRaWanDeviceClientService = MockRepository.Create<ILoRaWanDeviceClientService>();

_ = Services.AddSingleton(this.mockDialogService.Object);
Expand All @@ -65,6 +67,64 @@ public override void Setup()
this.mockNavigationManager = Services.GetRequiredService<FakeNavigationManager>();
}

[Test]
public void ShouldLoadDeviceDetails()
{
// Arrange
var deviceId = Guid.NewGuid().ToString();
var modelId = Guid.NewGuid().ToString();

_ = this.mockDeviceClientService
.Setup(service => service.GetDevice(deviceId))
.ReturnsAsync(new DeviceDetails() { ModelId = modelId });

_ = this.mockDeviceClientService
.Setup(service => service.GetDeviceProperties(deviceId))
.ReturnsAsync(new List<DevicePropertyValue>());

_ = this.mockDeviceModelsClientService.Setup(service => service.GetDeviceModel(modelId))
.ReturnsAsync(new DeviceModel());

_ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags())
.ReturnsAsync(new List<DeviceTag>());

// Act
var cut = RenderComponent<DeviceDetailPage>(ComponentParameter.CreateParameter("DeviceID", deviceId));

// Assert
_ = cut.WaitForElement("#returnButton");
}

[Test]
public void ShouldLoadLoRaDeviceDetails()
{

// Arrange
var deviceId = Guid.NewGuid().ToString();
var modelId = Guid.NewGuid().ToString();

_ = this.mockLoRaWanDeviceClientService
.Setup(service => service.GetDevice(deviceId))
.ReturnsAsync(new LoRaDeviceDetails() { ModelId = modelId });

_ = this.mockLoRaWanDeviceModelsClientService.Setup(service => service.GetDeviceModel(modelId))
.ReturnsAsync(new LoRaDeviceModel());

_ = this.mockLoRaWanDeviceModelsClientService.Setup(service => service.GetDeviceModelCommands(modelId))
.ReturnsAsync(new List<DeviceModelCommand>());

_ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags())
.ReturnsAsync(new List<DeviceTag>());

// Act
var cut = RenderComponent<DeviceDetailPage>(
ComponentParameter.CreateParameter("DeviceID", deviceId),
ComponentParameter.CreateParameter(nameof(DeviceModelDetailPage.IsLoRa), true));

// Assert
_ = cut.WaitForElement("#returnButton");
}

[Test]
public void ReturnButtonMustNavigateToPreviousPage()
{
Expand Down Expand Up @@ -157,7 +217,7 @@ public void ClickOnSaveShouldPutDeviceDetails()

// Act
var cut = RenderComponent<DeviceDetailPage>(ComponentParameter.CreateParameter("DeviceID", mockDeviceDetails.DeviceID));
cut.WaitForAssertion(() => cut.Find($"#{nameof(DeviceModel.Name)}>b").InnerHtml.Should().NotBeEmpty());
cut.WaitForAssertion(() => cut.Find($"#{nameof(DeviceModel.Name)}").InnerHtml.Should().NotBeEmpty());

var saveButton = cut.WaitForElement("#saveButton");
saveButton.Click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,7 @@ private LoRaDeviceModel SetupMockLoRaWANDeviceModel(DeviceModelCommand[] command
Name = this.mockModelId,
Description = Guid.NewGuid().ToString(),
IsBuiltin = false,
ImageUrl = new Uri($"http://fake.local/{this.mockModelId}"),
SupportLoRaFeatures = true
ImageUrl = new Uri($"http://fake.local/{this.mockModelId}")
};

_ = this.mockLoRaWanDeviceModelsClientService.Setup(service =>
Expand All @@ -412,8 +411,7 @@ private LoRaDeviceModel SetupMockLoRaWANDeviceModelThrowingException()
Name = this.mockModelId,
Description = Guid.NewGuid().ToString(),
IsBuiltin = false,
ImageUrl = new Uri($"http://fake.local/{this.mockModelId}"),
SupportLoRaFeatures = true
ImageUrl = new Uri($"http://fake.local/{this.mockModelId}")
};

_ = this.mockLoRaWanDeviceModelsClientService.Setup(service =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,14 @@ public void DuplicateSharedDeviceShouldReturnDuplicatedLoraWanDevice()
var appKey = Fixture.Create<string>();

// Act
var result = this.deviceLayoutService.DuplicateSharedDevice(new LoRaDeviceDetails
var loraWanDevice = this.deviceLayoutService.DuplicateSharedDevice(new LoRaDeviceDetails
{
DeviceID = deviceId,
DeviceName = deviceName,
AppKey = appKey
});

// Assert
var loraWanDevice = (LoRaDeviceDetails) result;

_ = loraWanDevice.DeviceID.Should().BeEmpty();
_ = loraWanDevice.DeviceName.Should().Be($"{deviceName} - copy");
_ = loraWanDevice.AppKey.Should().BeEmpty();
Expand All @@ -109,7 +107,7 @@ public void ResetSharedDeviceShouldReturnNewDevice()
var expectedDevice = new DeviceDetails();

// Act
var result = this.deviceLayoutService.ResetSharedDevice();
var result = this.deviceLayoutService.ResetSharedDevice<DeviceDetails>();

// Assert
_ = result.Should().BeEquivalentTo(expectedDevice);
Expand All @@ -129,7 +127,7 @@ public void ResetSharedDeviceShouldReturnNewDeviceWithExpectedTags()
}

// Act
var result = this.deviceLayoutService.ResetSharedDevice(expectedTags);
var result = this.deviceLayoutService.ResetSharedDevice<DeviceDetails>(expectedTags);

// Assert
_ = result.Should().BeEquivalentTo(expectedDevice);
Expand All @@ -142,36 +140,24 @@ public void ResetSharedDeviceModelShouldReturnNewDeviceModel()
var expectedDeviceModel = new DeviceModel();

// Act
var result = this.deviceLayoutService.ResetSharedDeviceModel();
var result = this.deviceLayoutService.ResetSharedDeviceModel<DeviceModel>();

// Assert
_ = result.Should().BeEquivalentTo(expectedDeviceModel);
}

[Test]
public void GetSharedDeviceShouldReturnDevice()
public void GetSharedDeviceShouldReturnNull()
{
// Arrange
var expectedDevice = new DeviceDetails();

// Act
var result = this.deviceLayoutService.GetSharedDevice();

// Assert
_ = result.Should().BeEquivalentTo(expectedDevice);
Assert.IsNull(this.deviceLayoutService.GetSharedDevice());
}

[Test]
public void GetSharedDeviceModelShouldReturnDeviceModel()
public void GetSharedDeviceModelShouldReturnNull()
{
// Arrange
var expectedDeviceModel = new DeviceModel();

// Act
var result = this.deviceLayoutService.GetSharedDeviceModel();

// Assert
_ = result.Should().BeEquivalentTo(expectedDeviceModel);
Assert.IsNull(this.deviceLayoutService.GetSharedDeviceModel());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,11 @@ public void CreateDeviceModelStateUnderTestExpectedBehavior(bool isBuiltin, bool
this.mockRepository.VerifyAll();
}

[TestCase(false, false)]
[TestCase(true, false)]
[TestCase(true, true)]
[TestCase(false, true)]
public void UpdateTableEntityStateUnderTestExpectedBehavior(bool isBuiltin, bool supportLora)
[TestCase(false)]
[TestCase(true)]
[TestCase(true)]
[TestCase(false)]
public void UpdateTableEntityStateUnderTestExpectedBehavior(bool isBuiltin)
{
// Arrange
var loRaDeviceModelMapper = CreateLoRaDeviceModelMapper();
Expand All @@ -119,9 +119,7 @@ public void UpdateTableEntityStateUnderTestExpectedBehavior(bool isBuiltin, bool
Description = Guid.NewGuid().ToString(),
ImageUrl = new Uri("http://fake.local"),
SensorDecoder = Guid.NewGuid().ToString(),
IsBuiltin = isBuiltin,
SupportLoRaFeatures = supportLora,
UseOTAA = true
IsBuiltin = isBuiltin
};

// Act
Expand All @@ -133,7 +131,7 @@ public void UpdateTableEntityStateUnderTestExpectedBehavior(bool isBuiltin, bool
Assert.AreEqual(model.ModelId, entity.RowKey);
Assert.AreEqual(model.Name, entity[nameof(LoRaDeviceModel.Name)]);
Assert.AreEqual(model.Description, entity[nameof(LoRaDeviceModel.Description)]);
Assert.AreEqual(supportLora, entity[nameof(LoRaDeviceModel.SupportLoRaFeatures)]);
Assert.AreEqual(true, entity[nameof(LoRaDeviceModel.SupportLoRaFeatures)]);
Assert.AreEqual(isBuiltin, entity[nameof(LoRaDeviceModel.IsBuiltin)]);
Assert.AreEqual(model.SensorDecoder, entity[nameof(LoRaDeviceModel.SensorDecoder)]);
this.mockRepository.VerifyAll();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
@using AzureIoTHub.Portal.Models
@using AzureIoTHub.Portal.Models.v10
@using AzureIoTHub.Portal.Models.v10.LoRaWAN
@using AzureIoTHub.Portal.Shared.Models

@attribute [Authorize]
@inject NavigationManager NavigationManager
Expand Down Expand Up @@ -42,7 +43,7 @@
</MudItem>
<MudItem xs="12" sm="8" md="9">
<MudTabs Elevation="1" Rounded="true" PanelClass="mt-6 scrollable-tab-content" id="tabs">
<MudTabPanel Text="General" Style=@(standardValidator.Validate(Model).IsValid ? "" : "color: red")>
<MudTabPanel Text="General" Style=@(this.CheckGeneralValidation() ? "color: red": "")>
<MudExpansionPanels MultiExpansion="true" id="general">
<MudGrid>
<MudItem xs="12">
Expand All @@ -62,12 +63,12 @@
<MudText>
<b>LoRa Device</b>
</MudText>
<MudSwitch @bind-Checked="@IsLoRa" Color="Color.Secondary" id="@nameof(Model.SupportLoRaFeatures)" Label="Support LoRa"></MudSwitch>

<MudSwitch @bind-Checked="@IsLoRa" id="SupportLoRaFeatures" Color="Color.Secondary" Label="Support LoRa"></MudSwitch>
@if (IsLoRa)
{
<MudText Typo="Typo.subtitle1" Class="mud-input-helper-text">The device <b>is</b> a LoRa Device.</MudText>

}
</MudItem>
}
Expand Down Expand Up @@ -124,18 +125,18 @@
Required="true">
@foreach (DevicePropertyType item in Enum.GetValues(typeof(DevicePropertyType)))
{
<MudSelectItem Value="@item">@item</MudSelectItem>
<MudSelectItem Value="@item">@item</MudSelectItem>
}
</MudSelect>
</MudItem>
<MudItem md="1" xs="3">
<MudSwitch id="@nameof(item.IsWritable)" Label="Writable" @bind-Checked="@item.IsWritable" Color="Color.Secondary" />

</MudItem>
<MudItem md="1" xs="3">
<MudIconButton id="deletePropertyButton" Icon="@Icons.Filled.Delete" OnClick="@(() => Properties.Remove(item))">Remove</MudIconButton>
</MudItem>
</MudGrid>
</MudSelect>
</MudItem>
<MudItem md="1" xs="3">
<MudSwitch id="@nameof(item.IsWritable)" Label="Writable" @bind-Checked="@item.IsWritable" Color="Color.Secondary" />

</MudItem>
<MudItem md="1" xs="3">
<MudIconButton id="deletePropertyButton" Icon="@Icons.Filled.Delete" OnClick="@(() => Properties.Remove(item))">Remove</MudIconButton>
</MudItem>
</MudGrid>
}
</MudItem>
</MudGrid>
Expand All @@ -148,9 +149,9 @@
</MudTabPanel>
@if (IsLoRa)
{
<MudTabPanel Class="LoRaWANTab" Text="LoRaWAN" Style=@(loraValidator.Validate(Model as LoRaDeviceModel).IsValid ? "" : "color: red")>
<MudTabPanel Class="LoRaWANTab" Text="LoRaWAN" Style=@(this.CheckLoRaValidation() ? "color: red": "")>
<CreateLoraDeviceModel LoRaDeviceModel="@(Model as LoRaDeviceModel)"
Commands="Commands"/>
Commands="Commands" />
</MudTabPanel>
}
</MudTabs>
Expand Down Expand Up @@ -209,7 +210,7 @@
};
}

internal DeviceModel Model { get; set; } = new DeviceModel
internal IDeviceModel Model { get; set; } = new DeviceModel
{
ModelId = Guid.NewGuid().ToString()
};
Expand All @@ -218,6 +219,26 @@
private MultipartFormDataContent content;
private string imageDataUrl;

private bool CheckLoRaValidation()
{
if (IsLoRa && this.Model is LoRaDeviceModel loRaDeviceModel)
{
return !this.loraValidator.Validate(loRaDeviceModel).IsValid;
}

return true;
}

private bool CheckGeneralValidation()
{
if (!IsLoRa && this.Model is DeviceModel deviceModel)
{
return !this.standardValidator.Validate(deviceModel).IsValid;
}

return CheckLoRaValidation();
}

private void DeleteAvatar()
{
content = null;
Expand Down Expand Up @@ -268,20 +289,20 @@
}

// Check validation error in commands
foreach(var cmd in Commands)
foreach (var cmd in Commands)
{
if (!CommandValidator.Validate(cmd).IsValid)
cmdValidationError = true;
}
}

if (!standardValidator.Validate(Model).IsValid
|| (IsLoRa && (!this.loraValidator.Validate(this.Model as LoRaDeviceModel).IsValid ||
duplicated ||
cmdValidationError)))
if (!IsLoRa ? !standardValidator.Validate(Model as DeviceModel).IsValid :
(!this.loraValidator.Validate(this.Model as LoRaDeviceModel).IsValid
|| duplicated
|| cmdValidationError))
{
Snackbar.Add("One or more validation errors occurred", Severity.Error);

isProcessing = false;

return;
Expand All @@ -291,17 +312,13 @@
{
if (IsLoRa)
{
var loraDeviceModel = Model as LoRaDeviceModel;

loraDeviceModel.SupportLoRaFeatures = true;

await LoRaWanDeviceModelsClientService.CreateDeviceModel(loraDeviceModel);
await LoRaWanDeviceModelsClientService.CreateDeviceModel(Model as LoRaDeviceModel);

await LoRaWanDeviceModelsClientService.SetDeviceModelCommands(Model.ModelId, Commands);
}
else
{
await DeviceModelsClientService.CreateDeviceModel(Model);
await DeviceModelsClientService.CreateDeviceModel(Model as DeviceModel);

await DeviceModelsClientService.SetDeviceModelModelProperties(Model.ModelId, Properties);
}
Expand Down Expand Up @@ -333,4 +350,4 @@
isProcessing = false;
}
}
}
}
Loading