diff options
Diffstat (limited to 'tests')
11 files changed, 188 insertions, 44 deletions
diff --git a/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs index 2e6ffb5f6..31d2b486b 100644 --- a/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs +++ b/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs @@ -1,14 +1,19 @@ +using System; using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; using AutoFixture; using AutoFixture.AutoMoq; +using Jellyfin.Api.Auth.DefaultAuthorizationPolicy; using Jellyfin.Api.Auth.FirstTimeSetupPolicy; using Jellyfin.Api.Constants; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Library; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; using Moq; using Xunit; @@ -18,7 +23,9 @@ namespace Jellyfin.Api.Tests.Auth.FirstTimeSetupPolicy { private readonly Mock<IConfigurationManager> _configurationManagerMock; private readonly List<IAuthorizationRequirement> _requirements; + private readonly DefaultAuthorizationHandler _defaultAuthorizationHandler; private readonly FirstTimeSetupHandler _firstTimeSetupHandler; + private readonly IAuthorizationService _authorizationService; private readonly Mock<IUserManager> _userManagerMock; private readonly Mock<IHttpContextAccessor> _httpContextAccessor; @@ -31,6 +38,21 @@ namespace Jellyfin.Api.Tests.Auth.FirstTimeSetupPolicy _httpContextAccessor = fixture.Freeze<Mock<IHttpContextAccessor>>(); _firstTimeSetupHandler = fixture.Create<FirstTimeSetupHandler>(); + _defaultAuthorizationHandler = fixture.Create<DefaultAuthorizationHandler>(); + + var services = new ServiceCollection(); + services.AddAuthorizationCore(); + services.AddLogging(); + services.AddOptions(); + services.AddSingleton<IAuthorizationHandler>(_defaultAuthorizationHandler); + services.AddSingleton<IAuthorizationHandler>(_firstTimeSetupHandler); + services.AddAuthorization(options => + { + options.AddPolicy("FirstTime", policy => policy.Requirements.Add(new FirstTimeSetupRequirement())); + options.AddPolicy("FirstTimeNoAdmin", policy => policy.Requirements.Add(new FirstTimeSetupRequirement(false, false))); + options.AddPolicy("FirstTimeSchedule", policy => policy.Requirements.Add(new FirstTimeSetupRequirement(true, false))); + }); + _authorizationService = services.BuildServiceProvider().GetRequiredService<IAuthorizationService>(); } [Theory] @@ -45,10 +67,9 @@ namespace Jellyfin.Api.Tests.Auth.FirstTimeSetupPolicy _httpContextAccessor, userRole); - var context = new AuthorizationHandlerContext(_requirements, claims, null); + var allowed = await _authorizationService.AuthorizeAsync(claims, "FirstTime"); - await _firstTimeSetupHandler.HandleAsync(context); - Assert.True(context.HasSucceeded); + Assert.True(allowed.Succeeded); } [Theory] @@ -63,17 +84,16 @@ namespace Jellyfin.Api.Tests.Auth.FirstTimeSetupPolicy _httpContextAccessor, userRole); - var context = new AuthorizationHandlerContext(_requirements, claims, null); + var allowed = await _authorizationService.AuthorizeAsync(claims, "FirstTime"); - await _firstTimeSetupHandler.HandleAsync(context); - Assert.Equal(shouldSucceed, context.HasSucceeded); + Assert.Equal(shouldSucceed, allowed.Succeeded); } [Theory] [InlineData(UserRoles.Administrator, true)] [InlineData(UserRoles.Guest, false)] [InlineData(UserRoles.User, true)] - public async Task ShouldRequireUserIfNotRequiresAdmin(string userRole, bool shouldSucceed) + public async Task ShouldRequireUserIfNotAdministrator(string userRole, bool shouldSucceed) { TestHelpers.SetupConfigurationManager(_configurationManagerMock, true); var claims = TestHelpers.SetupUser( @@ -81,24 +101,26 @@ namespace Jellyfin.Api.Tests.Auth.FirstTimeSetupPolicy _httpContextAccessor, userRole); - var context = new AuthorizationHandlerContext( - new List<IAuthorizationRequirement> { new FirstTimeSetupRequirement(false, false) }, - claims, - null); + var allowed = await _authorizationService.AuthorizeAsync(claims, "FirstTimeNoAdmin"); - await _firstTimeSetupHandler.HandleAsync(context); - Assert.Equal(shouldSucceed, context.HasSucceeded); + Assert.Equal(shouldSucceed, allowed.Succeeded); } [Fact] - public async Task ShouldAllowAdminApiKeyIfStartupWizardComplete() + public async Task ShouldDisallowUserIfOutsideSchedule() { + AccessSchedule[] accessSchedules = { new AccessSchedule(DynamicDayOfWeek.Everyday, 0, 0, Guid.Empty) }; + TestHelpers.SetupConfigurationManager(_configurationManagerMock, true); - var claims = new ClaimsPrincipal(new ClaimsIdentity([new Claim(ClaimTypes.Role, UserRoles.Administrator)])); - var context = new AuthorizationHandlerContext(_requirements, claims, null); + var claims = TestHelpers.SetupUser( + _userManagerMock, + _httpContextAccessor, + UserRoles.User, + accessSchedules); + + var allowed = await _authorizationService.AuthorizeAsync(claims, "FirstTimeSchedule"); - await _firstTimeSetupHandler.HandleAsync(context); - Assert.True(context.HasSucceeded); + Assert.False(allowed.Succeeded); } } } diff --git a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeExternalSourcesTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeExternalSourcesTests.cs index 263f74c90..84008cffd 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeExternalSourcesTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeExternalSourcesTests.cs @@ -35,7 +35,7 @@ namespace Jellyfin.MediaEncoding.Tests.Probing Protocol = MediaProtocol.Http, RequiredHttpHeaders = new Dictionary<string, string>() { - { "user_agent", userAgent }, + { "User-Agent", userAgent }, } }, ExtractChapters = false, @@ -44,7 +44,7 @@ namespace Jellyfin.MediaEncoding.Tests.Probing var extraArg = encoder.GetExtraArguments(req); - Assert.Contains(userAgent, extraArg, StringComparison.InvariantCulture); + Assert.Contains($"-user_agent \"{userAgent}\"", extraArg, StringComparison.InvariantCulture); } } } diff --git a/tests/Jellyfin.Providers.Tests/Manager/ItemImageProviderTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ItemImageProviderTests.cs index be5a401b1..5dd3eb8ab 100644 --- a/tests/Jellyfin.Providers.Tests/Manager/ItemImageProviderTests.cs +++ b/tests/Jellyfin.Providers.Tests/Manager/ItemImageProviderTests.cs @@ -209,7 +209,7 @@ namespace Jellyfin.Providers.Tests.Manager [InlineData(ImageType.Backdrop, 2, false)] [InlineData(ImageType.Primary, 1, true)] [InlineData(ImageType.Backdrop, 2, true)] - public async void RefreshImages_PopulatedItemPopulatedProviderDynamic_UpdatesImagesIfForced(ImageType imageType, int imageCount, bool forceRefresh) + public async Task RefreshImages_PopulatedItemPopulatedProviderDynamic_UpdatesImagesIfForced(ImageType imageType, int imageCount, bool forceRefresh) { var item = GetItemWithImages(imageType, imageCount, false); @@ -261,7 +261,7 @@ namespace Jellyfin.Providers.Tests.Manager [InlineData(ImageType.Backdrop, 2, true, MediaProtocol.File)] [InlineData(ImageType.Primary, 1, false, MediaProtocol.File)] [InlineData(ImageType.Backdrop, 2, false, MediaProtocol.File)] - public async void RefreshImages_EmptyItemPopulatedProviderDynamic_AddsImages(ImageType imageType, int imageCount, bool responseHasPath, MediaProtocol protocol) + public async Task RefreshImages_EmptyItemPopulatedProviderDynamic_AddsImages(ImageType imageType, int imageCount, bool responseHasPath, MediaProtocol protocol) { // Has to exist for querying DateModified time on file, results stored but not checked so not populating BaseItem.FileSystem = Mock.Of<IFileSystem>(); @@ -311,7 +311,7 @@ namespace Jellyfin.Providers.Tests.Manager [InlineData(ImageType.Primary, 1, true)] [InlineData(ImageType.Backdrop, 1, true)] [InlineData(ImageType.Backdrop, 2, true)] - public async void RefreshImages_PopulatedItemPopulatedProviderRemote_UpdatesImagesIfForced(ImageType imageType, int imageCount, bool forceRefresh) + public async Task RefreshImages_PopulatedItemPopulatedProviderRemote_UpdatesImagesIfForced(ImageType imageType, int imageCount, bool forceRefresh) { var item = GetItemWithImages(imageType, imageCount, false); @@ -366,7 +366,7 @@ namespace Jellyfin.Providers.Tests.Manager [InlineData(ImageType.Backdrop, 0, false)] // empty item, no cache to check [InlineData(ImageType.Backdrop, 1, false)] // populated item, cached so no download [InlineData(ImageType.Backdrop, 1, true)] // populated item, forced to download - public async void RefreshImages_NonStubItemPopulatedProviderRemote_DownloadsIfNecessary(ImageType imageType, int initialImageCount, bool fullRefresh) + public async Task RefreshImages_NonStubItemPopulatedProviderRemote_DownloadsIfNecessary(ImageType imageType, int initialImageCount, bool fullRefresh) { var targetImageCount = 1; @@ -429,7 +429,7 @@ namespace Jellyfin.Providers.Tests.Manager [Theory] [MemberData(nameof(GetImageTypesWithCount))] - public async void RefreshImages_EmptyItemPopulatedProviderRemoteExtras_LimitsImages(ImageType imageType, int imageCount) + public async Task RefreshImages_EmptyItemPopulatedProviderRemoteExtras_LimitsImages(ImageType imageType, int imageCount) { var item = new Video(); @@ -473,7 +473,7 @@ namespace Jellyfin.Providers.Tests.Manager [Theory] [MemberData(nameof(GetImageTypesWithCount))] - public async void RefreshImages_PopulatedItemEmptyProviderRemoteFullRefresh_DoesntClearImages(ImageType imageType, int imageCount) + public async Task RefreshImages_PopulatedItemEmptyProviderRemoteFullRefresh_DoesntClearImages(ImageType imageType, int imageCount) { var item = GetItemWithImages(imageType, imageCount, false); @@ -501,7 +501,7 @@ namespace Jellyfin.Providers.Tests.Manager [InlineData(9, false)] [InlineData(10, true)] [InlineData(null, true)] - public async void RefreshImages_ProviderRemote_FiltersByWidth(int? remoteImageWidth, bool expectedToUpdate) + public async Task RefreshImages_ProviderRemote_FiltersByWidth(int? remoteImageWidth, bool expectedToUpdate) { var imageType = ImageType.Primary; @@ -575,18 +575,22 @@ namespace Jellyfin.Providers.Tests.Manager // Has to exist for querying DateModified time on file, results stored but not checked so not populating BaseItem.FileSystem ??= Mock.Of<IFileSystem>(); - var item = new Video(); + var item = new Mock<Video> + { + CallBase = true + }; + item.Setup(m => m.IsSaveLocalMetadataEnabled()).Returns(false); var path = validPaths ? _testDataImagePath.Format : "invalid path {0}"; for (int i = 0; i < count; i++) { - item.SetImagePath(type, i, new FileSystemMetadata + item.Object.SetImagePath(type, i, new FileSystemMetadata { FullName = string.Format(CultureInfo.InvariantCulture, path, i), }); } - return item; + return item.Object; } private static ILocalImageProvider GetImageProvider(ImageType type, int count, bool validPaths) diff --git a/tests/Jellyfin.Providers.Tests/Manager/MetadataServiceTests.cs b/tests/Jellyfin.Providers.Tests/Manager/MetadataServiceTests.cs index ec4df9981..cedcaf9c0 100644 --- a/tests/Jellyfin.Providers.Tests/Manager/MetadataServiceTests.cs +++ b/tests/Jellyfin.Providers.Tests/Manager/MetadataServiceTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; @@ -19,7 +20,7 @@ namespace Jellyfin.Providers.Tests.Manager [InlineData(true, true)] public void MergeBaseItemData_MergeMetadataSettings_MergesWhenSet(bool mergeMetadataSettings, bool defaultDate) { - var newLocked = new[] { MetadataField.Cast }; + var newLocked = new[] { MetadataField.Genres, MetadataField.Cast }; var newString = "new"; var newDate = DateTime.Now; @@ -77,7 +78,7 @@ namespace Jellyfin.Providers.Tests.Manager [Theory] [InlineData("Name", MetadataField.Name, false)] - [InlineData("OriginalTitle", null, false)] + [InlineData("OriginalTitle", null)] [InlineData("OfficialRating", MetadataField.OfficialRating)] [InlineData("CustomRating")] [InlineData("Tagline")] diff --git a/tests/Jellyfin.Providers.Tests/MediaInfo/AudioResolverTests.cs b/tests/Jellyfin.Providers.Tests/MediaInfo/AudioResolverTests.cs index d5f6873a2..290cb817a 100644 --- a/tests/Jellyfin.Providers.Tests/MediaInfo/AudioResolverTests.cs +++ b/tests/Jellyfin.Providers.Tests/MediaInfo/AudioResolverTests.cs @@ -64,7 +64,7 @@ public class AudioResolverTests [InlineData("My.Video.mp3", false, true)] [InlineData("My.Video.srt", true, false)] [InlineData("My.Video.mp3", true, true)] - public async void GetExternalStreams_MixedFilenames_PicksAudio(string file, bool metadataDirectory, bool matches) + public async Task GetExternalStreams_MixedFilenames_PicksAudio(string file, bool metadataDirectory, bool matches) { BaseItem.MediaSourceManager = Mock.Of<IMediaSourceManager>(); diff --git a/tests/Jellyfin.Providers.Tests/MediaInfo/EmbeddedImageProviderTests.cs b/tests/Jellyfin.Providers.Tests/MediaInfo/EmbeddedImageProviderTests.cs index 85963e5de..c0b41ba43 100644 --- a/tests/Jellyfin.Providers.Tests/MediaInfo/EmbeddedImageProviderTests.cs +++ b/tests/Jellyfin.Providers.Tests/MediaInfo/EmbeddedImageProviderTests.cs @@ -37,7 +37,7 @@ namespace Jellyfin.Providers.Tests.MediaInfo } [Fact] - public async void GetImage_NoStreams_ReturnsNoImage() + public async Task GetImage_NoStreams_ReturnsNoImage() { var input = new Movie(); @@ -55,7 +55,7 @@ namespace Jellyfin.Providers.Tests.MediaInfo [InlineData("clearlogo.png", null, 1, ImageType.Logo, ImageFormat.Png)] // extract extension from name [InlineData("backdrop", "image/bmp", 2, ImageType.Backdrop, ImageFormat.Bmp)] // extract extension from mimetype [InlineData("poster", null, 3, ImageType.Primary, ImageFormat.Jpg)] // default extension to jpg - public async void GetImage_Attachment_ReturnsCorrectSelection(string filename, string? mimetype, int targetIndex, ImageType type, ImageFormat? expectedFormat) + public async Task GetImage_Attachment_ReturnsCorrectSelection(string filename, string? mimetype, int targetIndex, ImageType type, ImageFormat? expectedFormat) { var attachments = new List<MediaAttachment>(); string pathPrefix = "path"; @@ -103,7 +103,7 @@ namespace Jellyfin.Providers.Tests.MediaInfo [InlineData(null, "mjpeg", 1, ImageType.Primary, ImageFormat.Jpg)] [InlineData(null, "png", 1, ImageType.Primary, ImageFormat.Png)] [InlineData(null, "webp", 1, ImageType.Primary, ImageFormat.Webp)] - public async void GetImage_Embedded_ReturnsCorrectSelection(string? label, string? codec, int targetIndex, ImageType type, ImageFormat? expectedFormat) + public async Task GetImage_Embedded_ReturnsCorrectSelection(string? label, string? codec, int targetIndex, ImageType type, ImageFormat? expectedFormat) { var streams = new List<MediaStream>(); for (int i = 1; i <= targetIndex; i++) diff --git a/tests/Jellyfin.Providers.Tests/MediaInfo/MediaInfoResolverTests.cs b/tests/Jellyfin.Providers.Tests/MediaInfo/MediaInfoResolverTests.cs index 58b67ae55..db427308c 100644 --- a/tests/Jellyfin.Providers.Tests/MediaInfo/MediaInfoResolverTests.cs +++ b/tests/Jellyfin.Providers.Tests/MediaInfo/MediaInfoResolverTests.cs @@ -182,7 +182,7 @@ public class MediaInfoResolverTests [Theory] [InlineData("https://url.com/My.Video.mkv")] [InlineData(VideoDirectoryPath)] // valid but no files found for this test - public async void GetExternalStreams_BadPaths_ReturnsNoSubtitles(string path) + public async Task GetExternalStreams_BadPaths_ReturnsNoSubtitles(string path) { // need a media source manager capable of returning something other than file protocol var mediaSourceManager = new Mock<IMediaSourceManager>(); @@ -285,7 +285,7 @@ public class MediaInfoResolverTests [Theory] [MemberData(nameof(GetExternalStreams_MergeMetadata_HandlesOverridesCorrectly_Data))] - public async void GetExternalStreams_MergeMetadata_HandlesOverridesCorrectly(string file, MediaStream[] inputStreams, MediaStream[] expectedStreams) + public async Task GetExternalStreams_MergeMetadata_HandlesOverridesCorrectly(string file, MediaStream[] inputStreams, MediaStream[] expectedStreams) { BaseItem.MediaSourceManager = Mock.Of<IMediaSourceManager>(); @@ -335,7 +335,7 @@ public class MediaInfoResolverTests [InlineData(1, 2)] [InlineData(2, 1)] [InlineData(2, 2)] - public async void GetExternalStreams_StreamIndex_HandlesFilesAndContainers(int fileCount, int streamCount) + public async Task GetExternalStreams_StreamIndex_HandlesFilesAndContainers(int fileCount, int streamCount) { BaseItem.MediaSourceManager = Mock.Of<IMediaSourceManager>(); diff --git a/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs b/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs index 8077bd791..e0d365927 100644 --- a/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs +++ b/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs @@ -64,7 +64,7 @@ public class SubtitleResolverTests [InlineData("My.Video.mp3", false, false)] [InlineData("My.Video.srt", true, true)] [InlineData("My.Video.mp3", true, false)] - public async void GetExternalStreams_MixedFilenames_PicksSubtitles(string file, bool metadataDirectory, bool matches) + public async Task GetExternalStreams_MixedFilenames_PicksSubtitles(string file, bool metadataDirectory, bool matches) { BaseItem.MediaSourceManager = Mock.Of<IMediaSourceManager>(); diff --git a/tests/Jellyfin.Providers.Tests/MediaInfo/VideoImageProviderTests.cs b/tests/Jellyfin.Providers.Tests/MediaInfo/VideoImageProviderTests.cs index 7ea6f7d9c..028f6feba 100644 --- a/tests/Jellyfin.Providers.Tests/MediaInfo/VideoImageProviderTests.cs +++ b/tests/Jellyfin.Providers.Tests/MediaInfo/VideoImageProviderTests.cs @@ -34,7 +34,7 @@ namespace Jellyfin.Providers.Tests.MediaInfo [Theory] [MemberData(nameof(GetImage_UnsupportedInput_ReturnsNoImage_TestData))] - public async void GetImage_UnsupportedInput_ReturnsNoImage(Video input) + public async Task GetImage_UnsupportedInput_ReturnsNoImage(Video input) { var mediaSourceManager = GetMediaSourceManager(input, null, new List<MediaStream>()); var videoImageProvider = new VideoImageProvider(mediaSourceManager, Mock.Of<IMediaEncoder>(), new NullLogger<VideoImageProvider>()); @@ -47,7 +47,7 @@ namespace Jellyfin.Providers.Tests.MediaInfo [Theory] [InlineData(1, 1)] // default not first stream [InlineData(5, 0)] // default out of valid range - public async void GetImage_DefaultVideoStreams_ReturnsCorrectStreamImage(int defaultIndex, int targetIndex) + public async Task GetImage_DefaultVideoStreams_ReturnsCorrectStreamImage(int defaultIndex, int targetIndex) { var input = new Movie { DefaultVideoStreamIndex = defaultIndex }; @@ -80,7 +80,7 @@ namespace Jellyfin.Providers.Tests.MediaInfo [Theory] [InlineData(null, 10)] // default time [InlineData(500, 50)] // calculated time - public async void GetImage_TimeSpan_SelectsCorrectTime(int? runTimeSeconds, long expectedSeconds) + public async Task GetImage_TimeSpan_SelectsCorrectTime(int? runTimeSeconds, long expectedSeconds) { MediaStream targetStream = new() { Type = MediaStreamType.Video, Index = 0 }; var input = new Movie diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/LibraryStructureControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/LibraryStructureControllerTests.cs new file mode 100644 index 000000000..bf3bfdad4 --- /dev/null +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/LibraryStructureControllerTests.cs @@ -0,0 +1,114 @@ +using System; +using System.Linq; +using System.Net; +using System.Net.Http.Json; +using System.Text.Json; +using System.Threading.Tasks; +using Jellyfin.Api.Models.LibraryStructureDto; +using Jellyfin.Extensions.Json; +using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Entities; +using Xunit; +using Xunit.Priority; + +namespace Jellyfin.Server.Integration.Tests.Controllers; + +[TestCaseOrderer(PriorityOrderer.Name, PriorityOrderer.Assembly)] +public sealed class LibraryStructureControllerTests : IClassFixture<JellyfinApplicationFactory> +{ + private readonly JellyfinApplicationFactory _factory; + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; + private static string? _accessToken; + + public LibraryStructureControllerTests(JellyfinApplicationFactory factory) + { + _factory = factory; + } + + [Fact] + [Priority(-1)] + public async Task Post_NewVirtualFolder_NotFound() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); + + var body = new AddVirtualFolderDto() + { + LibraryOptions = new LibraryOptions() + { + Enabled = false + } + }; + + using var response = await client.PostAsJsonAsync("Library/VirtualFolders?name=test&refreshLibrary=true", body, _jsonOptions); + Assert.Equal(HttpStatusCode.NoContent, response.StatusCode); + } + + [Fact] + [Priority(0)] + public async Task UpdateLibraryOptions_Invalid_NotFound() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); + + var body = new UpdateLibraryOptionsDto() + { + Id = Guid.NewGuid(), + LibraryOptions = new LibraryOptions() + }; + + using var response = await client.PostAsJsonAsync("Library/VirtualFolders/LibraryOptions", body, _jsonOptions); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + [Priority(0)] + public async Task UpdateLibraryOptions_Valid_Success() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); + + using var response = await client.GetAsync("Library/VirtualFolders"); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + var library = await response.Content.ReadFromJsonAsAsyncEnumerable<VirtualFolderInfo>(_jsonOptions) + .FirstOrDefaultAsync(x => string.Equals(x?.Name, "test", StringComparison.Ordinal)); + Assert.NotNull(library); + + var options = library.LibraryOptions; + Assert.NotNull(options); + Assert.False(options.Enabled); + options.Enabled = true; + + var body = new UpdateLibraryOptionsDto() + { + Id = Guid.Parse(library.ItemId), + LibraryOptions = options + }; + + using var response2 = await client.PostAsJsonAsync("Library/VirtualFolders/LibraryOptions", body, _jsonOptions); + Assert.Equal(HttpStatusCode.NoContent, response2.StatusCode); + } + + [Fact] + [Priority(1)] + public async Task DeleteLibrary_Invalid_NotFound() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); + + using var response = await client.DeleteAsync("Library/VirtualFolders?name=doesntExist"); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + [Priority(1)] + public async Task DeleteLibrary_Valid_Success() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); + + using var response = await client.DeleteAsync("Library/VirtualFolders?name=test&refreshLibrary=true"); + Assert.Equal(HttpStatusCode.NoContent, response.StatusCode); + } +} diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Location/MovieNfoLocationTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Location/MovieNfoLocationTests.cs index 8019e0ab3..2f05c4ea2 100644 --- a/tests/Jellyfin.XbmcMetadata.Tests/Location/MovieNfoLocationTests.cs +++ b/tests/Jellyfin.XbmcMetadata.Tests/Location/MovieNfoLocationTests.cs @@ -47,6 +47,7 @@ namespace Jellyfin.XbmcMetadata.Tests.Location var movie = new Movie() { Path = "/media/movies/Avengers Endgame", VideoType = VideoType.Dvd }; var path1 = "/media/movies/Avengers Endgame/Avengers Endgame.nfo"; var path2 = "/media/movies/Avengers Endgame/VIDEO_TS/VIDEO_TS.nfo"; + var path3 = "/media/movies/Avengers Endgame/movie.nfo"; // uses ContainingFolderPath which uses Operating system specific paths if (OperatingSystem.IsWindows()) @@ -54,12 +55,14 @@ namespace Jellyfin.XbmcMetadata.Tests.Location movie.Path = movie.Path.Replace('/', '\\'); path1 = path1.Replace('/', '\\'); path2 = path2.Replace('/', '\\'); + path3 = path3.Replace('/', '\\'); } var paths = MovieNfoSaver.GetMovieSavePaths(new ItemInfo(movie)).ToArray(); - Assert.Equal(2, paths.Length); + Assert.Equal(3, paths.Length); Assert.Contains(path1, paths); Assert.Contains(path2, paths); + Assert.Contains(path3, paths); } } } |
