0
0
mirror of https://github.com/alex289/CleanArchitecture.git synced 2025-06-30 02:31:08 +00:00

test: Refactor authed user

This commit is contained in:
alex289 2023-08-31 16:00:25 +02:00
parent 3969db2bba
commit a04cc8bdd0
No known key found for this signature in database
GPG Key ID: 573F77CD2D87F863
13 changed files with 207 additions and 154 deletions

View File

@ -31,4 +31,5 @@
<ProjectReference Include="..\CleanArchitecture.Infrastructure\CleanArchitecture.Infrastructure.csproj"/>
</ItemGroup>
</Project>

View File

@ -27,8 +27,6 @@ public sealed class TenantControllerTests : IClassFixture<TenantTestFixture>
[Priority(0)]
public async Task Should_Get_Tenant_By_Id()
{
await _fixture.AuthenticateUserAsync();
var response = await _fixture.ServerClient.GetAsync($"/api/v1/Tenant/{_fixture.CreatedTenantId}");
response.StatusCode.Should().Be(HttpStatusCode.OK);
@ -45,8 +43,6 @@ public sealed class TenantControllerTests : IClassFixture<TenantTestFixture>
[Priority(5)]
public async Task Should_Get_All_Tenants()
{
await _fixture.AuthenticateUserAsync();
var response = await _fixture.ServerClient.GetAsync("api/v1/Tenant");
response.StatusCode.Should().Be(HttpStatusCode.OK);
@ -64,8 +60,6 @@ public sealed class TenantControllerTests : IClassFixture<TenantTestFixture>
[Priority(10)]
public async Task Should_Create_Tenant()
{
await _fixture.AuthenticateUserAsync();
var request = new CreateTenantViewModel("Test Tenant 2");
var response = await _fixture.ServerClient.PostAsJsonAsync("/api/v1/Tenant", request);
@ -92,8 +86,6 @@ public sealed class TenantControllerTests : IClassFixture<TenantTestFixture>
[Priority(15)]
public async Task Should_Update_Tenant()
{
await _fixture.AuthenticateUserAsync();
var request = new UpdateTenantViewModel(_fixture.CreatedTenantId, "Test Tenant 3");
var response = await _fixture.ServerClient.PutAsJsonAsync("/api/v1/Tenant", request);
@ -122,8 +114,6 @@ public sealed class TenantControllerTests : IClassFixture<TenantTestFixture>
[Priority(20)]
public async Task Should_Delete_Tenant()
{
await _fixture.AuthenticateUserAsync();
var response = await _fixture.ServerClient.DeleteAsync($"/api/v1/Tenant/{_fixture.CreatedTenantId}");
response.StatusCode.Should().Be(HttpStatusCode.OK);

View File

@ -8,6 +8,7 @@ using CleanArchitecture.Domain.Constants;
using CleanArchitecture.Domain.Enums;
using CleanArchitecture.IntegrationTests.Extensions;
using CleanArchitecture.IntegrationTests.Fixtures;
using CleanArchitecture.IntegrationTests.Infrastructure.Auth;
using FluentAssertions;
using Xunit;
using Xunit.Priority;
@ -24,20 +25,60 @@ public sealed class UserControllerTests : IClassFixture<UserTestFixture>
{
_fixture = fixture;
}
// Todo: Refactor tests to work alone
[Fact]
[Priority(0)]
public async Task Should_Get_All_User()
{
var response = await _fixture.ServerClient.GetAsync("/api/v1/user");
response.StatusCode.Should().Be(HttpStatusCode.OK);
var message = await response.Content.ReadAsJsonAsync<IEnumerable<UserViewModel>>();
message?.Data.Should().NotBeNull();
var content = message!.Data!.ToList();
content.Count.Should().Be(2);
var currentUser = content.First(x => x.Id == TestAuthenticationOptions.TestUserId);
currentUser.Role.Should().Be(UserRole.Admin);
currentUser.Email.Should().Be(TestAuthenticationOptions.Email);
currentUser.FirstName.Should().Be(TestAuthenticationOptions.FirstName);
currentUser.LastName.Should().Be(TestAuthenticationOptions.LastName);
}
[Fact]
[Priority(5)]
public async Task Should_Get_User_By_Id()
{
var response = await _fixture.ServerClient.GetAsync("/api/v1/user/" + TestAuthenticationOptions.TestUserId);
response.StatusCode.Should().Be(HttpStatusCode.OK);
var message = await response.Content.ReadAsJsonAsync<UserViewModel>();
message?.Data.Should().NotBeNull();
var content = message!.Data!;
content.Id.Should().Be(TestAuthenticationOptions.TestUserId);
content.Email.Should().Be(TestAuthenticationOptions.Email);
content.FirstName.Should().Be(TestAuthenticationOptions.FirstName);
content.LastName.Should().Be(TestAuthenticationOptions.LastName);
}
[Fact]
[Priority(10)]
public async Task Should_Create_User()
{
await _fixture.AuthenticateUserAsync();
var user = new CreateUserViewModel(
_fixture.CreatedUserEmail,
"some@user.com",
"Test",
"Email",
_fixture.CreatedUserPassword,
"1234#KSAD23s",
Ids.Seed.TenantId);
var response = await _fixture.ServerClient.PostAsJsonAsync("/api/v1/user", user);
@ -45,54 +86,27 @@ public sealed class UserControllerTests : IClassFixture<UserTestFixture>
response.StatusCode.Should().Be(HttpStatusCode.OK);
var message = await response.Content.ReadAsJsonAsync<Guid>();
message?.Data.Should().NotBeEmpty();
_fixture.CreatedUserId = message!.Data;
}
[Fact]
[Priority(5)]
[Priority(15)]
public async Task Should_Login_User()
{
var user = new LoginUserViewModel(
_fixture.CreatedUserEmail,
_fixture.CreatedUserPassword);
"admin@email.com",
"!Password123#");
var response = await _fixture.ServerClient.PostAsJsonAsync("/api/v1/user/login", user);
response.StatusCode.Should().Be(HttpStatusCode.OK);
var message = await response.Content.ReadAsJsonAsync<string>();
message?.Data.Should().NotBeEmpty();
_fixture.CreatedUserToken = message!.Data!;
_fixture.EnableAuthentication();
}
[Fact]
[Priority(10)]
public async Task Should_Get_Created_Users()
{
var response = await _fixture.ServerClient.GetAsync("/api/v1/user/" + _fixture.CreatedUserId);
response.StatusCode.Should().Be(HttpStatusCode.OK);
var message = await response.Content.ReadAsJsonAsync<UserViewModel>();
message?.Data.Should().NotBeNull();
var content = message!.Data!;
content.Id.Should().Be(_fixture.CreatedUserId);
content.Email.Should().Be("test@email.com");
content.FirstName.Should().Be("Test");
content.LastName.Should().Be("Email");
}
[Fact]
[Priority(10)]
[Priority(20)]
public async Task Should_Get_The_Current_Active_Users()
{
var response = await _fixture.ServerClient.GetAsync("/api/v1/user/me");
@ -105,18 +119,18 @@ public sealed class UserControllerTests : IClassFixture<UserTestFixture>
var content = message!.Data!;
content.Id.Should().Be(_fixture.CreatedUserId);
content.Email.Should().Be("test@email.com");
content.FirstName.Should().Be("Test");
content.LastName.Should().Be("Email");
content.Id.Should().Be(TestAuthenticationOptions.TestUserId);
content.Email.Should().Be(TestAuthenticationOptions.Email);
content.FirstName.Should().Be(TestAuthenticationOptions.FirstName);
content.LastName.Should().Be(TestAuthenticationOptions.LastName);
}
[Fact]
[Priority(15)]
[Priority(25)]
public async Task Should_Update_User()
{
var user = new UpdateUserViewModel(
_fixture.CreatedUserId,
Ids.Seed.UserId,
"newtest@email.com",
"NewTest",
"NewEmail",
@ -134,37 +148,32 @@ public sealed class UserControllerTests : IClassFixture<UserTestFixture>
var content = message!.Data;
content.Should().BeEquivalentTo(user);
// Check if user is really updated
var userResponse = await _fixture.ServerClient.GetAsync("/api/v1/user/" + user.Id);
userResponse.StatusCode.Should().Be(HttpStatusCode.OK);
var userMessage = await userResponse.Content.ReadAsJsonAsync<UserViewModel>();
userMessage?.Data.Should().NotBeNull();
var userContent = userMessage!.Data!;
userContent.Id.Should().Be(user.Id);
userContent.Email.Should().Be(user.Email);
userContent.FirstName.Should().Be(user.FirstName);
userContent.LastName.Should().Be(user.LastName);
userContent.Role.Should().Be(user.Role);
}
[Fact]
[Priority(20)]
public async Task Should_Get_Updated_Users()
{
var response = await _fixture.ServerClient.GetAsync("/api/v1/user/" + _fixture.CreatedUserId);
response.StatusCode.Should().Be(HttpStatusCode.OK);
var message = await response.Content.ReadAsJsonAsync<UserViewModel>();
message?.Data.Should().NotBeNull();
var content = message!.Data!;
content.Id.Should().Be(_fixture.CreatedUserId);
content.Email.Should().Be("newtest@email.com");
content.FirstName.Should().Be("NewTest");
content.LastName.Should().Be("NewEmail");
_fixture.CreatedUserEmail = content.Email;
}
[Fact]
[Priority(25)]
[Priority(30)]
public async Task Should_Change_User_Password()
{
var user = new ChangePasswordViewModel(
_fixture.CreatedUserPassword,
_fixture.CreatedUserPassword + "1");
"!Password123#",
"!Password123#1");
var response = await _fixture.ServerClient.PostAsJsonAsync("/api/v1/user/changePassword", user);
@ -180,8 +189,8 @@ public sealed class UserControllerTests : IClassFixture<UserTestFixture>
// Verify the user can login with the new password
var login = new LoginUserViewModel(
_fixture.CreatedUserEmail,
_fixture.CreatedUserPassword + "1");
TestAuthenticationOptions.Email,
user.NewPassword);
var loginResponse = await _fixture.ServerClient.PostAsJsonAsync("/api/v1/user/login", login);
@ -192,42 +201,11 @@ public sealed class UserControllerTests : IClassFixture<UserTestFixture>
loginMessage?.Data.Should().NotBeEmpty();
}
[Fact]
[Priority(30)]
public async Task Should_Get_All_User()
{
var response = await _fixture.ServerClient.GetAsync("/api/v1/user");
response.StatusCode.Should().Be(HttpStatusCode.OK);
var message = await response.Content.ReadAsJsonAsync<IEnumerable<UserViewModel>>();
message?.Data.Should().NotBeNull();
var content = message!.Data!.ToList();
content.Count.Should().Be(2);
var currentUser = content.First(x => x.Id == _fixture.CreatedUserId);
currentUser.Id.Should().Be(_fixture.CreatedUserId);
currentUser.Role.Should().Be(UserRole.User);
currentUser.Email.Should().Be("newtest@email.com");
currentUser.FirstName.Should().Be("NewTest");
currentUser.LastName.Should().Be("NewEmail");
var adminUser = content.First(x => x.Role == UserRole.Admin);
adminUser.Email.Should().Be("admin@email.com");
adminUser.FirstName.Should().Be("Admin");
adminUser.LastName.Should().Be("User");
}
[Fact]
[Priority(35)]
public async Task Should_Delete_User()
{
var response = await _fixture.ServerClient.DeleteAsync("/api/v1/user/" + _fixture.CreatedUserId);
var response = await _fixture.ServerClient.DeleteAsync("/api/v1/user/" + TestAuthenticationOptions.TestUserId);
response.StatusCode.Should().Be(HttpStatusCode.OK);
@ -236,8 +214,10 @@ public sealed class UserControllerTests : IClassFixture<UserTestFixture>
message?.Data.Should().NotBeEmpty();
var content = message!.Data;
content.Should().Be(_fixture.CreatedUserId);
content.Should().Be(TestAuthenticationOptions.TestUserId);
// Todo: Check if stuff is done
var userResponse = await _fixture.ServerClient.GetAsync("/api/v1/user/" + TestAuthenticationOptions.TestUserId);
userResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);
}
}

View File

@ -0,0 +1,8 @@
namespace CleanArchitecture.IntegrationTests.Fixtures;
public sealed class AuthTestFixure : TestFixtureBase
{
public AuthTestFixure() : base(false)
{
}
}

View File

@ -10,6 +10,8 @@ public sealed class TenantTestFixture : TestFixtureBase
protected override void SeedTestData(ApplicationDbContext context)
{
base.SeedTestData(context);
context.Tenants.Add(new Tenant(
CreatedTenantId,
"Test Tenant"));

View File

@ -1,10 +1,11 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using CleanArchitecture.Application.ViewModels.Users;
using CleanArchitecture.Domain.Constants;
using CleanArchitecture.Domain.Entities;
using CleanArchitecture.Domain.Enums;
using CleanArchitecture.Infrastructure.Database;
using CleanArchitecture.IntegrationTests.Extensions;
using CleanArchitecture.IntegrationTests.Infrastructure;
using CleanArchitecture.IntegrationTests.Infrastructure.Auth;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
@ -12,11 +13,12 @@ namespace CleanArchitecture.IntegrationTests.Fixtures;
public class TestFixtureBase
{
public TestFixtureBase()
public TestFixtureBase(bool useTestAuthentication = true)
{
Factory = new CleanArchitectureWebApplicationFactory(
SeedTestData,
RegisterCustomServicesHandler);
RegisterCustomServicesHandler,
useTestAuthentication);
ServerClient = Factory.CreateClient();
ServerClient.Timeout = TimeSpan.FromMinutes(5);
@ -27,6 +29,17 @@ public class TestFixtureBase
protected virtual void SeedTestData(ApplicationDbContext context)
{
context.Users.Add(new User(
TestAuthenticationOptions.TestUserId,
Ids.Seed.TenantId,
TestAuthenticationOptions.Email,
TestAuthenticationOptions.FirstName,
TestAuthenticationOptions.LastName,
// !Password123#
"$2a$12$Blal/uiFIJdYsCLTMUik/egLbfg3XhbnxBC6Sb5IKz2ZYhiU/MzL2",
UserRole.Admin));
context.SaveChanges();
}
protected virtual void RegisterCustomServicesHandler(
@ -35,18 +48,4 @@ public class TestFixtureBase
IServiceProvider scopedServices)
{
}
// Todo: Fix auth
public virtual async Task AuthenticateUserAsync()
{
ServerClient.DefaultRequestHeaders.Clear();
var user = new LoginUserViewModel(
"admin@email.com",
"!Password123#");
var response = await ServerClient.PostAsJsonAsync("/api/v1/user/login", user);
var message = await response.Content.ReadAsJsonAsync<string>();
ServerClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {message!.Data}");
}
}

View File

@ -1,17 +1,5 @@
using System;
namespace CleanArchitecture.IntegrationTests.Fixtures;
namespace CleanArchitecture.IntegrationTests.Fixtures;
public sealed class UserTestFixture : TestFixtureBase
{
public Guid CreatedUserId { get; set; }
public string CreatedUserEmail { get; set; } = "test@email.com";
public string CreatedUserPassword { get; set; } = "z8]tnayvd5FNLU9:]AQm";
public string CreatedUserToken { get; set; } = string.Empty;
public void EnableAuthentication()
{
ServerClient.DefaultRequestHeaders.Clear();
ServerClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {CreatedUserToken}");
}
}

View File

@ -0,0 +1,17 @@
using System;
using Microsoft.AspNetCore.Authentication;
namespace CleanArchitecture.IntegrationTests.Infrastructure.Auth;
public static class TestAuthenticationExtensions
{
public static AuthenticationBuilder AddTestAuthentication(
this AuthenticationBuilder builder,
Action<TestAuthenticationOptions> configureOptions)
{
return builder.AddScheme<TestAuthenticationOptions, TestAuthenticationHandler>(
"Testing",
"Test Authentication",
configureOptions);
}
}

View File

@ -0,0 +1,29 @@
using System.Security.Claims;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace CleanArchitecture.IntegrationTests.Infrastructure.Auth;
public sealed class TestAuthenticationHandler : AuthenticationHandler<TestAuthenticationOptions>
{
public TestAuthenticationHandler(
IOptionsMonitor<TestAuthenticationOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock) : base(options, logger, encoder, clock)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var authenticationTicket = new AuthenticationTicket(
new ClaimsPrincipal(Options.Identity),
new AuthenticationProperties(),
"Testing");
return Task.FromResult(AuthenticateResult.Success(authenticationTicket));
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Security.Claims;
using CleanArchitecture.Domain.Enums;
using Microsoft.AspNetCore.Authentication;
namespace CleanArchitecture.IntegrationTests.Infrastructure.Auth;
public sealed class TestAuthenticationOptions : AuthenticationSchemeOptions
{
public static Guid TestUserId = new("561e4300-94d6-4c3f-adf5-31c1bdbc64df");
public const string Email = "integration@tests.com";
public const string FirstName = "Integration";
public const string LastName = "Tests";
public ClaimsIdentity Identity { get; } = new ClaimsIdentity(
new[]
{
new Claim(ClaimTypes.Email, Email),
new Claim(ClaimTypes.Role, UserRole.Admin.ToString()),
new Claim(ClaimTypes.NameIdentifier, TestUserId.ToString()),
new Claim(ClaimTypes.Name, $"{FirstName} {LastName}")
},
"test");
}

View File

@ -2,6 +2,7 @@
using CleanArchitecture.Infrastructure.Database;
using CleanArchitecture.Infrastructure.Extensions;
using CleanArchitecture.IntegrationTests.Extensions;
using CleanArchitecture.IntegrationTests.Infrastructure.Auth;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Data.Sqlite;
@ -24,13 +25,16 @@ public sealed class CleanArchitectureWebApplicationFactory : WebApplicationFacto
private readonly SqliteConnection _connection = new("DataSource=:memory:");
private readonly RegisterCustomServicesHandler? _registerCustomServicesHandler;
private readonly bool _addTestAuthentication;
public CleanArchitectureWebApplicationFactory(
AddCustomSeedDataHandler? addCustomSeedDataHandler,
RegisterCustomServicesHandler? registerCustomServicesHandler)
RegisterCustomServicesHandler? registerCustomServicesHandler,
bool addTestAuthentication)
{
_addCustomSeedDataHandler = addCustomSeedDataHandler;
_registerCustomServicesHandler = registerCustomServicesHandler;
_addTestAuthentication = addTestAuthentication;
}
protected override void ConfigureWebHost(IWebHostBuilder builder)
@ -47,6 +51,15 @@ public sealed class CleanArchitectureWebApplicationFactory : WebApplicationFacto
services.SetupTestDatabase<EventStoreDbContext>(_connection);
services.SetupTestDatabase<DomainNotificationStoreDbContext>(_connection);
if (_addTestAuthentication)
{
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "Testing";
options.DefaultChallengeScheme = "Testing";
}).AddTestAuthentication(options => { });
}
var sp = services.BuildServiceProvider();
using var scope = sp.CreateScope();

View File

@ -9,11 +9,11 @@ namespace CleanArchitecture.IntegrationTests.UtilityTests;
[Collection("IntegrationTests")]
[TestCaseOrderer(PriorityOrderer.Name, PriorityOrderer.Assembly)]
public sealed class AuthTests : IClassFixture<TestFixtureBase>
public sealed class AuthTests : IClassFixture<AuthTestFixure>
{
private readonly TestFixtureBase _fixture;
private readonly AuthTestFixure _fixture;
public AuthTests(TestFixtureBase fixture)
public AuthTests(AuthTestFixure fixture)
{
_fixture = fixture;
}
@ -22,6 +22,8 @@ public sealed class AuthTests : IClassFixture<TestFixtureBase>
[InlineData("/api/v1/user")]
[InlineData("/api/v1/user/me")]
[InlineData("/api/v1/user/d74b112a-ece0-443d-9b4f-85bc418822ca")]
[InlineData("/api/v1/tenant")]
[InlineData("/api/v1/tenant/d74b112a-ece0-443d-9b4f-85bc418822ca")]
public async Task Should_Get_Unauthorized_If_Trying_To_Call_Endpoint_Without_Token(
string url)
{

View File

@ -11,11 +11,11 @@ namespace CleanArchitecture.IntegrationTests.UtilityTests;
[Collection("IntegrationTests")]
[TestCaseOrderer(PriorityOrderer.Name, PriorityOrderer.Assembly)]
public sealed class HealthChecksTests : IClassFixture<TestFixtureBase>
public sealed class HealthChecksTests : IClassFixture<AuthTestFixure>
{
private readonly TestFixtureBase _fixture;
private readonly AuthTestFixure _fixture;
public HealthChecksTests(TestFixtureBase fixture)
public HealthChecksTests(AuthTestFixure fixture)
{
_fixture = fixture;
}