d3ro-voice/apps/api-server.Tests/AuthBootstrapControllerTests.cs
2026-08-29 18:33:45 +09:00

91 lines
3 KiB
C#

using D3ROVoice.Api.Controllers;
using D3ROVoice.Api.Dtos;
using D3ROVoice.Api.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Xunit;
namespace D3ROVoice.Api.Tests;
public sealed class AuthBootstrapControllerTests
{
private static readonly RegisterDto Request = new(
"operator@example.test",
"test-only-password-1234");
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData("too-short")]
public async Task RegisterIsDisabledWithoutAStrongConfiguredBootstrapToken(string? configuredToken)
{
var service = new RecordingAuthService();
var configuration = Configuration(configuredToken);
var controller = new AuthController(service, configuration);
var result = await controller.Register(Request, configuredToken);
var unavailable = Assert.IsType<ObjectResult>(result);
Assert.Equal(503, unavailable.StatusCode);
Assert.Equal(0, service.RegisterCalls);
}
[Fact]
public async Task RegisterRejectsAnIncorrectBootstrapTokenWithoutCreatingAUser()
{
var service = new RecordingAuthService();
var configuration = Configuration("test-bootstrap-token-0123456789-abcdef");
var controller = new AuthController(service, configuration);
var result = await controller.Register(
Request,
"different-test-token-0123456789-abcdef");
Assert.IsType<UnauthorizedObjectResult>(result);
Assert.Equal(0, service.RegisterCalls);
}
[Fact]
public async Task RegisterAcceptsTheExactStrongBootstrapTokenOnce()
{
const string bootstrapToken = "test-bootstrap-token-0123456789-abcdef";
var service = new RecordingAuthService();
var controller = new AuthController(service, Configuration(bootstrapToken));
var result = await controller.Register(Request, bootstrapToken);
Assert.IsType<OkObjectResult>(result);
Assert.Equal(1, service.RegisterCalls);
}
private static IConfiguration Configuration(string? bootstrapToken)
{
var values = new Dictionary<string, string?>();
if (bootstrapToken is not null)
{
values["ADMIN_BOOTSTRAP_TOKEN"] = bootstrapToken;
}
return new ConfigurationBuilder().AddInMemoryCollection(values).Build();
}
private sealed class RecordingAuthService : IAuthService
{
public int RegisterCalls { get; private set; }
public Task<AuthResponseDto> RegisterAsync(RegisterDto dto)
{
RegisterCalls += 1;
return Task.FromResult(new AuthResponseDto(
"test-token",
dto.Email,
"SuperAdmin",
DateTime.UtcNow.AddMinutes(5)));
}
public Task<AuthResponseDto> LoginAsync(LoginDto dto) =>
throw new NotSupportedException();
public Task<UserInfoDto?> GetUserByEmailAsync(string email) =>
throw new NotSupportedException();
}
}