using System.Net.Http.Json; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Omika.Core.Contracts.Mobile.Languages; namespace Omika.Tests.Api; /// /// Tests HTTP de l'API dédiée de téléchargement des modèles de langue (ONNX). /// Accès anonyme : vérifie le manifeste, le streaming de fichier et les 404. /// public class LanguageEndpointsTests : IDisposable { private const string ManifestJson = """ { "packs": [ { "code": "es", "libelle": "Espagnol", "version": "1.0.0", "fichiers": [ { "sens": "versFrancais", "nomFichier": "encoder.onnx", "tailleOctets": 16, "sha256": "abc" } ] } ] } """; private readonly string _root; private readonly WebApplicationFactory _factory; public LanguageEndpointsTests() { _root = CreateRoot(); Populate(_root); _factory = CreateFactory(_root); } public void Dispose() { _factory.Dispose(); Directory.Delete(_root, true); } [Fact] public async Task Langues_Manifest_RetournePacksEtUrls() { var client = _factory.CreateClient(); var response = await client.GetAsync("/api/langues"); Assert.Equal(200, (int)response.StatusCode); var manifest = await response.Content.ReadFromJsonAsync(); Assert.NotNull(manifest); var pack = Assert.Single(manifest.Packs); Assert.Equal("es", pack.Code); Assert.Equal("Espagnol", pack.Libelle); var fichier = Assert.Single(pack.Fichiers); Assert.Equal("/api/langues/es/versFrancais/encoder.onnx", fichier.Url); } [Fact] public async Task Langues_Fichier_RetourneContenu() { var client = _factory.CreateClient(); var response = await client.GetAsync("/api/langues/es/versFrancais/encoder.onnx"); Assert.Equal(200, (int)response.StatusCode); string content = await response.Content.ReadAsStringAsync(); Assert.Equal("fake-model-bytes", content); } [Fact] public async Task Langues_Fichier_Introuvable_Retourne404() { var client = _factory.CreateClient(); var response = await client.GetAsync("/api/langues/es/versFrancais/absent.onnx"); Assert.Equal(404, (int)response.StatusCode); } [Fact] public async Task Langues_ManifestAbsent_Retourne404() { string emptyRoot = CreateRoot(); using var emptyFactory = CreateFactory(emptyRoot); try { var client = emptyFactory.CreateClient(); var response = await client.GetAsync("/api/langues"); Assert.Equal(404, (int)response.StatusCode); } finally { Directory.Delete(emptyRoot, true); } } // ===== Helpers ===== private static string CreateRoot() { string root = Path.Combine(Path.GetTempPath(), "omika-langues-" + Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); return root; } private static void Populate(string root) { Directory.CreateDirectory(Path.Combine(root, "es", "versFrancais")); File.WriteAllText(Path.Combine(root, "manifest.json"), ManifestJson); File.WriteAllText(Path.Combine(root, "es", "versFrancais", "encoder.onnx"), "fake-model-bytes"); } private static WebApplicationFactory CreateFactory(string root) => new WebApplicationFactory() .WithWebHostBuilder(builder => { builder.ConfigureServices(services => { var config = new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { ["Langues:RootPath"] = root, ["Langues:ManifestFileName"] = "manifest.json" }) .Build(); services.AddSingleton(config); }); }); }