Premiere commit - Omika
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
using System.Net.Http;
|
||||
using System.Security.Cryptography;
|
||||
using Omika.App.Local.Abstractions;
|
||||
using Omika.App.Local.Models;
|
||||
using Omika.App.Local.Repositories;
|
||||
using Omika.App.Local.Services;
|
||||
using Omika.Core.Contracts.Mobile.License;
|
||||
using Omika.Core.Observability.Diagnostic;
|
||||
using Omika.Core.Services.Mobile;
|
||||
|
||||
namespace Omika.Tests.Mobile.Local;
|
||||
|
||||
/// <summary>
|
||||
/// Tests du service d'inscription (QR → licence → API → stockage).
|
||||
/// </summary>
|
||||
public class MobileEnrollmentServiceTests : LocalTestBase
|
||||
{
|
||||
private const string Kid = "test-kid-1";
|
||||
|
||||
private sealed class FakeLicenseEnrollmentClient : ILicenseEnrollmentClient
|
||||
{
|
||||
public MobileLicenseSessionResponse ActivateResponse { get; set; } = new();
|
||||
public string? LastUrl { get; private set; }
|
||||
public LicenseActivateRequest? LastRequest { get; private set; }
|
||||
|
||||
public Task<MobileLicenseSessionResponse> ActivateAsync(
|
||||
string licenseServiceUrl, LicenseActivateRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
LastUrl = licenseServiceUrl;
|
||||
LastRequest = request;
|
||||
return Task.FromResult(ActivateResponse);
|
||||
}
|
||||
|
||||
public Task<MobileLicenseSessionResponse> ValidateAsync(
|
||||
string licenseServiceUrl, LicenseValidateRequest request, CancellationToken cancellationToken = default)
|
||||
=> Task.FromResult(new MobileLicenseSessionResponse());
|
||||
}
|
||||
|
||||
private sealed class FakeDeviceIdProvider : IDeviceIdProvider
|
||||
{
|
||||
public Task<string> GetDeviceIdAsync(CancellationToken cancellationToken = default)
|
||||
=> Task.FromResult("device-1");
|
||||
}
|
||||
|
||||
private static string CreateSignedQr(string code, string numero, string url, out IReadOnlyDictionary<string, string> registry)
|
||||
{
|
||||
using var rsa = RSA.Create(2048);
|
||||
registry = new Dictionary<string, string> { [Kid] = rsa.ToXmlString(false) };
|
||||
return EnrollmentQrCodec.Sign(
|
||||
EnrollmentQrCodec.BuildPayloadJson(Kid, code, numero, url),
|
||||
rsa.ToXmlString(true));
|
||||
}
|
||||
|
||||
private MobileEnrollmentService CreateService(
|
||||
FakeLicenseEnrollmentClient licenseClient,
|
||||
IReadOnlyDictionary<string, string> registry,
|
||||
MobileApiClient apiClient,
|
||||
MobileEnrollmentStore? store = null)
|
||||
=> new(
|
||||
licenseClient,
|
||||
store ?? new MobileEnrollmentStore(Database),
|
||||
new FakeDeviceIdProvider(),
|
||||
new StubSessionService(),
|
||||
apiClient,
|
||||
registry);
|
||||
|
||||
[Fact]
|
||||
public async Task LicenceInvalide_OmikaApiUrlNonEnregistree()
|
||||
{
|
||||
var licenseClient = new FakeLicenseEnrollmentClient
|
||||
{
|
||||
ActivateResponse = new MobileLicenseSessionResponse
|
||||
{
|
||||
License = new LicenseResponse { IsValid = false, ErrorCode = "E3002", ErrorMessage = "Licence inactive" }
|
||||
}
|
||||
};
|
||||
var apiClient = new MobileApiClient(new HttpClient());
|
||||
string qr = CreateSignedQr("BATIK.01", "LIC-001", "https://licence.example.com", out var registry);
|
||||
var service = CreateService(licenseClient, registry, apiClient);
|
||||
|
||||
EnrollmentResult result = await service.EnrollAsync(qr);
|
||||
|
||||
Assert.False(result.Success);
|
||||
Assert.Null(await service.LoadAsync());
|
||||
Assert.Null(apiClient.BaseUrl);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LicenceValideSansApiUrl_InscriptionRefusee()
|
||||
{
|
||||
var licenseClient = new FakeLicenseEnrollmentClient
|
||||
{
|
||||
ActivateResponse = new MobileLicenseSessionResponse
|
||||
{
|
||||
License = new LicenseResponse { IsValid = true, ApiUrl = null }
|
||||
}
|
||||
};
|
||||
var apiClient = new MobileApiClient(new HttpClient());
|
||||
string qr = CreateSignedQr("BATIK.01", "LIC-001", "https://licence.example.com", out var registry);
|
||||
var service = CreateService(licenseClient, registry, apiClient);
|
||||
|
||||
EnrollmentResult result = await service.EnrollAsync(qr);
|
||||
|
||||
Assert.False(result.Success);
|
||||
Assert.Null(await service.LoadAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LicenceValideApiUrlHttp_Refusee()
|
||||
{
|
||||
var licenseClient = new FakeLicenseEnrollmentClient
|
||||
{
|
||||
ActivateResponse = new MobileLicenseSessionResponse
|
||||
{
|
||||
License = new LicenseResponse { IsValid = true, ApiUrl = "http://api.example.com" }
|
||||
}
|
||||
};
|
||||
var apiClient = new MobileApiClient(new HttpClient());
|
||||
string qr = CreateSignedQr("BATIK.01", "LIC-001", "https://licence.example.com", out var registry);
|
||||
var service = CreateService(licenseClient, registry, apiClient);
|
||||
|
||||
EnrollmentResult result = await service.EnrollAsync(qr);
|
||||
|
||||
Assert.False(result.Success);
|
||||
Assert.Null(await service.LoadAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LicenceValideApiUrlHttps_Enregistree()
|
||||
{
|
||||
var licenseClient = new FakeLicenseEnrollmentClient
|
||||
{
|
||||
ActivateResponse = new MobileLicenseSessionResponse
|
||||
{
|
||||
License = new LicenseResponse { IsValid = true, ApiUrl = "https://api.example.com" },
|
||||
AccessToken = "token-1"
|
||||
}
|
||||
};
|
||||
var apiClient = new MobileApiClient(new HttpClient());
|
||||
string qr = CreateSignedQr("BATIK.01", "LIC-001", "https://licence.example.com", out var registry);
|
||||
var service = CreateService(licenseClient, registry, apiClient);
|
||||
|
||||
EnrollmentResult result = await service.EnrollAsync(qr);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.Equal("https://api.example.com", result.Configuration!.OmikaApiUrl);
|
||||
Assert.Equal("https://licence.example.com", result.Configuration.LicenseServiceUrl);
|
||||
Assert.Equal("https://api.example.com", apiClient.BaseUrl);
|
||||
|
||||
MobileEnrollmentConfiguration? persisted = await service.LoadAsync();
|
||||
Assert.NotNull(persisted);
|
||||
Assert.Equal("https://api.example.com", persisted!.OmikaApiUrl);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task QrInvalide_RefuseSansAppelReseau()
|
||||
{
|
||||
var licenseClient = new FakeLicenseEnrollmentClient();
|
||||
var apiClient = new MobileApiClient(new HttpClient());
|
||||
string qr = CreateSignedQr("BATIK.01", "LIC-001", "https://licence.example.com", out var registry);
|
||||
var service = CreateService(licenseClient, registry, apiClient);
|
||||
|
||||
EnrollmentResult result = await service.EnrollAsync("qr-corrompu");
|
||||
|
||||
Assert.False(result.Success);
|
||||
Assert.Null(licenseClient.LastUrl); // aucun appel au service de licence
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Enroll_AvecDeviceInfo_RemplitChampsActivation()
|
||||
{
|
||||
var licenseClient = new FakeLicenseEnrollmentClient
|
||||
{
|
||||
ActivateResponse = new MobileLicenseSessionResponse
|
||||
{
|
||||
License = new LicenseResponse { IsValid = false } // suffit pour observer la requête
|
||||
}
|
||||
};
|
||||
var apiClient = new MobileApiClient(new HttpClient());
|
||||
string qr = CreateSignedQr("BATIK.01", "LIC-001", "https://licence.example.com", out var registry);
|
||||
var deviceInfo = new DeviceInfoSnapshot
|
||||
{
|
||||
OperatingSystem = "Android",
|
||||
OperatingSystemVersion = "16",
|
||||
AppVersion = "1.0.0",
|
||||
DeviceManufacturer = "Xiaomi",
|
||||
DeviceModel = "23113RKC6G"
|
||||
};
|
||||
var service = new MobileEnrollmentService(
|
||||
licenseClient,
|
||||
new MobileEnrollmentStore(Database),
|
||||
new FakeDeviceIdProvider(),
|
||||
new StubSessionService(),
|
||||
apiClient,
|
||||
registry,
|
||||
deviceInfo);
|
||||
|
||||
await service.EnrollAsync(qr);
|
||||
|
||||
Assert.Equal("Android", licenseClient.LastRequest!.OsType);
|
||||
Assert.Equal("16", licenseClient.LastRequest.OsVersion);
|
||||
Assert.Equal("1.0.0", licenseClient.LastRequest.AppVersion);
|
||||
Assert.Equal("manufacturer=Xiaomi;model=23113RKC6G", licenseClient.LastRequest.DeviceInfo);
|
||||
Assert.Null(licenseClient.LastRequest.NotificationKey);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user