Initial commit, project structure and domain models

This commit is contained in:
2026-04-07 09:14:06 -07:00
commit 7b15086fe5
111 changed files with 19818 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
using System.Net;
using System.Net.Http.Json;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using NUnit.Framework;
using MicCheck.Api.Auth;
namespace MicCheck.Api.Tests.Unit.Auth;
[TestFixture]
public class AuthEndpointsTests
{
private WebApplicationFactory<Program> _factory = null!;
private Mock<ITokenService> _tokenService = null!;
[SetUp]
public void SetUp()
{
_tokenService = new Mock<ITokenService>();
_factory = new WebApplicationFactory<Program>()
.WithWebHostBuilder(host =>
{
host.ConfigureServices(services =>
{
services.AddScoped<ITokenService>(_ => _tokenService.Object);
});
});
}
[TearDown]
public void TearDown() => _factory.Dispose();
[Test]
public async Task WhenUsernameIsEmpty_ThenBadRequestIsReturned()
{
var client = _factory.CreateClient();
var response = await client.PostAsJsonAsync("/auth/token",
new TokenRequest("", "password123"));
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task WhenPasswordIsEmpty_ThenBadRequestIsReturned()
{
var client = _factory.CreateClient();
var response = await client.PostAsJsonAsync("/auth/token",
new TokenRequest("testuser", ""));
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
[Test]
public async Task WhenValidCredentialsAreProvided_ThenOkIsReturnedWithToken()
{
var expectedResponse = new TokenResponse("signed.jwt.token", DateTime.UtcNow.AddHours(1));
_tokenService
.Setup(s => s.GenerateToken("testuser"))
.Returns(expectedResponse);
var client = _factory.CreateClient();
var response = await client.PostAsJsonAsync("/auth/token",
new TokenRequest("testuser", "password123"));
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var body = await response.Content.ReadFromJsonAsync<TokenResponse>();
Assert.That(body?.Token, Is.EqualTo(expectedResponse.Token));
}
}

View File

@@ -0,0 +1,67 @@
using System.IdentityModel.Tokens.Jwt;
using Microsoft.Extensions.Configuration;
using MicCheck.Api.Auth;
using NUnit.Framework;
namespace MicCheck.Api.Tests.Unit.Auth;
[TestFixture]
public class TokenServiceTests
{
private IConfiguration _configuration = null!;
private TokenService _tokenService = null!;
[SetUp]
public void SetUp()
{
_configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["Jwt:SecretKey"] = "test-secret-key-that-is-long-enough-32c",
["Jwt:Issuer"] = "MicCheck",
["Jwt:Audience"] = "MicCheck",
["Jwt:ExpiryMinutes"] = "60",
})
.Build();
_tokenService = new TokenService(_configuration);
}
[Test]
public void WhenAUsernameIsProvided_ThenATokenIsReturned()
{
var result = _tokenService.GenerateToken("testuser");
Assert.That(result.Token, Is.Not.Null.And.Not.Empty);
}
[Test]
public void WhenATokenIsGenerated_ThenItContainsTheUsernameAsSubjectClaim()
{
var result = _tokenService.GenerateToken("testuser");
var handler = new JwtSecurityTokenHandler();
var jwt = handler.ReadJwtToken(result.Token);
Assert.That(jwt.Subject, Is.EqualTo("testuser"));
}
[Test]
public void WhenATokenIsGenerated_ThenItHasAFutureExpiry()
{
var result = _tokenService.GenerateToken("testuser");
Assert.That(result.ExpiresAt, Is.GreaterThan(DateTime.UtcNow));
}
[Test]
public void WhenATokenIsGenerated_ThenItHasTheConfiguredIssuer()
{
var result = _tokenService.GenerateToken("testuser");
var handler = new JwtSecurityTokenHandler();
var jwt = handler.ReadJwtToken(result.Token);
Assert.That(jwt.Issuer, Is.EqualTo("MicCheck"));
}
}