diff --git a/src/FiscalOS.API/Login/Endpoint.cs b/src/FiscalOS.API/Login/Endpoint.cs index a7e9e9e..89e7117 100644 --- a/src/FiscalOS.API/Login/Endpoint.cs +++ b/src/FiscalOS.API/Login/Endpoint.cs @@ -11,8 +11,30 @@ internal static class Endpoint private static async Task HandleAsync([FromBody] LoginRequest loginRequest) { - Console.WriteLine(loginRequest.Username); - Console.WriteLine(loginRequest.Password); + const string ADMIN_USERNAME = "Stevan"; + const string ADMIN_PASSWORD = "@Password1"; + + // TODO: Implement actual auth flow + // 1. We want to make sure that + // the user exists + // 2. We want to make sure that + // tha the password is correct + // 3. We want to issue an access token + // with a refresh token + // 4. We want to store the refresh + // token + // 5. We want to set the refresh + // token in a cookie + + // TODO: Things we need + // 1. We need a user model + // 2. We need a refresh token model + + if (loginRequest.Username is not ADMIN_USERNAME || loginRequest.Password is not ADMIN_PASSWORD) + { + return Results.Unauthorized(); + } + return Results.Ok(); } } \ No newline at end of file diff --git a/tests/FiscalOS.API.Tests/Integration/LoginTests.cs b/tests/FiscalOS.API.Tests/Integration/LoginTests.cs index aa2f856..0a79a3b 100644 --- a/tests/FiscalOS.API.Tests/Integration/LoginTests.cs +++ b/tests/FiscalOS.API.Tests/Integration/LoginTests.cs @@ -1,28 +1,127 @@ -using System.Net.Http.Json; - -using Microsoft.AspNetCore.Mvc; - namespace FiscalOS.API.Tests.Integration; public class LoginTests(TestApi testApi) : IClassFixture { private readonly TestApi _testApi = testApi; - [Fact] - public async Task Login_WhenUserSubmitsWithoutUsernameOrPassword_ItShouldReturn400WithProblemDetails() + [Theory] + [ClassData] + public async Task Login_WhenUserSubmitsInvalidRequest_ItShouldReturn400WithProblemDetails(LoginValidationTestCase tc) { var client = _testApi.CreateClient(); - var res = await client.PostAsJsonAsync("/login", new { }, TestContext.Current.CancellationToken); + var req = new + { + username = tc.Username, + password = tc.Password, + }; - res.StatusCode.Should().Be(System.Net.HttpStatusCode.BadRequest); + var res = await client.PostAsJsonAsync("/login", req, TestContext.Current.CancellationToken); + + res.StatusCode.Should().Be(HttpStatusCode.BadRequest); var problem = await res.Content.ReadFromJsonAsync(TestContext.Current.CancellationToken); - problem!.Errors.Should().BeEquivalentTo(new Dictionary() + problem!.Errors.Should().BeEquivalentTo(tc.ExpectedErrors); + } + + [Fact] + public async Task Login_WhenUserCredentialsAreIncorrect_ItShouldReturn401WithProblemDetails() + { + var client = _testApi.CreateClient(); + + var req = new { - ["Username"] = ["The Username field is required."], - ["Password"] = ["The Password field is required."] - }); + username = "Test", + password = "@Password2", + }; + + var res = await client.PostAsJsonAsync("/login", req, TestContext.Current.CancellationToken); + + res.StatusCode.Should().Be(HttpStatusCode.Unauthorized); + } +} + + +public class LoginValidationTestCases : TheoryData +{ + public LoginValidationTestCases() + { + Add(new LoginValidationTestCase( + "No username or password", + string.Empty, + string.Empty, + new Dictionary() + { + ["Username"] = ["The Username field is required."], + ["Password"] = ["The Password field is required."] + } + )); + + Add(new LoginValidationTestCase( + "No username", + string.Empty, + "@Password1", + new Dictionary() + { + ["Username"] = ["The Username field is required."], + } + )); + + Add(new LoginValidationTestCase( + "No password", + "Stevan", + string.Empty, + new Dictionary() + { + ["Password"] = ["The Password field is required."] + } + )); + } +} + +public record LoginValidationTestCase : IXunitSerializable +{ + public string Name { get; private set; } = string.Empty; + public string Username { get; private set; } = string.Empty; + public string Password { get; private set; } = string.Empty; + public Dictionary ExpectedErrors { get; private set; } = []; + + public override string ToString() + { + return Name; + } + + public LoginValidationTestCase() + { + } + + public LoginValidationTestCase( + string name, + string username, + string password, + Dictionary expectedErrors + ) + { + Name = name; + Username = username; + Password = password; + ExpectedErrors = expectedErrors; + } + + public void Deserialize(IXunitSerializationInfo info) + { + Name = info.GetValue(nameof(Name)) ?? string.Empty; + Username = info.GetValue(nameof(Username)) ?? string.Empty; + Password = info.GetValue(nameof(Password)) ?? string.Empty; + ExpectedErrors = info.GetValue>(nameof(ExpectedErrors)) ?? []; + } + + public void Serialize(IXunitSerializationInfo info) + { + info.AddValue(nameof(Name), Name); + info.AddValue(nameof(Username), Username); + info.AddValue(nameof(Password), Password); + info.AddValue(nameof(ExpectedErrors), ExpectedErrors); } } \ No newline at end of file