2026-03-16 19:15:04 +01:00
|
|
|
using FluentResults;
|
2026-02-15 07:15:11 +01:00
|
|
|
using IdentityShroud.Core.Contracts;
|
2026-03-16 19:15:04 +01:00
|
|
|
using IdentityShroud.Core.EFCore;
|
2026-02-27 17:57:42 +00:00
|
|
|
using IdentityShroud.Core.Model;
|
|
|
|
|
using IdentityShroud.Core.Security.Keys;
|
2026-02-08 11:57:57 +01:00
|
|
|
using IdentityShroud.Core.Services;
|
|
|
|
|
using IdentityShroud.Core.Tests.Fixtures;
|
2026-03-16 19:15:04 +01:00
|
|
|
using IdentityShroud.TestUtils.Substitutes;
|
2026-02-08 11:57:57 +01:00
|
|
|
using Microsoft.EntityFrameworkCore;
|
2026-03-16 19:15:04 +01:00
|
|
|
using Shouldly;
|
2026-02-08 11:57:57 +01:00
|
|
|
|
|
|
|
|
namespace IdentityShroud.Core.Tests.Services;
|
|
|
|
|
|
|
|
|
|
public class RealmServiceTests : IClassFixture<DbFixture>
|
|
|
|
|
{
|
2026-02-15 07:15:11 +01:00
|
|
|
private readonly DbFixture _dbFixture;
|
2026-02-27 17:57:42 +00:00
|
|
|
private readonly IKeyService _keyService = Substitute.For<IKeyService>();
|
2026-03-16 19:15:04 +01:00
|
|
|
private readonly IDekEncryptionService _dekCryptor = new NullDekEncryptionService();
|
2026-02-08 11:57:57 +01:00
|
|
|
|
|
|
|
|
public RealmServiceTests(DbFixture dbFixture)
|
|
|
|
|
{
|
2026-02-15 07:15:11 +01:00
|
|
|
_dbFixture = dbFixture;
|
|
|
|
|
using Db db = dbFixture.CreateDbContext();
|
|
|
|
|
if (!db.Database.EnsureCreated())
|
|
|
|
|
TruncateTables(db);
|
2026-02-08 11:57:57 +01:00
|
|
|
}
|
|
|
|
|
|
2026-02-15 07:15:11 +01:00
|
|
|
private void TruncateTables(Db db)
|
2026-02-08 11:57:57 +01:00
|
|
|
{
|
2026-02-15 07:15:11 +01:00
|
|
|
db.Database.ExecuteSqlRaw("TRUNCATE realm CASCADE;");
|
2026-02-08 11:57:57 +01:00
|
|
|
}
|
2026-03-16 19:15:04 +01:00
|
|
|
|
|
|
|
|
private RealmService CreateSut(Db db) => new(db, _keyService, _dekCryptor, new ClockService());
|
|
|
|
|
|
2026-02-08 11:57:57 +01:00
|
|
|
|
|
|
|
|
[Theory]
|
|
|
|
|
[InlineData(null)]
|
|
|
|
|
[InlineData("a7c2a39c-3ed9-4790-826e-43bb2e5e480c")]
|
|
|
|
|
public async Task Create(string? idString)
|
|
|
|
|
{
|
2026-02-15 07:15:11 +01:00
|
|
|
// Setup
|
2026-02-08 11:57:57 +01:00
|
|
|
Guid? realmId = null;
|
|
|
|
|
if (idString is not null)
|
|
|
|
|
realmId = new(idString);
|
2026-02-15 07:15:11 +01:00
|
|
|
|
2026-03-16 19:15:04 +01:00
|
|
|
Realm? val;
|
2026-02-27 17:57:42 +00:00
|
|
|
await using (var db = _dbFixture.CreateDbContext())
|
|
|
|
|
{
|
|
|
|
|
_keyService.CreateKey(Arg.Any<KeyPolicy>())
|
2026-03-16 19:15:04 +01:00
|
|
|
.Returns(new CreateKeyResponse(KeyType.AES, new KeyData([21])));
|
2026-02-27 17:57:42 +00:00
|
|
|
// Act
|
2026-03-16 19:15:04 +01:00
|
|
|
RealmService sut = CreateSut(db);
|
|
|
|
|
Result<Realm> response = await sut.Create(
|
2026-02-27 17:57:42 +00:00
|
|
|
new(realmId, "slug", "New realm"),
|
|
|
|
|
TestContext.Current.CancellationToken);
|
|
|
|
|
|
|
|
|
|
// Verify
|
|
|
|
|
val = ResultAssert.Success(response);
|
|
|
|
|
if (realmId.HasValue)
|
|
|
|
|
Assert.Equal(realmId, val.Id);
|
|
|
|
|
else
|
|
|
|
|
Assert.NotEqual(Guid.Empty, val.Id);
|
|
|
|
|
|
2026-03-16 19:15:04 +01:00
|
|
|
Assert.Multiple(
|
|
|
|
|
() => val.Slug.ShouldBe("slug"),
|
|
|
|
|
() => val.Name.ShouldBe("New realm"),
|
|
|
|
|
() => val.DataEncryptionKeys.ShouldContain(d => d.Active),
|
|
|
|
|
() => val.TokenSigningKeys.ShouldContain(d => !d.RevokedAt.HasValue)
|
|
|
|
|
);
|
2026-02-27 17:57:42 +00:00
|
|
|
|
|
|
|
|
_keyService.Received().CreateKey(Arg.Any<KeyPolicy>());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await using (var db = _dbFixture.CreateDbContext())
|
|
|
|
|
{
|
|
|
|
|
var dbRecord = await db.Realms
|
2026-03-16 19:15:04 +01:00
|
|
|
.Include(e => e.TokenSigningKeys)
|
2026-02-27 17:57:42 +00:00
|
|
|
.SingleAsync(e => e.Id == val.Id, TestContext.Current.CancellationToken);
|
2026-03-16 19:15:04 +01:00
|
|
|
Assert.Equal(KeyType.AES, dbRecord.TokenSigningKeys[0].KeyType);
|
2026-02-27 17:57:42 +00:00
|
|
|
}
|
2026-02-08 11:57:57 +01:00
|
|
|
}
|
2026-02-15 07:15:11 +01:00
|
|
|
|
|
|
|
|
[Theory]
|
|
|
|
|
[InlineData("slug", null)]
|
|
|
|
|
[InlineData("foo", "Foo")]
|
|
|
|
|
public async Task FindBySlug(string slug, string? name)
|
|
|
|
|
{
|
2026-02-27 17:57:42 +00:00
|
|
|
await using (var setupContext = _dbFixture.CreateDbContext())
|
2026-02-15 07:15:11 +01:00
|
|
|
{
|
|
|
|
|
setupContext.Realms.Add(new()
|
|
|
|
|
{
|
|
|
|
|
Slug = "foo",
|
|
|
|
|
Name = "Foo",
|
|
|
|
|
});
|
|
|
|
|
setupContext.Realms.Add(new()
|
|
|
|
|
{
|
|
|
|
|
Slug = "bar",
|
|
|
|
|
Name = "Bar",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await setupContext.SaveChangesAsync(TestContext.Current.CancellationToken);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-27 17:57:42 +00:00
|
|
|
await using var actContext = _dbFixture.CreateDbContext();
|
2026-02-15 07:15:11 +01:00
|
|
|
// Act
|
2026-03-16 19:15:04 +01:00
|
|
|
RealmService sut = CreateSut(actContext);
|
2026-02-15 07:15:11 +01:00
|
|
|
var result = await sut.FindBySlug(slug, TestContext.Current.CancellationToken);
|
|
|
|
|
|
2026-02-27 17:57:42 +00:00
|
|
|
// Verify
|
2026-02-15 07:15:11 +01:00
|
|
|
Assert.Equal(name, result?.Name);
|
|
|
|
|
}
|
2026-02-27 17:57:42 +00:00
|
|
|
|
|
|
|
|
[Theory]
|
|
|
|
|
[InlineData("b0423bba-2411-497b-a5b6-c5adf404b862", true)]
|
|
|
|
|
[InlineData("65ac9dba-6d43-4fa4-b57f-133ed639fbcb", false)]
|
|
|
|
|
public async Task FindById(string idString, bool shouldFind)
|
|
|
|
|
{
|
|
|
|
|
Guid id = new(idString);
|
|
|
|
|
await using (var setupContext = _dbFixture.CreateDbContext())
|
|
|
|
|
{
|
|
|
|
|
setupContext.Realms.Add(new()
|
|
|
|
|
{
|
|
|
|
|
Id = new("b0423bba-2411-497b-a5b6-c5adf404b862"),
|
|
|
|
|
Slug = "foo",
|
|
|
|
|
Name = "Foo",
|
|
|
|
|
});
|
|
|
|
|
setupContext.Realms.Add(new()
|
|
|
|
|
{
|
|
|
|
|
Id = new("d4ffc7d0-7b2c-4f02-82b9-a74610435b0d"),
|
|
|
|
|
Slug = "bar",
|
|
|
|
|
Name = "Bar",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await setupContext.SaveChangesAsync(TestContext.Current.CancellationToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await using var actContext = _dbFixture.CreateDbContext();
|
|
|
|
|
// Act
|
2026-03-16 19:15:04 +01:00
|
|
|
RealmService sut = CreateSut(actContext);
|
2026-02-27 17:57:42 +00:00
|
|
|
Realm? result = await sut.FindById(id, TestContext.Current.CancellationToken);
|
|
|
|
|
|
|
|
|
|
// Verify
|
|
|
|
|
if (shouldFind)
|
|
|
|
|
Assert.NotNull(result);
|
|
|
|
|
else
|
|
|
|
|
Assert.Null(result);
|
|
|
|
|
}
|
2026-02-08 11:57:57 +01:00
|
|
|
}
|