Skip to content

Commit

Permalink
Implemented Integration tests. (#36)
Browse files Browse the repository at this point in the history
* Added serialization constructors to contact informations.

* Fixed repositories and event handlers.

* Implemented Integration tests.
  • Loading branch information
Utar94 authored Jan 12, 2024
1 parent a8c4a8a commit 92a2e15
Show file tree
Hide file tree
Showing 19 changed files with 792 additions and 121 deletions.
9 changes: 8 additions & 1 deletion Identity.sln
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Logitar.Identity.Demo", "sr
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{BCB8A692-DF88-4E50-91A7-AD91E466559C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Logitar.Identity.Domain.UnitTests", "tests\Logitar.Identity.Domain.UnitTests\Logitar.Identity.Domain.UnitTests.csproj", "{9A27A378-14E7-4D3C-B847-27D0D4EFA8F9}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Logitar.Identity.Domain.UnitTests", "tests\Logitar.Identity.Domain.UnitTests\Logitar.Identity.Domain.UnitTests.csproj", "{9A27A378-14E7-4D3C-B847-27D0D4EFA8F9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Logitar.Identity.EFCore.SqlServer.IntegrationTests", "tests\Logitar.Identity.EFCore.SqlServer.IntegrationTests\Logitar.Identity.EFCore.SqlServer.IntegrationTests.csproj", "{FA9AB722-026B-4842-B888-E9824568CBC1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -58,12 +60,17 @@ Global
{9A27A378-14E7-4D3C-B847-27D0D4EFA8F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A27A378-14E7-4D3C-B847-27D0D4EFA8F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A27A378-14E7-4D3C-B847-27D0D4EFA8F9}.Release|Any CPU.Build.0 = Release|Any CPU
{FA9AB722-026B-4842-B888-E9824568CBC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA9AB722-026B-4842-B888-E9824568CBC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA9AB722-026B-4842-B888-E9824568CBC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA9AB722-026B-4842-B888-E9824568CBC1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{9A27A378-14E7-4D3C-B847-27D0D4EFA8F9} = {BCB8A692-DF88-4E50-91A7-AD91E466559C}
{FA9AB722-026B-4842-B888-E9824568CBC1} = {BCB8A692-DF88-4E50-91A7-AD91E466559C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {45FD7647-C5AB-4CE1-A93C-59A73FDD2196}
Expand Down
7 changes: 4 additions & 3 deletions src/Logitar.Identity.Domain/Logitar.Identity.Domain.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/Logitar/Identity</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<AssemblyVersion>0.10.0.0</AssemblyVersion>
<AssemblyVersion>0.10.1.0</AssemblyVersion>
<FileVersion>$(AssemblyVersion)</FileVersion>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<Version>0.10.0</Version>
<Version>0.10.1</Version>
<NeutralLanguage>en-CA</NeutralLanguage>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<PackageReleaseNotes>Implemented Identity domain layer.</PackageReleaseNotes>
<PackageReleaseNotes>Added serialization constructors to contact informations.</PackageReleaseNotes>
<PackageTags>logitar;net;framework;identity;domain</PackageTags>
<PackageProjectUrl>https://github.com/Logitar/Identity/tree/main/src/Logitar.Identity.Domain</PackageProjectUrl>
</PropertyGroup>
Expand Down Expand Up @@ -58,6 +58,7 @@
<Using Include="System.Collections.Immutable" />
<Using Include="System.Globalization" />
<Using Include="System.Text" />
<Using Include="System.Text.Json.Serialization" />
</ItemGroup>

</Project>
31 changes: 29 additions & 2 deletions src/Logitar.Identity.Domain/Users/AddressUnit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,33 @@ public record AddressUnit : ContactUnit, IAddress
/// </summary>
public string Country { get; }

/// <summary>
/// Initializes a new instance of the <see cref="AddressUnit"/> class.
/// </summary>
/// <param name="street">The street address.</param>
/// <param name="locality">The locality (city) of the address.</param>
/// <param name="country">The country of the address.</param>
/// <param name="region">The region of the address.</param>
/// <param name="postalCode">The postal code of the address.</param>
/// <param name="propertyName">The name of the property, used for validation.</param>
public AddressUnit(string street, string locality, string country, string? region = null, string? postalCode = null, string? propertyName = null)
: this(street, locality, country, region, postalCode, isVerified: false, propertyName)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AddressUnit"/> class.
/// </summary>
/// <param name="street">The street address.</param>
/// <param name="locality">The locality (city) of the address.</param>
/// <param name="country">The country of the address.</param>
/// <param name="region">The region of the address.</param>
/// <param name="postalCode">The postal code of the address.</param>
/// <param name="isVerified">A value indicating whether or not the postal address is verified.</param>
[JsonConstructor]
public AddressUnit(string street, string locality, string country, string? region, string? postalCode, bool isVerified)
: this(street, locality, country, region, postalCode, isVerified, propertyName: null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AddressUnit"/> class.
/// </summary>
Expand All @@ -44,8 +71,8 @@ public record AddressUnit : ContactUnit, IAddress
/// <param name="postalCode">The postal code of the address.</param>
/// <param name="isVerified">A value indicating whether or not the postal address is verified.</param>
/// <param name="propertyName">The name of the property, used for validation.</param>
public AddressUnit(string street, string locality, string country, string? region = null, string? postalCode = null,
bool isVerified = false, string? propertyName = null) : base(isVerified)
public AddressUnit(string street, string locality, string country, string? region, string? postalCode, bool isVerified, string? propertyName = null)
: base(isVerified)
{
Street = street.Trim();
Locality = locality.Trim();
Expand Down
22 changes: 21 additions & 1 deletion src/Logitar.Identity.Domain/Users/EmailUnit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,33 @@ public record EmailUnit : ContactUnit, IEmail
/// </summary>
public string Address { get; }

/// <summary>
/// Initializes a new instance of the <see cref="EmailUnit"/> class.
/// </summary>
/// <param name="address">The email address.</param>
/// <param name="propertyName">The name of the property, used for validation.</param>
public EmailUnit(string address, string? propertyName = null) : this(address, isVerified: false, propertyName)
{
Address = address.Trim();

new EmailValidator(propertyName).ValidateAndThrow(this);
}
/// <summary>
/// Initializes a new instance of the <see cref="EmailUnit"/> class.
/// </summary>
/// <param name="address">The email address.</param>
/// <param name="isVerified">A value indicating whether or not the email address is verified.</param>
[JsonConstructor]
public EmailUnit(string address, bool isVerified) : this(address, isVerified, propertyName: null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="EmailUnit"/> class.
/// </summary>
/// <param name="address">The email address.</param>
/// <param name="isVerified">A value indicating whether or not the email address is verified.</param>
/// <param name="propertyName">The name of the property, used for validation.</param>
public EmailUnit(string address, bool isVerified = false, string? propertyName = null) : base(isVerified)
public EmailUnit(string address, bool isVerified, string? propertyName) : base(isVerified)
{
Address = address.Trim();

Expand Down
25 changes: 24 additions & 1 deletion src/Logitar.Identity.Domain/Users/PhoneUnit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,29 @@ public record PhoneUnit : ContactUnit, IPhone
/// </summary>
public string? Extension { get; }

/// <summary>
/// Initializes a new instance of the <see cref="PhoneUnit"/> class.
/// </summary>
/// <param name="number">The phone number.</param>
/// <param name="countryCode">The <see href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-1 alpha-2 country code</see> of the phone.</param>
/// <param name="extension">The phone extension.</param>
/// <param name="propertyName">The name of the property, used for validation.</param>
public PhoneUnit(string number, string? countryCode = null, string? extension = null, string? propertyName = null)
: this(number, countryCode, extension, isVerified: false, propertyName)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PhoneUnit"/> class.
/// </summary>
/// <param name="number">The phone number.</param>
/// <param name="countryCode">The <see href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-1 alpha-2 country code</see> of the phone.</param>
/// <param name="extension">The phone extension.</param>
/// <param name="isVerified">A value indicating whether or not the phone number is verified.</param>
[JsonConstructor]
public PhoneUnit(string number, string? countryCode, string? extension, bool isVerified)
: this(number, countryCode, extension, isVerified, propertyName: null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PhoneUnit"/> class.
/// </summary>
Expand All @@ -42,7 +65,7 @@ public record PhoneUnit : ContactUnit, IPhone
/// <param name="extension">The phone extension.</param>
/// <param name="isVerified">A value indicating whether or not the phone number is verified.</param>
/// <param name="propertyName">The name of the property, used for validation.</param>
public PhoneUnit(string number, string? countryCode = null, string? extension = null, bool isVerified = false, string? propertyName = null)
public PhoneUnit(string number, string? countryCode, string? extension, bool isVerified, string? propertyName)
: base(isVerified)
{
CountryCode = countryCode?.CleanTrim();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ public ApiKeyEventHandler(IdentityContext context) : base(context)

public virtual async Task HandleAsync(ApiKeyAuthenticatedEvent @event, CancellationToken cancellationToken)
{
ApiKeyEntity apiKey = await LoadAsync(@event.AggregateId, cancellationToken);

apiKey.Authenticate(@event);
ApiKeyEntity? apiKey = await TryLoadAsync(@event.AggregateId, cancellationToken);
if (apiKey != null)
{
apiKey.Authenticate(@event);

await Context.SaveChangesAsync(cancellationToken);
await Context.SaveChangesAsync(cancellationToken);
}
}

public virtual async Task HandleAsync(ApiKeyCreatedEvent @event, CancellationToken cancellationToken)
Expand Down Expand Up @@ -50,35 +52,41 @@ public virtual async Task HandleAsync(ApiKeyDeletedEvent @event, CancellationTok

public virtual async Task HandleAsync(ApiKeyRoleAddedEvent @event, CancellationToken cancellationToken)
{
ApiKeyEntity apiKey = await LoadAsync(@event.AggregateId, cancellationToken);

RoleEntity role = await Context.Roles
.SingleOrDefaultAsync(x => x.AggregateId == @event.RoleId.AggregateId.Value, cancellationToken)
?? throw new InvalidOperationException($"The role entity 'AggregateId={@event.AggregateId}' could not be found.");
ApiKeyEntity? apiKey = await TryLoadAsync(@event.AggregateId, cancellationToken);
if (apiKey != null)
{
RoleEntity role = await Context.Roles
.SingleOrDefaultAsync(x => x.AggregateId == @event.RoleId.AggregateId.Value, cancellationToken)
?? throw new InvalidOperationException($"The role entity 'AggregateId={@event.AggregateId}' could not be found.");

apiKey.AddRole(role, @event);
apiKey.AddRole(role, @event);

await Context.SaveChangesAsync(cancellationToken);
await Context.SaveChangesAsync(cancellationToken);
}
}

public virtual async Task HandleAsync(ApiKeyRoleRemovedEvent @event, CancellationToken cancellationToken)
{
ApiKeyEntity apiKey = await LoadAsync(@event.AggregateId, cancellationToken);

apiKey.RemoveRole(@event);
ApiKeyEntity? apiKey = await TryLoadAsync(@event.AggregateId, cancellationToken);
if (apiKey != null)
{
apiKey.RemoveRole(@event);

await Context.SaveChangesAsync(cancellationToken);
await Context.SaveChangesAsync(cancellationToken);
}
}

public virtual async Task HandleAsync(ApiKeyUpdatedEvent @event, CancellationToken cancellationToken)
{
ApiKeyEntity apiKey = await LoadAsync(@event.AggregateId, cancellationToken);

apiKey.Update(@event);
ApiKeyEntity? apiKey = await TryLoadAsync(@event.AggregateId, cancellationToken);
if (apiKey != null)
{
apiKey.Update(@event);

await SynchronizeCustomAttributesAsync(EntityType, apiKey.ApiKeyId, @event.CustomAttributes, cancellationToken);
await SaveActorAsync(apiKey, cancellationToken);
await Context.SaveChangesAsync(cancellationToken);
await SynchronizeCustomAttributesAsync(EntityType, apiKey.ApiKeyId, @event.CustomAttributes, cancellationToken);
await SaveActorAsync(apiKey, cancellationToken);
await Context.SaveChangesAsync(cancellationToken);
}
}

protected virtual async Task<ApiKeyEntity> LoadAsync(AggregateId aggregateId, CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,25 @@ public virtual async Task HandleAsync(RoleDeletedEvent @event, CancellationToken

public virtual async Task HandleAsync(RoleUniqueNameChangedEvent @event, CancellationToken cancellationToken)
{
RoleEntity role = await LoadAsync(@event.AggregateId, cancellationToken);

role.SetUniqueName(@event);
RoleEntity? role = await TryLoadAsync(@event.AggregateId, cancellationToken);
if (role != null)
{
role.SetUniqueName(@event);

await Context.SaveChangesAsync(cancellationToken);
await Context.SaveChangesAsync(cancellationToken);
}
}

public virtual async Task HandleAsync(RoleUpdatedEvent @event, CancellationToken cancellationToken)
{
RoleEntity role = await LoadAsync(@event.AggregateId, cancellationToken);

role.Update(@event);
RoleEntity? role = await TryLoadAsync(@event.AggregateId, cancellationToken);
if (role != null)
{
role.Update(@event);

await SynchronizeCustomAttributesAsync(EntityType, role.RoleId, @event.CustomAttributes, cancellationToken);
await Context.SaveChangesAsync(cancellationToken);
await SynchronizeCustomAttributesAsync(EntityType, role.RoleId, @event.CustomAttributes, cancellationToken);
await Context.SaveChangesAsync(cancellationToken);
}
}

protected virtual async Task<RoleEntity> LoadAsync(AggregateId aggregateId, CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,30 +41,36 @@ public virtual async Task HandleAsync(SessionDeletedEvent @event, CancellationTo

public virtual async Task HandleAsync(SessionRenewedEvent @event, CancellationToken cancellationToken)
{
SessionEntity session = await LoadAsync(@event.AggregateId, cancellationToken);

session.Renew(@event);
SessionEntity? session = await TryLoadAsync(@event.AggregateId, cancellationToken);
if (session != null)
{
session.Renew(@event);

await Context.SaveChangesAsync(cancellationToken);
await Context.SaveChangesAsync(cancellationToken);
}
}

public virtual async Task HandleAsync(SessionSignedOutEvent @event, CancellationToken cancellationToken)
{
SessionEntity session = await LoadAsync(@event.AggregateId, cancellationToken);

session.SignOut(@event);
SessionEntity? session = await TryLoadAsync(@event.AggregateId, cancellationToken);
if (session != null)
{
session.SignOut(@event);

await Context.SaveChangesAsync(cancellationToken);
await Context.SaveChangesAsync(cancellationToken);
}
}

public virtual async Task HandleAsync(SessionUpdatedEvent @event, CancellationToken cancellationToken)
{
SessionEntity session = await LoadAsync(@event.AggregateId, cancellationToken);

session.Update(@event);
SessionEntity? session = await TryLoadAsync(@event.AggregateId, cancellationToken);
if (session != null)
{
session.Update(@event);

await SynchronizeCustomAttributesAsync(EntityType, session.SessionId, @event.CustomAttributes, cancellationToken);
await Context.SaveChangesAsync(cancellationToken);
await SynchronizeCustomAttributesAsync(EntityType, session.SessionId, @event.CustomAttributes, cancellationToken);
await Context.SaveChangesAsync(cancellationToken);
}
}

protected virtual async Task<SessionEntity> LoadAsync(AggregateId aggregateId, CancellationToken cancellationToken)
Expand Down
Loading

0 comments on commit 92a2e15

Please sign in to comment.