using System.Net; using Jellyfin.Plugin.Multilang.Data; using Jellyfin.Plugin.Multilang.Services.Assets; namespace Jellyfin.Plugin.Multilang.Tests; public sealed class AssetStorageServiceTests { [Fact] public async Task LocalStorageDownloadsAStableAssetPathAndServesIt() { var root = TestPaths.CreateRoot(); try { var store = new TranslationStore(new TestApplicationPaths(root)); var factory = new TestHttpClientFactory(_ => new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent([1, 2, 3]) }); var service = new AssetStorageService(factory, store); var path = await service.StoreAsync("item", "fi", "poster", "https://images.example/poster.jpg", true, CancellationToken.None); Assert.NotNull(path); Assert.StartsWith(TranslationStore.LocalAssetUrlPrefix, path, StringComparison.Ordinal); Assert.True(store.TryNormalizeLocalAssetPath(path, out var fullPath)); Assert.Equal([1, 2, 3], await File.ReadAllBytesAsync(fullPath)); Assert.True(service.TryResolveLocalAsset(path[TranslationStore.LocalAssetUrlPrefix.Length..], out var resolved, out var contentType)); Assert.Equal(fullPath, resolved); Assert.Equal("image/jpeg", contentType); } finally { TestPaths.DeleteRoot(root); } } [Fact] public async Task UrlStorageDoesNotFetchOrWriteAnAsset() { var root = TestPaths.CreateRoot(); try { var store = new TranslationStore(new TestApplicationPaths(root)); var factory = new TestHttpClientFactory(_ => throw new InvalidOperationException("URL storage must not fetch.")); var service = new AssetStorageService(factory, store); const string url = "https://images.example/poster.webp"; var result = await service.StoreAsync("item", "fi", "poster", url, false, CancellationToken.None); Assert.Equal(url, result); Assert.Empty(factory.Requests); Assert.Empty(Directory.EnumerateFiles(store.AssetsDirectory, "*", SearchOption.AllDirectories)); } finally { TestPaths.DeleteRoot(root); } } [Fact] public async Task LocalStorageRejectsAnOversizedResponseBeforeWritingIt() { var root = TestPaths.CreateRoot(); try { var store = new TranslationStore(new TestApplicationPaths(root)); var factory = new TestHttpClientFactory(_ => { var content = new ByteArrayContent([1]); content.Headers.ContentLength = 51L * 1024L * 1024L; return new HttpResponseMessage(HttpStatusCode.OK) { Content = content }; }); var service = new AssetStorageService(factory, store); await Assert.ThrowsAsync(() => service.StoreAsync("item", "fi", "poster", "https://images.example/poster.jpg", true, CancellationToken.None)); Assert.Empty(Directory.EnumerateFiles(store.AssetsDirectory, "*", SearchOption.AllDirectories)); } finally { TestPaths.DeleteRoot(root); } } }