Skip to content
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 @@ -35,6 +35,7 @@ public async Task ConfigurationService_GetConfiguration_ResultSuccess_And_Config

ConfigurationResponse expectedConfiguration = new ConfigurationResponse
{
ApplicationUpdateUri = "http://localhost:9210",
ClientId = "clientId",
ClientSecret = Guid.NewGuid().ToString(),
EnableAutoUpdates = false,
Expand Down Expand Up @@ -62,6 +63,7 @@ public async Task ConfigurationService_GetConfiguration_ResultSuccess_And_Config
configurationResult.Data.ShouldNotBeNull();
configurationResult.Data.ClientSecret.ShouldBe(expectedConfiguration.ClientSecret);
configurationResult.Data.ClientId.ShouldBe(expectedConfiguration.ClientId);
configurationResult.Data.ApplicationUpdateUri.ShouldBe(expectedConfiguration.ApplicationUpdateUri);
configurationResult.Data.EnableAutoUpdates.ShouldBe(expectedConfiguration.EnableAutoUpdates);
configurationResult.Data.SecurityServiceUri.ShouldBe(expectedConfiguration.HostAddresses.Single(s => s.ServiceType == ServiceType.Security).Uri);
configurationResult.Data.TransactionProcessorAclUri.ShouldBe(expectedConfiguration.HostAddresses.Single(s => s.ServiceType == ServiceType.TransactionProcessorAcl).Uri);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using Newtonsoft.Json;
using RichardSzalay.MockHttp;
using Shouldly;
using SimpleResults;
using TransactionProcessor.Mobile.BusinessLogic.Logging;
using TransactionProcessor.Mobile.BusinessLogic.Models;
using TransactionProcessor.Mobile.BusinessLogic.Services;

namespace TransactionProcessor.Mobile.BusinessLogic.Tests.ServicesTests;

public class UpdateServiceTests
{
private readonly MockHttpMessageHandler MockHttpMessageHandler;

private readonly IUpdateService UpdateService;

public UpdateServiceTests()
{
this.MockHttpMessageHandler = new MockHttpMessageHandler();
this.UpdateService = new UpdateService(_ => "http://localhost", this.MockHttpMessageHandler.ToHttpClient());
}

[Fact]
public async Task UpdateService_CheckForUpdates_ResultSuccess_And_UpdateResponseReturned()
{
Logger.Initialise(new NullLogger());

ApplicationUpdateCheckResponse expectedResponse = new()
{
DownloadUri = "https://updates.example.com/transactionmobile.apk",
LatestVersion = "1.0.1",
Message = "Install the latest version.",
UpdateRequired = true
};

this.MockHttpMessageHandler.When("http://localhost/api/applicationupdates/check")
.Respond("application/json", JsonConvert.SerializeObject(expectedResponse));

Result<ApplicationUpdateCheckResponse> updateResult = await this.UpdateService.CheckForUpdates(TestData.ApplicationVersion,
"com.transactionprocessor.mobile",
"Android",
TestData.DeviceIdentifier,
CancellationToken.None);

updateResult.IsSuccess.ShouldBeTrue();
updateResult.Data.ShouldNotBeNull();
updateResult.Data.UpdateRequired.ShouldBeTrue();
updateResult.Data.DownloadUri.ShouldBe(expectedResponse.DownloadUri);
updateResult.Data.LatestVersion.ShouldBe(expectedResponse.LatestVersion);
}

[Fact]
public async Task UpdateService_CheckForUpdates_FailedHttpCall_ResultFailed()
{
Logger.Initialise(new NullLogger());

this.MockHttpMessageHandler.When("http://localhost/api/applicationupdates/check")
.Respond(System.Net.HttpStatusCode.BadRequest);

Result<ApplicationUpdateCheckResponse> updateResult = await this.UpdateService.CheckForUpdates(TestData.ApplicationVersion,
"com.transactionprocessor.mobile",
"Android",
TestData.DeviceIdentifier,
CancellationToken.None);

updateResult.IsFailed.ShouldBeTrue();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,26 @@ public class LoginPageViewModelTests

private readonly Mock<IApplicationInfoService> ApplicationInfoService;

private readonly Mock<IApplicationUpdateLauncherService> ApplicationUpdateLauncherService;

private readonly Mock<IDialogService> DialogService;

private readonly Mock<IUpdateService> UpdateService;
public LoginPageViewModelTests() {
this.Mediator = new Mock<IMediator>();
this.NavigationService = new Mock<INavigationService>();
this.NavigationParameterService = new Mock<INavigationParameterService>();
this.ApplicationCache = new Mock<IApplicationCache>();
this.DeviceService = new Mock<IDeviceService>();
this.ApplicationInfoService = new Mock<IApplicationInfoService>();
this.ApplicationUpdateLauncherService = new Mock<IApplicationUpdateLauncherService>();
this.DialogService = new Mock<IDialogService>();
this.UpdateService = new Mock<IUpdateService>();

this.ViewModel = new LoginPageViewModel(this.Mediator.Object, this.NavigationService.Object, this.ApplicationCache.Object,
this.DeviceService.Object, this.ApplicationInfoService.Object,
this.DialogService.Object, this.NavigationParameterService.Object);
this.DialogService.Object, this.NavigationParameterService.Object,
this.UpdateService.Object, this.ApplicationUpdateLauncherService.Object);
Logger.Initialise(new Logging.NullLogger());
}

Expand Down Expand Up @@ -127,6 +134,101 @@ public void LoginPageViewModel_LoginCommand_Execute_ErrorGettingToken_WarningToa
CancellationToken.None), Times.Once);
}

[Fact]
public async Task LoginPageViewModel_LoginCommand_Execute_UpdateCheckFails_LogonContinues()
{
this.Mediator.Setup(m => m.Send(It.IsAny<GetConfigurationRequest>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(Result.Success(new Configuration { EnableAutoUpdates = true }));
this.Mediator.Setup(m => m.Send(It.IsAny<LoginRequest>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.AccessToken));
this.Mediator.Setup(m => m.Send(It.IsAny<LogonTransactionRequest>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.PerformLogonResponseModel));
this.Mediator.Setup(m => m.Send(It.IsAny<GetContractProductsRequest>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.ContractProductList));
this.Mediator.Setup(m => m.Send(It.IsAny<GetMerchantBalanceRequest>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Success(TestData.MerchantBalance));
this.ApplicationInfoService.Setup(a => a.VersionString).Returns(TestData.ApplicationVersion);
this.ApplicationInfoService.Setup(a => a.PackageName).Returns("com.transactionprocessor.mobile");
this.DeviceService.Setup(d => d.GetPlatform()).Returns("Android");
this.DeviceService.Setup(d => d.GetIdentifier()).Returns(TestData.DeviceIdentifier);
this.UpdateService.Setup(u => u.CheckForUpdates(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<String>(), It.IsAny<String>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(Result.Failure("Update check failed"));

await this.ViewModel.LogonCommand.ExecuteAsync(null);

this.UpdateService.Verify(u => u.CheckForUpdates(TestData.ApplicationVersion,
"com.transactionprocessor.mobile",
"Android",
TestData.DeviceIdentifier,
It.IsAny<CancellationToken>()), Times.Once);
this.NavigationService.Verify(n => n.GoToHome(), Times.Once);
}

[Fact]
public async Task LoginPageViewModel_LoginCommand_Execute_UpdateRequired_UpdateLauncherIsCalled_And_AppQuits()
{
this.Mediator.Setup(m => m.Send(It.IsAny<GetConfigurationRequest>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(Result.Success(new Configuration { EnableAutoUpdates = true }));
this.ApplicationInfoService.Setup(a => a.VersionString).Returns(TestData.ApplicationVersion);
this.ApplicationInfoService.Setup(a => a.PackageName).Returns("com.transactionprocessor.mobile");
this.DeviceService.Setup(d => d.GetPlatform()).Returns("Android");
this.DeviceService.Setup(d => d.GetIdentifier()).Returns(TestData.DeviceIdentifier);
this.UpdateService.Setup(u => u.CheckForUpdates(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<String>(), It.IsAny<String>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(Result.Success(new ApplicationUpdateCheckResponse
{
DownloadUri = "https://updates.example.com/transactionmobile.apk",
LatestVersion = "1.0.1",
Message = "Install update",
UpdateRequired = true
}));
this.DialogService.Setup(d => d.ShowDialog(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<String>(), It.IsAny<String>())).ReturnsAsync(true);

await this.ViewModel.LogonCommand.ExecuteAsync(null);

this.DialogService.Verify(d => d.ShowInformationToast("Downloading the required update...",
null,
"OK",
null,
CancellationToken.None), Times.Once);
this.ApplicationUpdateLauncherService.Verify(l => l.LaunchUpdateAsync("https://updates.example.com/transactionmobile.apk", It.IsAny<CancellationToken>()), Times.Once);
this.NavigationService.Verify(n => n.QuitApplication(), Times.Once);
this.Mediator.Verify(x => x.Send(It.IsAny<LoginRequest>(), It.IsAny<CancellationToken>()), Times.Never);
this.NavigationService.Verify(n => n.GoToHome(), Times.Never);
this.DialogService.Verify(n => n.ShowWarningToast(It.IsAny<String>(),
null,
"OK",
null,
CancellationToken.None), Times.Never);
}

[Fact]
public async Task LoginPageViewModel_LoginCommand_Execute_UpdateLauncherFails_WarningToastIsShown_And_AppStaysOpen()
{
this.Mediator.Setup(m => m.Send(It.IsAny<GetConfigurationRequest>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(Result.Success(new Configuration { EnableAutoUpdates = true }));
this.ApplicationInfoService.Setup(a => a.VersionString).Returns(TestData.ApplicationVersion);
this.ApplicationInfoService.Setup(a => a.PackageName).Returns("com.transactionprocessor.mobile");
this.DeviceService.Setup(d => d.GetPlatform()).Returns("Android");
this.DeviceService.Setup(d => d.GetIdentifier()).Returns(TestData.DeviceIdentifier);
this.UpdateService.Setup(u => u.CheckForUpdates(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<String>(), It.IsAny<String>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(Result.Success(new ApplicationUpdateCheckResponse
{
DownloadUri = "https://updates.example.com/transactionmobile.apk",
LatestVersion = "1.0.1",
Message = "Install update",
UpdateRequired = true
}));
this.DialogService.Setup(d => d.ShowDialog(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<String>(), It.IsAny<String>())).ReturnsAsync(true);
this.ApplicationUpdateLauncherService.Setup(l => l.LaunchUpdateAsync(It.IsAny<String>(), It.IsAny<CancellationToken>()))
.ThrowsAsync(new ApplicationException("Unable to start the application update installer."));

await this.ViewModel.LogonCommand.ExecuteAsync(null);

this.NavigationService.Verify(n => n.QuitApplication(), Times.Never);
this.NavigationService.Verify(n => n.GoToHome(), Times.Never);
this.DialogService.Verify(d => d.ShowWarningToast("Unable to start the application update installer.",
null,
"OK",
null,
CancellationToken.None), Times.Once);
}

[Fact]
public void LoginPageViewModel_LoginCommand_Execute_ErrorDuringLogonTransaction_WarningToastIsShown()
{
Expand Down Expand Up @@ -196,4 +298,4 @@ public void LoginPageViewModel_PropertyTests_ValuesAreAsExpected(){
this.ViewModel.UseTrainingMode.ShouldBeTrue();
this.ViewModel.DeviceIdentifier.ShouldBe("testidentifier");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Diagnostics.CodeAnalysis;

namespace TransactionProcessor.Mobile.BusinessLogic.Models;

[ExcludeFromCodeCoverage]
public class ApplicationUpdateCheckResponse
{
public Boolean UpdateRequired { get; set; }

public String? DownloadUri { get; set; }

public String? LatestVersion { get; set; }

public String? Message { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public class Configuration

public String EstateReportingUri { get; set; }

public String ApplicationUpdateUri { get; set; }

public LogLevel LogLevel { get; set; }

public Boolean EnableAutoUpdates { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public async Task<Result<Configuration>> GetConfiguration(String deviceIdentifie
response = new Configuration() {
ClientSecret = apiResponse.ClientSecret,
ClientId = apiResponse.ClientId,
ApplicationUpdateUri = apiResponse.ApplicationUpdateUri,
EnableAutoUpdates = apiResponse.EnableAutoUpdates,
SecurityServiceUri = apiResponse.HostAddresses.Single(h => h.ServiceType == ServiceType.Security).Uri,
TransactionProcessorAclUri =
Expand Down Expand Up @@ -125,4 +126,4 @@ public async Task PostDiagnosticLogs(String deviceIdentifier,

await this.HandleResponse(httpResponse, cancellationToken);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ public class ConfigurationResponse

public bool EnableAutoUpdates { get; set; }

public string ApplicationUpdateUri { get; set; }

public List<HostAddress> HostAddresses { get; set; }

public string Id { get; set; }

public LoggingLevel LogLevel { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class TrainingConfigurationService : IConfigurationService
public async Task<Result<Configuration>> GetConfiguration(String deviceIdentifier,
CancellationToken cancellationToken) {
return Result.Success(new Configuration {
ApplicationUpdateUri = String.Empty,
ClientId = "dummyClientId",
ClientSecret = "dummyClientSecret",
EnableAutoUpdates = false,
Expand All @@ -27,4 +28,4 @@ public async Task PostDiagnosticLogs(String deviceIdentifier,
CancellationToken cancellationToken) {
// Do nothing
}
}
}
Loading
Loading