104 lines
3.5 KiB
C#
104 lines
3.5 KiB
C#
using EntKube.Provisioning.Domain;
|
|
using EntKube.Provisioning.Infrastructure;
|
|
using FluentAssertions;
|
|
using Microsoft.Data.Sqlite;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace EntKube.Provisioning.Tests.Features;
|
|
|
|
/// <summary>
|
|
/// Integration tests for EF Core provisioning repositories. Uses a real SQLite
|
|
/// database to verify that change tracking works correctly when adding child
|
|
/// entities with pre-set Guid keys to tracked aggregates.
|
|
/// </summary>
|
|
public class EfIdentityRealmRepositoryTests : IDisposable
|
|
{
|
|
private readonly SqliteConnection connection;
|
|
private readonly ProvisioningDbContext db;
|
|
private readonly EfIdentityRealmRepository repository;
|
|
|
|
public EfIdentityRealmRepositoryTests()
|
|
{
|
|
connection = new SqliteConnection("DataSource=:memory:");
|
|
connection.Open();
|
|
|
|
DbContextOptions<ProvisioningDbContext> options = new DbContextOptionsBuilder<ProvisioningDbContext>()
|
|
.UseSqlite(connection)
|
|
.Options;
|
|
|
|
db = new ProvisioningDbContext(options);
|
|
db.Database.EnsureCreated();
|
|
repository = new EfIdentityRealmRepository(db);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpdateAsync_AddingIdentityProvider_DoesNotThrowConcurrencyException()
|
|
{
|
|
// Arrange — Create and persist a realm, then load it back.
|
|
|
|
Guid environmentId = Guid.NewGuid();
|
|
Guid clusterId = Guid.NewGuid();
|
|
|
|
IdentityRealm realm = IdentityRealm.Create(environmentId, "test-realm", clusterId);
|
|
await repository.AddAsync(realm);
|
|
|
|
IdentityRealm? loaded = await repository.GetByIdAsync(realm.Id);
|
|
loaded.Should().NotBeNull();
|
|
|
|
// Act — Add a new identity provider to the tracked realm and save.
|
|
// Before the fix, Update() would mark the new provider as Modified
|
|
// instead of Added, causing DbUpdateConcurrencyException.
|
|
|
|
RealmIdentityProvider idp = RealmIdentityProvider.Create(
|
|
"google", "Google", IdentityProviderType.Google);
|
|
|
|
loaded!.AddIdentityProvider(idp);
|
|
|
|
Func<Task> act = async () => await repository.UpdateAsync(loaded);
|
|
|
|
// Assert — Should save without throwing.
|
|
|
|
await act.Should().NotThrowAsync<DbUpdateConcurrencyException>();
|
|
|
|
IdentityRealm? reloaded = await repository.GetByIdAsync(realm.Id);
|
|
reloaded!.IdentityProviders.Should().HaveCount(1);
|
|
reloaded.IdentityProviders[0].Alias.Should().Be("google");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpdateAsync_AddingOrganization_DoesNotThrowConcurrencyException()
|
|
{
|
|
// Arrange — Create and persist a realm.
|
|
|
|
Guid environmentId = Guid.NewGuid();
|
|
Guid clusterId = Guid.NewGuid();
|
|
|
|
IdentityRealm realm = IdentityRealm.Create(environmentId, "org-realm", clusterId);
|
|
await repository.AddAsync(realm);
|
|
|
|
IdentityRealm? loaded = await repository.GetByIdAsync(realm.Id);
|
|
loaded.Should().NotBeNull();
|
|
|
|
// Act — Add a new organization and save.
|
|
|
|
RealmOrganization org = RealmOrganization.Create("Engineering", "Dev teams");
|
|
loaded!.AddOrganization(org);
|
|
|
|
Func<Task> act = async () => await repository.UpdateAsync(loaded);
|
|
|
|
// Assert
|
|
|
|
await act.Should().NotThrowAsync<DbUpdateConcurrencyException>();
|
|
|
|
IdentityRealm? reloaded = await repository.GetByIdAsync(realm.Id);
|
|
reloaded!.Organizations.Should().HaveCount(1);
|
|
reloaded.Organizations[0].Name.Should().Be("Engineering");
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
db.Dispose();
|
|
connection.Dispose();
|
|
}
|
|
}
|