Ver Fonte

Add tests for DashboardController

Bond_009 há 4 anos atrás
pai
commit
57102090d3

+ 11 - 31
Jellyfin.Api/Controllers/DashboardController.cs

@@ -22,22 +22,18 @@ namespace Jellyfin.Api.Controllers
     public class DashboardController : BaseJellyfinApiController
     {
         private readonly ILogger<DashboardController> _logger;
-        private readonly IServerApplicationHost _appHost;
         private readonly IPluginManager _pluginManager;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="DashboardController"/> class.
         /// </summary>
         /// <param name="logger">Instance of <see cref="ILogger{DashboardController}"/> interface.</param>
-        /// <param name="appHost">Instance of <see cref="IServerApplicationHost"/> interface.</param>
         /// <param name="pluginManager">Instance of <see cref="IPluginManager"/> interface.</param>
         public DashboardController(
             ILogger<DashboardController> logger,
-            IServerApplicationHost appHost,
             IPluginManager pluginManager)
         {
             _logger = logger;
-            _appHost = appHost;
             _pluginManager = pluginManager;
         }
 
@@ -51,7 +47,7 @@ namespace Jellyfin.Api.Controllers
         [HttpGet("web/ConfigurationPages")]
         [ProducesResponseType(StatusCodes.Status200OK)]
         [ProducesResponseType(StatusCodes.Status404NotFound)]
-        public ActionResult<IEnumerable<ConfigurationPageInfo?>> GetConfigurationPages(
+        public ActionResult<IEnumerable<ConfigurationPageInfo>> GetConfigurationPages(
             [FromQuery] bool? enableInMainMenu)
         {
             var configPages = _pluginManager.Plugins.SelectMany(GetConfigPages).ToList();
@@ -77,38 +73,22 @@ namespace Jellyfin.Api.Controllers
         [ProducesFile(MediaTypeNames.Text.Html, "application/x-javascript")]
         public ActionResult GetDashboardConfigurationPage([FromQuery] string? name)
         {
-            IPlugin? plugin = null;
-            Stream? stream = null;
-
-            var isJs = false;
-            var isTemplate = false;
-
             var altPage = GetPluginPages().FirstOrDefault(p => string.Equals(p.Item1.Name, name, StringComparison.OrdinalIgnoreCase));
-            if (altPage != null)
+            if (altPage == null)
             {
-                plugin = altPage.Item2;
-                stream = plugin.GetType().Assembly.GetManifestResourceStream(altPage.Item1.EmbeddedResourcePath);
-
-                isJs = string.Equals(Path.GetExtension(altPage.Item1.EmbeddedResourcePath), ".js", StringComparison.OrdinalIgnoreCase);
-                isTemplate = altPage.Item1.EmbeddedResourcePath.EndsWith(".template.html", StringComparison.Ordinal);
+                return NotFound();
             }
 
-            if (plugin != null && stream != null)
+            IPlugin plugin = altPage.Item2;
+            string resourcePath = altPage.Item1.EmbeddedResourcePath;
+            Stream? stream = plugin.GetType().Assembly.GetManifestResourceStream(resourcePath);
+            if (stream == null)
             {
-                if (isJs)
-                {
-                    return File(stream, MimeTypes.GetMimeType("page.js"));
-                }
-
-                if (isTemplate)
-                {
-                    return File(stream, MimeTypes.GetMimeType("page.html"));
-                }
-
-                return File(stream, MimeTypes.GetMimeType("page.html"));
+                _logger.LogError("Failed to get resource {Resource} from plugin {Plugin}", resourcePath, plugin.Name);
+                return NotFound();
             }
 
-            return NotFound();
+            return File(stream, MimeTypes.GetMimeType(resourcePath));
         }
 
         private IEnumerable<ConfigurationPageInfo> GetConfigPages(LocalPlugin plugin)
@@ -120,7 +100,7 @@ namespace Jellyfin.Api.Controllers
         {
             if (plugin?.Instance is not IHasWebPages hasWebPages)
             {
-                return new List<Tuple<PluginPageInfo, IPlugin>>();
+                return Enumerable.Empty<Tuple<PluginPageInfo, IPlugin>>();
             }
 
             return hasWebPages.GetPages().Select(i => new Tuple<PluginPageInfo, IPlugin>(i, plugin.Instance));

+ 0 - 1
Jellyfin.Api/Models/ConfigurationPageInfo.cs

@@ -1,6 +1,5 @@
 using System;
 using MediaBrowser.Common.Plugins;
-using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Model.Plugins;
 
 namespace Jellyfin.Api.Models

+ 0 - 1
Jellyfin.Server/CoreAppHost.cs

@@ -11,7 +11,6 @@ using Jellyfin.Server.Implementations;
 using Jellyfin.Server.Implementations.Activity;
 using Jellyfin.Server.Implementations.Events;
 using Jellyfin.Server.Implementations.Users;
-using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.BaseItemManager;
 using MediaBrowser.Controller.Drawing;

+ 0 - 3
MediaBrowser.Common/Plugins/BasePlugin.cs

@@ -1,10 +1,7 @@
 using System;
 using System.IO;
 using System.Reflection;
-using System.Runtime.InteropServices;
-using MediaBrowser.Common.Configuration;
 using MediaBrowser.Model.Plugins;
-using MediaBrowser.Model.Serialization;
 
 namespace MediaBrowser.Common.Plugins
 {

+ 6 - 5
tests/Jellyfin.Api.Tests/BrandingServiceTests.cs → tests/Jellyfin.Api.Tests/Controllers/BrandingControllerTests.cs

@@ -5,11 +5,11 @@ using Xunit;
 
 namespace Jellyfin.Api.Tests
 {
-    public sealed class BrandingServiceTests : IClassFixture<JellyfinApplicationFactory>
+    public sealed class BrandingControllerTests : IClassFixture<JellyfinApplicationFactory>
     {
         private readonly JellyfinApplicationFactory _factory;
 
-        public BrandingServiceTests(JellyfinApplicationFactory factory)
+        public BrandingControllerTests(JellyfinApplicationFactory factory)
         {
             _factory = factory;
         }
@@ -24,8 +24,9 @@ namespace Jellyfin.Api.Tests
             var response = await client.GetAsync("/Branding/Configuration");
 
             // Assert
-            response.EnsureSuccessStatusCode();
-            Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType?.ToString());
+            Assert.True(response.IsSuccessStatusCode);
+            Assert.Equal("application/json", response.Content.Headers.ContentType?.MediaType);
+            Assert.Equal("utf-8", response.Content.Headers.ContentType?.CharSet);
             var responseBody = await response.Content.ReadAsStreamAsync();
             _ = await JsonSerializer.DeserializeAsync<BrandingOptions>(responseBody);
         }
@@ -42,7 +43,7 @@ namespace Jellyfin.Api.Tests
             var response = await client.GetAsync(url);
 
             // Assert
-            response.EnsureSuccessStatusCode();
+            Assert.True(response.IsSuccessStatusCode);
             Assert.Equal("text/css; charset=utf-8", response.Content.Headers.ContentType?.ToString());
         }
     }

+ 76 - 0
tests/Jellyfin.Api.Tests/Controllers/DashboardControllerTests.cs

@@ -0,0 +1,76 @@
+using System.IO;
+using System.Net;
+using System.Text.Json;
+using System.Threading.Tasks;
+using Jellyfin.Api.Models;
+using Xunit;
+
+namespace Jellyfin.Api.Tests.Controllers
+{
+    public sealed class DashboardControllerTests : IClassFixture<JellyfinApplicationFactory>
+    {
+        private readonly JellyfinApplicationFactory _factory;
+
+        public DashboardControllerTests(JellyfinApplicationFactory factory)
+        {
+            _factory = factory;
+        }
+
+        [Fact]
+        public async Task GetDashboardConfigurationPage_NonExistingPage_NotFound()
+        {
+            var client = _factory.CreateClient();
+
+            var response = await client.GetAsync("web/ConfigurationPage/ThisPageTotally/Doesnt/Exists.html").ConfigureAwait(false);
+
+            Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
+        }
+
+        [Fact]
+        public async Task GetDashboardConfigurationPage_ExistingPage_CorrectPage()
+        {
+            var client = _factory.CreateClient();
+
+            var response = await client.GetAsync("/web/ConfigurationPage?name=TestPlugin").ConfigureAwait(false);
+
+            Assert.True(response.IsSuccessStatusCode);
+            Assert.Equal("text/html", response.Content.Headers.ContentType?.MediaType);
+            StreamReader reader = new StreamReader(typeof(TestPlugin).Assembly.GetManifestResourceStream("Jellyfin.Api.Tests.TestPage.html")!);
+            Assert.Equal(await response.Content.ReadAsStringAsync(), reader.ReadToEnd());
+        }
+
+        [Fact]
+        public async Task GetDashboardConfigurationPage_BrokenPage_NotFound()
+        {
+            var client = _factory.CreateClient();
+
+            var response = await client.GetAsync("/web/ConfigurationPage?name=BrokenPage").ConfigureAwait(false);
+
+            Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
+        }
+
+        [Fact]
+        public async Task GetConfigurationPages_NoParams_AllConfigurationPages()
+        {
+            var client = _factory.CreateClient();
+
+            var response = await client.GetAsync("/web/ConfigurationPages").ConfigureAwait(false);
+
+            Assert.True(response.IsSuccessStatusCode);
+            var res = await JsonSerializer.DeserializeAsync<ConfigurationPageInfo[]>(await response.Content.ReadAsStreamAsync());
+            // TODO: check content
+        }
+
+        [Fact]
+        public async Task GetConfigurationPages_True_MainMenuConfigurationPages()
+        {
+            var client = _factory.CreateClient();
+
+            var response = await client.GetAsync("/web/ConfigurationPages?enableInMainMenu=true").ConfigureAwait(false);
+
+            Assert.True(response.IsSuccessStatusCode);
+            var res = await JsonSerializer.DeserializeAsync<ConfigurationPageInfo[]>(await response.Content.ReadAsStreamAsync());
+            Assert.Empty(res);
+        }
+    }
+}

+ 4 - 0
tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj

@@ -41,4 +41,8 @@
     <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
   </PropertyGroup>
 
+  <ItemGroup>
+    <EmbeddedResource Include="TestPage.html" />
+  </ItemGroup>
+
 </Project>

+ 2 - 2
tests/Jellyfin.Api.Tests/JellyfinApplicationFactory.cs

@@ -73,7 +73,7 @@ namespace Jellyfin.Api.Tests
             _disposableComponents.Add(loggerFactory);
 
             // Create the app host and initialize it
-            var appHost = new CoreAppHost(
+            var appHost = new TestAppHost(
                 appPaths,
                 loggerFactory,
                 commandLineOpts,
@@ -93,7 +93,7 @@ namespace Jellyfin.Api.Tests
             var testServer = base.CreateServer(builder);
 
             // Finish initializing the app host
-            var appHost = (CoreAppHost)testServer.Services.GetRequiredService<IApplicationHost>();
+            var appHost = (TestAppHost)testServer.Services.GetRequiredService<IApplicationHost>();
             appHost.ServiceProvider = testServer.Services;
             appHost.InitializeServices().GetAwaiter().GetResult();
             appHost.RunStartupTasksAsync().GetAwaiter().GetResult();

+ 51 - 0
tests/Jellyfin.Api.Tests/TestAppHost.cs

@@ -0,0 +1,51 @@
+using System.Collections.Generic;
+using System.Reflection;
+using Emby.Server.Implementations;
+using Jellyfin.Server;
+using MediaBrowser.Controller;
+using MediaBrowser.Model.IO;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+
+namespace Jellyfin.Api.Tests
+{
+    /// <summary>
+    /// Implementation of the abstract <see cref="ApplicationHost" /> class.
+    /// </summary>
+    public class TestAppHost : CoreAppHost
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TestAppHost" /> class.
+        /// </summary>
+        /// <param name="applicationPaths">The <see cref="ServerApplicationPaths" /> to be used by the <see cref="CoreAppHost" />.</param>
+        /// <param name="loggerFactory">The <see cref="ILoggerFactory" /> to be used by the <see cref="CoreAppHost" />.</param>
+        /// <param name="options">The <see cref="StartupOptions" /> to be used by the <see cref="CoreAppHost" />.</param>
+        /// <param name="fileSystem">The <see cref="IFileSystem" /> to be used by the <see cref="CoreAppHost" />.</param>
+        /// <param name="collection">The <see cref="IServiceCollection"/> to be used by the <see cref="CoreAppHost"/>.</param>
+        public TestAppHost(
+            IServerApplicationPaths applicationPaths,
+            ILoggerFactory loggerFactory,
+            IStartupOptions options,
+            IFileSystem fileSystem,
+            IServiceCollection collection)
+            : base(
+                applicationPaths,
+                loggerFactory,
+                options,
+                fileSystem,
+                collection)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override IEnumerable<Assembly> GetAssembliesWithPartsInternal()
+        {
+            foreach (var a in base.GetAssembliesWithPartsInternal())
+            {
+                yield return a;
+            }
+
+            yield return typeof(TestPlugin).Assembly;
+        }
+    }
+}

+ 9 - 0
tests/Jellyfin.Api.Tests/TestPage.html

@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>TestPlugin</title>
+</head>
+<body>
+    <h1>This is a Test Page.</h1>
+</body>
+</html>

+ 43 - 0
tests/Jellyfin.Api.Tests/TestPlugin.cs

@@ -0,0 +1,43 @@
+#pragma warning disable CS1591
+
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Plugins;
+using MediaBrowser.Model.Plugins;
+using MediaBrowser.Model.Serialization;
+
+namespace Jellyfin.Api.Tests
+{
+    public class TestPlugin : BasePlugin<BasePluginConfiguration>, IHasWebPages
+    {
+        public TestPlugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
+            : base(applicationPaths, xmlSerializer)
+        {
+            Instance = this;
+        }
+
+        public static TestPlugin? Instance { get; private set; }
+
+        public override Guid Id => new Guid("2d350a13-0bf7-4b61-859c-d5e601b5facf");
+
+        public override string Name => nameof(TestPlugin);
+
+        public override string Description => "Server test Plugin.";
+
+        public IEnumerable<PluginPageInfo> GetPages()
+        {
+            yield return new PluginPageInfo
+            {
+                Name = Name,
+                EmbeddedResourcePath = GetType().Namespace + ".TestPage.html"
+            };
+
+            yield return new PluginPageInfo
+            {
+                Name = "BrokenPage",
+                EmbeddedResourcePath = GetType().Namespace + ".foobar"
+            };
+        }
+    }
+}