-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Remove unused import. * Rename AccountRecoveryTests. * Add RecoverAccount route. * Create test acount recovery tests. * Add new result. * Implement TestRecovery. * Add GET /account/recover/{id} endpoint. * Update openapi.json. * Fix test file naming. * Fix missing Test attributes. * Don't recreate the client for each test. * formatting * Fix incorrect role checking. * Allow admins to recover their accounts. * Generalize role-based test. * Delete Old result. * Only banned users cannot recover their account. * Use OneTimeSetUp instead of constructor.
- Loading branch information
Showing
8 changed files
with
285 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
161 changes: 161 additions & 0 deletions
161
LeaderboardBackend.Test/Features/Users/TestRecoveryTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
using System.Net; | ||
using System.Net.Http; | ||
using System.Threading.Tasks; | ||
using LeaderboardBackend.Models.Entities; | ||
using LeaderboardBackend.Test.Fixtures; | ||
using Microsoft.AspNetCore.TestHost; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using NodaTime; | ||
using NodaTime.Testing; | ||
using NUnit.Framework; | ||
|
||
namespace LeaderboardBackend.Test.Features.Users; | ||
|
||
public class TestRecoveryTests : IntegrationTestsBase | ||
{ | ||
private IServiceScope _scope = null!; | ||
private HttpClient _client = null!; | ||
private readonly FakeClock _clock = new(Instant.FromUnixTimeSeconds(1)); | ||
|
||
[OneTimeSetUp] | ||
public void OneTimeSetUp() | ||
{ | ||
_client = _factory.WithWebHostBuilder(builder => | ||
builder.ConfigureTestServices(services => | ||
services.AddSingleton<IClock, FakeClock>(_ => _clock) | ||
) | ||
).CreateClient(); | ||
} | ||
|
||
[SetUp] | ||
public void Init() | ||
{ | ||
_factory.ResetDatabase(); | ||
_scope = _factory.Services.CreateScope(); | ||
} | ||
|
||
[TearDown] | ||
public void TearDown() => _scope.Dispose(); | ||
|
||
[TestCase("not_a_guid")] | ||
[TestCase("L8msfy9wd0qWbDJMZwwgQg")] | ||
public async Task TestRecovery_BadRecoveryId(string id) | ||
{ | ||
HttpResponseMessage res = await _client.GetAsync(Routes.RecoverAccount(id)); | ||
res.Should().HaveStatusCode(HttpStatusCode.NotFound); | ||
} | ||
|
||
[Test] | ||
public async Task TestRecovery_Expired() | ||
{ | ||
_clock.Reset(Instant.FromUnixTimeSeconds(1) + Duration.FromHours(2)); | ||
ApplicationContext context = _scope.ServiceProvider.GetRequiredService<ApplicationContext>(); | ||
|
||
AccountRecovery recovery = new() | ||
{ | ||
CreatedAt = Instant.FromUnixTimeSeconds(0), | ||
ExpiresAt = Instant.FromUnixTimeSeconds(0).Plus(Duration.FromHours(1)), | ||
User = new() | ||
{ | ||
Email = "[email protected]", | ||
Password = "password", | ||
Username = "username", | ||
Role = UserRole.Confirmed | ||
} | ||
}; | ||
|
||
await context.AccountRecoveries.AddAsync(recovery); | ||
await context.SaveChangesAsync(); | ||
HttpResponseMessage res = await _client.GetAsync(Routes.RecoverAccount(recovery.Id)); | ||
res.StatusCode.Should().Be(HttpStatusCode.NotFound); | ||
} | ||
|
||
[Test] | ||
public async Task TestRecovery_Old() | ||
{ | ||
_clock.Reset(Instant.FromUnixTimeSeconds(10)); | ||
ApplicationContext context = _scope.ServiceProvider.GetRequiredService<ApplicationContext>(); | ||
|
||
User user = new() | ||
{ | ||
Email = "[email protected]", | ||
Password = "password", | ||
Username = "username", | ||
Role = UserRole.Confirmed | ||
}; | ||
await context.Users.AddAsync(user); | ||
|
||
AccountRecovery recovery1 = new() | ||
{ | ||
CreatedAt = Instant.FromUnixTimeSeconds(0), | ||
ExpiresAt = Instant.FromUnixTimeSeconds(0).Plus(Duration.FromHours(1)), | ||
User = user | ||
}; | ||
|
||
AccountRecovery recovery2 = new() | ||
{ | ||
CreatedAt = Instant.FromUnixTimeSeconds(5), | ||
ExpiresAt = Instant.FromUnixTimeSeconds(5).Plus(Duration.FromHours(1)), | ||
User = user | ||
}; | ||
|
||
await context.AccountRecoveries.AddRangeAsync(recovery1, recovery2); | ||
await context.SaveChangesAsync(); | ||
HttpResponseMessage res = await _client.GetAsync(Routes.RecoverAccount(recovery1.Id)); | ||
res.Should().HaveStatusCode(HttpStatusCode.NotFound); | ||
} | ||
|
||
[Test] | ||
public async Task TestRecovery_Used() | ||
{ | ||
_clock.Reset(Instant.FromUnixTimeSeconds(10)); | ||
ApplicationContext context = _scope.ServiceProvider.GetRequiredService<ApplicationContext>(); | ||
|
||
AccountRecovery recovery = new() | ||
{ | ||
CreatedAt = Instant.FromUnixTimeSeconds(0), | ||
ExpiresAt = Instant.FromUnixTimeSeconds(0).Plus(Duration.FromHours(1)), | ||
UsedAt = Instant.FromUnixTimeSeconds(5), | ||
User = new() | ||
{ | ||
Email = "[email protected]", | ||
Password = "password", | ||
Username = "username", | ||
Role = UserRole.Confirmed | ||
} | ||
}; | ||
|
||
await context.AccountRecoveries.AddAsync(recovery); | ||
await context.SaveChangesAsync(); | ||
HttpResponseMessage res = await _client.GetAsync(Routes.RecoverAccount(recovery.Id)); | ||
res.Should().HaveStatusCode(HttpStatusCode.NotFound); | ||
} | ||
|
||
[TestCase(UserRole.Administrator, HttpStatusCode.OK)] | ||
[TestCase(UserRole.Banned, HttpStatusCode.NotFound)] | ||
[TestCase(UserRole.Confirmed, HttpStatusCode.OK)] | ||
[TestCase(UserRole.Registered, HttpStatusCode.OK)] | ||
public async Task TestRecovery_Roles(UserRole role, HttpStatusCode expected) | ||
{ | ||
_clock.Reset(Instant.FromUnixTimeSeconds(1)); | ||
ApplicationContext context = _scope.ServiceProvider.GetRequiredService<ApplicationContext>(); | ||
|
||
AccountRecovery recovery = new() | ||
{ | ||
CreatedAt = Instant.FromUnixTimeSeconds(0), | ||
ExpiresAt = Instant.FromUnixTimeSeconds(0).Plus(Duration.FromHours(1)), | ||
User = new() | ||
{ | ||
Email = "[email protected]", | ||
Password = "password", | ||
Username = "username", | ||
Role = role | ||
} | ||
}; | ||
|
||
await context.AccountRecoveries.AddAsync(recovery); | ||
await context.SaveChangesAsync(); | ||
HttpResponseMessage res = await _client.GetAsync(Routes.RecoverAccount(recovery.Id)); | ||
res.Should().HaveStatusCode(expected); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,18 @@ | ||
using LeaderboardBackend.Models.Entities; | ||
using LeaderboardBackend.Result; | ||
using OneOf; | ||
using OneOf.Types; | ||
|
||
namespace LeaderboardBackend.Services; | ||
|
||
public interface IAccountRecoveryService | ||
{ | ||
Task<CreateRecoveryResult> CreateRecoveryAndSendEmail(User user); | ||
Task<RecoverAccountResult> TestRecovery(Guid id); | ||
} | ||
|
||
[GenerateOneOf] | ||
public partial class CreateRecoveryResult : OneOfBase<AccountRecovery, BadRole, EmailFailed> { }; | ||
|
||
[GenerateOneOf] | ||
public partial class RecoverAccountResult : OneOfBase<AlreadyUsed, BadRole, Expired, NotFound, Success> { }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters