Premiere commit - Omika

This commit is contained in:
2026-10-23 18:46:50 +02:00
commit 8ea76c1b24
2155 changed files with 984301 additions and 0 deletions
@@ -0,0 +1,187 @@
using Omika.Diagnostics.Models;
using Omika.Diagnostics.Tests.Fakes;
using Omika.Diagnostics.Web.Pages;
namespace Omika.Diagnostics.Tests;
/// <summary>
/// T17-E — PageModel /Parc : vue générale, répartitions, liste appareils, filtres,
/// pagination, drill-down et réattribution de licence. Testés sans HttpContext
/// (constructeur repository uniquement, comme les autres PageModels).
/// </summary>
public class DiagnosticParcModelTests
{
private static DiagnosticEventRecord Ev(
long id,
string deviceKey,
DateTimeOffset ts,
string? client = null,
string? license = null,
string? platform = "Android",
string? os = "Android",
string? osVersion = "15",
string? manufacturer = null,
string? model = null,
string? appVersion = null)
{
DiagnosticEventRecord e = DiagnosticTestData.Event(Guid.NewGuid(), timestamp: ts);
e.Id = id;
e.DeviceKey = deviceKey;
e.ClientCode = client;
e.LicenseNumber = license;
e.Platform = platform;
e.OperatingSystem = os;
e.OperatingSystemVersion = osVersion;
e.DeviceManufacturer = manufacturer;
e.DeviceModel = model;
e.AppVersion = appVersion;
return e;
}
// ------------------------------- vue générale + répartitions ----
[Fact]
public async Task ParcModel_LoadsOverviewAndDistributions()
{
var repo = new FakeDiagnosticEventRepository();
DateTimeOffset now = DateTimeOffset.UtcNow;
await repo.InsertBatchAsync(new[]
{
Ev(1, "d1", now.AddMinutes(-60), platform: "Android", osVersion: "16", manufacturer: "Xiaomi"),
Ev(2, "d2", now.AddMinutes(-50), platform: "iOS", os: "iOS", osVersion: "18.5", manufacturer: "Apple"),
Ev(3, "d3", now.AddMinutes(-40), platform: "Android", osVersion: "15", manufacturer: "Samsung")
});
var model = new ParcModel(repo);
await model.OnGetAsync();
Assert.True(model.PostgreSqlAvailable);
Assert.True(model.HasData);
Assert.Equal(3, model.ActiveDevices);
Assert.Equal(2, model.AndroidDevices);
Assert.Equal(1, model.IosDevices);
Assert.Equal(0, model.DesktopDevices);
Assert.Equal(3, model.Devices.Count);
Assert.NotEmpty(model.ManufacturerDistribution);
Assert.NotEmpty(model.OsVersionDistribution);
}
// ------------------------------- réattribution de licence ----
[Fact]
public async Task ParcModel_LicenseReassigned_ShowsTwoDevices()
{
var repo = new FakeDiagnosticEventRepository();
DateTimeOffset now = DateTimeOffset.UtcNow;
await repo.InsertBatchAsync(new[]
{
Ev(1, "dev-a", now.AddDays(-20), license: "LIC-001", manufacturer: "Samsung", model: "SM-DEMO"),
Ev(2, "dev-b", now.AddDays(-1), license: "LIC-001", manufacturer: "Apple", model: "iPhoneDemo", os: "iOS", osVersion: "18")
});
var model = new ParcModel(repo);
await model.OnGetAsync();
Assert.Equal(2, model.ActiveDevices);
Assert.Equal(2, model.Devices.Count);
Assert.Contains(model.Devices, d => d.DeviceKey == "dev-a");
Assert.Contains(model.Devices, d => d.DeviceKey == "dev-b");
// « Appareils observés par licence » : LIC-001 → 2 appareils distincts, jamais 1.
Omika.Diagnostics.Queries.DeviceDistribution lic = Assert.Single(model.LicenseDistribution);
Assert.Equal("LIC-001", lic.Key);
Assert.Equal(2, lic.DeviceCount);
}
// ------------------------------- filtre licence ----
[Fact]
public async Task ParcModel_LicenseFilter_ReturnsOnlyMatchingDevices()
{
var repo = new FakeDiagnosticEventRepository();
DateTimeOffset now = DateTimeOffset.UtcNow;
await repo.InsertBatchAsync(new[]
{
Ev(1, "dev-a", now.AddMinutes(-30), license: "LIC-A"),
Ev(2, "dev-b", now.AddMinutes(-20), license: "LIC-A"),
Ev(3, "dev-c", now.AddMinutes(-10), license: "LIC-B")
});
var model = new ParcModel(repo) { LicenseNumber = "LIC-A" };
await model.OnGetAsync();
Assert.Equal(2, model.ActiveDevices);
Assert.All(model.Devices, d => Assert.Equal("LIC-A", d.LicenseNumber));
}
// ------------------------------- filtre client + plateforme ----
[Fact]
public async Task ParcModel_ClientAndPlatformFilters_Combine()
{
var repo = new FakeDiagnosticEventRepository();
DateTimeOffset now = DateTimeOffset.UtcNow;
await repo.InsertBatchAsync(new[]
{
Ev(1, "d1", now.AddMinutes(-60), client: "CLIENT-A", platform: "Android"),
Ev(2, "d2", now.AddMinutes(-50), client: "CLIENT-A", platform: "iOS", os: "iOS"),
Ev(3, "d3", now.AddMinutes(-40), client: "CLIENT-B", platform: "Android")
});
var model = new ParcModel(repo) { ClientCode = "CLIENT-A", Platform = "Android" };
await model.OnGetAsync();
Assert.Equal(1, model.ActiveDevices);
Omika.Diagnostics.Queries.DeviceFleetRecord device = Assert.Single(model.Devices);
Assert.Equal("d1", device.DeviceKey);
}
// ------------------------------- pagination / Route ----
[Fact]
public void ParcModel_Route_PreservesFilters()
{
var model = new ParcModel(new FakeDiagnosticEventRepository())
{
ClientCode = "CLIENT-A",
LicenseNumber = "LIC-A",
Platform = "Android",
Manufacturer = "Samsung"
};
Dictionary<string, string> route = model.Route(2);
Assert.Equal("2", route["pageNumber"]);
Assert.Equal("CLIENT-A", route["clientCode"]);
Assert.Equal("LIC-A", route["licenseNumber"]);
Assert.Equal("Android", route["platform"]);
Assert.Equal("Samsung", route["manufacturer"]);
}
// ------------------------------- zéro appareil ----
[Fact]
public async Task ParcModel_NoDevices_HasDataFalse()
{
var repo = new FakeDiagnosticEventRepository();
var model = new ParcModel(repo);
await model.OnGetAsync();
Assert.False(model.HasData);
Assert.Equal(0, model.ActiveDevices);
Assert.Empty(model.Devices);
}
// ------------------------------- pourcentage formaté ----
[Fact]
public async Task ParcModel_FormatPercentage_NoNaN()
{
var repo = new FakeDiagnosticEventRepository();
DateTimeOffset now = DateTimeOffset.UtcNow;
await repo.InsertBatchAsync(new[]
{
Ev(1, "d1", now.AddMinutes(-60), platform: "Android"),
Ev(2, "d2", now.AddMinutes(-50), platform: "iOS", os: "iOS")
});
var model = new ParcModel(repo);
await model.OnGetAsync();
Assert.Equal(2, model.ActiveDevices);
Assert.Equal("50 %", model.FormatPercentage(1));
}
}