feat(wbs): AEG-VS-01-05 Event/Job/Inbox - Part 2-3 Complete (Outbox/Inbox + Consumers)
Part 2: Transaction + Outbox Integration - RegisterIdentityEndpoint: DbConnection → DbTransaction → Outbox write - RegisterIdentitySql: Accept NpgsqlConnection + NpgsqlTransaction (Dapper) - Fixed schema references: identity.identity → public.identity - Hash computation (SHA256) for Outbox payload integrity Part 3: Consumer + Job Implementation - IdentityCreatedConsumer: SignalR group 'identity-notifications' - MfaReminderJob: Hangfire job, 24-hour reminder, idempotent via DB tracking - IdentityAuditConsumer: Immutable append-only audit trail - Migration 0043: identity_mfa_reminder + identity_audit_log tables Testing - Unit: IdentityCreated event serialization + immutability (4 tests) - Integration: RegisterIdentityWithOutbox (3 tests: happy path, rollback, duplicate email) - Updated existing tests: Transaction management (6 test methods) Architecture - Outbox/Inbox pattern ensures exactly-once delivery - Consumers decouple from identity creation (async, independent retry) - Audit trail immutable (trigger prevents updates/deletes) - MFA reminder idempotent (tracked in DB) Status: 40% COMPLETE (event + endpoint + 3 consumers) Next: E2E tests + Hangfire job registration + Admin UI Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
using Xunit;
|
||||
using KArtSell.Modules.IdentityAccess.ManageIdentityAndRoles.Events;
|
||||
|
||||
namespace KArtSell.IdentityAccess.Tests.Features;
|
||||
|
||||
public class IdentityCreatedEventTests
|
||||
{
|
||||
[Fact]
|
||||
public void IdentityCreated_Create_ReturnsValidRecord()
|
||||
{
|
||||
var identityId = Guid.NewGuid();
|
||||
var email = "test@example.com";
|
||||
var displayName = "Test User";
|
||||
var correlationId = Guid.NewGuid().ToString();
|
||||
var occurredAt = DateTime.UtcNow;
|
||||
|
||||
var @event = new IdentityCreated
|
||||
{
|
||||
IdentityId = identityId,
|
||||
Email = email,
|
||||
DisplayName = displayName,
|
||||
CorrelationId = correlationId,
|
||||
OccurredAt = occurredAt
|
||||
};
|
||||
|
||||
Assert.Equal(identityId, @event.IdentityId);
|
||||
Assert.Equal(email, @event.Email);
|
||||
Assert.Equal(displayName, @event.DisplayName);
|
||||
Assert.Equal(correlationId, @event.CorrelationId);
|
||||
Assert.Equal(occurredAt, @event.OccurredAt);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IdentityCreated_Immutability_RecordBehavior()
|
||||
{
|
||||
var event1 = new IdentityCreated
|
||||
{
|
||||
IdentityId = Guid.NewGuid(),
|
||||
Email = "test1@example.com",
|
||||
DisplayName = "Test 1",
|
||||
CorrelationId = "corr-1",
|
||||
OccurredAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
var event2 = event1 with { Email = "test2@example.com" };
|
||||
|
||||
Assert.NotEqual(event1.Email, event2.Email);
|
||||
Assert.Equal(event1.IdentityId, event2.IdentityId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IdentityCreated_Equality_SameValuesAreEqual()
|
||||
{
|
||||
var id = Guid.NewGuid();
|
||||
var email = "test@example.com";
|
||||
var displayName = "Test User";
|
||||
var correlationId = "corr-123";
|
||||
var occurredAt = new DateTime(2026, 8, 17, 12, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
var event1 = new IdentityCreated
|
||||
{
|
||||
IdentityId = id,
|
||||
Email = email,
|
||||
DisplayName = displayName,
|
||||
CorrelationId = correlationId,
|
||||
OccurredAt = occurredAt
|
||||
};
|
||||
|
||||
var event2 = new IdentityCreated
|
||||
{
|
||||
IdentityId = id,
|
||||
Email = email,
|
||||
DisplayName = displayName,
|
||||
CorrelationId = correlationId,
|
||||
OccurredAt = occurredAt
|
||||
};
|
||||
|
||||
Assert.Equal(event1, event2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IdentityCreated_Serialization_CanRoundTrip()
|
||||
{
|
||||
var @event = new IdentityCreated
|
||||
{
|
||||
IdentityId = Guid.NewGuid(),
|
||||
Email = "test@example.com",
|
||||
DisplayName = "Test User",
|
||||
CorrelationId = Guid.NewGuid().ToString(),
|
||||
OccurredAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
var json = System.Text.Json.JsonSerializer.Serialize(@event);
|
||||
var deserialized = System.Text.Json.JsonSerializer.Deserialize<IdentityCreated>(json);
|
||||
|
||||
Assert.NotNull(deserialized);
|
||||
Assert.Equal(@event.IdentityId, deserialized.IdentityId);
|
||||
Assert.Equal(@event.Email, deserialized.Email);
|
||||
Assert.Equal(@event.DisplayName, deserialized.DisplayName);
|
||||
Assert.Equal(@event.CorrelationId, deserialized.CorrelationId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user