Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
3013027
Move registration endpoint to new RegisterController
Foqsz Apr 7, 2026
42bcc0f
Update password and email validation in client use cases
Foqsz Apr 7, 2026
54ed0e3
Update login error messages to cover email and password
Foqsz Apr 7, 2026
da1174a
Refactor product use cases to use authenticated user ID
Foqsz Apr 8, 2026
f725125
Add unit tests for UpdateClientUseCase and refactor helpers
Foqsz Apr 8, 2026
b353c73
Integrate RabbitMQ messaging for client creation events
Foqsz Apr 9, 2026
8e76df4
#
Foqsz Apr 11, 2026
7af0a1c
#
Foqsz Apr 13, 2026
b6f1b0b
Merge branch 'master' into develop
Foqsz Apr 13, 2026
03daf8b
#
Foqsz Apr 14, 2026
68f5577
Merge branch 'develop' of https://github.com/Foqsz/ProductClientHub i…
Foqsz Apr 14, 2026
91cba1d
#
Foqsz Apr 15, 2026
f350e18
Merge branch 'master' into develop
Foqsz Apr 15, 2026
a57d179
#
Foqsz Apr 15, 2026
5359eb5
Merge branch 'develop' of https://github.com/Foqsz/ProductClientHub i…
Foqsz Apr 15, 2026
9c4ad17
#
Foqsz Apr 16, 2026
e08b4a6
Merge branch 'master' into develop
Foqsz Apr 16, 2026
8111877
feat: remove open api
Foqsz Apr 19, 2026
1b9657a
feat: update client integration test.
Foqsz Apr 20, 2026
7e38534
feat: Moq realizado para a integração test
Foqsz Apr 20, 2026
fee32f4
feat: teste para caso ja exista um e-mail na tentativa de update.
Foqsz Apr 20, 2026
ffa46d8
Merge branch 'master' into develop
Foqsz Apr 20, 2026
00cb12a
feat: adicionando logged user ao teste
Foqsz Apr 22, 2026
5c6fe04
feat: agora nao preciso mais do clientid no endpoint, ja recebo via l…
Foqsz Apr 22, 2026
dcb366e
Merge branch 'develop' of https://github.com/Foqsz/ProductClientHub i…
Foqsz Apr 22, 2026
adeeacb
fix: fiz esse ajuste pq mesmo se o usuario tentasse trocar seu e-mail…
Foqsz Apr 24, 2026
68a0b64
feat: teste de integração para o update do usuario. Tudo ok, devidame…
Foqsz Apr 24, 2026
7a77730
Merge branch 'master' into develop
Foqsz Apr 24, 2026
c01147c
#
Foqsz Apr 28, 2026
6cbb6e9
Merge branch 'master' into develop
Foqsz Apr 30, 2026
14ca130
##
Foqsz Apr 30, 2026
915a3e1
Merge branch 'develop' of https://github.com/Foqsz/ProductClientHub i…
Foqsz Apr 30, 2026
9324aa2
Refactor delete repo interface; add use case tests
Foqsz Apr 30, 2026
2258166
Add test utilities and RegisterProduct use case tests
Foqsz May 5, 2026
2b8c597
Refactor product update: rename Upload to Update
Foqsz May 5, 2026
56975d6
feat:testes de integração pra detelect product
Foqsz May 6, 2026
143f282
feat: teste de integração no register product
Foqsz May 6, 2026
15c3a70
feat: testes de integração pro get all
Foqsz May 6, 2026
d05358c
feat:testes de integração update
Foqsz May 6, 2026
4488a36
feat:testes de integração get by id
Foqsz May 6, 2026
fa1310b
feat:cuustom web factory com o teste de integração para os products
Foqsz May 6, 2026
d03de79
feat:testes de unidade
Foqsz May 6, 2026
46a722f
feat: correção no client notfound, pois estava quebrando em dois testes.
Foqsz May 6, 2026
b938197
Resolve merge conflicts
Foqsz May 7, 2026
a93e80a
feat: validator test para register client
Foqsz May 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CommonTestUtilities/CommonTestUtilities.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@
<ProjectReference Include="..\ProductClientHub.Infrastructure\ProductClientHub.Infrastructure.csproj" />
</ItemGroup>

<ItemGroup>
<Folder Include="Validators\Client\" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Moq;
using ProductClientHub.Domain.Repositories.Product;

namespace CommonTestUtilities.Repositories;

public class ProductsWriteOnlyRepositoryBuild
{
public static IProductsWriteOnlyRepository Build()
{
var mock = new Mock<IProductsWriteOnlyRepository>();
return mock.Object;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Moq;
using ProductClientHub.Domain.Repositories.Product;

namespace CommonTestUtilities.Repositories;

public class UpdateProductWriteOnlyRepository
{
public static IUpdateProductOnlyRepository Build()
{
var mock = new Mock<IUpdateProductOnlyRepository>();

return mock.Object;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Moq;
using ProductClientHub.Domain.Repositories.Product;

namespace CommonTestUtilities.Repositories;

public class UpdateProductsWriteOnlyRepositoryBuilder
{
public static IUpdateProductOnlyRepository Build()
{
var mock = new Mock<IUpdateProductOnlyRepository>();
return mock.Object;
}
}
16 changes: 16 additions & 0 deletions CommonTestUtilities/Requests/RequestProductJsonBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using ProductClientHub.Communication.Requests;

namespace CommonTestUtilities.Requests;

public class RequestProductJsonBuilder
{
public static RequestProductJson Build(string Name, string Brand, decimal Price)
{
return new RequestProductJson
{
Name = Name,
Brand = Brand,
Price = Price
};
}
}
2 changes: 1 addition & 1 deletion ProductClientHub.API/Controllers/ProductsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public async Task<IActionResult> Register([FromBody] RequestProductJson request,
[ProducesResponseType(typeof(ResponseErrorMessagesJson), StatusCodes.Status404NotFound)]
public async Task<IActionResult> Update([FromBody] RequestProductJson request,
[FromRoute] Guid productId,
[FromServices] IUploadProductUseCase useCase)
[FromServices] IUpdateProductUseCase useCase)
{
var response = await useCase.Execute(productId, request);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ private static void AddUseCases(IServiceCollection services)
services.AddScoped<IGetAllProductsUseCase, GetAllProductsUseCase>();
services.AddScoped<IGetProductByIdUseCase, GetProductByIdUseCase>();
services.AddScoped<IDeleteProductUseCase, DeleteProductUseCase>();
services.AddScoped<IUploadProductUseCase, UploadProductUseCase>();
services.AddScoped<IUpdateProductUseCase, UpdateProductUseCase>();

//login
services.AddScoped<IDoLoginUseCase, DoLoginUseCase>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace ProductClientHub.Application.UseCases.Products.Update;

public interface IUploadProductUseCase
public interface IUpdateProductUseCase
{
Task<ResponseShortProductJson> Execute(Guid productId, RequestProductJson request);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@

namespace ProductClientHub.Application.UseCases.Products.Update;

public class UploadProductUseCase : IUploadProductUseCase
public class UpdateProductUseCase : IUpdateProductUseCase
{
private readonly IUnitOfWork _unitOfWork;
private readonly IClientReadOnlyRepository _clientReadOnlyRepository;
private readonly IProductsReadOnlyRepository _productsReadOnlyRepository;
private readonly IUploadProductOnlyRepository _productWriteOnlyRepository;
private readonly IUpdateProductOnlyRepository _productWriteOnlyRepository;
private readonly ILoggedClient _loggedClient;

public UploadProductUseCase(IUnitOfWork unitOfWork,
IUploadProductOnlyRepository productWriteOnlyRepository,
public UpdateProductUseCase(IUnitOfWork unitOfWork,
IUpdateProductOnlyRepository productWriteOnlyRepository,
IClientReadOnlyRepository clientReadOnlyRepository,
IProductsReadOnlyRepository productsReadOnlyRepository,
ILoggedClient loggedClient)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace ProductClientHub.Domain.Repositories.Product;

public interface IUploadProductOnlyRepository
public interface IUpdateProductOnlyRepository
{
Task Update(Guid clientId, Guid productId, Domain.Entities.Product product);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace ProductClientHub.Infrastructure.DataAcess.Repositories.Products;

public class ProductsWriteOnlyRepository : IProductsWriteOnlyRepository, IDeleteProductWriteOnlyRepository, IUploadProductOnlyRepository
public class ProductsWriteOnlyRepository : IProductsWriteOnlyRepository, IDeleteProductWriteOnlyRepository, IUpdateProductOnlyRepository
{
private readonly ProductClientHubDbContext _dbContext;

Expand All @@ -32,9 +32,9 @@ public async Task<bool> Delete(Guid clientId, Guid productId)

public async Task Update(Guid clientId, Guid productId, Product product)
{
var productUpload = await _dbContext.Products.Where(p => p.ClientId == clientId && p.Id == productId).FirstOrDefaultAsync();
var productUpdate = await _dbContext.Products.Where(p => p.ClientId == clientId && p.Id == productId).FirstOrDefaultAsync();

if (productUpload is null) return;
if (productUpdate is null) return;

var createdOn = await _dbContext.Products
.Where(x => x.Id == product.Id)
Expand All @@ -43,7 +43,7 @@ public async Task Update(Guid clientId, Guid productId, Product product)

product.CreatedOn = DateTime.SpecifyKind(createdOn, DateTimeKind.Utc);

_dbContext.Products.Update(productUpload);
_dbContext.Products.Update(productUpdate);

_dbContext.Entry(product).Property(x => x.CreatedOn).IsModified = false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
services.AddScoped<IProductsWriteOnlyRepository, ProductsWriteOnlyRepository>();
services.AddScoped<IProductsReadOnlyRepository, ProductsReadOnlyRepository>();
services.AddScoped<IDeleteProductWriteOnlyRepository, ProductsWriteOnlyRepository>();
services.AddScoped<IUploadProductOnlyRepository, ProductsWriteOnlyRepository>();
services.AddScoped<IUpdateProductOnlyRepository, ProductsWriteOnlyRepository>();
}

private static void AddTokens(IServiceCollection services, IConfiguration configuration)
Expand All @@ -75,7 +75,7 @@
services.AddScoped<IAccessTokenGenerator>(option => new JwtTokenGenerator(expirationTimeMinutes, signingKey!));
services.AddScoped<IAccessTokenValidator>(option => new JwtTokenValidator(signingKey!));

//services.AddScoped<IRefreshTokenGenerator, RefreshTokenGenerator>();

Check warning on line 78 in ProductClientHub.Infrastructure/DependencyInjectionExtension.cs

View workflow job for this annotation

GitHub Actions / build

Remove this commented out code.

Check warning on line 78 in ProductClientHub.Infrastructure/DependencyInjectionExtension.cs

View workflow job for this annotation

GitHub Actions / build

Remove this commented out code.
}

private static void AddloggedClient(IServiceCollection services) => services.AddScoped<ILoggedClient, loggedClient>();
Expand Down
60 changes: 60 additions & 0 deletions UseCase.Test/Product/Register/RegisterProductUseCaseTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using CommonTestUtilities.Entities;
using CommonTestUtilities.loggedClient;
using CommonTestUtilities.Repositories;
using CommonTestUtilities.Requests;
using ProductClientHub.Application.UseCases.Products.Register;
using ProductClientHub.Domain.Extensions;
using ProductClientHub.Exceptions.ExceptionsBase;
using Shouldly;

namespace UseCase.Test.Product.Register;

public class RegisterProductUseCaseTest
{
[Fact]
public async Task RegisterProductUseCaseTest_Success()
{
(var client, _) = ClientBuilder.Build();
var product = ProductBuilder.Build(client);

var productJson =RequestProductJsonBuilder.Build(product.Name, product.Brand, product.Price);

var useCase = CreateUseCase(product, client, ClientNull: false);

var result = await useCase.Execute(productJson);

result.ShouldNotBeNull();
result.Name.ShouldBe(product.Name);
result.Brand.ShouldBe(product.Brand);
result.Price.ShouldBe(product.Price);
}

[Fact]
public async Task RegisterProductUseCaseTest_Client_NotFound_Error()
{
(var client, _) = ClientBuilder.Build();
var product = ProductBuilder.Build(client);

var productJson = RequestProductJsonBuilder.Build(product.Name, product.Brand, product.Price);

var useCase = CreateUseCase(product, client, ClientNull: true);

var result = await Should.ThrowAsync<NotFoundException>(async () => await useCase.Execute(productJson));

result.Message.ShouldBe(ResourceMessagesExceptions.CLIENT_NOCONTENT);
result.GetHttpStatusCode().ShouldBe(System.Net.HttpStatusCode.NotFound);
}

private static RegisterProductUseCase CreateUseCase(ProductClientHub.Domain.Entities.Product product, ProductClientHub.Domain.Entities.Client client, bool ClientNull)
{
var productsWriteOnly = ProductsWriteOnlyRepositoryBuild.Build();
var clientReadOnly = new ClientReadOnlyRepositoryBuilder();
var unitOfWork = UnitOfWorkBuilder.Build();
var loggedClient = LoggedClientBuilder.Build(client);

if(ClientNull.IsFalse())
clientReadOnly.GetById(client);

return new RegisterProductUseCase(productsWriteOnly, unitOfWork, clientReadOnly.Build(), loggedClient);
}
}
97 changes: 97 additions & 0 deletions UseCase.Test/Product/Update/UpdateProductsUseCaseTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
using CommonTestUtilities.Entities;
using CommonTestUtilities.loggedClient;
using CommonTestUtilities.Repositories;
using CommonTestUtilities.Requests;
using ProductClientHub.Application.UseCases.Products.Update;
using ProductClientHub.Domain.Extensions;
using ProductClientHub.Exceptions.ExceptionsBase;
using Shouldly;

namespace UseCase.Test.Product.Update;

public class UpdateProductsUseCaseTest
{
[Fact]
public async Task UpdateProductUseCaseTest_Success()
{
(var client, _) = ClientBuilder.Build();

var product = ProductBuilder.Build(client);

var productUpdate = RequestProductJsonBuilder.Build(
Name: "New Name",
Brand: "New Brand",
Price: 100);

var useCase = CreateUseCase(product, client, clientNull: false, productNull: false);

var result = await useCase.Execute(product.Id, productUpdate);

result.ShouldNotBeNull();
result.Brand.ShouldBe(product.Brand);
result.Name.ShouldBe(product.Name);
result.Price.ShouldBe(product.Price);
}

[Fact]
public async Task UpdateProductUseCaseTest_Client_NotFound()
{
(var client, _) = ClientBuilder.Build();

var product = ProductBuilder.Build(client);

var productUpdate = RequestProductJsonBuilder.Build(
Name: "New Name",
Brand: "New Brand",
Price: 100);

var useCase = CreateUseCase(product, client, clientNull: true, productNull: false);

var exception = await Should.ThrowAsync<NotFoundException>(() => useCase.Execute(product.Id, productUpdate));

exception.Message.ShouldBe(ResourceMessagesExceptions.CLIENT_NOCONTENT);
exception.GetHttpStatusCode().ShouldBe(System.Net.HttpStatusCode.NotFound);
}

[Fact]
public async Task UpdateProductUseCaseTest_Product_NotFound()
{
(var client, _) = ClientBuilder.Build();

var product = ProductBuilder.Build(client);

var productUpdate = RequestProductJsonBuilder.Build(
Name: "New Name",
Brand: "New Brand",
Price: 100);

var useCase = CreateUseCase(product, client, clientNull: false, productNull: true);

var exception = await Should.ThrowAsync<NotFoundException>(() => useCase.Execute(product.Id, productUpdate));

exception.Message.ShouldBe(ResourceMessagesExceptions.PRODUCT_NOTFOUND);
exception.GetHttpStatusCode().ShouldBe(System.Net.HttpStatusCode.NotFound);
}

private static UpdateProductUseCase CreateUseCase(ProductClientHub.Domain.Entities.Product product, ProductClientHub.Domain.Entities.Client client, bool clientNull, bool productNull)
{
var unitOfWork = UnitOfWorkBuilder.Build();
var clientReadOnlyRepository = new ClientReadOnlyRepositoryBuilder();
var productUpdateWriteOnlyRepository = UpdateProductsWriteOnlyRepositoryBuilder.Build();
var productReadOnlyRepository = new ProductsReadOnlyRepositoryBuild();
var loggedClient = LoggedClientBuilder.Build(client);

if (clientNull.IsFalse())
{
clientReadOnlyRepository.GetById(client);
}

if (productNull.IsFalse())
{
productReadOnlyRepository.GetById(product);
}


return new UpdateProductUseCase(unitOfWork, productUpdateWriteOnlyRepository, clientReadOnlyRepository.Build(), productReadOnlyRepository.Build(), loggedClient);
}
}
68 changes: 68 additions & 0 deletions Validators.Test/Client/RegisterClientValidatorTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using CommonTestUtilities.Requests;
using ProductClientHub.Application.UseCases.Users.SharedValidator;
using ProductClientHub.Communication.Requests;
using Shouldly;

namespace Validators.Test.Client;

public class RegisterClientValidatorTest
{
[Fact]
public void Success()
{
var validate = new RequestClientValidator();

var request = RequestClientJsonBuilder.Build("John Carlos", "john@gmail.com", "123456a");

var result = validate.Validate(request);

result.IsValid.ShouldBeTrue();
}

[Fact]
public void Error_Email_Empty()
{
var validate = new RequestClientValidator();

var request = RequestClientJsonBuilder.Build("John Carlos", "", "123456a");

var result = validate.Validate(request);

result.IsValid.ShouldBeFalse();
}

[Fact]
public void Error_Email_Invalid()
{
var validate = new RequestClientValidator();

var request = RequestClientJsonBuilder.Build("John Carlos", "john", "123456a");

var result = validate.Validate(request);

result.IsValid.ShouldBeFalse();
}

[Fact]
public void Error_Password_Empty()
{
var validate = new RequestClientValidator();

var request = RequestClientJsonBuilder.Build("John Carlos", "john@gmail.com", "");

var result = validate.Validate(request);

result.IsValid.ShouldBeFalse();
}

[Fact]
public void Error_Password_Short()
{
var validate = new RequestClientValidator();
var request = RequestClientJsonBuilder.Build("John Carlos", "john@gmail.com", "123");

var result = validate.Validate(request);

result.IsValid.ShouldBeFalse();
}
}
Loading
Loading