repo creation with initial code after cloning public repo
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
using System.Net;
|
||||
using System.Net.Mime;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests.Controllers
|
||||
{
|
||||
public sealed class ActivityLogControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
private static string? _accessToken;
|
||||
|
||||
public ActivityLogControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ActivityLog_GetEntries_Ok()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var response = await client.GetAsync("System/ActivityLog/Entries");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using Jellyfin.Api;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Base controller for testing infrastructure.
|
||||
/// Automatically ignored in generated openapi spec.
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public class BaseJellyfinTestController : BaseJellyfinApiController
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Branding;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests
|
||||
{
|
||||
public sealed class BrandingControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
|
||||
public BrandingControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetConfiguration_ReturnsCorrectResponse()
|
||||
{
|
||||
// Arrange
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("/Branding/Configuration");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
||||
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
||||
await response.Content.ReadFromJsonAsync<BrandingOptions>();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/Branding/Css")]
|
||||
[InlineData("/Branding/Css.css")]
|
||||
public async Task GetCss_ReturnsCorrectResponse(string url)
|
||||
{
|
||||
// Arrange
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync(url);
|
||||
|
||||
// Assert
|
||||
Assert.True(response.IsSuccessStatusCode);
|
||||
Assert.Equal("text/css", response.Content.Headers.ContentType?.MediaType);
|
||||
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Api.Models;
|
||||
using Jellyfin.Extensions.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests.Controllers
|
||||
{
|
||||
public sealed class DashboardControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||
private static string? _accessToken;
|
||||
|
||||
public DashboardControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDashboardConfigurationPage_NonExistingPage_NotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("web/ConfigurationPage?name=ThisPageDoesntExists");
|
||||
|
||||
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");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(MediaTypeNames.Text.Html, response.Content.Headers.ContentType?.MediaType);
|
||||
StreamReader reader = new StreamReader(typeof(TestPlugin).Assembly.GetManifestResourceStream("Jellyfin.Server.Integration.Tests.TestPage.html")!);
|
||||
Assert.Equal(await response.Content.ReadAsStringAsync(), await reader.ReadToEndAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDashboardConfigurationPage_BrokenPage_NotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/web/ConfigurationPage?name=BrokenPage");
|
||||
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetConfigurationPages_NoParams_AllConfigurationPages()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var response = await client.GetAsync("/web/ConfigurationPages");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
_ = await response.Content.ReadFromJsonAsync<ConfigurationPageInfo[]>(_jsonOptions);
|
||||
// TODO: check content
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetConfigurationPages_True_MainMenuConfigurationPages()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var response = await client.GetAsync("/web/ConfigurationPages?enableInMainMenu=true");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
||||
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
||||
|
||||
var data = await response.Content.ReadFromJsonAsync<ConfigurationPageInfo[]>(_jsonOptions);
|
||||
Assert.NotNull(data);
|
||||
Assert.Empty(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Controller for testing the encoded url.
|
||||
/// </summary>
|
||||
public class EncoderController : BaseJellyfinTestController
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests the url decoding.
|
||||
/// </summary>
|
||||
/// <param name="params">Parameters to echo back in the response.</param>
|
||||
/// <returns>An <see cref="OkResult"/>.</returns>
|
||||
/// <response code="200">Information retrieved.</response>
|
||||
[HttpGet("UrlDecode")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public ContentResult TestUrlDecoding([FromQuery] Dictionary<string, string>? @params = null)
|
||||
{
|
||||
return new ContentResult()
|
||||
{
|
||||
Content = (@params is not null && @params.Count > 0)
|
||||
? string.Join("&", @params.Select(x => x.Key + "=" + x.Value))
|
||||
: string.Empty,
|
||||
ContentType = "text/plain; charset=utf-8",
|
||||
StatusCode = 200
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests the url decoding.
|
||||
/// </summary>
|
||||
/// <param name="params">Parameters to echo back in the response.</param>
|
||||
/// <returns>An <see cref="OkResult"/>.</returns>
|
||||
/// <response code="200">Information retrieved.</response>
|
||||
[HttpGet("UrlArrayDecode")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public ContentResult TestUrlArrayDecoding([FromQuery] Dictionary<string, string[]>? @params = null)
|
||||
{
|
||||
return new ContentResult()
|
||||
{
|
||||
Content = (@params is not null && @params.Count > 0)
|
||||
? string.Join("&", @params.Select(x => x.Key + "=" + string.Join(',', x.Value)))
|
||||
: string.Empty,
|
||||
ContentType = "text/plain; charset=utf-8",
|
||||
StatusCode = 200
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Extensions.Json;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests.Controllers;
|
||||
|
||||
public sealed class ItemsControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||
private static string? _accessToken;
|
||||
|
||||
public ItemsControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetItems_NoApiKeyOrUserId_Success()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var response = await client.GetAsync("Items");
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Users/{0}/Items")]
|
||||
[InlineData("Users/{0}/Items/Resume")]
|
||||
public async Task GetUserItems_NonexistentUserId_NotFound(string format)
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var response = await client.GetAsync(string.Format(CultureInfo.InvariantCulture, format, Guid.NewGuid()));
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Items?userId={0}")]
|
||||
[InlineData("Users/{0}/Items")]
|
||||
[InlineData("Users/{0}/Items/Resume")]
|
||||
public async Task GetItems_UserId_Ok(string format)
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var userDto = await AuthHelper.GetUserDtoAsync(client);
|
||||
|
||||
var response = await client.GetAsync(string.Format(CultureInfo.InvariantCulture, format, userDto.Id));
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var items = await response.Content.ReadFromJsonAsync<QueryResult<BaseItemDto>>(_jsonOptions);
|
||||
Assert.NotNull(items);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests.Controllers;
|
||||
|
||||
public sealed class LibraryControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
private static string? _accessToken;
|
||||
|
||||
public LibraryControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Items/{0}/File")]
|
||||
[InlineData("Items/{0}/ThemeSongs")]
|
||||
[InlineData("Items/{0}/ThemeVideos")]
|
||||
[InlineData("Items/{0}/ThemeMedia")]
|
||||
[InlineData("Items/{0}/Ancestors")]
|
||||
[InlineData("Items/{0}/Download")]
|
||||
[InlineData("Artists/{0}/Similar")]
|
||||
[InlineData("Items/{0}/Similar")]
|
||||
[InlineData("Albums/{0}/Similar")]
|
||||
[InlineData("Shows/{0}/Similar")]
|
||||
[InlineData("Movies/{0}/Similar")]
|
||||
[InlineData("Trailers/{0}/Similar")]
|
||||
public async Task Get_NonexistentItemId_NotFound(string format)
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var response = await client.GetAsync(string.Format(CultureInfo.InvariantCulture, format, Guid.NewGuid()));
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Items/{0}")]
|
||||
[InlineData("Items?ids={0}")]
|
||||
public async Task Delete_NonexistentItemId_Unauthorised(string format)
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
var response = await client.DeleteAsync(string.Format(CultureInfo.InvariantCulture, format, Guid.NewGuid()));
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Items/{0}")]
|
||||
[InlineData("Items?ids={0}")]
|
||||
public async Task Delete_NonexistentItemId_NotFound(string format)
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var response = await client.DeleteAsync(string.Format(CultureInfo.InvariantCulture, format, Guid.NewGuid()));
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
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(-2)]
|
||||
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(-2)]
|
||||
public async Task UpdateLibraryOptions_Valid_Success()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var createBody = new AddVirtualFolderDto()
|
||||
{
|
||||
LibraryOptions = new LibraryOptions()
|
||||
{
|
||||
Enabled = false
|
||||
}
|
||||
};
|
||||
|
||||
using var createResponse = await client.PostAsJsonAsync("Library/VirtualFolders?name=test&refreshLibrary=true", createBody, _jsonOptions);
|
||||
Assert.Equal(HttpStatusCode.NoContent, createResponse.StatusCode);
|
||||
|
||||
await Task.Delay(2000).ConfigureAwait(true);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Extensions.Json;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests.Controllers;
|
||||
|
||||
public sealed class LiveTvControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||
private static string? _accessToken;
|
||||
|
||||
public LiveTvControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddTunerHost_Unauthorized_ReturnsUnauthorized()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
var body = new TunerHostInfo()
|
||||
{
|
||||
Type = "m3u",
|
||||
Url = "Test Data/dummy.m3u8"
|
||||
};
|
||||
|
||||
var response = await client.PostAsJsonAsync("/LiveTv/TunerHosts", body, _jsonOptions);
|
||||
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddTunerHost_Valid_ReturnsCorrectResponse()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var body = new TunerHostInfo()
|
||||
{
|
||||
Type = "m3u",
|
||||
Url = "Test Data/dummy.m3u8"
|
||||
};
|
||||
|
||||
var response = await client.PostAsJsonAsync("/LiveTv/TunerHosts", body, _jsonOptions);
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
||||
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
||||
var responseBody = await response.Content.ReadFromJsonAsync<TunerHostInfo>();
|
||||
Assert.NotNull(responseBody);
|
||||
Assert.Equal(body.Type, responseBody.Type);
|
||||
Assert.Equal(body.Url, responseBody.Url);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddTunerHost_InvalidType_ReturnsNotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var body = new TunerHostInfo()
|
||||
{
|
||||
Type = "invalid",
|
||||
Url = "Test Data/dummy.m3u8"
|
||||
};
|
||||
|
||||
var response = await client.PostAsJsonAsync("/LiveTv/TunerHosts", body, _jsonOptions);
|
||||
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddTunerHost_InvalidUrl_ReturnsNotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var body = new TunerHostInfo()
|
||||
{
|
||||
Type = "m3u",
|
||||
Url = "thisgoesnowhere"
|
||||
};
|
||||
|
||||
var response = await client.PostAsJsonAsync("/LiveTv/TunerHosts", body, _jsonOptions);
|
||||
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.Net.Mime;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests.Controllers
|
||||
{
|
||||
public sealed class MediaInfoControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
private static string? _accessToken;
|
||||
|
||||
public MediaInfoControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BitrateTest_Default_Ok()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var response = await client.GetAsync("Playback/BitrateTest");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(MediaTypeNames.Application.Octet, response.Content.Headers.ContentType?.MediaType);
|
||||
Assert.NotNull(response.Content.Headers.ContentLength);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(102400)]
|
||||
public async Task BitrateTest_WithValidParam_Ok(int size)
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var response = await client.GetAsync("Playback/BitrateTest?size=" + size.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(MediaTypeNames.Application.Octet, response.Content.Headers.ContentType?.MediaType);
|
||||
Assert.NotNull(response.Content.Headers.ContentLength);
|
||||
Assert.InRange(response.Content.Headers.ContentLength!.Value, size, long.MaxValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)] // Zero
|
||||
[InlineData(-102400)] // Negative value
|
||||
[InlineData(1000000000)] // Too large
|
||||
public async Task BitrateTest_InvalidValue_BadRequest(int size)
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var response = await client.GetAsync("Playback/BitrateTest?size=" + size.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
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 Xunit;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests.Controllers
|
||||
{
|
||||
public sealed class MediaStructureControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||
private static string? _accessToken;
|
||||
|
||||
public MediaStructureControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RenameVirtualFolder_WhiteSpaceName_ReturnsBadRequest()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
using var postContent = new ByteArrayContent(Array.Empty<byte>());
|
||||
var response = await client.PostAsync("Library/VirtualFolders/Name?name=+&newName=test", postContent);
|
||||
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RenameVirtualFolder_WhiteSpaceNewName_ReturnsBadRequest()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
using var postContent = new ByteArrayContent(Array.Empty<byte>());
|
||||
var response = await client.PostAsync("Library/VirtualFolders/Name?name=test&newName=+", postContent);
|
||||
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RenameVirtualFolder_NameDoesntExist_ReturnsNotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
using var postContent = new ByteArrayContent(Array.Empty<byte>());
|
||||
var response = await client.PostAsync("Library/VirtualFolders/Name?name=doesnt+exist&newName=test", postContent);
|
||||
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddMediaPath_PathDoesntExist_ReturnsNotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var data = new MediaPathDto()
|
||||
{
|
||||
Name = "Test",
|
||||
Path = "/this/path/doesnt/exist"
|
||||
};
|
||||
|
||||
var response = await client.PostAsJsonAsync("Library/VirtualFolders/Paths", data, _jsonOptions);
|
||||
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateMediaPath_WhiteSpaceName_ReturnsBadRequest()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var data = new UpdateMediaPathRequestDto()
|
||||
{
|
||||
Name = " ",
|
||||
PathInfo = new MediaPathInfo("test")
|
||||
};
|
||||
|
||||
var response = await client.PostAsJsonAsync("Library/VirtualFolders/Paths/Update", data, _jsonOptions);
|
||||
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RemoveMediaPath_WhiteSpaceName_ReturnsBadRequest()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var response = await client.DeleteAsync("Library/VirtualFolders/Paths?name=+");
|
||||
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RemoveMediaPath_PathDoesntExist_ReturnsNotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var response = await client.DeleteAsync("Library/VirtualFolders/Paths?name=none&path=%2Fthis%2Fpath%2Fdoesnt%2Fexist");
|
||||
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests.Controllers;
|
||||
|
||||
public sealed class MusicGenreControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
private static string? _accessToken;
|
||||
|
||||
public MusicGenreControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MusicGenres_FakeMusicGenre_NotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var response = await client.GetAsync("MusicGenres/Fake-MusicGenre");
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests.Controllers;
|
||||
|
||||
public class PersonsControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
private static string? _accessToken;
|
||||
|
||||
public PersonsControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetPerson_DoesntExist_NotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
using var response = await client.GetAsync($"Persons/DoesntExist");
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests.Controllers;
|
||||
|
||||
public class PlaystateControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
private static string? _accessToken;
|
||||
|
||||
public PlaystateControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteMarkUnplayedItem_NonexistentUserId_NotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
using var response = await client.DeleteAsync($"Users/{Guid.NewGuid()}/PlayedItems/{Guid.NewGuid()}");
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostMarkPlayedItem_NonexistentUserId_NotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
using var response = await client.PostAsync($"Users/{Guid.NewGuid()}/PlayedItems/{Guid.NewGuid()}", null);
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteMarkUnplayedItem_NonexistentItemId_NotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var userDto = await AuthHelper.GetUserDtoAsync(client);
|
||||
|
||||
using var response = await client.DeleteAsync($"Users/{userDto.Id}/PlayedItems/{Guid.NewGuid()}");
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostMarkPlayedItem_NonexistentItemId_NotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var userDto = await AuthHelper.GetUserDtoAsync(client);
|
||||
|
||||
using var response = await client.PostAsync($"Users/{userDto.Id}/PlayedItems/{Guid.NewGuid()}", null);
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Extensions.Json;
|
||||
using MediaBrowser.Model.Plugins;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests.Controllers;
|
||||
|
||||
public sealed class PluginsControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
private static string? _accessToken;
|
||||
|
||||
public PluginsControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetPlugins_Unauthorized_ReturnsUnauthorized()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
var response = await client.GetAsync("/Plugins");
|
||||
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetPlugins_Authorized_ReturnsCorrectResponse()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var response = await client.GetAsync("/Plugins");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
||||
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
||||
_ = await response.Content.ReadFromJsonAsync<PluginInfo[]>(JsonDefaults.Options);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Net.Mime;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Api.Models.StartupDtos;
|
||||
using Jellyfin.Extensions.Json;
|
||||
using Xunit;
|
||||
using Xunit.Priority;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests.Controllers
|
||||
{
|
||||
[TestCaseOrderer(PriorityOrderer.Name, PriorityOrderer.Assembly)]
|
||||
public sealed class StartupControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||
|
||||
public StartupControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Priority(-2)]
|
||||
public async Task Configuration_EditConfig_Success()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
var config = new StartupConfigurationDto()
|
||||
{
|
||||
ServerName = "NewServer",
|
||||
UICulture = "NewCulture",
|
||||
MetadataCountryCode = "be",
|
||||
PreferredMetadataLanguage = "nl"
|
||||
};
|
||||
|
||||
using var postResponse = await client.PostAsJsonAsync("/Startup/Configuration", config, _jsonOptions);
|
||||
Assert.Equal(HttpStatusCode.NoContent, postResponse.StatusCode);
|
||||
|
||||
using var getResponse = await client.GetAsync("/Startup/Configuration");
|
||||
Assert.Equal(HttpStatusCode.OK, getResponse.StatusCode);
|
||||
Assert.Equal(MediaTypeNames.Application.Json, getResponse.Content.Headers.ContentType?.MediaType);
|
||||
|
||||
var newConfig = await getResponse.Content.ReadFromJsonAsync<StartupConfigurationDto>(_jsonOptions);
|
||||
Assert.Equal(config.ServerName, newConfig!.ServerName);
|
||||
Assert.Equal(config.UICulture, newConfig.UICulture);
|
||||
Assert.Equal(config.MetadataCountryCode, newConfig.MetadataCountryCode);
|
||||
Assert.Equal(config.PreferredMetadataLanguage, newConfig.PreferredMetadataLanguage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Priority(-2)]
|
||||
public async Task User_DefaultUser_NameWithoutPassword()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
using var response = await client.GetAsync("/Startup/User");
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
||||
|
||||
var user = await response.Content.ReadFromJsonAsync<StartupUserDto>(_jsonOptions);
|
||||
Assert.NotNull(user);
|
||||
Assert.NotNull(user.Name);
|
||||
Assert.NotEmpty(user.Name);
|
||||
Assert.Null(user.Password);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Priority(-1)]
|
||||
public async Task User_EditUser_Success()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
var user = new StartupUserDto()
|
||||
{
|
||||
Name = "NewName",
|
||||
Password = "NewPassword"
|
||||
};
|
||||
|
||||
var postResponse = await client.PostAsJsonAsync("/Startup/User", user, _jsonOptions);
|
||||
Assert.Equal(HttpStatusCode.NoContent, postResponse.StatusCode);
|
||||
|
||||
var getResponse = await client.GetAsync("/Startup/User");
|
||||
Assert.Equal(HttpStatusCode.OK, getResponse.StatusCode);
|
||||
Assert.Equal(MediaTypeNames.Application.Json, getResponse.Content.Headers.ContentType?.MediaType);
|
||||
|
||||
var newUser = await getResponse.Content.ReadFromJsonAsync<StartupUserDto>(_jsonOptions);
|
||||
Assert.NotNull(newUser);
|
||||
Assert.Equal(user.Name, newUser.Name);
|
||||
Assert.Null(newUser.Password);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Priority(0)]
|
||||
public async Task CompleteWizard_Success()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
var response = await client.PostAsync("/Startup/Complete", new ByteArrayContent(Array.Empty<byte>()));
|
||||
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Priority(1)]
|
||||
public async Task GetFirstUser_CompleteWizard_Unauthorized()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
using var response = await client.GetAsync("/Startup/User");
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Api.Models.UserDtos;
|
||||
using Jellyfin.Extensions.Json;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using Xunit;
|
||||
using Xunit.Priority;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests.Controllers
|
||||
{
|
||||
[TestCaseOrderer(PriorityOrderer.Name, PriorityOrderer.Assembly)]
|
||||
public sealed class UserControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private const string TestUsername = "testUser01";
|
||||
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||
private static string? _accessToken;
|
||||
private static Guid _testUserId = Guid.Empty;
|
||||
|
||||
public UserControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
private Task<HttpResponseMessage> CreateUserByName(HttpClient httpClient, CreateUserByName request)
|
||||
=> httpClient.PostAsJsonAsync("Users/New", request, _jsonOptions);
|
||||
|
||||
private Task<HttpResponseMessage> UpdateUserPassword(HttpClient httpClient, Guid userId, UpdateUserPassword request)
|
||||
=> httpClient.PostAsJsonAsync("Users/" + userId.ToString("N", CultureInfo.InvariantCulture) + "/Password", request, _jsonOptions);
|
||||
|
||||
[Fact]
|
||||
[Priority(-1)]
|
||||
public async Task GetPublicUsers_Valid_Success()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
using var response = await client.GetAsync("Users/Public");
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var users = await response.Content.ReadFromJsonAsync<UserDto[]>(_jsonOptions);
|
||||
// User are hidden by default
|
||||
Assert.NotNull(users);
|
||||
Assert.Empty(users);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Priority(-1)]
|
||||
public async Task GetUsers_Valid_Success()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
using var response = await client.GetAsync("Users");
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var users = await response.Content.ReadFromJsonAsync<UserDto[]>(_jsonOptions);
|
||||
Assert.NotNull(users);
|
||||
Assert.Single(users);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Priority(-1)]
|
||||
public async Task Me_Valid_Success()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
_ = await AuthHelper.GetUserDtoAsync(client);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Priority(0)]
|
||||
public async Task New_Valid_Success()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
// access token can't be null here as the previous test populated it
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken!);
|
||||
|
||||
var createRequest = new CreateUserByName()
|
||||
{
|
||||
Name = TestUsername
|
||||
};
|
||||
|
||||
using var response = await CreateUserByName(client, createRequest);
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var user = await response.Content.ReadFromJsonAsync<UserDto>(_jsonOptions);
|
||||
Assert.Equal(TestUsername, user!.Name);
|
||||
|
||||
_testUserId = user.Id;
|
||||
|
||||
Console.WriteLine(user.Id.ToString("N", CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
[InlineData(" ")]
|
||||
[InlineData("‼️")]
|
||||
[Priority(0)]
|
||||
public async Task New_Invalid_Fail(string? username)
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
// access token can't be null here as the previous test populated it
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken!);
|
||||
|
||||
var createRequest = new CreateUserByName()
|
||||
{
|
||||
Name = username!
|
||||
};
|
||||
|
||||
using var response = await CreateUserByName(client, createRequest);
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Priority(0)]
|
||||
public async Task Delete_DoesntExist_NotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
// access token can't be null here as the previous test populated it
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken!);
|
||||
|
||||
using var response = await client.DeleteAsync($"User/{Guid.NewGuid()}");
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Priority(1)]
|
||||
public async Task UpdateUserPassword_Valid_Success()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken!);
|
||||
|
||||
var createRequest = new UpdateUserPassword()
|
||||
{
|
||||
NewPw = "4randomPa$$word"
|
||||
};
|
||||
|
||||
using var response = await UpdateUserPassword(client, _testUserId, createRequest);
|
||||
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Priority(2)]
|
||||
public async Task UpdateUserPassword_Empty_RemoveSetPassword()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken!);
|
||||
|
||||
var createRequest = new UpdateUserPassword()
|
||||
{
|
||||
CurrentPw = "4randomPa$$word",
|
||||
};
|
||||
|
||||
using var response = await UpdateUserPassword(client, _testUserId, createRequest);
|
||||
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Extensions.Json;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests.Controllers;
|
||||
|
||||
public sealed class UserLibraryControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||
private static string? _accessToken;
|
||||
|
||||
public UserLibraryControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetRootFolder_NonexistentUserId_NotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var response = await client.GetAsync($"Users/{Guid.NewGuid()}/Items/Root");
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetRootFolder_UserId_Valid()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
_ = await AuthHelper.GetRootFolderDtoAsync(client);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Users/{0}/Items/{1}")]
|
||||
[InlineData("Users/{0}/Items/{1}/Intros")]
|
||||
[InlineData("Users/{0}/Items/{1}/LocalTrailers")]
|
||||
[InlineData("Users/{0}/Items/{1}/SpecialFeatures")]
|
||||
[InlineData("Users/{0}/Items/{1}/Lyrics")]
|
||||
public async Task GetItem_NonexistentUserId_NotFound(string format)
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var rootFolderDto = await AuthHelper.GetRootFolderDtoAsync(client);
|
||||
|
||||
var response = await client.GetAsync(string.Format(CultureInfo.InvariantCulture, format, Guid.NewGuid(), rootFolderDto.Id));
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Users/{0}/Items/{1}")]
|
||||
[InlineData("Users/{0}/Items/{1}/Intros")]
|
||||
[InlineData("Users/{0}/Items/{1}/LocalTrailers")]
|
||||
[InlineData("Users/{0}/Items/{1}/SpecialFeatures")]
|
||||
[InlineData("Users/{0}/Items/{1}/Lyrics")]
|
||||
public async Task GetItem_NonexistentItemId_NotFound(string format)
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var userDto = await AuthHelper.GetUserDtoAsync(client);
|
||||
|
||||
var response = await client.GetAsync(string.Format(CultureInfo.InvariantCulture, format, userDto.Id, Guid.NewGuid()));
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Disabled for flaky execution after refactor.")]
|
||||
public async Task GetItem_UserIdAndItemId_Valid()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var userDto = await AuthHelper.GetUserDtoAsync(client);
|
||||
var rootFolderDto = await AuthHelper.GetRootFolderDtoAsync(client, userDto.Id);
|
||||
|
||||
var response = await client.GetAsync($"Users/{userDto.Id}/Items/{rootFolderDto.Id}");
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var rootDto = await response.Content.ReadFromJsonAsync<BaseItemDto>(_jsonOptions);
|
||||
Assert.NotNull(rootDto);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Disabled for flaky execution after refactor.")]
|
||||
public async Task GetIntros_UserIdAndItemId_Valid()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var userDto = await AuthHelper.GetUserDtoAsync(client);
|
||||
var rootFolderDto = await AuthHelper.GetRootFolderDtoAsync(client, userDto.Id);
|
||||
|
||||
var response = await client.GetAsync($"Users/{userDto.Id}/Items/{rootFolderDto.Id}/Intros");
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var rootDto = await response.Content.ReadFromJsonAsync<QueryResult<BaseItemDto>>(_jsonOptions);
|
||||
Assert.NotNull(rootDto);
|
||||
}
|
||||
|
||||
[Theory(Skip = "Disabled for flaky execution after refactor.")]
|
||||
[InlineData("Users/{0}/Items/{1}/LocalTrailers")]
|
||||
[InlineData("Users/{0}/Items/{1}/SpecialFeatures")]
|
||||
public async Task LocalTrailersAndSpecialFeatures_UserIdAndItemId_Valid(string format)
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var userDto = await AuthHelper.GetUserDtoAsync(client);
|
||||
var rootFolderDto = await AuthHelper.GetRootFolderDtoAsync(client, userDto.Id);
|
||||
|
||||
var response = await client.GetAsync(string.Format(CultureInfo.InvariantCulture, format, userDto.Id, rootFolderDto.Id));
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var rootDto = await response.Content.ReadFromJsonAsync<BaseItemDto[]>(_jsonOptions);
|
||||
Assert.NotNull(rootDto);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Server.Integration.Tests.Controllers;
|
||||
|
||||
public sealed class VideosControllerTests : IClassFixture<JellyfinApplicationFactory>
|
||||
{
|
||||
private readonly JellyfinApplicationFactory _factory;
|
||||
private static string? _accessToken;
|
||||
|
||||
public VideosControllerTests(JellyfinApplicationFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteAlternateSources_NonexistentItemId_NotFound()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client));
|
||||
|
||||
var response = await client.DeleteAsync($"Videos/{Guid.NewGuid()}");
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user