mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-04-23 10:42:37 -04:00
221 lines
8.2 KiB
C#
221 lines
8.2 KiB
C#
using System.Net;
|
|
using System.Net.Http;
|
|
using System.Text;
|
|
using allstarr.Controllers;
|
|
using allstarr.Models.Admin;
|
|
using allstarr.Models.Settings;
|
|
using allstarr.Services.Admin;
|
|
using allstarr.Services.Common;
|
|
using allstarr.Services.Spotify;
|
|
using allstarr.Services.SquidWTF;
|
|
using Microsoft.AspNetCore.Hosting;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
using Moq;
|
|
|
|
namespace allstarr.Tests;
|
|
|
|
public class DiagnosticsControllerTests
|
|
{
|
|
[Fact]
|
|
public async Task TestSquidWtfEndpoints_WithoutAdministratorSession_ReturnsForbidden()
|
|
{
|
|
var controller = CreateController(
|
|
CreateHttpContextWithSession(isAdmin: false),
|
|
_ => new HttpResponseMessage(HttpStatusCode.OK));
|
|
|
|
var result = await controller.TestSquidWtfEndpoints(CancellationToken.None);
|
|
|
|
var forbidden = Assert.IsType<ObjectResult>(result);
|
|
Assert.Equal(StatusCodes.Status403Forbidden, forbidden.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task TestSquidWtfEndpoints_ReturnsIndependentApiAndStreamingResults()
|
|
{
|
|
var controller = CreateController(
|
|
CreateHttpContextWithSession(isAdmin: true),
|
|
request =>
|
|
{
|
|
var uri = request.RequestUri!;
|
|
|
|
if (uri.Host == "node-one.example" && uri.AbsolutePath == "/search/")
|
|
{
|
|
return new HttpResponseMessage(HttpStatusCode.OK)
|
|
{
|
|
Content = new StringContent(
|
|
"""
|
|
{"data":{"items":[{"id":227242909,"title":"Monica Lewinsky"}]}}
|
|
""",
|
|
Encoding.UTF8,
|
|
"application/json")
|
|
};
|
|
}
|
|
|
|
if (uri.Host == "node-one.example" && uri.AbsolutePath == "/track/")
|
|
{
|
|
return new HttpResponseMessage(HttpStatusCode.OK)
|
|
{
|
|
Content = new StringContent(
|
|
"""
|
|
{"data":{"manifest":"ZmFrZS1tYW5pZmVzdA=="}}
|
|
""",
|
|
Encoding.UTF8,
|
|
"application/json")
|
|
};
|
|
}
|
|
|
|
if (uri.Host == "node-two.example" && uri.AbsolutePath == "/search/")
|
|
{
|
|
return new HttpResponseMessage(HttpStatusCode.ServiceUnavailable);
|
|
}
|
|
|
|
if (uri.Host == "node-two.example" && uri.AbsolutePath == "/track/")
|
|
{
|
|
return new HttpResponseMessage(HttpStatusCode.GatewayTimeout);
|
|
}
|
|
|
|
throw new InvalidOperationException($"Unexpected request URI: {uri}");
|
|
});
|
|
|
|
var result = await controller.TestSquidWtfEndpoints(CancellationToken.None);
|
|
|
|
var ok = Assert.IsType<OkObjectResult>(result);
|
|
var payload = Assert.IsType<SquidWtfEndpointHealthResponse>(ok.Value);
|
|
Assert.Equal(2, payload.TotalRows);
|
|
|
|
var nodeOne = Assert.Single(payload.Endpoints, e => e.Host == "node-one.example");
|
|
Assert.True(nodeOne.Api.Configured);
|
|
Assert.True(nodeOne.Api.IsUp);
|
|
Assert.Equal("up", nodeOne.Api.State);
|
|
Assert.Equal(200, nodeOne.Api.StatusCode);
|
|
Assert.True(nodeOne.Streaming.Configured);
|
|
Assert.True(nodeOne.Streaming.IsUp);
|
|
Assert.Equal("up", nodeOne.Streaming.State);
|
|
Assert.Equal(200, nodeOne.Streaming.StatusCode);
|
|
|
|
var nodeTwo = Assert.Single(payload.Endpoints, e => e.Host == "node-two.example");
|
|
Assert.True(nodeTwo.Api.Configured);
|
|
Assert.False(nodeTwo.Api.IsUp);
|
|
Assert.Equal("down", nodeTwo.Api.State);
|
|
Assert.Equal(503, nodeTwo.Api.StatusCode);
|
|
Assert.True(nodeTwo.Streaming.Configured);
|
|
Assert.False(nodeTwo.Streaming.IsUp);
|
|
Assert.Equal("down", nodeTwo.Streaming.State);
|
|
Assert.Equal(504, nodeTwo.Streaming.StatusCode);
|
|
}
|
|
|
|
private static HttpContext CreateHttpContextWithSession(bool isAdmin)
|
|
{
|
|
var context = new DefaultHttpContext();
|
|
context.Connection.LocalPort = 5275;
|
|
context.Items[AdminAuthSessionService.HttpContextSessionItemKey] = new AdminAuthSession
|
|
{
|
|
SessionId = "session-id",
|
|
UserId = "user-id",
|
|
UserName = "user",
|
|
IsAdministrator = isAdmin,
|
|
JellyfinAccessToken = "token",
|
|
JellyfinServerId = "server-id",
|
|
ExpiresAtUtc = DateTime.UtcNow.AddHours(1),
|
|
LastSeenUtc = DateTime.UtcNow
|
|
};
|
|
|
|
return context;
|
|
}
|
|
|
|
private static DiagnosticsController CreateController(
|
|
HttpContext httpContext,
|
|
Func<HttpRequestMessage, HttpResponseMessage> responseFactory)
|
|
{
|
|
var logger = new Mock<ILogger<DiagnosticsController>>();
|
|
var configuration = new ConfigurationBuilder()
|
|
.AddInMemoryCollection(new Dictionary<string, string?>())
|
|
.Build();
|
|
|
|
var webHostEnvironment = new Mock<IWebHostEnvironment>();
|
|
webHostEnvironment.SetupGet(e => e.EnvironmentName).Returns(Environments.Development);
|
|
webHostEnvironment.SetupGet(e => e.ContentRootPath).Returns(Directory.GetCurrentDirectory());
|
|
|
|
var helperLogger = new Mock<ILogger<AdminHelperService>>();
|
|
var helperService = new AdminHelperService(
|
|
helperLogger.Object,
|
|
Options.Create(new JellyfinSettings()),
|
|
webHostEnvironment.Object);
|
|
|
|
var spotifyCookieLogger = new Mock<ILogger<SpotifySessionCookieService>>();
|
|
var spotifySessionCookieService = new SpotifySessionCookieService(
|
|
Options.Create(new SpotifyApiSettings()),
|
|
helperService,
|
|
spotifyCookieLogger.Object);
|
|
|
|
var redisLogger = new Mock<ILogger<RedisCacheService>>();
|
|
var redisCache = new RedisCacheService(
|
|
Options.Create(new RedisSettings
|
|
{
|
|
Enabled = false,
|
|
ConnectionString = "localhost:6379"
|
|
}),
|
|
redisLogger.Object,
|
|
new Microsoft.Extensions.Caching.Memory.MemoryCache(
|
|
new Microsoft.Extensions.Caching.Memory.MemoryCacheOptions()));
|
|
|
|
var httpClientFactory = new Mock<IHttpClientFactory>();
|
|
httpClientFactory.Setup(f => f.CreateClient(It.IsAny<string>()))
|
|
.Returns(() => new HttpClient(new StubHttpMessageHandler(responseFactory)));
|
|
|
|
var controller = new DiagnosticsController(
|
|
logger.Object,
|
|
configuration,
|
|
Options.Create(new SpotifyApiSettings()),
|
|
Options.Create(new SpotifyImportSettings()),
|
|
Options.Create(new JellyfinSettings()),
|
|
Options.Create(new DeezerSettings()),
|
|
Options.Create(new QobuzSettings()),
|
|
Options.Create(new SquidWTFSettings()),
|
|
spotifySessionCookieService,
|
|
new SquidWtfEndpointCatalog(
|
|
new List<string>
|
|
{
|
|
"https://node-one.example",
|
|
"https://node-two.example"
|
|
},
|
|
new List<string>
|
|
{
|
|
"https://node-one.example",
|
|
"https://node-two.example"
|
|
}),
|
|
redisCache,
|
|
httpClientFactory.Object)
|
|
{
|
|
ControllerContext = new ControllerContext
|
|
{
|
|
HttpContext = httpContext
|
|
}
|
|
};
|
|
|
|
return controller;
|
|
}
|
|
|
|
private sealed class StubHttpMessageHandler : HttpMessageHandler
|
|
{
|
|
private readonly Func<HttpRequestMessage, HttpResponseMessage> _responseFactory;
|
|
|
|
public StubHttpMessageHandler(Func<HttpRequestMessage, HttpResponseMessage> responseFactory)
|
|
{
|
|
_responseFactory = responseFactory;
|
|
}
|
|
|
|
protected override Task<HttpResponseMessage> SendAsync(
|
|
HttpRequestMessage request,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
return Task.FromResult(_responseFactory(request));
|
|
}
|
|
}
|
|
}
|