mirror of
https://github.com/meysamhadeli/booking-microservices.git
synced 2026-04-15 05:25:36 +08:00
- use test-container for integration-test
- improvement test base
This commit is contained in:
parent
27c63a4efa
commit
cfab34e3ae
@ -251,7 +251,7 @@ services:
|
||||
# Mongo
|
||||
#######################################################
|
||||
mongo:
|
||||
image: mongo
|
||||
image: mongo:4
|
||||
container_name: mongo
|
||||
restart: unless-stopped
|
||||
# environment:
|
||||
|
||||
@ -91,7 +91,7 @@ services:
|
||||
# Mongo
|
||||
#######################################################
|
||||
mongo:
|
||||
image: mongo
|
||||
image: mongo:4
|
||||
container_name: mongo
|
||||
restart: unless-stopped
|
||||
# environment:
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
<PackageReference Include="Ben.BlockingDetector" Version="0.0.4" />
|
||||
<PackageReference Include="EasyCaching.Core" Version="1.7.0" />
|
||||
<PackageReference Include="EasyCaching.InMemory" Version="1.7.0" />
|
||||
<PackageReference Include="EasyNetQ.Management.Client" Version="1.4.2" />
|
||||
<PackageReference Include="EFCore.NamingConventions" Version="7.0.0" />
|
||||
<PackageReference Include="EntityFrameworkCore.Triggered" Version="3.2.1" />
|
||||
<PackageReference Include="Figgle" Version="0.4.1" />
|
||||
@ -149,6 +150,7 @@
|
||||
<ItemGroup>
|
||||
<Folder Include="Contracts" />
|
||||
<Folder Include="EventStoreDB\BackgroundWorkers" />
|
||||
<Folder Include="PersistMessageProcessor\Data\Migrations" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@ -2,8 +2,8 @@ using System.Collections.Immutable;
|
||||
using System.Data;
|
||||
using BuildingBlocks.Core.Event;
|
||||
using BuildingBlocks.Core.Model;
|
||||
using BuildingBlocks.PersistMessageProcessor;
|
||||
using BuildingBlocks.Utils;
|
||||
using BuildingBlocks.Web;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
|
||||
@ -71,7 +71,7 @@ public abstract class AppDbContextBase : DbContext, IDbContext
|
||||
OnBeforeSaving();
|
||||
return base.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
public IReadOnlyList<IDomainEvent> GetDomainEvents()
|
||||
{
|
||||
var domainEntities = ChangeTracker
|
||||
@ -119,6 +119,7 @@ public abstract class AppDbContextBase : DbContext, IDbContext
|
||||
entry.Entity.LastModifiedBy = userId;
|
||||
entry.Entity.LastModified = DateTime.Now;
|
||||
entry.Entity.IsDeleted = true;
|
||||
entry.Entity.Version++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,11 @@
|
||||
using System.Linq.Expressions;
|
||||
using BuildingBlocks.Core.Model;
|
||||
using BuildingBlocks.PersistMessageProcessor;
|
||||
using BuildingBlocks.PersistMessageProcessor.Data;
|
||||
using BuildingBlocks.Web;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Query;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
@ -15,12 +14,12 @@ namespace BuildingBlocks.EFCore;
|
||||
public static class Extensions
|
||||
{
|
||||
public static IServiceCollection AddCustomDbContext<TContext>(
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration)
|
||||
this IServiceCollection services)
|
||||
where TContext : DbContext, IDbContext
|
||||
{
|
||||
|
||||
services.AddOptions<DatabaseOptions>()
|
||||
.Bind(configuration.GetSection(nameof(DatabaseOptions)))
|
||||
.BindConfiguration(nameof(DatabaseOptions))
|
||||
.ValidateDataAnnotations();
|
||||
|
||||
services.AddDbContext<TContext>((sp, options) =>
|
||||
@ -28,7 +27,10 @@ public static class Extensions
|
||||
var databaseOptions = services.GetOptions<DatabaseOptions>(nameof(DatabaseOptions));
|
||||
|
||||
options.UseSqlServer(databaseOptions?.DefaultConnection,
|
||||
dbOptions => dbOptions.MigrationsAssembly(typeof(TContext).Assembly.GetName().Name));
|
||||
dbOptions =>
|
||||
{
|
||||
dbOptions.MigrationsAssembly(typeof(TContext).Assembly.GetName().Name);
|
||||
});
|
||||
});
|
||||
|
||||
services.AddScoped<IDbContext>(provider => provider.GetService<TContext>());
|
||||
@ -71,8 +73,10 @@ public static class Extensions
|
||||
{
|
||||
using var scope = serviceProvider.CreateScope();
|
||||
|
||||
var context = scope.ServiceProvider.GetRequiredService<TContext>();
|
||||
var persistMessageContext = scope.ServiceProvider.GetRequiredService<PersistMessageDbContext>();
|
||||
await persistMessageContext.Database.MigrateAsync();
|
||||
|
||||
var context = scope.ServiceProvider.GetRequiredService<TContext>();
|
||||
await context.Database.MigrateAsync();
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using BuildingBlocks.Core.Event;
|
||||
using BuildingBlocks.PersistMessageProcessor;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace BuildingBlocks.EFCore;
|
||||
@ -7,8 +6,6 @@ namespace BuildingBlocks.EFCore;
|
||||
public interface IDbContext
|
||||
{
|
||||
DbSet<TEntity> Set<TEntity>() where TEntity : class;
|
||||
DbSet<PersistMessage> PersistMessages => Set<PersistMessage>();
|
||||
|
||||
IReadOnlyList<IDomainEvent> GetDomainEvents();
|
||||
Task BeginTransactionAsync(CancellationToken cancellationToken = default);
|
||||
Task CommitTransactionAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
@ -21,6 +21,10 @@ public static class Extensions
|
||||
public static IServiceCollection AddCustomMassTransit(this IServiceCollection services, Assembly assembly,
|
||||
IWebHostEnvironment env)
|
||||
{
|
||||
services.AddOptions<RabbitMqOptions>()
|
||||
.BindConfiguration(nameof(RabbitMqOptions))
|
||||
.ValidateDataAnnotations();
|
||||
|
||||
if (env.IsEnvironment("test"))
|
||||
{
|
||||
services.AddMassTransitTestHarness(configure =>
|
||||
@ -47,12 +51,13 @@ public static class Extensions
|
||||
configure.UsingRabbitMq((context, configurator) =>
|
||||
{
|
||||
var rabbitMqOptions = services.GetOptions<RabbitMqOptions>(nameof(RabbitMqOptions));
|
||||
|
||||
var host = IsRunningInContainer ? "rabbitmq" : rabbitMqOptions.HostName;
|
||||
|
||||
configurator.Host(host, rabbitMqOptions?.Port ?? 5672, "/", h =>
|
||||
{
|
||||
h.Username(rabbitMqOptions.UserName);
|
||||
h.Password(rabbitMqOptions.Password);
|
||||
h.Username(rabbitMqOptions?.UserName);
|
||||
h.Password(rabbitMqOptions?.Password);
|
||||
});
|
||||
|
||||
var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
using BuildingBlocks.EFCore;
|
||||
using BuildingBlocks.PersistMessageProcessor;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Passenger.Data.Configurations;
|
||||
namespace BuildingBlocks.PersistMessageProcessor.Data.Configurations;
|
||||
|
||||
public class PersistMessageConfiguration : IEntityTypeConfiguration<PersistMessage>
|
||||
{
|
||||
@ -13,8 +12,8 @@ public class PersistMessageConfiguration : IEntityTypeConfiguration<PersistMessa
|
||||
|
||||
builder.HasKey(x => x.Id);
|
||||
|
||||
builder.Property(x => x.Id)
|
||||
.IsRequired();
|
||||
builder.Property(r => r.Id)
|
||||
.IsRequired().ValueGeneratedNever();
|
||||
|
||||
builder.Property(x => x.DeliveryType)
|
||||
.HasMaxLength(50)
|
||||
@ -0,0 +1,16 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
|
||||
namespace BuildingBlocks.PersistMessageProcessor.Data;
|
||||
|
||||
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<PersistMessageDbContext>
|
||||
{
|
||||
public PersistMessageDbContext CreateDbContext(string[] args)
|
||||
{
|
||||
var builder = new DbContextOptionsBuilder<PersistMessageDbContext>();
|
||||
|
||||
builder.UseSqlServer(
|
||||
"Data Source=.\\sqlexpress;Initial Catalog=PersistMessageDB;Persist Security Info=False;Integrated Security=SSPI;TrustServerCertificate=True");
|
||||
return new PersistMessageDbContext(builder.Options);
|
||||
}
|
||||
}
|
||||
64
src/BuildingBlocks/PersistMessageProcessor/Data/Migrations/20221206184130_initial.Designer.cs
generated
Normal file
64
src/BuildingBlocks/PersistMessageProcessor/Data/Migrations/20221206184130_initial.Designer.cs
generated
Normal file
@ -0,0 +1,64 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using BuildingBlocks.PersistMessageProcessor.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace BuildingBlocks.PersistMessageProcessor.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(PersistMessageDbContext))]
|
||||
[Migration("20221206184130_initial")]
|
||||
partial class initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "7.0.0")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("BuildingBlocks.PersistMessageProcessor.PersistMessage", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<DateTime>("Created")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DataType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DeliveryType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<string>("MessageStatus")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<int>("RetryCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PersistMessage", "dbo");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace BuildingBlocks.PersistMessageProcessor.Data.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class initial : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.EnsureSchema(
|
||||
name: "dbo");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PersistMessage",
|
||||
schema: "dbo",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<long>(type: "bigint", nullable: false),
|
||||
DataType = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Data = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Created = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
RetryCount = table.Column<int>(type: "int", nullable: false),
|
||||
MessageStatus = table.Column<string>(type: "varchar(50)", unicode: false, maxLength: 50, nullable: false),
|
||||
DeliveryType = table.Column<string>(type: "varchar(50)", unicode: false, maxLength: 50, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PersistMessage", x => x.Id);
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "PersistMessage",
|
||||
schema: "dbo");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using BuildingBlocks.PersistMessageProcessor.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace BuildingBlocks.PersistMessageProcessor.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(PersistMessageDbContext))]
|
||||
partial class PersistMessageDbContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "7.0.0")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("BuildingBlocks.PersistMessageProcessor.PersistMessage", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<DateTime>("Created")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DataType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DeliveryType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<string>("MessageStatus")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<int>("RetryCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PersistMessage", "dbo");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
using BuildingBlocks.EFCore;
|
||||
using BuildingBlocks.PersistMessageProcessor.Data.Configurations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace BuildingBlocks.PersistMessageProcessor.Data;
|
||||
|
||||
public class PersistMessageDbContext : AppDbContextBase, IPersistMessageDbContext
|
||||
{
|
||||
public PersistMessageDbContext(DbContextOptions<PersistMessageDbContext> options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
builder.ApplyConfiguration(new PersistMessageConfiguration());
|
||||
base.OnModelCreating(builder);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
dotnet ef migrations add initial --context PersistMessageDbContext -o "PersistMessageProcessor\Data\Migrations"
|
||||
dotnet ef database update --context PersistMessageDbContext
|
||||
@ -1,4 +1,7 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using BuildingBlocks.PersistMessageProcessor.Data;
|
||||
using BuildingBlocks.Web;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace BuildingBlocks.PersistMessageProcessor;
|
||||
|
||||
@ -6,6 +9,20 @@ public static class Extensions
|
||||
{
|
||||
public static IServiceCollection AddPersistMessageProcessor(this IServiceCollection services)
|
||||
{
|
||||
services.AddOptions<PersistMessageOptions>()
|
||||
.BindConfiguration(nameof(PersistMessageOptions))
|
||||
.ValidateDataAnnotations();
|
||||
|
||||
services.AddDbContext<PersistMessageDbContext>(options =>
|
||||
{
|
||||
var persistMessageOptions = services.GetOptions<PersistMessageOptions>(nameof(PersistMessageOptions));
|
||||
|
||||
options.UseSqlServer(persistMessageOptions.ConnectionString,
|
||||
x => x.MigrationsAssembly(typeof(PersistMessageDbContext).Assembly.GetName().Name));
|
||||
});
|
||||
|
||||
services.AddScoped<IPersistMessageDbContext>(provider => provider.GetService<PersistMessageDbContext>());
|
||||
|
||||
services.AddScoped<IPersistMessageProcessor, PersistMessageProcessor>();
|
||||
services.AddHostedService<PersistMessageBackgroundService>();
|
||||
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
using BuildingBlocks.EFCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace BuildingBlocks.PersistMessageProcessor;
|
||||
|
||||
public interface IPersistMessageDbContext : IDbContext
|
||||
{
|
||||
DbSet<PersistMessage> PersistMessages => Set<PersistMessage>();
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
@ -8,18 +7,18 @@ namespace BuildingBlocks.PersistMessageProcessor;
|
||||
public class PersistMessageBackgroundService : BackgroundService
|
||||
{
|
||||
private readonly ILogger<PersistMessageBackgroundService> _logger;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IPersistMessageProcessor _persistMessageProcessor;
|
||||
private PersistMessageOptions _options;
|
||||
|
||||
private Task? _executingTask;
|
||||
|
||||
public PersistMessageBackgroundService(
|
||||
ILogger<PersistMessageBackgroundService> logger,
|
||||
IServiceProvider serviceProvider,
|
||||
IPersistMessageProcessor persistMessageProcessor,
|
||||
IOptions<PersistMessageOptions> options)
|
||||
{
|
||||
_logger = logger;
|
||||
_serviceProvider = serviceProvider;
|
||||
_persistMessageProcessor = persistMessageProcessor;
|
||||
_options = options.Value;
|
||||
}
|
||||
|
||||
@ -45,11 +44,7 @@ public class PersistMessageBackgroundService : BackgroundService
|
||||
{
|
||||
try
|
||||
{
|
||||
await using (var scope = _serviceProvider.CreateAsyncScope())
|
||||
{
|
||||
var service = scope.ServiceProvider.GetRequiredService<IPersistMessageProcessor>();
|
||||
await service.ProcessAllAsync(stoppingToken);
|
||||
}
|
||||
await _persistMessageProcessor.ProcessAllAsync(stoppingToken);
|
||||
|
||||
var delay = _options.Interval is { }
|
||||
? TimeSpan.FromSeconds((int)_options.Interval)
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
using System.Text.Json;
|
||||
using Ardalis.GuardClauses;
|
||||
using BuildingBlocks.Core.Event;
|
||||
using BuildingBlocks.EFCore;
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
using BuildingBlocks.Utils;
|
||||
using MassTransit;
|
||||
@ -16,18 +15,18 @@ public class PersistMessageProcessor : IPersistMessageProcessor
|
||||
{
|
||||
private readonly ILogger<PersistMessageProcessor> _logger;
|
||||
private readonly IMediator _mediator;
|
||||
private readonly IDbContext _dbContext;
|
||||
private readonly IPersistMessageDbContext _persistMessageDbContext;
|
||||
private readonly IPublishEndpoint _publishEndpoint;
|
||||
|
||||
public PersistMessageProcessor(
|
||||
ILogger<PersistMessageProcessor> logger,
|
||||
IMediator mediator,
|
||||
IDbContext dbContext,
|
||||
IPersistMessageDbContext persistMessageDbContext,
|
||||
IPublishEndpoint publishEndpoint)
|
||||
{
|
||||
_logger = logger;
|
||||
_mediator = mediator;
|
||||
_dbContext = dbContext;
|
||||
_persistMessageDbContext = persistMessageDbContext;
|
||||
_publishEndpoint = publishEndpoint;
|
||||
}
|
||||
|
||||
@ -55,13 +54,13 @@ public class PersistMessageProcessor : IPersistMessageProcessor
|
||||
public async Task<IReadOnlyList<PersistMessage>> GetByFilterAsync(Expression<Func<PersistMessage, bool>> predicate,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return (await _dbContext.PersistMessages.Where(predicate).ToListAsync(cancellationToken))
|
||||
return (await _persistMessageDbContext.PersistMessages.Where(predicate).ToListAsync(cancellationToken))
|
||||
.AsReadOnly();
|
||||
}
|
||||
|
||||
public Task<PersistMessage> ExistMessageAsync(long messageId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _dbContext.PersistMessages.FirstOrDefaultAsync(x =>
|
||||
return _persistMessageDbContext.PersistMessages.FirstOrDefaultAsync(x =>
|
||||
x.Id == messageId &&
|
||||
x.DeliveryType == MessageDeliveryType.Inbox &&
|
||||
x.MessageStatus == MessageStatus.Processed,
|
||||
@ -74,7 +73,7 @@ public class PersistMessageProcessor : IPersistMessageProcessor
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var message =
|
||||
await _dbContext.PersistMessages.FirstOrDefaultAsync(
|
||||
await _persistMessageDbContext.PersistMessages.FirstOrDefaultAsync(
|
||||
x => x.Id == messageId && x.DeliveryType == deliveryType, cancellationToken);
|
||||
|
||||
if (message is null)
|
||||
@ -111,7 +110,7 @@ public class PersistMessageProcessor : IPersistMessageProcessor
|
||||
|
||||
public async Task ProcessAllAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var messages = await _dbContext.PersistMessages
|
||||
var messages = await _persistMessageDbContext.PersistMessages
|
||||
.Where(x => x.MessageStatus != MessageStatus.Processed)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
@ -120,7 +119,7 @@ public class PersistMessageProcessor : IPersistMessageProcessor
|
||||
|
||||
public async Task ProcessInboxAsync(long messageId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var message = await _dbContext.PersistMessages.FirstOrDefaultAsync(
|
||||
var message = await _persistMessageDbContext.PersistMessages.FirstOrDefaultAsync(
|
||||
x => x.Id == messageId &&
|
||||
x.DeliveryType == MessageDeliveryType.Inbox &&
|
||||
x.MessageStatus == MessageStatus.InProgress,
|
||||
@ -191,7 +190,7 @@ public class PersistMessageProcessor : IPersistMessageProcessor
|
||||
else
|
||||
id = SnowFlakIdGenerator.NewId();
|
||||
|
||||
await _dbContext.PersistMessages.AddAsync(
|
||||
await _persistMessageDbContext.PersistMessages.AddAsync(
|
||||
new PersistMessage(
|
||||
id,
|
||||
messageEnvelope.Message.GetType().ToString(),
|
||||
@ -199,7 +198,7 @@ public class PersistMessageProcessor : IPersistMessageProcessor
|
||||
deliveryType),
|
||||
cancellationToken);
|
||||
|
||||
await _dbContext.SaveChangesAsync(cancellationToken);
|
||||
await _persistMessageDbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
_logger.LogInformation(
|
||||
"Message with id: {MessageID} and delivery type: {DeliveryType} saved in persistence message store.",
|
||||
@ -213,8 +212,8 @@ public class PersistMessageProcessor : IPersistMessageProcessor
|
||||
{
|
||||
message.ChangeState(MessageStatus.Processed);
|
||||
|
||||
_dbContext.PersistMessages.Update(message);
|
||||
_persistMessageDbContext.PersistMessages.Update(message);
|
||||
|
||||
await _dbContext.SaveChangesAsync(cancellationToken);
|
||||
await _persistMessageDbContext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,10 +2,12 @@
|
||||
using BuildingBlocks.Core.Event;
|
||||
using BuildingBlocks.Core.Model;
|
||||
using BuildingBlocks.EFCore;
|
||||
using BuildingBlocks.MassTransit;
|
||||
using BuildingBlocks.Mongo;
|
||||
using BuildingBlocks.PersistMessageProcessor;
|
||||
using BuildingBlocks.Web;
|
||||
using DotNet.Testcontainers.Containers;
|
||||
using EasyNetQ.Management.Client;
|
||||
using Grpc.Net.Client;
|
||||
using MassTransit;
|
||||
using MassTransit.Testing;
|
||||
@ -18,7 +20,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Mongo2Go;
|
||||
using MongoDB.Driver;
|
||||
using NSubstitute;
|
||||
using Respawn;
|
||||
using Respawn.Graph;
|
||||
@ -28,42 +30,43 @@ using Xunit.Abstractions;
|
||||
|
||||
namespace BuildingBlocks.TestBase;
|
||||
|
||||
public class IntegrationTestFixture<TEntryPoint> : IAsyncLifetime
|
||||
public class IntegrationTestFactory<TEntryPoint> : IAsyncLifetime
|
||||
where TEntryPoint : class
|
||||
{
|
||||
private readonly WebApplicationFactory<TEntryPoint> _factory;
|
||||
private int Timeout => 60; // Second
|
||||
private int Timeout => 120; // Second
|
||||
|
||||
public MsSqlTestcontainer MsSqlTestContainer;
|
||||
public MsSqlTestcontainer MsSqlPersistTestContainer;
|
||||
public RabbitMqTestcontainer RabbitMqTestContainer;
|
||||
public MongoDbTestcontainer MongoDbTestContainer;
|
||||
|
||||
private ITestHarness TestHarness => ServiceProvider?.GetTestHarness();
|
||||
public HttpClient HttpClient => _factory?.CreateClient();
|
||||
|
||||
public GrpcChannel Channel =>
|
||||
GrpcChannel.ForAddress(HttpClient.BaseAddress!, new GrpcChannelOptions { HttpClient = HttpClient });
|
||||
public GrpcChannel Channel => GrpcChannel.ForAddress(HttpClient.BaseAddress!, new GrpcChannelOptions { HttpClient = HttpClient });
|
||||
|
||||
public Action<IServiceCollection> TestRegistrationServices { get; set; }
|
||||
public IServiceProvider ServiceProvider => _factory?.Services;
|
||||
public IConfiguration Configuration => _factory?.Services.GetRequiredService<IConfiguration>();
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public IntegrationTestFixture()
|
||||
public IntegrationTestFactory()
|
||||
{
|
||||
_factory = new WebApplicationFactory<TEntryPoint>()
|
||||
.WithWebHostBuilder(builder =>
|
||||
{
|
||||
builder.ConfigureAppConfiguration(AddCustomAppSettings);
|
||||
|
||||
builder.UseEnvironment("test");
|
||||
builder.ConfigureServices(services =>
|
||||
{
|
||||
TestRegistrationServices?.Invoke(services);
|
||||
services.ReplaceSingleton(AddHttpContextAccessorMock);
|
||||
});
|
||||
|
||||
builder.ConfigureAppConfiguration(AddCustomAppSettings);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
await StartTestContainerAsync();
|
||||
@ -134,32 +137,35 @@ public class IntegrationTestFixture<TEntryPoint> : IAsyncLifetime
|
||||
await TestHarness.Bus.Publish<TMessage>(message, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task WaitForPublishing<TMessage>(CancellationToken cancellationToken = default)
|
||||
public async Task<bool> WaitForPublishing<TMessage>(CancellationToken cancellationToken = default)
|
||||
where TMessage : class, IEvent
|
||||
{
|
||||
await WaitUntilConditionMet(async () =>
|
||||
var result = await WaitUntilConditionMet(async () =>
|
||||
{
|
||||
var published = await TestHarness.Published.Any<TMessage>(cancellationToken);
|
||||
var faulty = await TestHarness.Published.Any<Fault<TMessage>>(cancellationToken);
|
||||
|
||||
return published && faulty == false;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task WaitForConsuming<TMessage>(CancellationToken cancellationToken = default)
|
||||
public async Task<bool> WaitForConsuming<TMessage>(CancellationToken cancellationToken = default)
|
||||
where TMessage : class, IEvent
|
||||
{
|
||||
await WaitUntilConditionMet(async () =>
|
||||
var result = await WaitUntilConditionMet(async () =>
|
||||
{
|
||||
var consumed = await TestHarness.Consumed.Any<TMessage>(cancellationToken);
|
||||
var faulty = await TestHarness.Consumed.Any<Fault<TMessage>>(cancellationToken);
|
||||
|
||||
return consumed && faulty == false;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Ref: https://tech.energyhelpline.com/in-memory-testing-with-masstransit/
|
||||
public async ValueTask WaitUntilConditionMet(Func<Task<bool>> conditionToMet, int? timeoutSecond = null)
|
||||
public async Task<bool> WaitUntilConditionMet(Func<Task<bool>> conditionToMet, int? timeoutSecond = null)
|
||||
{
|
||||
var time = timeoutSecond ?? Timeout;
|
||||
|
||||
@ -168,18 +174,20 @@ public class IntegrationTestFixture<TEntryPoint> : IAsyncLifetime
|
||||
var meet = await conditionToMet.Invoke();
|
||||
while (!meet)
|
||||
{
|
||||
if (timeoutExpired) throw new TimeoutException("Condition not met for the test.");
|
||||
if (timeoutExpired) return false;
|
||||
|
||||
await Task.Delay(100);
|
||||
meet = await conditionToMet.Invoke();
|
||||
timeoutExpired = DateTime.Now - startTime > TimeSpan.FromSeconds(time);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async ValueTask ShouldProcessedPersistInternalCommand<TInternalCommand>()
|
||||
public async Task<bool> ShouldProcessedPersistInternalCommand<TInternalCommand>()
|
||||
where TInternalCommand : class, IInternalCommand
|
||||
{
|
||||
await WaitUntilConditionMet(async () =>
|
||||
var result = await WaitUntilConditionMet(async () =>
|
||||
{
|
||||
return await ExecuteScopeAsync(async sp =>
|
||||
{
|
||||
@ -195,22 +203,30 @@ public class IntegrationTestFixture<TEntryPoint> : IAsyncLifetime
|
||||
return res;
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private async Task StartTestContainerAsync()
|
||||
{
|
||||
MsSqlTestContainer = TestContainers.MsSqlTestContainer;
|
||||
MsSqlPersistTestContainer = TestContainers.MsSqlPersistTestContainer;
|
||||
RabbitMqTestContainer = TestContainers.RabbitMqTestContainer;
|
||||
MongoDbTestContainer = TestContainers.MongoTestContainer;
|
||||
|
||||
await MongoDbTestContainer.StartAsync();
|
||||
await MsSqlTestContainer.StartAsync();
|
||||
await MsSqlPersistTestContainer.StartAsync();
|
||||
await RabbitMqTestContainer.StartAsync();
|
||||
}
|
||||
|
||||
private async Task StopTestContainerAsync()
|
||||
{
|
||||
await MsSqlTestContainer.StopAsync();
|
||||
await MsSqlPersistTestContainer.StopAsync();
|
||||
await RabbitMqTestContainer.StopAsync();
|
||||
await MongoDbTestContainer.StopAsync();
|
||||
}
|
||||
|
||||
private void AddCustomAppSettings(IConfigurationBuilder configuration)
|
||||
@ -218,10 +234,13 @@ public class IntegrationTestFixture<TEntryPoint> : IAsyncLifetime
|
||||
configuration.AddInMemoryCollection(new KeyValuePair<string, string>[]
|
||||
{
|
||||
new("DatabaseOptions:DefaultConnection", MsSqlTestContainer.ConnectionString + "TrustServerCertificate=True"),
|
||||
new("PersistMessageOptions:ConnectionString", MsSqlPersistTestContainer.ConnectionString + "TrustServerCertificate=True"),
|
||||
new("RabbitMqOptions:HostName", RabbitMqTestContainer.Hostname),
|
||||
new("RabbitMqOptions:UserName", RabbitMqTestContainer.Username),
|
||||
new("RabbitMqOptions:Password", RabbitMqTestContainer.Password),
|
||||
new("RabbitMqOptions:Port", RabbitMqTestContainer.Port.ToString())
|
||||
new("RabbitMqOptions:Port", RabbitMqTestContainer.Port.ToString()),
|
||||
new("MongoOptions:ConnectionString", MongoDbTestContainer.ConnectionString),
|
||||
new("MongoOptions:DatabaseName", MongoDbTestContainer.Database)
|
||||
});
|
||||
}
|
||||
|
||||
@ -238,7 +257,7 @@ public class IntegrationTestFixture<TEntryPoint> : IAsyncLifetime
|
||||
}
|
||||
}
|
||||
|
||||
public class IntegrationTestFixture<TEntryPoint, TWContext> : IntegrationTestFixture<TEntryPoint>
|
||||
public class IntegrationTestFactory<TEntryPoint, TWContext> : IntegrationTestFactory<TEntryPoint>
|
||||
where TEntryPoint : class
|
||||
where TWContext : DbContext
|
||||
{
|
||||
@ -345,7 +364,7 @@ public class IntegrationTestFixture<TEntryPoint, TWContext> : IntegrationTestFix
|
||||
}
|
||||
}
|
||||
|
||||
public class IntegrationTestFixture<TEntryPoint, TWContext, TRContext> : IntegrationTestFixture<TEntryPoint, TWContext>
|
||||
public class IntegrationTestFactory<TEntryPoint, TWContext, TRContext> : IntegrationTestFactory<TEntryPoint, TWContext>
|
||||
where TEntryPoint : class
|
||||
where TWContext : DbContext
|
||||
where TRContext : MongoDbContext
|
||||
@ -365,48 +384,93 @@ public class IntegrationTestFixtureCore<TEntryPoint> : IAsyncLifetime
|
||||
where TEntryPoint : class
|
||||
{
|
||||
private Respawner _reSpawnerDefaultDb;
|
||||
private MongoDbRunner _mongoRunner;
|
||||
private Respawner _reSpawnerPersistDb;
|
||||
private SqlConnection DefaultDbConnection { get; set; }
|
||||
private SqlConnection PersistDbConnection { get; set; }
|
||||
|
||||
|
||||
public IntegrationTestFixtureCore(IntegrationTestFixture<TEntryPoint> integrationTestFixture)
|
||||
public IntegrationTestFixtureCore(IntegrationTestFactory<TEntryPoint> integrationTestFixture, ITestOutputHelper outputHelper)
|
||||
{
|
||||
Fixture = integrationTestFixture;
|
||||
integrationTestFixture.RegisterServices(services => RegisterTestsServices(services));
|
||||
integrationTestFixture.Logger = integrationTestFixture.CreateLogger(outputHelper);
|
||||
}
|
||||
|
||||
public IntegrationTestFixture<TEntryPoint> Fixture { get; }
|
||||
public IntegrationTestFactory<TEntryPoint> Fixture { get; }
|
||||
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
var databaseOptions = Fixture.ServiceProvider.GetRequiredService<IOptions<DatabaseOptions>>()?.Value;
|
||||
var mongoOptions = Fixture.ServiceProvider.GetRequiredService<IOptions<MongoOptions>>()?.Value;
|
||||
var persistOptions = Fixture.ServiceProvider.GetRequiredService<IOptions<PersistMessageOptions>>()?.Value;
|
||||
|
||||
if (!string.IsNullOrEmpty(persistOptions?.ConnectionString))
|
||||
{
|
||||
PersistDbConnection = new SqlConnection(persistOptions?.ConnectionString);
|
||||
await PersistDbConnection.OpenAsync();
|
||||
|
||||
_reSpawnerPersistDb = await Respawner.CreateAsync(PersistDbConnection,
|
||||
new RespawnerOptions { TablesToIgnore = new Table[] { "__EFMigrationsHistory" }, });
|
||||
|
||||
await _reSpawnerPersistDb.ResetAsync(PersistDbConnection);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(databaseOptions?.DefaultConnection))
|
||||
{
|
||||
var dbConnection = new SqlConnection(databaseOptions.DefaultConnection);
|
||||
await dbConnection.OpenAsync();
|
||||
DefaultDbConnection = new SqlConnection(databaseOptions.DefaultConnection);
|
||||
await DefaultDbConnection.OpenAsync();
|
||||
|
||||
_reSpawnerDefaultDb = await Respawner.CreateAsync(dbConnection,
|
||||
new RespawnerOptions
|
||||
{
|
||||
TablesToIgnore = new Table[] { "__EFMigrationsHistory" },
|
||||
});
|
||||
_reSpawnerDefaultDb = await Respawner.CreateAsync(DefaultDbConnection,
|
||||
new RespawnerOptions { TablesToIgnore = new Table[] { "__EFMigrationsHistory" }, });
|
||||
|
||||
await _reSpawnerDefaultDb.ResetAsync(dbConnection);
|
||||
await _reSpawnerDefaultDb.ResetAsync(DefaultDbConnection);
|
||||
|
||||
await SeedDataAsync();
|
||||
}
|
||||
|
||||
_mongoRunner = MongoDbRunner.Start();
|
||||
|
||||
if (!string.IsNullOrEmpty(mongoOptions?.ConnectionString))
|
||||
mongoOptions.ConnectionString = _mongoRunner.ConnectionString;
|
||||
|
||||
await SeedDataAsync();
|
||||
}
|
||||
|
||||
public async Task DisposeAsync()
|
||||
{
|
||||
_mongoRunner.Dispose();
|
||||
await ResetMongoAsync();
|
||||
await ResetRabbitMqAsync();
|
||||
}
|
||||
|
||||
private async Task ResetMongoAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
//https://stackoverflow.com/questions/3366397/delete-everything-in-a-mongodb-database
|
||||
MongoClient dbClient = new MongoClient(Fixture.MongoDbTestContainer?.ConnectionString);
|
||||
var collections = await dbClient.GetDatabase(Fixture.MongoDbTestContainer?.Database)
|
||||
.ListCollectionsAsync(cancellationToken: cancellationToken);
|
||||
|
||||
foreach (var collection in collections.ToList())
|
||||
{
|
||||
await dbClient.GetDatabase(Fixture.MongoDbTestContainer?.Database)
|
||||
.DropCollectionAsync(collection["name"].AsString, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ResetRabbitMqAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var port = Fixture.RabbitMqTestContainer?.GetMappedPublicPort(15672) ?? 15672;
|
||||
|
||||
var rabbitmqOptions = Fixture.ServiceProvider.GetRequiredService<IOptions<RabbitMqOptions>>()?.Value;
|
||||
|
||||
var managementClient = new ManagementClient(rabbitmqOptions?.HostName, rabbitmqOptions?.UserName,
|
||||
rabbitmqOptions?.Password, port);
|
||||
|
||||
var bd = await managementClient.GetBindingsAsync(cancellationToken);
|
||||
var bindings = bd.Where(x => !string.IsNullOrEmpty(x.Source) && !string.IsNullOrEmpty(x.Destination));
|
||||
|
||||
foreach (var binding in bindings)
|
||||
{
|
||||
await managementClient.DeleteBindingAsync(binding, cancellationToken);
|
||||
}
|
||||
|
||||
var queues = await managementClient.GetQueuesAsync(cancellationToken);
|
||||
|
||||
foreach (var queue in queues)
|
||||
{
|
||||
await managementClient.DeleteQueueAsync(queue, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void RegisterTestsServices(IServiceCollection services)
|
||||
@ -422,44 +486,32 @@ public class IntegrationTestFixtureCore<TEntryPoint> : IAsyncLifetime
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class IntegrationTestBase<TEntryPoint> : IntegrationTestFixtureCore<TEntryPoint>,
|
||||
IClassFixture<IntegrationTestFixture<TEntryPoint>>
|
||||
where TEntryPoint : class
|
||||
{
|
||||
protected IntegrationTestBase(
|
||||
IntegrationTestFixture<TEntryPoint> integrationTestFixture) : base(integrationTestFixture)
|
||||
{
|
||||
Fixture = integrationTestFixture;
|
||||
}
|
||||
|
||||
public IntegrationTestFixture<TEntryPoint> Fixture { get; }
|
||||
}
|
||||
|
||||
public abstract class IntegrationTestBase<TEntryPoint, TWContext> : IntegrationTestFixtureCore<TEntryPoint>,
|
||||
IClassFixture<IntegrationTestFixture<TEntryPoint, TWContext>>
|
||||
public abstract class IntegrationTestBase<TEntryPoint, TWContext> : IntegrationTestFixtureCore<TEntryPoint>
|
||||
//,IClassFixture<IntegrationTestFactory<TEntryPoint, TWContext>>
|
||||
where TEntryPoint : class
|
||||
where TWContext : DbContext
|
||||
{
|
||||
protected IntegrationTestBase(
|
||||
IntegrationTestFixture<TEntryPoint, TWContext> integrationTestFixture) : base(integrationTestFixture)
|
||||
IntegrationTestFactory<TEntryPoint, TWContext> integrationTestFixture, ITestOutputHelper outputHelper = null) : base(integrationTestFixture, outputHelper)
|
||||
{
|
||||
Fixture = integrationTestFixture;
|
||||
}
|
||||
|
||||
public IntegrationTestFixture<TEntryPoint, TWContext> Fixture { get; }
|
||||
public IntegrationTestFactory<TEntryPoint, TWContext> Fixture { get; }
|
||||
}
|
||||
|
||||
public abstract class IntegrationTestBase<TEntryPoint, TWContext, TRContext> : IntegrationTestFixtureCore<TEntryPoint>,
|
||||
IClassFixture<IntegrationTestFixture<TEntryPoint, TWContext, TRContext>>
|
||||
public abstract class IntegrationTestBase<TEntryPoint, TWContext, TRContext> : IntegrationTestFixtureCore<TEntryPoint>
|
||||
//,IClassFixture<IntegrationTestFactory<TEntryPoint, TWContext, TRContext>>
|
||||
where TEntryPoint : class
|
||||
where TWContext : DbContext
|
||||
where TRContext : MongoDbContext
|
||||
{
|
||||
protected IntegrationTestBase(
|
||||
IntegrationTestFixture<TEntryPoint, TWContext, TRContext> integrationTestFixture) : base(integrationTestFixture)
|
||||
IntegrationTestFactory<TEntryPoint, TWContext, TRContext> integrationTestFixture, ITestOutputHelper outputHelper = null) : base(integrationTestFixture, outputHelper)
|
||||
{
|
||||
Fixture = integrationTestFixture;
|
||||
}
|
||||
|
||||
public IntegrationTestFixture<TEntryPoint, TWContext, TRContext> Fixture { get; }
|
||||
public IntegrationTestFactory<TEntryPoint, TWContext, TRContext> Fixture { get; }
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using DotNet.Testcontainers.Builders;
|
||||
using System;
|
||||
using DotNet.Testcontainers.Builders;
|
||||
using DotNet.Testcontainers.Configurations;
|
||||
using DotNet.Testcontainers.Containers;
|
||||
|
||||
@ -15,18 +16,28 @@ public static class TestContainers
|
||||
Username = Guid.NewGuid().ToString("D")
|
||||
})
|
||||
.WithImage("postgres:latest")
|
||||
.WithCleanUp(true)
|
||||
.Build();
|
||||
|
||||
|
||||
// issue ref: https://github.com/testcontainers/testcontainers-dotnet/discussions/533
|
||||
public static MsSqlTestcontainer MsSqlTestContainer = new TestcontainersBuilder<MsSqlTestcontainer>()
|
||||
.WithDatabase(new MsSqlTestcontainerConfiguration()
|
||||
{
|
||||
Password = Guid.NewGuid().ToString("D")
|
||||
})
|
||||
.WithImage("mcr.microsoft.com/mssql/server:2022-latest")
|
||||
.WithExposedPort(1433)
|
||||
.WithPortBinding(1433, true) // Add this line for issue in hangup MsSqlTestContainer in docker desktop
|
||||
.WithPortBinding(1433, true)
|
||||
.WithCleanUp(true)
|
||||
.Build();
|
||||
|
||||
public static MsSqlTestcontainer MsSqlPersistTestContainer = new TestcontainersBuilder<MsSqlTestcontainer>()
|
||||
.WithDatabase(new MsSqlTestcontainerConfiguration()
|
||||
{
|
||||
Password = Guid.NewGuid().ToString("D")
|
||||
})
|
||||
.WithImage("mcr.microsoft.com/mssql/server:2022-latest")
|
||||
.WithPortBinding(1433, true)
|
||||
.WithCleanUp(true)
|
||||
.Build();
|
||||
|
||||
|
||||
@ -35,14 +46,24 @@ public static class TestContainers
|
||||
{
|
||||
Database = Guid.NewGuid().ToString("D"),
|
||||
Username = Guid.NewGuid().ToString("D"),
|
||||
Password = Guid.NewGuid().ToString("D")
|
||||
Password = Guid.NewGuid().ToString("D"),
|
||||
})
|
||||
.WithImage("mongo")
|
||||
.WithImage("mongo:4")
|
||||
.WithCleanUp(true)
|
||||
.Build();
|
||||
|
||||
|
||||
public static RabbitMqTestcontainer RabbitMqTestContainer => new TestcontainersBuilder<RabbitMqTestcontainer>()
|
||||
.WithMessageBroker(new RabbitMqTestcontainerConfiguration() { Password = "guest", Username = "guest" })
|
||||
.WithMessageBroker(new RabbitMqTestcontainerConfiguration()
|
||||
{
|
||||
Password = "guest",
|
||||
Username = "guest"
|
||||
})
|
||||
.WithImage("rabbitmq:3-management")
|
||||
.WithPortBinding(15672, true)
|
||||
.WithPortBinding(5672, true)
|
||||
.WithCleanUp(true)
|
||||
.Build();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace BuildingBlocks.Utils;
|
||||
namespace BuildingBlocks.Web;
|
||||
|
||||
public interface ICurrentUserProvider
|
||||
{
|
||||
30
src/BuildingBlocks/Web/ServiceProviderExtensions.cs
Normal file
30
src/BuildingBlocks/Web/ServiceProviderExtensions.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace BuildingBlocks.Web;
|
||||
|
||||
public static class ServiceProviderExtensions
|
||||
{
|
||||
public static async Task StartTestHostedServices(
|
||||
this IServiceProvider serviceProvider,
|
||||
Type[] hostedServiceTypes,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
foreach (var hostedServiceType in hostedServiceTypes)
|
||||
{
|
||||
if (serviceProvider.GetService(hostedServiceType) is IHostedService hostedService)
|
||||
await hostedService.StartAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task StopTestHostedServices(
|
||||
this IServiceProvider serviceProvider,
|
||||
Type[] hostedServiceTypes,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
foreach (var hostedServiceType in hostedServiceTypes)
|
||||
{
|
||||
if (serviceProvider.GetService(hostedServiceType) is IHostedService hostedService)
|
||||
await hostedService.StopAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
||||
namespace BuildingBlocks.Utils;
|
||||
namespace BuildingBlocks.Web;
|
||||
|
||||
public class SlugifyParameterTransformer : IOutboundParameterTransformer
|
||||
{
|
||||
@ -1,8 +1,2 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,11 @@
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"PersistMessageOptions": {
|
||||
"Interval": 30,
|
||||
"Enabled": true,
|
||||
"ConnectionString": "Server=db;Database=PersistMessageDB;User ID=sa;Password=@Aa123456"
|
||||
},
|
||||
"RabbitMqOptions": {
|
||||
"HostName": "rabbitmq",
|
||||
"ExchangeName": "booking",
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
"PersistMessageOptions": {
|
||||
"Interval": 30,
|
||||
"Enabled": true,
|
||||
"ConnectionString": "Server=localhost;Port=5432;Database=persist_message_db;User Id=postgres;Password=postgres;Include Error Detail=true"
|
||||
"ConnectionString": "Server=.\\sqlexpress;Database=PersistMessageDB;Trusted_Connection=True;MultipleActiveResultSets=true;TrustServerCertificate=True"
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
|
||||
@ -14,16 +14,16 @@
|
||||
"Microsoft.EntityFrameworkCore.Database.Command": "Debug"
|
||||
}
|
||||
},
|
||||
"PersistMessageOptions": {
|
||||
"Interval": 1,
|
||||
"Enabled": true,
|
||||
"ConnectionString": "Server=localhost;Port=5432;Database=persist_message_db_test;User Id=postgres;Password=postgres;Include Error Detail=true"
|
||||
},
|
||||
"MongoOptions": {
|
||||
"ConnectionString": "mongodb://localhost:27017",
|
||||
"DatabaseName": "booking-db-test"
|
||||
},
|
||||
"EventStore": {
|
||||
"ConnectionString": "esdb://localhost:2113?tls=false"
|
||||
},
|
||||
"PersistMessageOptions": {
|
||||
"Interval": 30,
|
||||
"Enabled": true,
|
||||
"ConnectionString": "Server=.\\sqlexpress;Database=PersistMessageDB_Test;Trusted_Connection=True;MultipleActiveResultSets=true;TrustServerCertificate=True"
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ using Booking.Booking.Models.ValueObjects;
|
||||
using BuildingBlocks.Core;
|
||||
using BuildingBlocks.Core.CQRS;
|
||||
using BuildingBlocks.EventStoreDB.Repository;
|
||||
using BuildingBlocks.Utils;
|
||||
using BuildingBlocks.Web;
|
||||
using Flight;
|
||||
using Passenger;
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
using System.Threading.RateLimiting;
|
||||
using Booking.Data;
|
||||
using BuildingBlocks.Core;
|
||||
using BuildingBlocks.EFCore;
|
||||
using BuildingBlocks.EventStoreDB;
|
||||
using BuildingBlocks.HealthCheck;
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
@ -11,8 +12,8 @@ using BuildingBlocks.MassTransit;
|
||||
using BuildingBlocks.Mongo;
|
||||
using BuildingBlocks.OpenTelemetry;
|
||||
using BuildingBlocks.PersistMessageProcessor;
|
||||
using BuildingBlocks.PersistMessageProcessor.Data;
|
||||
using BuildingBlocks.Swagger;
|
||||
using BuildingBlocks.Utils;
|
||||
using BuildingBlocks.Web;
|
||||
using Figgle;
|
||||
using FluentValidation;
|
||||
@ -97,6 +98,7 @@ public static class InfrastructureExtensions
|
||||
app.UseCorrelationId();
|
||||
app.UseRouting();
|
||||
app.UseHttpMetrics();
|
||||
app.UseMigration<PersistMessageDbContext>(env);
|
||||
app.UseHttpsRedirection();
|
||||
app.UseCustomHealthCheck();
|
||||
app.MapMetrics();
|
||||
|
||||
@ -3,7 +3,7 @@ using System.Threading.Tasks;
|
||||
using Booking.Api;
|
||||
using Booking.Data;
|
||||
using BuildingBlocks.Contracts.EventBus.Messages;
|
||||
using BuildingBlocks.EFCore;
|
||||
using BuildingBlocks.PersistMessageProcessor.Data;
|
||||
using BuildingBlocks.TestBase;
|
||||
using Flight;
|
||||
using FluentAssertions;
|
||||
@ -19,11 +19,9 @@ using GetByIdRequest = Flight.GetByIdRequest;
|
||||
|
||||
namespace Integration.Test.Booking.Features;
|
||||
|
||||
public class CreateBookingTests : IntegrationTestBase<Program, AppDbContextBase, BookingReadDbContext>
|
||||
public class CreateBookingTests : BookingIntegrationTestBase
|
||||
{
|
||||
public CreateBookingTests(
|
||||
IntegrationTestFixture<Program, AppDbContextBase, BookingReadDbContext> integrationTestFixture) : base(
|
||||
integrationTestFixture)
|
||||
public CreateBookingTests(IntegrationTestFactory<Program, PersistMessageDbContext, BookingReadDbContext> integrationTestFixture) : base(integrationTestFixture)
|
||||
{
|
||||
}
|
||||
|
||||
@ -46,7 +44,7 @@ public class CreateBookingTests : IntegrationTestBase<Program, AppDbContextBase,
|
||||
// Assert
|
||||
response.Should().BeGreaterOrEqualTo(0);
|
||||
|
||||
await Fixture.WaitForPublishing<BookingCreated>();
|
||||
(await Fixture.WaitForPublishing<BookingCreated>()).Should().Be(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
using Booking.Api;
|
||||
using Booking.Data;
|
||||
using BuildingBlocks.PersistMessageProcessor.Data;
|
||||
using BuildingBlocks.TestBase;
|
||||
using Xunit;
|
||||
|
||||
namespace Integration.Test;
|
||||
|
||||
[Collection(IntegrationTestCollection.Name)]
|
||||
public class BookingIntegrationTestBase: IntegrationTestBase<Program, PersistMessageDbContext, BookingReadDbContext>
|
||||
{
|
||||
public BookingIntegrationTestBase(IntegrationTestFactory<Program, PersistMessageDbContext, BookingReadDbContext> integrationTestFixture) : base(integrationTestFixture)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[CollectionDefinition(Name)]
|
||||
public class IntegrationTestCollection : ICollectionFixture<IntegrationTestFactory<Program, PersistMessageDbContext, BookingReadDbContext>>
|
||||
{
|
||||
public const string Name = "Booking Integration Test";
|
||||
}
|
||||
@ -1,8 +1,2 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"DatabaseOptions": {
|
||||
"DefaultConnection": "Server=db;Database=FlightDB;User ID=sa;Password=@Aa123456"
|
||||
},
|
||||
"Jwt": {
|
||||
@ -20,5 +20,10 @@
|
||||
"Password": "guest",
|
||||
"Port": 5672
|
||||
},
|
||||
"PersistMessageOptions": {
|
||||
"Interval": 30,
|
||||
"Enabled": true,
|
||||
"ConnectionString": "Server=db;Database=PersistMessageDB;User ID=sa;Password=@Aa123456"
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
|
||||
@ -35,7 +35,8 @@
|
||||
},
|
||||
"PersistMessageOptions": {
|
||||
"Interval": 30,
|
||||
"Enabled": true
|
||||
"Enabled": true,
|
||||
"ConnectionString": "Server=.\\sqlexpress;Database=PersistMessageDB;Trusted_Connection=True;MultipleActiveResultSets=true;TrustServerCertificate=True"
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
|
||||
@ -18,7 +18,8 @@
|
||||
}
|
||||
},
|
||||
"PersistMessageOptions": {
|
||||
"Interval": 1,
|
||||
"Enabled": true
|
||||
"Interval": 2,
|
||||
"Enabled": true,
|
||||
"ConnectionString": "Server=.\\sqlexpress;Database=PersistMessageDB_Test;Trusted_Connection=True;MultipleActiveResultSets=true;TrustServerCertificate=True"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,45 +0,0 @@
|
||||
using System;
|
||||
using BuildingBlocks.EFCore;
|
||||
using BuildingBlocks.PersistMessageProcessor;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Flight.Data.Configurations;
|
||||
|
||||
public class PersistMessageConfiguration : IEntityTypeConfiguration<PersistMessage>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<PersistMessage> builder)
|
||||
{
|
||||
builder.ToTable("PersistMessage", AppDbContextBase.DefaultSchema);
|
||||
|
||||
builder.HasKey(x => x.Id);
|
||||
builder.Property(r => r.Id).ValueGeneratedNever();
|
||||
|
||||
builder.Property(x => x.Id)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(x => x.DeliveryType)
|
||||
.HasMaxLength(50)
|
||||
.HasConversion(
|
||||
v => v.ToString(),
|
||||
v => (MessageDeliveryType)Enum.Parse(typeof(MessageDeliveryType), v))
|
||||
.IsRequired()
|
||||
.IsUnicode(false);
|
||||
|
||||
builder.Property(x => x.DeliveryType)
|
||||
.HasMaxLength(50)
|
||||
.HasConversion(
|
||||
v => v.ToString(),
|
||||
v => (MessageDeliveryType)Enum.Parse(typeof(MessageDeliveryType), v))
|
||||
.IsRequired()
|
||||
.IsUnicode(false);
|
||||
|
||||
builder.Property(x => x.MessageStatus)
|
||||
.HasMaxLength(50)
|
||||
.HasConversion(
|
||||
v => v.ToString(),
|
||||
v => (MessageStatus)Enum.Parse(typeof(MessageStatus), v))
|
||||
.IsRequired()
|
||||
.IsUnicode(false);
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
using BuildingBlocks.EFCore;
|
||||
using BuildingBlocks.Utils;
|
||||
using BuildingBlocks.Web;
|
||||
using Flight.Aircrafts.Models;
|
||||
using Flight.Airports.Models;
|
||||
using Flight.Seats.Models;
|
||||
|
||||
@ -12,7 +12,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
namespace Flight.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(FlightDbContext))]
|
||||
[Migration("20221203201848_Initial")]
|
||||
[Migration("20221206180723_Initial")]
|
||||
partial class Initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
@ -25,40 +25,6 @@ namespace Flight.Data.Migrations
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("BuildingBlocks.PersistMessageProcessor.PersistMessage", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<DateTime>("Created")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DataType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DeliveryType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<string>("MessageStatus")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<int>("RetryCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PersistMessage", "dbo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Flight.Aircrafts.Models.Aircraft", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
@ -56,24 +56,6 @@ namespace Flight.Data.Migrations
|
||||
table.PrimaryKey("PK_Airport", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PersistMessage",
|
||||
schema: "dbo",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<long>(type: "bigint", nullable: false),
|
||||
DataType = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Data = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Created = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
RetryCount = table.Column<int>(type: "int", nullable: false),
|
||||
MessageStatus = table.Column<string>(type: "varchar(50)", unicode: false, maxLength: 50, nullable: false),
|
||||
DeliveryType = table.Column<string>(type: "varchar(50)", unicode: false, maxLength: 50, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PersistMessage", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Flight",
|
||||
schema: "dbo",
|
||||
@ -167,10 +149,6 @@ namespace Flight.Data.Migrations
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "PersistMessage",
|
||||
schema: "dbo");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Seat",
|
||||
schema: "dbo");
|
||||
@ -22,40 +22,6 @@ namespace Flight.Data.Migrations
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("BuildingBlocks.PersistMessageProcessor.PersistMessage", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<DateTime>("Created")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DataType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DeliveryType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<string>("MessageStatus")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<int>("RetryCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PersistMessage", "dbo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Flight.Aircrafts.Models.Aircraft", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BuildingBlocks.EFCore;
|
||||
using Flight.Aircrafts.Models;
|
||||
using Flight.Aircrafts.Models.Reads;
|
||||
using Flight.Airports.Models;
|
||||
using Flight.Airports.Models.Reads;
|
||||
using Flight.Flights.Models;
|
||||
using Flight.Flights.Models.Reads;
|
||||
using Flight.Seats.Models;
|
||||
using Flight.Seats.Models.Reads;
|
||||
|
||||
@ -66,11 +66,10 @@ public static class InfrastructureExtensions
|
||||
}));
|
||||
});
|
||||
|
||||
builder.Services.AddPersistMessageProcessor();
|
||||
builder.Services.AddCustomDbContext<FlightDbContext>(configuration);
|
||||
builder.Services.AddCustomDbContext<FlightDbContext>();
|
||||
builder.Services.AddScoped<IDataSeeder, FlightDataSeeder>();
|
||||
builder.Services.AddMongoDbContext<FlightReadDbContext>(configuration);
|
||||
|
||||
builder.Services.AddPersistMessageProcessor();
|
||||
|
||||
builder.AddCustomSerilog(env);
|
||||
builder.Services.AddJwt();
|
||||
|
||||
@ -10,11 +10,10 @@ using Xunit;
|
||||
|
||||
namespace Integration.Test.Aircraft.Features;
|
||||
|
||||
public class CreateAircraftTests : IntegrationTestBase<Program, FlightDbContext, FlightReadDbContext>
|
||||
public class CreateAircraftTests : FlightIntegrationTestBase
|
||||
{
|
||||
public CreateAircraftTests(
|
||||
IntegrationTestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(
|
||||
integrationTestFixture)
|
||||
IntegrationTestFactory<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)
|
||||
{
|
||||
}
|
||||
|
||||
@ -31,8 +30,8 @@ public class CreateAircraftTests : IntegrationTestBase<Program, FlightDbContext,
|
||||
response?.Should().NotBeNull();
|
||||
response?.Name.Should().Be(command.Name);
|
||||
|
||||
await Fixture.WaitForPublishing<AircraftCreated>();
|
||||
(await Fixture.WaitForPublishing<AircraftCreated>()).Should().Be(true);
|
||||
|
||||
await Fixture.ShouldProcessedPersistInternalCommand<CreateAircraftMongoCommand>();
|
||||
(await Fixture.ShouldProcessedPersistInternalCommand<CreateAircraftMongoCommand>()).Should().Be(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,11 +10,10 @@ using Xunit;
|
||||
|
||||
namespace Integration.Test.Airport.Features;
|
||||
|
||||
public class CreateAirportTests : IntegrationTestBase<Program, FlightDbContext, FlightReadDbContext>
|
||||
public class CreateAirportTests : FlightIntegrationTestBase
|
||||
{
|
||||
public CreateAirportTests(
|
||||
IntegrationTestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(
|
||||
integrationTestFixture)
|
||||
IntegrationTestFactory<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)
|
||||
{
|
||||
}
|
||||
|
||||
@ -31,8 +30,8 @@ public class CreateAirportTests : IntegrationTestBase<Program, FlightDbContext,
|
||||
response?.Should().NotBeNull();
|
||||
response?.Name.Should().Be(command.Name);
|
||||
|
||||
await Fixture.WaitForPublishing<AirportCreated>();
|
||||
(await Fixture.WaitForPublishing<AirportCreated>()).Should().Be(true);
|
||||
|
||||
await Fixture.ShouldProcessedPersistInternalCommand<CreateAirportMongoCommand>();
|
||||
(await Fixture.ShouldProcessedPersistInternalCommand<CreateAirportMongoCommand>()).Should().Be(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,17 +10,17 @@ using Xunit;
|
||||
|
||||
namespace Integration.Test.Flight.Features;
|
||||
|
||||
public class CreateFlightTests : IntegrationTestBase<Program, FlightDbContext, FlightReadDbContext>
|
||||
public class CreateFlightTests : FlightIntegrationTestBase
|
||||
{
|
||||
public CreateFlightTests(
|
||||
IntegrationTestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(
|
||||
integrationTestFixture)
|
||||
{ }
|
||||
IntegrationTestFactory<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)
|
||||
{
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task should_create_new_flight_to_db_and_publish_message_to_broker()
|
||||
{
|
||||
// Arrange
|
||||
//Arrange
|
||||
var command = new FakeCreateFlightCommand().Generate();
|
||||
|
||||
// Act
|
||||
@ -30,9 +30,9 @@ public class CreateFlightTests : IntegrationTestBase<Program, FlightDbContext, F
|
||||
response.Should().NotBeNull();
|
||||
response?.FlightNumber.Should().Be(command.FlightNumber);
|
||||
|
||||
await Fixture.WaitForPublishing<FlightCreated>();
|
||||
await Fixture.WaitForConsuming<FlightCreated>();
|
||||
(await Fixture.WaitForPublishing<FlightCreated>()).Should().Be(true);
|
||||
(await Fixture.WaitForConsuming<FlightCreated>()).Should().Be(true);
|
||||
|
||||
await Fixture.ShouldProcessedPersistInternalCommand<CreateFlightMongoCommand>();
|
||||
(await Fixture.ShouldProcessedPersistInternalCommand<CreateFlightMongoCommand>()).Should().Be(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,11 +12,10 @@ using Xunit;
|
||||
|
||||
namespace Integration.Test.Flight.Features;
|
||||
|
||||
public class DeleteFlightTests : IntegrationTestBase<Program, FlightDbContext, FlightReadDbContext>
|
||||
public class DeleteFlightTests : FlightIntegrationTestBase
|
||||
{
|
||||
public DeleteFlightTests(
|
||||
IntegrationTestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(
|
||||
integrationTestFixture)
|
||||
IntegrationTestFactory<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)
|
||||
{
|
||||
}
|
||||
|
||||
@ -38,8 +37,8 @@ public class DeleteFlightTests : IntegrationTestBase<Program, FlightDbContext, F
|
||||
// Assert
|
||||
deletedFlight?.IsDeleted.Should().BeTrue();
|
||||
|
||||
await Fixture.WaitForPublishing<FlightDeleted>();
|
||||
(await Fixture.WaitForPublishing<FlightDeleted>()).Should().Be(true);
|
||||
|
||||
await Fixture.ShouldProcessedPersistInternalCommand<DeleteFlightMongoCommand>();
|
||||
(await Fixture.ShouldProcessedPersistInternalCommand<DeleteFlightMongoCommand>()).Should().Be(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,11 +11,10 @@ using Xunit;
|
||||
|
||||
namespace Integration.Test.Flight.Features;
|
||||
|
||||
public class GetAvailableFlightsTests : IntegrationTestBase<Program, FlightDbContext, FlightReadDbContext>
|
||||
public class GetAvailableFlightsTests : FlightIntegrationTestBase
|
||||
{
|
||||
public GetAvailableFlightsTests(
|
||||
IntegrationTestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture)
|
||||
: base(integrationTestFixture)
|
||||
IntegrationTestFactory<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)
|
||||
{
|
||||
}
|
||||
|
||||
@ -27,7 +26,7 @@ public class GetAvailableFlightsTests : IntegrationTestBase<Program, FlightDbCon
|
||||
|
||||
await Fixture.SendAsync(flightCommand);
|
||||
|
||||
await Fixture.ShouldProcessedPersistInternalCommand<CreateFlightMongoCommand>();
|
||||
(await Fixture.ShouldProcessedPersistInternalCommand<CreateFlightMongoCommand>()).Should().Be(true);
|
||||
|
||||
var query = new GetAvailableFlightsQuery();
|
||||
|
||||
|
||||
@ -6,21 +6,16 @@ using Flight.Data;
|
||||
using Flight.Flights.Features.CreateFlight.Commands.V1.Reads;
|
||||
using Flight.Flights.Features.GetFlightById.Queries.V1;
|
||||
using FluentAssertions;
|
||||
using Grpc.Net.Client;
|
||||
using Integration.Test.Fakes;
|
||||
using Xunit;
|
||||
|
||||
namespace Integration.Test.Flight.Features;
|
||||
|
||||
public class GetFlightByIdTests : IntegrationTestBase<Program, FlightDbContext, FlightReadDbContext>
|
||||
public class GetFlightByIdTests : FlightIntegrationTestBase
|
||||
{
|
||||
private readonly GrpcChannel _channel;
|
||||
|
||||
public GetFlightByIdTests(
|
||||
IntegrationTestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(
|
||||
integrationTestFixture)
|
||||
IntegrationTestFactory<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)
|
||||
{
|
||||
_channel = Fixture.Channel;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -30,7 +25,7 @@ public class GetFlightByIdTests : IntegrationTestBase<Program, FlightDbContext,
|
||||
var command = new FakeCreateFlightCommand().Generate();
|
||||
await Fixture.SendAsync(command);
|
||||
|
||||
await Fixture.ShouldProcessedPersistInternalCommand<CreateFlightMongoCommand>();
|
||||
(await Fixture.ShouldProcessedPersistInternalCommand<CreateFlightMongoCommand>()).Should().Be(true);
|
||||
|
||||
var query = new GetFlightByIdQuery(command.Id);
|
||||
|
||||
@ -49,9 +44,9 @@ public class GetFlightByIdTests : IntegrationTestBase<Program, FlightDbContext,
|
||||
var command = new FakeCreateFlightCommand().Generate();
|
||||
await Fixture.SendAsync(command);
|
||||
|
||||
await Fixture.ShouldProcessedPersistInternalCommand<CreateFlightMongoCommand>();
|
||||
(await Fixture.ShouldProcessedPersistInternalCommand<CreateFlightMongoCommand>()).Should().Be(true);
|
||||
|
||||
var flightGrpcClient = new FlightGrpcService.FlightGrpcServiceClient(_channel);
|
||||
var flightGrpcClient = new FlightGrpcService.FlightGrpcServiceClient(Fixture.Channel);
|
||||
|
||||
// Act
|
||||
var response = await flightGrpcClient.GetByIdAsync(new GetByIdRequest {Id = command.Id});
|
||||
|
||||
@ -10,11 +10,10 @@ using Xunit;
|
||||
|
||||
namespace Integration.Test.Flight.Features;
|
||||
|
||||
public class UpdateFlightTests : IntegrationTestBase<Program, FlightDbContext, FlightReadDbContext>
|
||||
public class UpdateFlightTests : FlightIntegrationTestBase
|
||||
{
|
||||
public UpdateFlightTests(
|
||||
IntegrationTestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(
|
||||
integrationTestFixture)
|
||||
IntegrationTestFactory<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)
|
||||
{
|
||||
}
|
||||
|
||||
@ -33,8 +32,8 @@ public class UpdateFlightTests : IntegrationTestBase<Program, FlightDbContext, F
|
||||
response?.Id.Should().Be(flightEntity?.Id);
|
||||
response?.Price.Should().NotBe(flightEntity?.Price);
|
||||
|
||||
await Fixture.WaitForPublishing<FlightUpdated>();
|
||||
(await Fixture.WaitForPublishing<FlightUpdated>()).Should().Be(true);
|
||||
|
||||
await Fixture.ShouldProcessedPersistInternalCommand<UpdateFlightMongoCommand>();
|
||||
(await Fixture.ShouldProcessedPersistInternalCommand<UpdateFlightMongoCommand>()).Should().Be(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
using BuildingBlocks.TestBase;
|
||||
using Flight.Api;
|
||||
using Flight.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace Integration.Test;
|
||||
|
||||
[Collection(IntegrationTestCollection.Name)]
|
||||
public class FlightIntegrationTestBase: IntegrationTestBase<Program, FlightDbContext, FlightReadDbContext>
|
||||
{
|
||||
public FlightIntegrationTestBase(IntegrationTestFactory<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(integrationTestFixture)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[CollectionDefinition(Name)]
|
||||
public class IntegrationTestCollection : ICollectionFixture<IntegrationTestFactory<Program, FlightDbContext, FlightReadDbContext>>
|
||||
{
|
||||
public const string Name = "Flight Integration Test";
|
||||
}
|
||||
@ -6,19 +6,16 @@ using Flight.Data;
|
||||
using Flight.Flights.Features.CreateFlight.Commands.V1.Reads;
|
||||
using Flight.Seats.Features.CreateSeat.Commands.V1.Reads;
|
||||
using FluentAssertions;
|
||||
using Grpc.Net.Client;
|
||||
using Integration.Test.Fakes;
|
||||
using Xunit;
|
||||
|
||||
namespace Integration.Test.Seat.Features;
|
||||
|
||||
public class GetAvailableSeatsTests : IntegrationTestBase<Program, FlightDbContext, FlightReadDbContext>
|
||||
public class GetAvailableSeatsTests : FlightIntegrationTestBase
|
||||
{
|
||||
private readonly GrpcChannel _channel;
|
||||
|
||||
public GetAvailableSeatsTests(IntegrationTestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(integrationTestFixture)
|
||||
public GetAvailableSeatsTests(
|
||||
IntegrationTestFactory<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)
|
||||
{
|
||||
_channel = Fixture.Channel;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -29,15 +26,15 @@ public class GetAvailableSeatsTests : IntegrationTestBase<Program, FlightDbConte
|
||||
|
||||
await Fixture.SendAsync(flightCommand);
|
||||
|
||||
await Fixture.ShouldProcessedPersistInternalCommand<CreateFlightMongoCommand>();
|
||||
(await Fixture.ShouldProcessedPersistInternalCommand<CreateFlightMongoCommand>()).Should().Be(true);
|
||||
|
||||
var seatCommand = new FakeCreateSeatCommand(flightCommand.Id).Generate();
|
||||
|
||||
await Fixture.SendAsync(seatCommand);
|
||||
|
||||
await Fixture.ShouldProcessedPersistInternalCommand<CreateSeatMongoCommand>();
|
||||
(await Fixture.ShouldProcessedPersistInternalCommand<CreateSeatMongoCommand>()).Should().Be(true);
|
||||
|
||||
var flightGrpcClient = new FlightGrpcService.FlightGrpcServiceClient(_channel);
|
||||
var flightGrpcClient = new FlightGrpcService.FlightGrpcServiceClient(Fixture.Channel);
|
||||
|
||||
// Act
|
||||
var response = await flightGrpcClient.GetAvailableSeatsAsync(new GetAvailableSeatsRequest{FlightId = flightCommand.Id});
|
||||
|
||||
@ -6,21 +6,16 @@ using Flight.Data;
|
||||
using Flight.Flights.Features.CreateFlight.Commands.V1.Reads;
|
||||
using Flight.Seats.Features.CreateSeat.Commands.V1.Reads;
|
||||
using FluentAssertions;
|
||||
using Grpc.Net.Client;
|
||||
using Integration.Test.Fakes;
|
||||
using Xunit;
|
||||
|
||||
namespace Integration.Test.Seat.Features;
|
||||
|
||||
public class ReserveSeatTests : IntegrationTestBase<Program, FlightDbContext, FlightReadDbContext>
|
||||
public class ReserveSeatTests : FlightIntegrationTestBase
|
||||
{
|
||||
private readonly GrpcChannel _channel;
|
||||
|
||||
public ReserveSeatTests(
|
||||
IntegrationTestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(
|
||||
integrationTestFixture)
|
||||
IntegrationTestFactory<Program, FlightDbContext, FlightReadDbContext> integrationTestFactory) : base(integrationTestFactory)
|
||||
{
|
||||
_channel = Fixture.Channel;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -31,15 +26,15 @@ public class ReserveSeatTests : IntegrationTestBase<Program, FlightDbContext, Fl
|
||||
|
||||
await Fixture.SendAsync(flightCommand);
|
||||
|
||||
await Fixture.ShouldProcessedPersistInternalCommand<CreateFlightMongoCommand>();
|
||||
(await Fixture.ShouldProcessedPersistInternalCommand<CreateFlightMongoCommand>()).Should().Be(true);
|
||||
|
||||
var seatCommand = new FakeCreateSeatCommand(flightCommand.Id).Generate();
|
||||
|
||||
await Fixture.SendAsync(seatCommand);
|
||||
|
||||
await Fixture.ShouldProcessedPersistInternalCommand<CreateSeatMongoCommand>();
|
||||
(await Fixture.ShouldProcessedPersistInternalCommand<CreateSeatMongoCommand>()).Should().Be(true);
|
||||
|
||||
var flightGrpcClient = new FlightGrpcService.FlightGrpcServiceClient(_channel);
|
||||
var flightGrpcClient = new FlightGrpcService.FlightGrpcServiceClient(Fixture.Channel);
|
||||
|
||||
// Act
|
||||
var response = await flightGrpcClient.ReserveSeatAsync(new ReserveSeatRequest()
|
||||
|
||||
@ -3,6 +3,11 @@
|
||||
"DatabaseOptions": {
|
||||
"DefaultConnection": "Server=db;Database=IdentityDB;User ID=sa;Password=@Aa123456"
|
||||
},
|
||||
"PersistMessageOptions": {
|
||||
"Interval": 30,
|
||||
"Enabled": true,
|
||||
"ConnectionString": "Server=db;Database=PersistMessageDB;User ID=sa;Password=@Aa123456"
|
||||
},
|
||||
"RabbitMqOptions": {
|
||||
"HostName": "rabbitmq",
|
||||
"ExchangeName": "identity",
|
||||
|
||||
@ -31,7 +31,8 @@
|
||||
},
|
||||
"PersistMessageOptions": {
|
||||
"Interval": 30,
|
||||
"Enabled": true
|
||||
"Enabled": true,
|
||||
"ConnectionString": "Server=.\\sqlexpress;Database=PersistMessageDB;Trusted_Connection=True;MultipleActiveResultSets=true;TrustServerCertificate=True"
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
|
||||
@ -18,7 +18,8 @@
|
||||
}
|
||||
},
|
||||
"PersistMessageOptions": {
|
||||
"Interval": 1,
|
||||
"Enabled": true
|
||||
"Interval": 30,
|
||||
"Enabled": true,
|
||||
"ConnectionString": "Server=.\\sqlexpress;Database=PersistMessageDB_Test;Trusted_Connection=True;MultipleActiveResultSets=true;TrustServerCertificate=True"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,44 +0,0 @@
|
||||
using System;
|
||||
using BuildingBlocks.EFCore;
|
||||
using BuildingBlocks.PersistMessageProcessor;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Identity.Data.Configurations;
|
||||
|
||||
public class PersistMessageConfiguration : IEntityTypeConfiguration<PersistMessage>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<PersistMessage> builder)
|
||||
{
|
||||
builder.ToTable("PersistMessage", AppDbContextBase.DefaultSchema);
|
||||
|
||||
builder.HasKey(x => x.Id);
|
||||
|
||||
builder.Property(x => x.Id)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(x => x.DeliveryType)
|
||||
.HasMaxLength(50)
|
||||
.HasConversion(
|
||||
v => v.ToString(),
|
||||
v => (MessageDeliveryType)Enum.Parse(typeof(MessageDeliveryType), v))
|
||||
.IsRequired()
|
||||
.IsUnicode(false);
|
||||
|
||||
builder.Property(x => x.DeliveryType)
|
||||
.HasMaxLength(50)
|
||||
.HasConversion(
|
||||
v => v.ToString(),
|
||||
v => (MessageDeliveryType)Enum.Parse(typeof(MessageDeliveryType), v))
|
||||
.IsRequired()
|
||||
.IsUnicode(false);
|
||||
|
||||
builder.Property(x => x.MessageStatus)
|
||||
.HasMaxLength(50)
|
||||
.HasConversion(
|
||||
v => v.ToString(),
|
||||
v => (MessageStatus)Enum.Parse(typeof(MessageStatus), v))
|
||||
.IsRequired()
|
||||
.IsUnicode(false);
|
||||
}
|
||||
}
|
||||
@ -12,7 +12,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
namespace Identity.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(IdentityContext))]
|
||||
[Migration("20221203211306_initial")]
|
||||
[Migration("20221206180831_initial")]
|
||||
partial class initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
@ -25,43 +25,6 @@ namespace Identity.Data.Migrations
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("BuildingBlocks.PersistMessageProcessor.PersistMessage", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<DateTime>("Created")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DataType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DeliveryType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<string>("MessageStatus")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<int>("RetryCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PersistMessage", "dbo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Identity.Identity.Models.ApplicationUser", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
@ -60,25 +60,6 @@ namespace Identity.Data.Migrations
|
||||
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PersistMessage",
|
||||
schema: "dbo",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<long>(type: "bigint", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
DataType = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Data = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Created = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
RetryCount = table.Column<int>(type: "int", nullable: false),
|
||||
MessageStatus = table.Column<string>(type: "varchar(50)", unicode: false, maxLength: 50, nullable: false),
|
||||
DeliveryType = table.Column<string>(type: "varchar(50)", unicode: false, maxLength: 50, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PersistMessage", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoleClaims",
|
||||
schema: "dbo",
|
||||
@ -266,10 +247,6 @@ namespace Identity.Data.Migrations
|
||||
name: "AspNetUserTokens",
|
||||
schema: "dbo");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "PersistMessage",
|
||||
schema: "dbo");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRoles",
|
||||
schema: "dbo");
|
||||
@ -22,43 +22,6 @@ namespace Identity.Data.Migrations
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("BuildingBlocks.PersistMessageProcessor.PersistMessage", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<DateTime>("Created")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DataType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DeliveryType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<string>("MessageStatus")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<int>("RetryCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PersistMessage", "dbo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Identity.Identity.Models.ApplicationUser", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
|
||||
@ -57,7 +57,7 @@ public static class InfrastructureExtensions
|
||||
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddPersistMessageProcessor();
|
||||
builder.Services.AddCustomDbContext<IdentityContext>(configuration);
|
||||
builder.Services.AddCustomDbContext<IdentityContext>();
|
||||
builder.Services.AddScoped<IDataSeeder, IdentityDataSeeder>();
|
||||
builder.AddCustomSerilog(env);
|
||||
builder.Services.AddCustomSwagger(configuration, typeof(IdentityRoot).Assembly);
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Data\Configurations" />
|
||||
<Folder Include="Data\Migrations" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@ -5,16 +5,14 @@ using FluentAssertions;
|
||||
using Identity.Api;
|
||||
using Identity.Data;
|
||||
using Integration.Test.Fakes;
|
||||
using MassTransit;
|
||||
using MassTransit.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Integration.Test.Identity.Features;
|
||||
|
||||
public class RegisterNewUserTests : IntegrationTestBase<Program, IdentityContext>
|
||||
public class RegisterNewUserTests : IdentityIntegrationTestBase
|
||||
{
|
||||
public RegisterNewUserTests(IntegrationTestFixture<Program, IdentityContext> integrationTestFixture) : base(
|
||||
integrationTestFixture)
|
||||
public RegisterNewUserTests(
|
||||
IntegrationTestFactory<Program, IdentityContext> integrationTestFactory) : base(integrationTestFactory)
|
||||
{
|
||||
}
|
||||
|
||||
@ -31,6 +29,6 @@ public class RegisterNewUserTests : IntegrationTestBase<Program, IdentityContext
|
||||
response?.Should().NotBeNull();
|
||||
response?.Username.Should().Be(command.Username);
|
||||
|
||||
await Fixture.WaitForPublishing<UserCreated>();
|
||||
(await Fixture.WaitForPublishing<UserCreated>()).Should().Be(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
using BuildingBlocks.TestBase;
|
||||
using Identity.Api;
|
||||
using Identity.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace Integration.Test;
|
||||
|
||||
[Collection(IntegrationTestCollection.Name)]
|
||||
public class IdentityIntegrationTestBase: IntegrationTestBase<Program, IdentityContext>
|
||||
{
|
||||
public IdentityIntegrationTestBase(IntegrationTestFactory<Program, IdentityContext> integrationTestFactory)
|
||||
: base(integrationTestFactory)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[CollectionDefinition(Name)]
|
||||
public class IntegrationTestCollection : ICollectionFixture<IntegrationTestFactory<Program, IdentityContext>>
|
||||
{
|
||||
public const string Name = "Identity Integration Test";
|
||||
}
|
||||
@ -3,6 +3,11 @@
|
||||
"DatabaseOptions": {
|
||||
"DefaultConnection": "Server=db;Database=PassengerDB;User ID=sa;Password=@Aa123456"
|
||||
},
|
||||
"PersistMessageOptions": {
|
||||
"Interval": 30,
|
||||
"Enabled": true,
|
||||
"ConnectionString": "Server=db;Database=PersistMessageDB;User ID=sa;Password=@Aa123456"
|
||||
},
|
||||
"Jwt": {
|
||||
"Authority": "https://localhost:5005",
|
||||
"Audience": "passenger-api"
|
||||
|
||||
@ -35,7 +35,8 @@
|
||||
},
|
||||
"PersistMessageOptions": {
|
||||
"Interval": 30,
|
||||
"Enabled": true
|
||||
"Enabled": true,
|
||||
"ConnectionString": "Server=.\\sqlexpress;Database=PersistMessageDB;Trusted_Connection=True;MultipleActiveResultSets=true;TrustServerCertificate=True"
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
|
||||
@ -18,7 +18,8 @@
|
||||
}
|
||||
},
|
||||
"PersistMessageOptions": {
|
||||
"Interval": 1,
|
||||
"Enabled": true
|
||||
"Interval": 30,
|
||||
"Enabled": true,
|
||||
"ConnectionString": "Server=.\\sqlexpress;Database=PersistMessageDB_Test;Trusted_Connection=True;MultipleActiveResultSets=true;TrustServerCertificate=True"
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ using Passenger.Data;
|
||||
namespace Passenger.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(PassengerDbContext))]
|
||||
[Migration("20221203211633_initial")]
|
||||
[Migration("20221206180929_initial")]
|
||||
partial class initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
@ -25,43 +25,6 @@ namespace Passenger.Data.Migrations
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("BuildingBlocks.PersistMessageProcessor.PersistMessage", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<DateTime>("Created")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DataType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DeliveryType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<string>("MessageStatus")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<int>("RetryCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PersistMessage", "dbo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Passenger.Passengers.Models.Passenger", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
@ -35,25 +35,6 @@ namespace Passenger.Data.Migrations
|
||||
{
|
||||
table.PrimaryKey("PK_Passenger", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PersistMessage",
|
||||
schema: "dbo",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<long>(type: "bigint", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
DataType = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Data = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Created = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
RetryCount = table.Column<int>(type: "int", nullable: false),
|
||||
MessageStatus = table.Column<string>(type: "varchar(50)", unicode: false, maxLength: 50, nullable: false),
|
||||
DeliveryType = table.Column<string>(type: "varchar(50)", unicode: false, maxLength: 50, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PersistMessage", x => x.Id);
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -62,10 +43,6 @@ namespace Passenger.Data.Migrations
|
||||
migrationBuilder.DropTable(
|
||||
name: "Passenger",
|
||||
schema: "dbo");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "PersistMessage",
|
||||
schema: "dbo");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -22,43 +22,6 @@ namespace Passenger.Data.Migrations
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("BuildingBlocks.PersistMessageProcessor.PersistMessage", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<DateTime>("Created")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DataType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DeliveryType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<string>("MessageStatus")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<int>("RetryCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PersistMessage", "dbo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Passenger.Passengers.Models.Passenger", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
|
||||
@ -1,15 +1,12 @@
|
||||
using System.Reflection;
|
||||
using BuildingBlocks.EFCore;
|
||||
using BuildingBlocks.Utils;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using BuildingBlocks.Web;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Passenger.Data;
|
||||
|
||||
public sealed class PassengerDbContext : AppDbContextBase
|
||||
{
|
||||
public const string DefaultSchema = "dbo";
|
||||
|
||||
public PassengerDbContext(DbContextOptions<PassengerDbContext> options, ICurrentUserProvider currentUserProvider) : base(options, currentUserProvider)
|
||||
{
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ public static class InfrastructureExtensions
|
||||
});
|
||||
|
||||
builder.Services.AddPersistMessageProcessor();
|
||||
builder.Services.AddCustomDbContext<PassengerDbContext>(configuration);
|
||||
builder.Services.AddCustomDbContext<PassengerDbContext>();
|
||||
builder.Services.AddMongoDbContext<PassengerReadDbContext>(configuration);
|
||||
|
||||
builder.AddCustomSerilog(env);
|
||||
|
||||
@ -9,7 +9,7 @@ public class FakeUserCreated : AutoFaker<UserCreated>
|
||||
public FakeUserCreated()
|
||||
{
|
||||
RuleFor(r => r.Id, _ => SnowFlakIdGenerator.NewId());
|
||||
RuleFor(r => r.Name, _ => "Meysam");
|
||||
RuleFor(r => r.PassportNumber, _ => "1299878");
|
||||
RuleFor(r => r.Name, _ => "Sam");
|
||||
RuleFor(r => r.PassportNumber, _ => "123456789");
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,18 +3,16 @@ using BuildingBlocks.Contracts.EventBus.Messages;
|
||||
using BuildingBlocks.TestBase;
|
||||
using FluentAssertions;
|
||||
using Integration.Test.Fakes;
|
||||
using MassTransit.Testing;
|
||||
using Passenger.Api;
|
||||
using Passenger.Data;
|
||||
using Passenger.Passengers.Features.CompleteRegisterPassenger.Commands.V1.Reads;
|
||||
using Xunit;
|
||||
|
||||
namespace Integration.Test.Passenger.Features;
|
||||
|
||||
public class CompleteRegisterPassengerTests : IntegrationTestBase<Program, PassengerDbContext>
|
||||
public class CompleteRegisterPassengerTests : PassengerIntegrationTestBase
|
||||
{
|
||||
public CompleteRegisterPassengerTests(IntegrationTestFixture<Program, PassengerDbContext> integrationTestFixture) :
|
||||
base(integrationTestFixture)
|
||||
public CompleteRegisterPassengerTests(
|
||||
IntegrationTestFactory<Program, PassengerDbContext> integrationTestFactory) : base(integrationTestFactory)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,7 @@
|
||||
using System.Threading.Tasks;
|
||||
using BuildingBlocks.Contracts.EventBus.Messages;
|
||||
using BuildingBlocks.TestBase;
|
||||
using FluentAssertions;
|
||||
using Grpc.Net.Client;
|
||||
using Integration.Test.Fakes;
|
||||
using MassTransit.Testing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Passenger;
|
||||
using Passenger.Api;
|
||||
using Passenger.Data;
|
||||
@ -14,17 +10,13 @@ using Xunit;
|
||||
|
||||
namespace Integration.Test.Passenger.Features;
|
||||
|
||||
public class GetPassengerByIdTests : IntegrationTestBase<Program, PassengerDbContext>
|
||||
public class GetPassengerByIdTests : PassengerIntegrationTestBase
|
||||
{
|
||||
private readonly GrpcChannel _channel;
|
||||
|
||||
public GetPassengerByIdTests(IntegrationTestFixture<Program, PassengerDbContext> integrationTestFixture) : base(
|
||||
integrationTestFixture)
|
||||
public GetPassengerByIdTests(
|
||||
IntegrationTestFactory<Program, PassengerDbContext> integrationTestFactory) : base(integrationTestFactory)
|
||||
{
|
||||
_channel = Fixture.Channel;
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task should_retrive_a_passenger_by_id_currectly()
|
||||
{
|
||||
@ -53,7 +45,7 @@ public class GetPassengerByIdTests : IntegrationTestBase<Program, PassengerDbCon
|
||||
var passengerEntity = FakePassengerCreated.Generate(userCreated);
|
||||
await Fixture.InsertAsync(passengerEntity);
|
||||
|
||||
var passengerGrpcClient = new PassengerGrpcService.PassengerGrpcServiceClient(_channel);
|
||||
var passengerGrpcClient = new PassengerGrpcService.PassengerGrpcServiceClient(Fixture.Channel);
|
||||
|
||||
// Act
|
||||
var response = await passengerGrpcClient.GetByIdAsync(new GetByIdRequest {Id = passengerEntity.Id});
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
using BuildingBlocks.TestBase;
|
||||
using Passenger.Api;
|
||||
using Passenger.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace Integration.Test;
|
||||
|
||||
[Collection(IntegrationTestCollection.Name)]
|
||||
public class PassengerIntegrationTestBase: IntegrationTestBase<Program, PassengerDbContext>
|
||||
{
|
||||
public PassengerIntegrationTestBase(IntegrationTestFactory<Program, PassengerDbContext> integrationTestFactory)
|
||||
: base(integrationTestFactory)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[CollectionDefinition(Name)]
|
||||
public class IntegrationTestCollection : ICollectionFixture<IntegrationTestFactory<Program, PassengerDbContext>>
|
||||
{
|
||||
public const string Name = "Passenger Integration Test";
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user