Skip to content
This repository has been archived by the owner on Jul 9, 2024. It is now read-only.

Commit

Permalink
Added integration tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
Utar94 committed Apr 26, 2024
1 parent 617a407 commit 823a5f8
Show file tree
Hide file tree
Showing 6 changed files with 254 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Logitar.Master.Domain.Projects;
using Logitar.EventSourcing;
using Logitar.Master.Domain.Projects;
using Logitar.Master.Domain.Projects.Events;
using MediatR;

namespace Logitar.Master.Application.Projects.Commands;
Expand All @@ -16,9 +18,22 @@ public async Task Handle(SaveProjectCommand command, CancellationToken cancellat
{
ProjectAggregate project = command.Project;

if (await _projectRepository.LoadAsync(project.UniqueKey, cancellationToken) != null)
bool hasUniqueKeyChanged = false;
foreach (DomainEvent change in project.Changes)
{
throw new UniqueKeyAlreadyUsedException(project.UniqueKey);
if (change is ProjectCreatedEvent)
{
hasUniqueKeyChanged = true;
}
}

if (hasUniqueKeyChanged)
{
ProjectAggregate? conflict = await _projectRepository.LoadAsync(project.UniqueKey, cancellationToken);
if (conflict?.Equals(project) == false)
{
throw new UniqueKeyAlreadyUsedException(conflict.UniqueKey);
}
}

await _projectRepository.SaveAsync(project, cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public async Task It_should_create_a_new_project()
Assert.True(project.CreatedOn < project.UpdatedOn);

Assert.Equal(payload.UniqueKey.Trim(), project.UniqueKey);
Assert.Equal(payload.DisplayName?.CleanTrim(), project.DisplayName);
Assert.Equal(payload.DisplayName.Trim(), project.DisplayName);
Assert.Equal(payload.Description?.CleanTrim(), project.Description);

ProjectEntity? entity = await MasterContext.Projects.AsNoTracking()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Logitar.Master.Contracts.Projects;
using Logitar.Master.Domain.Projects;
using Logitar.Master.EntityFrameworkCore.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

namespace Logitar.Master.Application.Projects.Commands;

[Trait(Traits.Category, Categories.Integration)]
public class DeleteProjectCommandTests : IntegrationTests
{
private readonly IProjectRepository _projectRepository;

private readonly ProjectAggregate _project;

public DeleteProjectCommandTests() : base()
{
_projectRepository = ServiceProvider.GetRequiredService<IProjectRepository>();

_project = new(new UniqueKeyUnit("MASTER"));
}

public override async Task InitializeAsync()
{
await base.InitializeAsync();

await _projectRepository.SaveAsync(_project);
}

[Fact(DisplayName = "It should update an existing project.")]
public async Task It_should_delete_an_existing_project()
{
DeleteProjectCommand command = new(_project.Id.ToGuid());
Project? project = await Mediator.Send(command);
Assert.NotNull(project);
Assert.Equal(_project.Id.ToGuid(), project.Id);

ProjectEntity? entity = await MasterContext.Projects.AsNoTracking()
.SingleOrDefaultAsync(x => x.AggregateId == _project.Id.AggregateId.Value);
Assert.Null(entity);
}

[Fact(DisplayName = "It should return null when the project cannot be found.")]
public async Task It_should_return_null_when_the_project_cannot_be_found()
{
DeleteProjectCommand command = new(Id: Guid.Empty);
Project? project = await Mediator.Send(command);
Assert.Null(project);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using FluentValidation.Results;
using Logitar.Master.Contracts.Projects;
using Logitar.Master.Domain.Projects;
using Logitar.Master.Domain.Shared;
using Logitar.Security.Cryptography;
using Microsoft.Extensions.DependencyInjection;

namespace Logitar.Master.Application.Projects.Commands;

[Trait(Traits.Category, Categories.Integration)]
public class ReplaceProjectCommandTests : IntegrationTests
{
private readonly IProjectRepository _projectRepository;

private readonly ProjectAggregate _project;

public ReplaceProjectCommandTests() : base()
{
_projectRepository = ServiceProvider.GetRequiredService<IProjectRepository>();

_project = new(new UniqueKeyUnit("MASTER"));
}

public override async Task InitializeAsync()
{
await base.InitializeAsync();

await _projectRepository.SaveAsync(_project);
}

[Fact(DisplayName = "It should replace an existing project with delta.")]
public async Task It_should_replace_an_existing_project_with_delta()
{
long version = _project.Version;
_project.Description = new DescriptionUnit("This is the master project.");
_project.Update();
await _projectRepository.SaveAsync(_project);

ReplaceProjectPayload payload = new()
{
DisplayName = " Master ",
Description = " "
};
ReplaceProjectCommand command = new(_project.Id.ToGuid(), payload, version);
Project? project = await Mediator.Send(command);
Assert.NotNull(project);

Assert.Equal(_project.Id.ToGuid(), project.Id);
Assert.Equal(3, project.Version);
// TODO(fpion): CreatedBy, UpdatedBy
Assert.True(project.CreatedOn < project.UpdatedOn);

Assert.Equal(_project.UniqueKey.Value, project.UniqueKey);
Assert.Equal(payload.DisplayName.Trim(), project.DisplayName);
Assert.Equal(_project.Description.Value, project.Description);
}

[Fact(DisplayName = "It should replace an existing project.")]
public async Task It_should_replace_an_existing_project()
{
ReplaceProjectPayload payload = new()
{
DisplayName = " Master ",
Description = " "
};
ReplaceProjectCommand command = new(_project.Id.ToGuid(), payload, Version: null);
Project? project = await Mediator.Send(command);
Assert.NotNull(project);

Assert.Equal(_project.Id.ToGuid(), project.Id);
Assert.Equal(2, project.Version);
// TODO(fpion): CreatedBy, UpdatedBy
Assert.True(project.CreatedOn < project.UpdatedOn);

Assert.Equal(_project.UniqueKey.Value, project.UniqueKey);
Assert.Equal(payload.DisplayName.Trim(), project.DisplayName);
Assert.Equal(payload.Description?.CleanTrim(), project.Description);
}

[Fact(DisplayName = "It should return null when the project cannot be found.")]
public async Task It_should_return_null_when_the_project_cannot_be_found()
{
ReplaceProjectPayload payload = new();
ReplaceProjectCommand command = new(Id: Guid.Empty, payload, Version: null);
Project? project = await Mediator.Send(command);
Assert.Null(project);
}

[Fact(DisplayName = "It should throw ValidationException when the payload is not valid.")]
public async Task It_should_throw_ValidationException_when_the_payload_is_not_valid()
{
ReplaceProjectPayload payload = new()
{
DisplayName = RandomStringGenerator.GetString(DisplayNameUnit.MaximumLength + 1)
};
ReplaceProjectCommand command = new(_project.Id.ToGuid(), payload, Version: null);
var exception = await Assert.ThrowsAsync<FluentValidation.ValidationException>(async () => await Mediator.Send(command));

ValidationFailure error = Assert.Single(exception.Errors);
Assert.Equal("MaximumLengthValidator", error.ErrorCode);
Assert.Equal("DisplayName", error.PropertyName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using FluentValidation.Results;
using Logitar.Master.Contracts;
using Logitar.Master.Contracts.Projects;
using Logitar.Master.Domain.Projects;
using Logitar.Master.Domain.Shared;
using Logitar.Security.Cryptography;
using Microsoft.Extensions.DependencyInjection;

namespace Logitar.Master.Application.Projects.Commands;

[Trait(Traits.Category, Categories.Integration)]
public class UpdateProjectCommandTests : IntegrationTests
{
private readonly IProjectRepository _projectRepository;

private readonly ProjectAggregate _project;

public UpdateProjectCommandTests() : base()
{
_projectRepository = ServiceProvider.GetRequiredService<IProjectRepository>();

_project = new(new UniqueKeyUnit("MASTER"));
}

public override async Task InitializeAsync()
{
await base.InitializeAsync();

await _projectRepository.SaveAsync(_project);
}

[Fact(DisplayName = "It should return null when the project cannot be found.")]
public async Task It_should_return_null_when_the_project_cannot_be_found()
{
UpdateProjectPayload payload = new();
UpdateProjectCommand command = new(Id: Guid.Empty, payload);
Project? project = await Mediator.Send(command);
Assert.Null(project);
}

[Fact(DisplayName = "It should throw ValidationException when the payload is not valid.")]
public async Task It_should_throw_ValidationException_when_the_payload_is_not_valid()
{
UpdateProjectPayload payload = new()
{
DisplayName = new Change<string>(RandomStringGenerator.GetString(DisplayNameUnit.MaximumLength + 1))
};
UpdateProjectCommand command = new(_project.Id.ToGuid(), payload);
var exception = await Assert.ThrowsAsync<FluentValidation.ValidationException>(async () => await Mediator.Send(command));

ValidationFailure error = Assert.Single(exception.Errors);
Assert.Equal("MaximumLengthValidator", error.ErrorCode);
Assert.Equal("DisplayName.Value", error.PropertyName);
}

[Fact(DisplayName = "It should update an existing project.")]
public async Task It_should_update_an_existing_project()
{
_project.DisplayName = new DisplayNameUnit("Master");
_project.Description = new DescriptionUnit("This is the master project.");
_project.Update();
await _projectRepository.SaveAsync(_project);

UpdateProjectPayload payload = new()
{
Description = new Change<string>(" ")
};
UpdateProjectCommand command = new(_project.Id.ToGuid(), payload);
Project? project = await Mediator.Send(command);
Assert.NotNull(project);

Assert.Equal(_project.Id.ToGuid(), project.Id);
Assert.Equal(3, project.Version);
// TODO(fpion): CreatedBy, UpdatedBy
Assert.True(project.CreatedOn < project.UpdatedOn);

Assert.Equal(_project.UniqueKey.Value, project.UniqueKey);
Assert.Equal(_project.DisplayName.Value, project.DisplayName);
Assert.Equal(payload.Description.Value?.CleanTrim(), project.Description);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Logitar.Security" Version="6.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="xunit" Version="2.7.1" />
Expand Down

0 comments on commit 823a5f8

Please sign in to comment.