feat: Add functional tests for OrderService and update InventoryService command and idempotency logic.

This commit is contained in:
Ho Ngoc Hai
2026-01-18 00:19:46 +07:00
parent 844e40f818
commit 811ddd1e19
384 changed files with 6939 additions and 2793 deletions

View File

@@ -1,72 +0,0 @@
version: '3.8'
# EN: Docker Compose for local development
# VI: Docker Compose cho phát triển local
services:
myservice-api:
build:
context: .
dockerfile: Dockerfile
container_name: myservice-api
ports:
- "5000:8080"
environment:
- ASPNETCORE_ENVIRONMENT=Development
- DATABASE_URL=Host=postgres;Port=5432;Database=myservice_db;Username=postgres;Password=postgres
- REDIS_URL=redis:6379
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- myservice-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health/live"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
postgres:
image: postgres:16-alpine
container_name: myservice-postgres
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: myservice_db
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- myservice-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
container_name: myservice-redis
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- myservice-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
volumes:
postgres_data:
redis_data:
networks:
myservice-network:
driver: bridge

View File

@@ -1,7 +1,7 @@
using System.Diagnostics;
using MediatR;
namespace MyService.API.Application.Behaviors;
namespace FnbEngine.API.Application.Behaviors;
/// <summary>
/// EN: MediatR behavior for logging request handling.

View File

@@ -1,8 +1,8 @@
using MediatR;
using Microsoft.EntityFrameworkCore;
using MyService.Infrastructure;
using FnbEngine.Infrastructure;
namespace MyService.API.Application.Behaviors;
namespace FnbEngine.API.Application.Behaviors;
/// <summary>
/// EN: MediatR behavior for handling database transactions.
@@ -13,11 +13,11 @@ namespace MyService.API.Application.Behaviors;
public class TransactionBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly MyServiceContext _dbContext;
private readonly FnbEngineContext _dbContext;
private readonly ILogger<TransactionBehavior<TRequest, TResponse>> _logger;
public TransactionBehavior(
MyServiceContext dbContext,
FnbEngineContext dbContext,
ILogger<TransactionBehavior<TRequest, TResponse>> logger)
{
_dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));

View File

@@ -1,7 +1,7 @@
using FluentValidation;
using MediatR;
namespace MyService.API.Application.Behaviors;
namespace FnbEngine.API.Application.Behaviors;
/// <summary>
/// EN: MediatR behavior for FluentValidation integration.

View File

@@ -1,6 +1,6 @@
using MediatR;
namespace MyService.API.Application.Commands;
namespace FnbEngine.API.Application.Commands;
/// <summary>
/// EN: Command to change status of a Sample.

View File

@@ -1,7 +1,7 @@
using MediatR;
using MyService.Domain.AggregatesModel.SampleAggregate;
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
namespace MyService.API.Application.Commands;
namespace FnbEngine.API.Application.Commands;
/// <summary>
/// EN: Handler for ChangeSampleStatusCommand.

View File

@@ -1,6 +1,6 @@
using MediatR;
namespace MyService.API.Application.Commands;
namespace FnbEngine.API.Application.Commands;
/// <summary>
/// EN: Command to create a new Sample.

View File

@@ -1,7 +1,7 @@
using MediatR;
using MyService.Domain.AggregatesModel.SampleAggregate;
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
namespace MyService.API.Application.Commands;
namespace FnbEngine.API.Application.Commands;
/// <summary>
/// EN: Handler for CreateSampleCommand.

View File

@@ -1,6 +1,6 @@
using MediatR;
namespace MyService.API.Application.Commands;
namespace FnbEngine.API.Application.Commands;
/// <summary>
/// EN: Command to delete a Sample.

View File

@@ -1,7 +1,7 @@
using MediatR;
using MyService.Domain.AggregatesModel.SampleAggregate;
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
namespace MyService.API.Application.Commands;
namespace FnbEngine.API.Application.Commands;
/// <summary>
/// EN: Handler for DeleteSampleCommand.

View File

@@ -1,6 +1,6 @@
using MediatR;
namespace MyService.API.Application.Commands;
namespace FnbEngine.API.Application.Commands;
/// <summary>
/// EN: Command to update an existing Sample.

View File

@@ -1,7 +1,7 @@
using MediatR;
using MyService.Domain.AggregatesModel.SampleAggregate;
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
namespace MyService.API.Application.Commands;
namespace FnbEngine.API.Application.Commands;
/// <summary>
/// EN: Handler for UpdateSampleCommand.

View File

@@ -1,6 +1,6 @@
using MediatR;
namespace MyService.API.Application.Queries;
namespace FnbEngine.API.Application.Queries;
/// <summary>
/// EN: Query to get a Sample by ID.

View File

@@ -1,7 +1,7 @@
using MediatR;
using MyService.Domain.AggregatesModel.SampleAggregate;
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
namespace MyService.API.Application.Queries;
namespace FnbEngine.API.Application.Queries;
/// <summary>
/// EN: Handler for GetSampleQuery.

View File

@@ -1,6 +1,6 @@
using MediatR;
namespace MyService.API.Application.Queries;
namespace FnbEngine.API.Application.Queries;
/// <summary>
/// EN: Query to get all Samples.

View File

@@ -1,7 +1,7 @@
using MediatR;
using MyService.Domain.AggregatesModel.SampleAggregate;
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
namespace MyService.API.Application.Queries;
namespace FnbEngine.API.Application.Queries;
/// <summary>
/// EN: Handler for GetSamplesQuery.

View File

@@ -1,7 +1,7 @@
using FluentValidation;
using MyService.API.Application.Commands;
using FnbEngine.API.Application.Commands;
namespace MyService.API.Application.Validations;
namespace FnbEngine.API.Application.Validations;
/// <summary>
/// EN: Validator for CreateSampleCommand.

View File

@@ -1,7 +1,7 @@
using FluentValidation;
using MyService.API.Application.Commands;
using FnbEngine.API.Application.Commands;
namespace MyService.API.Application.Validations;
namespace FnbEngine.API.Application.Validations;
/// <summary>
/// EN: Validator for UpdateSampleCommand.

View File

@@ -1,10 +1,10 @@
using Asp.Versioning;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using MyService.API.Application.Commands;
using MyService.API.Application.Queries;
using FnbEngine.API.Application.Commands;
using FnbEngine.API.Application.Queries;
namespace MyService.API.Controllers;
namespace FnbEngine.API.Controllers;
/// <summary>
/// EN: Controller for Sample CRUD operations using CQRS pattern.

View File

@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<AssemblyName>MyService.API</AssemblyName>
<RootNamespace>MyService.API</RootNamespace>
<AssemblyName>FnbEngine.API</AssemblyName>
<RootNamespace>FnbEngine.API</RootNamespace>
<Description>Web API layer with CQRS pattern</Description>
<UserSecretsId>myservice-api</UserSecretsId>
</PropertyGroup>
@@ -36,8 +36,8 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MyService.Domain\MyService.Domain.csproj" />
<ProjectReference Include="..\MyService.Infrastructure\MyService.Infrastructure.csproj" />
<ProjectReference Include="..\FnbEngine.Domain\FnbEngine.Domain.csproj" />
<ProjectReference Include="..\FnbEngine.Infrastructure\FnbEngine.Infrastructure.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,8 +1,8 @@
using Asp.Versioning;
using FluentValidation;
using Hellang.Middleware.ProblemDetails;
using MyService.API.Application.Behaviors;
using MyService.Infrastructure;
using FnbEngine.API.Application.Behaviors;
using FnbEngine.Infrastructure;
using Serilog;
// EN: Configure Serilog early / VI: Cấu hình Serilog sớm
@@ -12,7 +12,7 @@ Log.Logger = new LoggerConfiguration()
try
{
Log.Information("Starting MyService API / Khởi động MyService API");
Log.Information("Starting FnbEngine API / Khởi động FnbEngine API");
var builder = WebApplication.CreateBuilder(args);
@@ -70,9 +70,9 @@ try
{
options.SwaggerDoc("v1", new()
{
Title = "MyService API",
Title = "FnbEngine API",
Version = "v1",
Description = "MyService microservice API / API microservice MyService"
Description = "FnbEngine microservice API / API microservice FnbEngine"
});
});
@@ -107,7 +107,7 @@ try
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyService API v1");
c.SwaggerEndpoint("/swagger/v1/swagger.json", "FnbEngine API v1");
c.RoutePrefix = "swagger";
});
}

View File

@@ -0,0 +1,63 @@
// EN: Kitchen ticket entity for kitchen display.
// VI: Entity KitchenTicket cho hiển thị bếp.
using FnbEngine.Domain.SeedWork;
namespace FnbEngine.Domain.AggregatesModel.KitchenAggregate;
/// <summary>
/// EN: Kitchen ticket entity - represents an order item in the kitchen.
/// VI: Entity KitchenTicket - đại diện cho item đơn hàng trong bếp.
/// </summary>
public class KitchenTicket : Entity, IAggregateRoot
{
private Guid _sessionId;
private Guid _orderItemId;
private string _itemName = null!;
private string? _station; // Bar, Kitchen, Grill, etc.
private int _priority;
private string _status = null!; // Pending, InProgress, Ready, Served
private DateTime _createdAt;
private DateTime? _completedAt;
public Guid SessionId => _sessionId;
public Guid OrderItemId => _orderItemId;
public string ItemName => _itemName;
public string? Station => _station;
public int Priority => _priority;
public string Status => _status;
public DateTime CreatedAt => _createdAt;
public DateTime? CompletedAt => _completedAt;
protected KitchenTicket()
{
}
public KitchenTicket(Guid sessionId, Guid orderItemId, string itemName, string? station = null, int priority = 0)
{
Id = Guid.NewGuid();
_sessionId = sessionId;
_orderItemId = orderItemId;
_itemName = itemName;
_station = station;
_priority = priority;
_status = "Pending";
_createdAt = DateTime.UtcNow;
}
public void MarkAsInProgress()
{
_status = "InProgress";
}
public void MarkAsReady()
{
_status = "Ready";
_completedAt = DateTime.UtcNow;
}
public void MarkAsServed()
{
_status = "Served";
}
}

View File

@@ -1,6 +1,6 @@
using MyService.Domain.SeedWork;
using FnbEngine.Domain.SeedWork;
namespace MyService.Domain.AggregatesModel.SampleAggregate;
namespace FnbEngine.Domain.AggregatesModel.SampleAggregate;
/// <summary>
/// EN: Repository interface for Sample aggregate.

View File

@@ -1,8 +1,8 @@
using MyService.Domain.Events;
using MyService.Domain.Exceptions;
using MyService.Domain.SeedWork;
using FnbEngine.Domain.Events;
using FnbEngine.Domain.Exceptions;
using FnbEngine.Domain.SeedWork;
namespace MyService.Domain.AggregatesModel.SampleAggregate;
namespace FnbEngine.Domain.AggregatesModel.SampleAggregate;
/// <summary>
/// EN: Sample aggregate root demonstrating DDD patterns.

View File

@@ -1,6 +1,6 @@
using MyService.Domain.SeedWork;
using FnbEngine.Domain.SeedWork;
namespace MyService.Domain.AggregatesModel.SampleAggregate;
namespace FnbEngine.Domain.AggregatesModel.SampleAggregate;
/// <summary>
/// EN: Sample status enumeration following type-safe enum pattern.

View File

@@ -0,0 +1,58 @@
// EN: Session entity for dining sessions.
// VI: Entity Session cho phiên ăn uống.
using FnbEngine.Domain.Exceptions;
using FnbEngine.Domain.SeedWork;
namespace FnbEngine.Domain.AggregatesModel.SessionAggregate;
/// <summary>
/// EN: Session entity - represents a dining session at a table.
/// VI: Entity Session - đại diện cho phiên ăn tại bàn.
/// </summary>
public class Session : Entity, IAggregateRoot
{
private Guid _tableId;
private Guid _shopId;
private int _guestCount;
private DateTime _startedAt;
private DateTime? _closedAt;
private string _status = null!; // Active, Closed
public Guid TableId => _tableId;
public Guid ShopId => _shopId;
public int GuestCount => _guestCount;
public DateTime StartedAt => _startedAt;
public DateTime? ClosedAt => _closedAt;
public string Status => _status;
protected Session()
{
}
public Session(Guid tableId, Guid shopId, int guestCount = 1)
{
if (tableId == Guid.Empty)
throw new DomainException("Table ID cannot be empty");
if (shopId == Guid.Empty)
throw new DomainException("Shop ID cannot be empty");
if (guestCount <= 0)
throw new DomainException("Guest count must be greater than zero");
Id = Guid.NewGuid();
_tableId = tableId;
_shopId = shopId;
_guestCount = guestCount;
_startedAt = DateTime.UtcNow;
_status = "Active";
}
public void Close()
{
if (_status == "Closed")
throw new DomainException("Session is already closed");
_closedAt = DateTime.UtcNow;
_status = "Closed";
}
}

View File

@@ -0,0 +1,78 @@
// EN: Table aggregate root for FnB.
// VI: Aggregate root Table cho FnB.
using FnbEngine.Domain.Exceptions;
using FnbEngine.Domain.SeedWork;
namespace FnbEngine.Domain.AggregatesModel.TableAggregate;
/// <summary>
/// EN: Table aggregate root - represents a dining table.
/// VI: Aggregate root Table - đại diện cho bàn ăn.
/// </summary>
public class Table : Entity, IAggregateRoot
{
private Guid _shopId;
private string _tableNumber = null!;
private int _capacity;
private string? _zone;
private TableStatus _status = null!;
private DateTime _createdAt;
private DateTime? _updatedAt;
public Guid ShopId => _shopId;
public string TableNumber => _tableNumber;
public int Capacity => _capacity;
public string? Zone => _zone;
public TableStatus Status => _status;
public int StatusId { get; private set; }
public DateTime CreatedAt => _createdAt;
public DateTime? UpdatedAt => _updatedAt;
protected Table()
{
}
public Table(Guid shopId, string tableNumber, int capacity, string? zone = null)
{
if (shopId == Guid.Empty)
throw new DomainException("Shop ID cannot be empty");
if (string.IsNullOrWhiteSpace(tableNumber))
throw new DomainException("Table number cannot be empty");
if (capacity <= 0)
throw new DomainException("Capacity must be greater than zero");
Id = Guid.NewGuid();
_shopId = shopId;
_tableNumber = tableNumber.Trim();
_capacity = capacity;
_zone = zone?.Trim();
_status = TableStatus.Available;
StatusId = TableStatus.Available.Id;
_createdAt = DateTime.UtcNow;
}
public void MarkAsOccupied()
{
if (_status != TableStatus.Available && _status != TableStatus.Reserved)
throw new DomainException($"Cannot occupy table with status {_status.Name}");
_status = TableStatus.Occupied;
StatusId = TableStatus.Occupied.Id;
_updatedAt = DateTime.UtcNow;
}
public void MarkAsAvailable()
{
_status = TableStatus.Available;
StatusId = TableStatus.Available.Id;
_updatedAt = DateTime.UtcNow;
}
public void MarkAsCleaning()
{
_status = TableStatus.Cleaning;
StatusId = TableStatus.Cleaning.Id;
_updatedAt = DateTime.UtcNow;
}
}

View File

@@ -0,0 +1,22 @@
// EN: Table status enumeration for FnB.
// VI: Enumeration trạng thái bàn cho FnB.
using FnbEngine.Domain.SeedWork;
namespace FnbEngine.Domain.AggregatesModel.TableAggregate;
/// <summary>
/// EN: Table status enumeration.
/// VI: Enumeration trạng thái bàn.
/// </summary>
public class TableStatus : Enumeration
{
public static readonly TableStatus Available = new(1, nameof(Available));
public static readonly TableStatus Occupied = new(2, nameof(Occupied));
public static readonly TableStatus Reserved = new(3, nameof(Reserved));
public static readonly TableStatus Cleaning = new(4, nameof(Cleaning));
public TableStatus(int id, string name) : base(id, name)
{
}
}

View File

@@ -1,7 +1,7 @@
using MediatR;
using MyService.Domain.AggregatesModel.SampleAggregate;
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
namespace MyService.Domain.Events;
namespace FnbEngine.Domain.Events;
/// <summary>
/// EN: Domain event raised when a new Sample is created.

View File

@@ -1,7 +1,7 @@
using MediatR;
using MyService.Domain.AggregatesModel.SampleAggregate;
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
namespace MyService.Domain.Events;
namespace FnbEngine.Domain.Events;
/// <summary>
/// EN: Domain event raised when Sample status changes.

View File

@@ -1,4 +1,4 @@
namespace MyService.Domain.Exceptions;
namespace FnbEngine.Domain.Exceptions;
/// <summary>
/// EN: Base exception for domain errors.

View File

@@ -1,4 +1,4 @@
namespace MyService.Domain.Exceptions;
namespace FnbEngine.Domain.Exceptions;
/// <summary>
/// EN: Exception for Sample aggregate domain errors.

View File

@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>MyService.Domain</AssemblyName>
<RootNamespace>MyService.Domain</RootNamespace>
<AssemblyName>FnbEngine.Domain</AssemblyName>
<RootNamespace>FnbEngine.Domain</RootNamespace>
<Description>Domain layer containing core business logic and entities</Description>
</PropertyGroup>

View File

@@ -1,6 +1,6 @@
using MediatR;
namespace MyService.Domain.SeedWork;
namespace FnbEngine.Domain.SeedWork;
/// <summary>
/// EN: Base class for all domain entities.

View File

@@ -1,6 +1,6 @@
using System.Reflection;
namespace MyService.Domain.SeedWork;
namespace FnbEngine.Domain.SeedWork;
/// <summary>
/// EN: Base class for enumeration classes (type-safe enum pattern).

View File

@@ -1,4 +1,4 @@
namespace MyService.Domain.SeedWork;
namespace FnbEngine.Domain.SeedWork;
/// <summary>
/// EN: Marker interface for aggregate roots.

View File

@@ -1,4 +1,4 @@
namespace MyService.Domain.SeedWork;
namespace FnbEngine.Domain.SeedWork;
/// <summary>
/// EN: Generic repository interface for aggregate roots.

View File

@@ -1,4 +1,4 @@
namespace MyService.Domain.SeedWork;
namespace FnbEngine.Domain.SeedWork;
/// <summary>
/// EN: Unit of Work pattern interface.

View File

@@ -1,4 +1,4 @@
namespace MyService.Domain.SeedWork;
namespace FnbEngine.Domain.SeedWork;
/// <summary>
/// EN: Base class for Value Objects following DDD patterns.

View File

@@ -1,11 +1,11 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using MyService.Domain.AggregatesModel.SampleAggregate;
using MyService.Infrastructure.Idempotency;
using MyService.Infrastructure.Repositories;
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
using FnbEngine.Infrastructure.Idempotency;
using FnbEngine.Infrastructure.Repositories;
namespace MyService.Infrastructure;
namespace FnbEngine.Infrastructure;
/// <summary>
/// EN: Dependency injection extensions for Infrastructure layer.
@@ -22,7 +22,7 @@ public static class DependencyInjection
IConfiguration configuration)
{
// EN: Add DbContext with PostgreSQL / VI: Thêm DbContext với PostgreSQL
services.AddDbContext<MyServiceContext>(options =>
services.AddDbContext<FnbEngineContext>(options =>
{
var connectionString = configuration.GetConnectionString("DefaultConnection")
?? configuration["DATABASE_URL"]
@@ -30,7 +30,7 @@ public static class DependencyInjection
options.UseNpgsql(connectionString, npgsqlOptions =>
{
npgsqlOptions.MigrationsAssembly(typeof(MyServiceContext).Assembly.FullName);
npgsqlOptions.MigrationsAssembly(typeof(FnbEngineContext).Assembly.FullName);
npgsqlOptions.EnableRetryOnFailure(
maxRetryCount: 5,
maxRetryDelay: TimeSpan.FromSeconds(30),

View File

@@ -1,8 +1,8 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using MyService.Domain.AggregatesModel.SampleAggregate;
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
namespace MyService.Infrastructure.EntityConfigurations;
namespace FnbEngine.Infrastructure.EntityConfigurations;
/// <summary>
/// EN: EF Core configuration for Sample entity.

View File

@@ -1,8 +1,8 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using MyService.Domain.AggregatesModel.SampleAggregate;
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
namespace MyService.Infrastructure.EntityConfigurations;
namespace FnbEngine.Infrastructure.EntityConfigurations;
/// <summary>
/// EN: EF Core configuration for SampleStatus enumeration.

View File

@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>MyService.Infrastructure</AssemblyName>
<RootNamespace>MyService.Infrastructure</RootNamespace>
<AssemblyName>FnbEngine.Infrastructure</AssemblyName>
<RootNamespace>FnbEngine.Infrastructure</RootNamespace>
<Description>Infrastructure layer for data access and external services</Description>
</PropertyGroup>
@@ -30,7 +30,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MyService.Domain\MyService.Domain.csproj" />
<ProjectReference Include="..\FnbEngine.Domain\FnbEngine.Domain.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,4 +1,4 @@
namespace MyService.Infrastructure.Idempotency;
namespace FnbEngine.Infrastructure.Idempotency;
/// <summary>
/// EN: Entity for tracking client requests to ensure idempotency.

View File

@@ -1,4 +1,4 @@
namespace MyService.Infrastructure.Idempotency;
namespace FnbEngine.Infrastructure.Idempotency;
/// <summary>
/// EN: Interface for managing client request idempotency.

View File

@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
namespace MyService.Infrastructure.Idempotency;
namespace FnbEngine.Infrastructure.Idempotency;
/// <summary>
/// EN: Implementation of request manager for idempotency.
@@ -8,9 +8,9 @@ namespace MyService.Infrastructure.Idempotency;
/// </summary>
public class RequestManager : IRequestManager
{
private readonly MyServiceContext _context;
private readonly FnbEngineContext _context;
public RequestManager(MyServiceContext context)
public RequestManager(FnbEngineContext context)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
}

View File

@@ -1,17 +1,17 @@
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using MyService.Domain.AggregatesModel.SampleAggregate;
using MyService.Domain.SeedWork;
using MyService.Infrastructure.EntityConfigurations;
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
using FnbEngine.Domain.SeedWork;
using FnbEngine.Infrastructure.EntityConfigurations;
namespace MyService.Infrastructure;
namespace FnbEngine.Infrastructure;
/// <summary>
/// EN: EF Core DbContext for MyService.
/// VI: EF Core DbContext cho MyService.
/// EN: EF Core DbContext for FnbEngine.
/// VI: EF Core DbContext cho FnbEngine.
/// </summary>
public class MyServiceContext : DbContext, IUnitOfWork
public class FnbEngineContext : DbContext, IUnitOfWork
{
private readonly IMediator _mediator;
private IDbContextTransaction? _currentTransaction;
@@ -34,16 +34,16 @@ public class MyServiceContext : DbContext, IUnitOfWork
/// </summary>
public bool HasActiveTransaction => _currentTransaction != null;
public MyServiceContext(DbContextOptions<MyServiceContext> options) : base(options)
public FnbEngineContext(DbContextOptions<FnbEngineContext> options) : base(options)
{
_mediator = null!;
}
public MyServiceContext(DbContextOptions<MyServiceContext> options, IMediator mediator) : base(options)
public FnbEngineContext(DbContextOptions<FnbEngineContext> options, IMediator mediator) : base(options)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
System.Diagnostics.Debug.WriteLine("MyServiceContext::ctor - " + GetHashCode());
System.Diagnostics.Debug.WriteLine("FnbEngineContext::ctor - " + GetHashCode());
}
protected override void OnModelCreating(ModelBuilder modelBuilder)

View File

@@ -1,8 +1,8 @@
using Microsoft.EntityFrameworkCore;
using MyService.Domain.AggregatesModel.SampleAggregate;
using MyService.Domain.SeedWork;
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
using FnbEngine.Domain.SeedWork;
namespace MyService.Infrastructure.Repositories;
namespace FnbEngine.Infrastructure.Repositories;
/// <summary>
/// EN: Repository implementation for Sample aggregate.
@@ -10,7 +10,7 @@ namespace MyService.Infrastructure.Repositories;
/// </summary>
public class SampleRepository : ISampleRepository
{
private readonly MyServiceContext _context;
private readonly FnbEngineContext _context;
/// <summary>
/// EN: Unit of work for transaction management.
@@ -18,7 +18,7 @@ public class SampleRepository : ISampleRepository
/// </summary>
public IUnitOfWork UnitOfWork => _context;
public SampleRepository(MyServiceContext context)
public SampleRepository(FnbEngineContext context)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
}

View File

@@ -4,7 +4,7 @@ using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;
namespace MyService.FunctionalTests.Controllers;
namespace FnbEngine.FunctionalTests.Controllers;
/// <summary>
/// EN: Functional tests for Samples API endpoints.

View File

@@ -2,9 +2,9 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using MyService.Infrastructure;
using FnbEngine.Infrastructure;
namespace MyService.FunctionalTests;
namespace FnbEngine.FunctionalTests;
/// <summary>
/// EN: Custom WebApplicationFactory for functional tests.
@@ -21,7 +21,7 @@ public class CustomWebApplicationFactory : WebApplicationFactory<Program>
// EN: Remove the existing DbContext registration
// VI: Xóa đăng ký DbContext hiện tại
var descriptor = services.SingleOrDefault(
d => d.ServiceType == typeof(DbContextOptions<MyServiceContext>));
d => d.ServiceType == typeof(DbContextOptions<FnbEngineContext>));
if (descriptor != null)
{
@@ -31,7 +31,7 @@ public class CustomWebApplicationFactory : WebApplicationFactory<Program>
// EN: Remove DbContext service
// VI: Xóa DbContext service
var dbContextDescriptor = services.SingleOrDefault(
d => d.ServiceType == typeof(MyServiceContext));
d => d.ServiceType == typeof(FnbEngineContext));
if (dbContextDescriptor != null)
{
@@ -40,7 +40,7 @@ public class CustomWebApplicationFactory : WebApplicationFactory<Program>
// EN: Add in-memory database for testing
// VI: Thêm in-memory database để test
services.AddDbContext<MyServiceContext>(options =>
services.AddDbContext<FnbEngineContext>(options =>
{
options.UseInMemoryDatabase("TestDatabase_" + Guid.NewGuid().ToString());
});
@@ -49,7 +49,7 @@ public class CustomWebApplicationFactory : WebApplicationFactory<Program>
// VI: Đảm bảo database được tạo với seed data
var sp = services.BuildServiceProvider();
using var scope = sp.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<MyServiceContext>();
var db = scope.ServiceProvider.GetRequiredService<FnbEngineContext>();
db.Database.EnsureCreated();
});
}

View File

@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>MyService.FunctionalTests</AssemblyName>
<RootNamespace>MyService.FunctionalTests</RootNamespace>
<AssemblyName>FnbEngine.FunctionalTests</AssemblyName>
<RootNamespace>FnbEngine.FunctionalTests</RootNamespace>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
@@ -32,7 +32,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\MyService.API\MyService.API.csproj" />
<ProjectReference Include="..\..\src\FnbEngine.API\FnbEngine.API.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,12 +1,12 @@
using FluentAssertions;
using Microsoft.Extensions.Logging;
using Moq;
using MyService.API.Application.Commands;
using MyService.Domain.AggregatesModel.SampleAggregate;
using MyService.Domain.SeedWork;
using FnbEngine.API.Application.Commands;
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
using FnbEngine.Domain.SeedWork;
using Xunit;
namespace MyService.UnitTests.Application;
namespace FnbEngine.UnitTests.Application;
/// <summary>
/// EN: Unit tests for CreateSampleCommandHandler.

View File

@@ -1,9 +1,9 @@
using FluentAssertions;
using MyService.Domain.AggregatesModel.SampleAggregate;
using MyService.Domain.Exceptions;
using FnbEngine.Domain.AggregatesModel.SampleAggregate;
using FnbEngine.Domain.Exceptions;
using Xunit;
namespace MyService.UnitTests.Domain;
namespace FnbEngine.UnitTests.Domain;
/// <summary>
/// EN: Unit tests for Sample aggregate.

View File

@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>MyService.UnitTests</AssemblyName>
<RootNamespace>MyService.UnitTests</RootNamespace>
<AssemblyName>FnbEngine.UnitTests</AssemblyName>
<RootNamespace>FnbEngine.UnitTests</RootNamespace>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
@@ -28,8 +28,8 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\MyService.Domain\MyService.Domain.csproj" />
<ProjectReference Include="..\..\src\MyService.API\MyService.API.csproj" />
<ProjectReference Include="..\..\src\FnbEngine.Domain\FnbEngine.Domain.csproj" />
<ProjectReference Include="..\..\src\FnbEngine.API\FnbEngine.API.csproj" />
</ItemGroup>
</Project>