91 lines
3.4 KiB
C#
91 lines
3.4 KiB
C#
using System.Net;
|
|
using System.Net.Http;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using Omika.App.Local.Abstractions;
|
|
using Omika.App.Local.Services;
|
|
using Omika.Core.Contracts.Mobile.License;
|
|
|
|
namespace Omika.Tests.Mobile.Local;
|
|
|
|
/// <summary>
|
|
/// Tests du MobileApiClient : aucun fallback d'URL, échec propre sans URL,
|
|
/// et utilisation de l'URL d'inscription une fois configurée.
|
|
/// </summary>
|
|
public class MobileApiClientNoUrlTests
|
|
{
|
|
private sealed class RecordingHandler : HttpMessageHandler
|
|
{
|
|
public int Calls { get; private set; }
|
|
public string? LastUri { get; private set; }
|
|
|
|
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
|
{
|
|
Calls++;
|
|
LastUri = request.RequestUri?.ToString();
|
|
string json = JsonSerializer.Serialize(new MobileLicenseSessionResponse
|
|
{
|
|
License = new LicenseResponse { IsValid = true }
|
|
}, new JsonSerializerOptions(JsonSerializerDefaults.Web));
|
|
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)
|
|
{
|
|
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
|
});
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Aucune URL d'API : l'échec est immédiat, typé, et AUCUN octet ne part (aucun
|
|
/// fallback localhost). Le type dédié permet de classer cet état en Warning/P2 —
|
|
/// et non en incident P1 — tout en restant une InvalidOperationException pour les
|
|
/// traitements existants qui le considèrent comme non terminal.
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task SansUrl_LeveExceptionDedieeSansAppelHttp()
|
|
{
|
|
var handler = new RecordingHandler();
|
|
var client = new MobileApiClient(new HttpClient(handler));
|
|
|
|
MobileEnrollmentRequiredException ex =
|
|
await Assert.ThrowsAsync<MobileEnrollmentRequiredException>(() => client.GetBootstrapAsync());
|
|
|
|
Assert.Equal(0, handler.Calls); // aucun appel HTTP, aucun fallback localhost.
|
|
Assert.Equal(MobileEnrollmentRequiredException.DefaultMessage, ex.Message);
|
|
Assert.IsAssignableFrom<InvalidOperationException>(ex);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ticket de production du 09/10 (AgendaViewModel) : c'est le repli API de
|
|
/// l'agenda qui a révélé l'absence d'URL. Le garde-fou doit s'appliquer à tout
|
|
/// appel métier, sans jamais émettre de requête.
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task SansUrl_AppelMetierAgenda_LeveExceptionDedieeSansAppelHttp()
|
|
{
|
|
var handler = new RecordingHandler();
|
|
var client = new MobileApiClient(new HttpClient(handler));
|
|
|
|
await Assert.ThrowsAsync<MobileEnrollmentRequiredException>(() =>
|
|
client.GetRendezVousByCollaborateurAsync(
|
|
Guid.NewGuid(), DateTime.Today, DateTime.Today.AddDays(7)));
|
|
|
|
Assert.Equal(0, handler.Calls);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UrlConfiguree_UtiliseUrlEnregistree()
|
|
{
|
|
var handler = new RecordingHandler();
|
|
var client = new MobileApiClient(new HttpClient(handler))
|
|
{
|
|
BaseUrl = "https://api.example.com"
|
|
};
|
|
client.AccessToken = "token";
|
|
|
|
await client.GetBootstrapAsync();
|
|
|
|
Assert.Equal(1, handler.Calls);
|
|
Assert.StartsWith("https://api.example.com/api/mobile/bootstrap", handler.LastUri);
|
|
}
|
|
}
|