From d10524c53b0117e6858bc7a9a88cfe43935e04c3 Mon Sep 17 00:00:00 2001 From: Italo Pessoa Date: Sat, 16 Nov 2024 10:41:54 -0300 Subject: [PATCH 1/2] test: add gherkin unit tests #173 --- ...lenge.ByteMeBurger.Application.Test.csproj | 6 ++ .../Orders/Gherkin/CreateOrder.feature | 8 ++ .../Orders/Gherkin/CreateOrderSteps.cs | 73 +++++++++++++++++++ ...hChallenge.ByteMeBurger.Test.Common.csproj | 1 + 4 files changed, 88 insertions(+) create mode 100644 tests/FIAP.TechChallenge.ByteMeBurger.Application.Test/UseCases/Orders/Gherkin/CreateOrder.feature create mode 100644 tests/FIAP.TechChallenge.ByteMeBurger.Application.Test/UseCases/Orders/Gherkin/CreateOrderSteps.cs diff --git a/tests/FIAP.TechChallenge.ByteMeBurger.Application.Test/FIAP.TechChallenge.ByteMeBurger.Application.Test.csproj b/tests/FIAP.TechChallenge.ByteMeBurger.Application.Test/FIAP.TechChallenge.ByteMeBurger.Application.Test.csproj index 8e4b82f..261d30d 100644 --- a/tests/FIAP.TechChallenge.ByteMeBurger.Application.Test/FIAP.TechChallenge.ByteMeBurger.Application.Test.csproj +++ b/tests/FIAP.TechChallenge.ByteMeBurger.Application.Test/FIAP.TechChallenge.ByteMeBurger.Application.Test.csproj @@ -29,4 +29,10 @@ + + + Always + + + diff --git a/tests/FIAP.TechChallenge.ByteMeBurger.Application.Test/UseCases/Orders/Gherkin/CreateOrder.feature b/tests/FIAP.TechChallenge.ByteMeBurger.Application.Test/UseCases/Orders/Gherkin/CreateOrder.feature new file mode 100644 index 0000000..9ba190d --- /dev/null +++ b/tests/FIAP.TechChallenge.ByteMeBurger.Application.Test/UseCases/Orders/Gherkin/CreateOrder.feature @@ -0,0 +1,8 @@ +Feature: Create new order + + Scenario: Create a new order successfully + Given Selected product exists + And Tracking code is created + When UseCase is called + Then it should create the order + And it should publish integration event diff --git a/tests/FIAP.TechChallenge.ByteMeBurger.Application.Test/UseCases/Orders/Gherkin/CreateOrderSteps.cs b/tests/FIAP.TechChallenge.ByteMeBurger.Application.Test/UseCases/Orders/Gherkin/CreateOrderSteps.cs new file mode 100644 index 0000000..dc11b21 --- /dev/null +++ b/tests/FIAP.TechChallenge.ByteMeBurger.Application.Test/UseCases/Orders/Gherkin/CreateOrderSteps.cs @@ -0,0 +1,73 @@ +using Bmb.Domain.Core.Events; +using Bmb.Domain.Core.Interfaces; +using FIAP.TechChallenge.ByteMeBurger.Application.UseCases.Orders; +using Xunit.Gherkin.Quick; +using OrderCreated = Bmb.Domain.Core.Events.Integration.OrderCreated; + +namespace FIAP.TechChallenge.ByteMeBurger.Application.Test.UseCases.Orders.Gherkin; + +[FeatureFile("./UseCases/Orders/Gherkin/CreateOrder.feature")] +public class CreateOrderSteps : Feature +{ +// Given Selected product exists +// And Tracking code is created +// When UseCase is called +// Then it should create the order + private readonly CreateOrderUseCase _useCase; + private readonly Mock _mockProductRepository; + private readonly Mock _mockOrderTrackingCodeService; + private readonly Mock _mockDispatcher; + private Order _order; + private Product _product; + + public CreateOrderSteps() + { + _mockDispatcher = new Mock(); + _mockProductRepository = new Mock(); + _mockOrderTrackingCodeService = new Mock(); + + _useCase = new CreateOrderUseCase(_mockProductRepository.Object, _mockOrderTrackingCodeService.Object, + _mockDispatcher.Object); + } + + [Given("Selected product exists")] + public void SetupExistingProduct() + { + _product = new Product(Guid.NewGuid(), "product", "description", ProductCategory.Drink, 10, []); + _mockProductRepository.Setup(p => p.FindByIdAsync(_product.Id)) + .ReturnsAsync(_product) + .Verifiable(); + } + + [And("Tracking code is created")] + public void SetupTrackingCode() + { + _mockOrderTrackingCodeService.Setup(s => s.GetNextAsync()) + .ReturnsAsync(new OrderTrackingCode("code")) + .Verifiable(); + } + + [When("UseCase is called")] + public async Task WhenUseCaseIsCalled() + { + _order = await _useCase.Execute(null, new List + { + new(_product.Id, 1) + }); + } + + [Then("it should create the order")] + public void ThenItShouldCreateTheOrder() + { + _order.Should().NotBeNull(); + _order.TrackingCode.Should().Be(new OrderTrackingCode("code")); + _order.OrderItems[0].ProductId.Should().Be(_product.Id); + _mockProductRepository.VerifyAll(); + } + + [And("it should publish integration event")] + public void ThenItShouldPublishTheEvent() + { + _mockDispatcher.Verify(d => d.PublishIntegrationAsync(It.IsAny(), default), Times.Once); + } +} diff --git a/tests/FIAP.TechChallenge.ByteMeBurger.Test.Common/FIAP.TechChallenge.ByteMeBurger.Test.Common.csproj b/tests/FIAP.TechChallenge.ByteMeBurger.Test.Common/FIAP.TechChallenge.ByteMeBurger.Test.Common.csproj index 034172b..668e41d 100644 --- a/tests/FIAP.TechChallenge.ByteMeBurger.Test.Common/FIAP.TechChallenge.ByteMeBurger.Test.Common.csproj +++ b/tests/FIAP.TechChallenge.ByteMeBurger.Test.Common/FIAP.TechChallenge.ByteMeBurger.Test.Common.csproj @@ -15,6 +15,7 @@ + From d02faec579699f30bca622553b07598fe74cd4d0 Mon Sep 17 00:00:00 2001 From: Italo Pessoa Date: Sat, 16 Nov 2024 11:26:27 -0300 Subject: [PATCH 2/2] fix: use bmb.auth package --- .../Auth/AccessTokenAuthEventsHandler.cs | 30 ---------------- .../Auth/BmbRoles.cs | 8 ----- .../Auth/JwtExtensions.cs | 36 ------------------- .../Auth/JwtOptions.cs | 20 ----------- .../Controllers/CustomersController.cs | 2 +- .../Controllers/OrdersController.cs | 3 +- .../Controllers/ProductsController.cs | 2 +- ...FIAP.TechChallenge.ByteMeBurger.Api.csproj | 2 +- .../Program.cs | 2 +- tf/variables.tf | 17 ++++----- 10 files changed, 15 insertions(+), 107 deletions(-) delete mode 100644 src/FIAP.TechChallenge.ByteMeBurger.Api/Auth/AccessTokenAuthEventsHandler.cs delete mode 100644 src/FIAP.TechChallenge.ByteMeBurger.Api/Auth/BmbRoles.cs delete mode 100644 src/FIAP.TechChallenge.ByteMeBurger.Api/Auth/JwtOptions.cs diff --git a/src/FIAP.TechChallenge.ByteMeBurger.Api/Auth/AccessTokenAuthEventsHandler.cs b/src/FIAP.TechChallenge.ByteMeBurger.Api/Auth/AccessTokenAuthEventsHandler.cs deleted file mode 100644 index 09f5262..0000000 --- a/src/FIAP.TechChallenge.ByteMeBurger.Api/Auth/AccessTokenAuthEventsHandler.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Microsoft.AspNetCore.Authentication.JwtBearer; - -namespace FIAP.TechChallenge.ByteMeBurger.Api.Auth; - -/// -/// Singleton class handler of events related to JWT authentication -/// -internal class AccessTokenAuthEventsHandler : JwtBearerEvents -{ - private const string BearerPrefix = "Bearer "; - - private AccessTokenAuthEventsHandler() => OnMessageReceived = MessageReceivedHandler; - - /// - /// Gets single available instance of - /// - public static AccessTokenAuthEventsHandler Instance { get; } = new AccessTokenAuthEventsHandler(); - - private Task MessageReceivedHandler(MessageReceivedContext context) - { - if (context.Request.Headers.TryGetValue("AccessToken", out var headerValue) && - !string.IsNullOrWhiteSpace(headerValue)) - { - var accessToken = headerValue.ToString(); - context.Token = accessToken.StartsWith(BearerPrefix) ? accessToken[BearerPrefix.Length..] : accessToken; - } - - return Task.CompletedTask; - } -} diff --git a/src/FIAP.TechChallenge.ByteMeBurger.Api/Auth/BmbRoles.cs b/src/FIAP.TechChallenge.ByteMeBurger.Api/Auth/BmbRoles.cs deleted file mode 100644 index b26e8c0..0000000 --- a/src/FIAP.TechChallenge.ByteMeBurger.Api/Auth/BmbRoles.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace FIAP.TechChallenge.ByteMeBurger.Api.Auth; - -public static class BmbRoles -{ - public const string Admin = "admin"; - public const string Kitchen = "kitchen"; - public const string Customer = "customer"; -} diff --git a/src/FIAP.TechChallenge.ByteMeBurger.Api/Auth/JwtExtensions.cs b/src/FIAP.TechChallenge.ByteMeBurger.Api/Auth/JwtExtensions.cs index 2ef88de..dad5f71 100644 --- a/src/FIAP.TechChallenge.ByteMeBurger.Api/Auth/JwtExtensions.cs +++ b/src/FIAP.TechChallenge.ByteMeBurger.Api/Auth/JwtExtensions.cs @@ -1,8 +1,5 @@ using System.Security.Claims; -using System.Text; using FIAP.TechChallenge.ByteMeBurger.Controllers.Dto; -using Microsoft.IdentityModel.Tokens; - namespace FIAP.TechChallenge.ByteMeBurger.Api.Auth; /// @@ -10,39 +7,6 @@ namespace FIAP.TechChallenge.ByteMeBurger.Api.Auth; /// public static class JwtExtensions { - /// - /// Configure Jtw token validation - /// - /// Service collection - /// Configuration - public static void ConfigureJwt(this IServiceCollection services, IConfiguration configuration) - { - var jwtOptions = configuration - .GetSection("JwtOptions") - .Get(); - - services.AddAuthentication() - .AddJwtBearer(options => - { - if (jwtOptions.UseAccessToken) - { - options.Events = AccessTokenAuthEventsHandler.Instance; - } - - options.TokenValidationParameters = new TokenValidationParameters - { - ValidIssuer = jwtOptions.Issuer, - ValidAudience = jwtOptions.Audience, - ValidateAudience = true, - ValidateIssuer = true, - ValidateLifetime = true, - LogValidationExceptions = true, - IssuerSigningKey = - new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SigningKey)) - }; - }); - } - // https://stackoverflow.com/a/55740879/2921329 /// /// Get customer details from Jwt Claims diff --git a/src/FIAP.TechChallenge.ByteMeBurger.Api/Auth/JwtOptions.cs b/src/FIAP.TechChallenge.ByteMeBurger.Api/Auth/JwtOptions.cs deleted file mode 100644 index 41e22fd..0000000 --- a/src/FIAP.TechChallenge.ByteMeBurger.Api/Auth/JwtOptions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Diagnostics.CodeAnalysis; - -namespace FIAP.TechChallenge.ByteMeBurger.Api.Auth; - -/// -/// JWT token config -/// -/// Issuer -/// Audience -/// Signing key secret -/// Expiration in seconds -/// Flag to use AccessCode header instead of normal Authorization header. -[ExcludeFromCodeCoverage] -public record JwtOptions( - string Issuer, - string Audience, - string SigningKey, - int ExpirationSeconds, - bool UseAccessToken -); diff --git a/src/FIAP.TechChallenge.ByteMeBurger.Api/Controllers/CustomersController.cs b/src/FIAP.TechChallenge.ByteMeBurger.Api/Controllers/CustomersController.cs index 57b0a04..5a2cb3a 100644 --- a/src/FIAP.TechChallenge.ByteMeBurger.Api/Controllers/CustomersController.cs +++ b/src/FIAP.TechChallenge.ByteMeBurger.Api/Controllers/CustomersController.cs @@ -1,5 +1,5 @@ using System.ComponentModel.DataAnnotations; -using FIAP.TechChallenge.ByteMeBurger.Api.Auth; +using Bmb.Auth; using FIAP.TechChallenge.ByteMeBurger.Api.Model.Customers; using FIAP.TechChallenge.ByteMeBurger.Controllers.Contracts; using FIAP.TechChallenge.ByteMeBurger.Controllers.Dto; diff --git a/src/FIAP.TechChallenge.ByteMeBurger.Api/Controllers/OrdersController.cs b/src/FIAP.TechChallenge.ByteMeBurger.Api/Controllers/OrdersController.cs index 791dfb3..03313a5 100644 --- a/src/FIAP.TechChallenge.ByteMeBurger.Api/Controllers/OrdersController.cs +++ b/src/FIAP.TechChallenge.ByteMeBurger.Api/Controllers/OrdersController.cs @@ -1,9 +1,10 @@ using System.Collections.ObjectModel; -using FIAP.TechChallenge.ByteMeBurger.Api.Auth; +using Bmb.Auth; using FIAP.TechChallenge.ByteMeBurger.Api.Model.Orders; using FIAP.TechChallenge.ByteMeBurger.Controllers.Contracts; using FIAP.TechChallenge.ByteMeBurger.Controllers.Dto; using Bmb.Domain.Core.ValueObjects; +using FIAP.TechChallenge.ByteMeBurger.Api.Auth; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Hybrid; diff --git a/src/FIAP.TechChallenge.ByteMeBurger.Api/Controllers/ProductsController.cs b/src/FIAP.TechChallenge.ByteMeBurger.Api/Controllers/ProductsController.cs index 6c0cd16..03df65a 100644 --- a/src/FIAP.TechChallenge.ByteMeBurger.Api/Controllers/ProductsController.cs +++ b/src/FIAP.TechChallenge.ByteMeBurger.Api/Controllers/ProductsController.cs @@ -1,4 +1,4 @@ -using FIAP.TechChallenge.ByteMeBurger.Api.Auth; +using Bmb.Auth; using FIAP.TechChallenge.ByteMeBurger.Api.Model.Products; using FIAP.TechChallenge.ByteMeBurger.Controllers.Contracts; using FIAP.TechChallenge.ByteMeBurger.Controllers.Dto; diff --git a/src/FIAP.TechChallenge.ByteMeBurger.Api/FIAP.TechChallenge.ByteMeBurger.Api.csproj b/src/FIAP.TechChallenge.ByteMeBurger.Api/FIAP.TechChallenge.ByteMeBurger.Api.csproj index 5708290..583aa86 100644 --- a/src/FIAP.TechChallenge.ByteMeBurger.Api/FIAP.TechChallenge.ByteMeBurger.Api.csproj +++ b/src/FIAP.TechChallenge.ByteMeBurger.Api/FIAP.TechChallenge.ByteMeBurger.Api.csproj @@ -18,8 +18,8 @@ + - diff --git a/src/FIAP.TechChallenge.ByteMeBurger.Api/Program.cs b/src/FIAP.TechChallenge.ByteMeBurger.Api/Program.cs index 32ae9f9..28f2604 100644 --- a/src/FIAP.TechChallenge.ByteMeBurger.Api/Program.cs +++ b/src/FIAP.TechChallenge.ByteMeBurger.Api/Program.cs @@ -1,7 +1,7 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text.Json.Serialization; -using FIAP.TechChallenge.ByteMeBurger.Api.Auth; +using Bmb.Auth; using FIAP.TechChallenge.ByteMeBurger.DI; using HealthChecks.UI.Client; using Microsoft.AspNetCore.Diagnostics.HealthChecks; diff --git a/tf/variables.tf b/tf/variables.tf index c323b95..2f8880b 100644 --- a/tf/variables.tf +++ b/tf/variables.tf @@ -1,6 +1,6 @@ variable "rds_cluster_identifier" { type = string - default = "techchallenge-mysql-default" + default = "gh-techchallenge-mysql" } variable "profile" { @@ -17,7 +17,7 @@ variable "region" { variable "eks_cluster_name" { type = string - default = "quixada" + default = "eks_dev_quixada" } variable "apgw_name" { @@ -28,6 +28,7 @@ variable "apgw_name" { variable "jwt_signing_key" { type = string sensitive = true + default = "" } variable "jwt_issuer" { @@ -44,7 +45,7 @@ variable "jwt_aud" { variable "api_docker_image" { type = string - default = "ghcr.io/soat-fiap/fiap.techchallenge.bytemeburger/api:sha-b83177c" + default = "ghcr.io/soat-fiap/fiap.techchallenge.bytemeburger/api:latest" } variable "internal_elb_name" { @@ -55,28 +56,28 @@ variable "internal_elb_name" { variable "db_user" { type = string sensitive = true - default = "db_user" + default = "test" } - variable "db_pwd" { type = string sensitive = true - default = "db_password" + default = "test" } variable "api_access_key_id" { type = string nullable = false sensitive = true + default = "" } variable "api_secret_access_key" { type = string nullable = false sensitive = true + default = "" } - variable "user_pool_name" { type = string - default = "bmb-users-pool-local" + default = "bmb-users-pool-dev" }