IdentityShroud/IdentityShroud.Core.Tests/Services/ClientServiceTests.cs

194 lines
5.7 KiB
C#
Raw Normal View History

using IdentityShroud.Api;
using IdentityShroud.Core.Contracts;
using IdentityShroud.Core.EFCore;
using IdentityShroud.Core.Model;
using IdentityShroud.Core.Security;
using IdentityShroud.Core.Security.Keys;
using IdentityShroud.Core.Services;
using IdentityShroud.Core.Tests.Fixtures;
using IdentityShroud.TestUtils.Substitutes;
using Microsoft.EntityFrameworkCore;
namespace IdentityShroud.Core.Tests.Services;
public static class RealmDekBuilder
{
public static RealmDek DefaultActive() =>
new()
{
Id = DekId.NewId(),
Active = true,
Algorithm = KeyType.AES,
KeyData = new EncryptedDek(KekId.NewId(),
[
0
])
};
}
public static class ClientCreateRequestBuilder
{
public static ClientCreateRequest Default() => new(
"test-client",
"Test Client",
"A test client");
}
public class ClientServiceTests : IClassFixture<DbFixture>
{
private readonly DbFixture _dbFixture;
private readonly NullDataEncryptionService _dataEncryptionService = new();
private readonly IClock _clock = Substitute.For<IClock>();
private readonly Guid _realmId = new("a1b2c3d4-0000-0000-0000-000000000001");
public ClientServiceTests(DbFixture dbFixture)
{
_dbFixture = dbFixture;
using Db db = dbFixture.CreateDbContext();
if (!db.Database.EnsureCreated())
TruncateTables(db);
EnsureRealm(db);
}
private void TruncateTables(Db db)
{
db.Database.ExecuteSqlRaw("TRUNCATE client CASCADE;");
db.Database.ExecuteSqlRaw("TRUNCATE realm CASCADE;");
}
private void EnsureRealm(Db db)
{
if (!db.Realms.Any(r => r.Id == _realmId))
{
db.Realms.Add(new()
{
Id = _realmId,
Slug = "test-realm",
Name = "Test Realm",
DataEncryptionKeys = [ RealmDekBuilder.DefaultActive(), ],
});
db.SaveChanges();
}
}
private ClientService CreateSut(Db db) => new(db,
_dataEncryptionService,
new ClientCreateRequestValidator(),
_clock);
[Theory]
[InlineData(false)]
[InlineData(true)]
public async Task Create(bool withSecret)
{
// Setup
DateTime now = DateTime.UtcNow;
_clock.UtcNow().Returns(now);
Client val;
await using (var db = _dbFixture.CreateDbContext())
{
// Act
ClientService sut = CreateSut(db);
var response = await sut.Create(
_realmId,
ClientCreateRequestBuilder.Default() with
{
Confidential = withSecret,
GenerateSecret = withSecret,
},
TestContext.Current.CancellationToken);
// Verify
val = ResultAssert.Success(response);
Assert.Equal(_realmId, val.RealmId);
Assert.Equal("test-client", val.ClientId);
Assert.Equal("Test Client", val.Name);
Assert.Equal("A test client", val.Description);
Assert.Equal(withSecret, val.Confidential);
Assert.Equal(now, val.CreatedAt);
}
await using (var db = _dbFixture.CreateDbContext())
{
var dbRecord = await db.Clients
.Include(e => e.Secrets)
.SingleAsync(e => e.Id == val.Id, TestContext.Current.CancellationToken);
if (withSecret)
Assert.Single(dbRecord.Secrets);
else
Assert.Empty(dbRecord.Secrets);
}
}
[Theory]
[InlineData("existing-client", true)]
[InlineData("missing-client", false)]
public async Task GetByClientId(string clientId, bool shouldFind)
{
// Setup
_clock.UtcNow().Returns(DateTime.UtcNow);
await using (var setupContext = _dbFixture.CreateDbContext())
{
setupContext.Clients.Add(new()
{
RealmId = _realmId,
ClientId = "existing-client",
CreatedAt = DateTime.UtcNow,
});
await setupContext.SaveChangesAsync(TestContext.Current.CancellationToken);
}
await using var actContext = _dbFixture.CreateDbContext();
// Act
ClientService sut = CreateSut(actContext);
Client? result = await sut.GetByClientId(_realmId, clientId, TestContext.Current.CancellationToken);
// Verify
if (shouldFind)
Assert.NotNull(result);
else
Assert.Null(result);
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task FindById(bool shouldFind)
{
// Setup
_clock.UtcNow().Returns(DateTime.UtcNow);
int existingId;
await using (var setupContext = _dbFixture.CreateDbContext())
{
Client client = new()
{
RealmId = _realmId,
ClientId = "find-by-id-client",
CreatedAt = DateTime.UtcNow,
};
setupContext.Clients.Add(client);
await setupContext.SaveChangesAsync(TestContext.Current.CancellationToken);
existingId = client.Id;
}
int searchId = shouldFind ? existingId : existingId + 9999;
await using var actContext = _dbFixture.CreateDbContext();
// Act
ClientService sut = CreateSut(actContext);
Client? result = await sut.FindById(_realmId, searchId, TestContext.Current.CancellationToken);
// Verify
if (shouldFind)
Assert.NotNull(result);
else
Assert.Null(result);
}
}