mirror of
https://github.com/meysamhadeli/booking-microservices.git
synced 2026-04-14 20:54:05 +08:00
commit
271e752af8
1
assets/microservices.drawio
Normal file
1
assets/microservices.drawio
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="Electron" modified="2022-06-29T20:19:24.031Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/19.0.2 Chrome/102.0.5005.63 Electron/19.0.3 Safari/537.36" etag="Qjh03weoUslFN_OtWUfm" version="19.0.2" type="device"><diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">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</diagram></mxfile>
|
||||
@ -25,6 +25,7 @@
|
||||
<PackageReference Include="MagicOnion.Abstractions" Version="4.4.0" />
|
||||
<PackageReference Include="MagicOnion.Client" Version="4.4.0" />
|
||||
<PackageReference Include="MagicOnion.Server" Version="4.4.0" />
|
||||
<PackageReference Include="Mongo2Go" Version="3.1.3" />
|
||||
<PackageReference Include="NSubstitute" Version="4.3.0" />
|
||||
<PackageReference Include="Polly" Version="7.2.3" />
|
||||
<PackageReference Include="protobuf-net.BuildTools" Version="3.0.115">
|
||||
|
||||
@ -4,5 +4,5 @@ namespace BuildingBlocks.Core.Event;
|
||||
public enum EventType
|
||||
{
|
||||
IntegrationEvent = 1,
|
||||
DomainEvent = 2,
|
||||
DomainEvent = 2
|
||||
}
|
||||
|
||||
@ -2,5 +2,4 @@ namespace BuildingBlocks.Core.Event;
|
||||
|
||||
public interface IDomainEvent : IEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -30,36 +30,43 @@ public sealed class EventDispatcher : IEventDispatcher
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public async Task SendAsync(IDomainEvent domainEvent,
|
||||
CancellationToken cancellationToken = default) => await SendAsync(new[] {domainEvent}, cancellationToken);
|
||||
|
||||
public async Task SendAsync(IReadOnlyList<IDomainEvent> domainEvents, CancellationToken cancellationToken = default)
|
||||
public async Task SendAsync<T>(IReadOnlyList<T> events, CancellationToken cancellationToken = default)
|
||||
where T : IEvent
|
||||
{
|
||||
if (domainEvents is null) return;
|
||||
|
||||
var integrationEvents = await MapDomainEventToIntegrationEventAsync(domainEvents).ConfigureAwait(false);
|
||||
|
||||
if (integrationEvents.Count == 0) return;
|
||||
|
||||
foreach (var integrationEvent in integrationEvents)
|
||||
async Task PublishIntegrationEvent(IReadOnlyList<IIntegrationEvent> integrationEvents)
|
||||
{
|
||||
await _persistMessageProcessor.PublishMessageAsync(new MessageEnvelope(integrationEvent, SetHeaders()),
|
||||
cancellationToken);
|
||||
foreach (var integrationEvent in integrationEvents)
|
||||
{
|
||||
await _persistMessageProcessor.PublishMessageAsync(new MessageEnvelope(integrationEvent, SetHeaders()),
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
if (events.Count > 0)
|
||||
{
|
||||
switch (events)
|
||||
{
|
||||
case IReadOnlyList<IDomainEvent> domainEvents:
|
||||
{
|
||||
var integrationEvents = await MapDomainEventToIntegrationEventAsync(domainEvents)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
await PublishIntegrationEvent(integrationEvents);
|
||||
break;
|
||||
}
|
||||
|
||||
case IReadOnlyList<IIntegrationEvent> integrationEvents:
|
||||
await PublishIntegrationEvent(integrationEvents);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SendAsync<T>(T @event, CancellationToken cancellationToken = default)
|
||||
where T : IEvent =>
|
||||
await SendAsync(new[] {@event}, cancellationToken);
|
||||
|
||||
public async Task SendAsync(IIntegrationEvent integrationEvent,
|
||||
CancellationToken cancellationToken = default) => await SendAsync(new[] {integrationEvent}, cancellationToken);
|
||||
|
||||
public async Task SendAsync(IReadOnlyList<IIntegrationEvent> integrationEvents,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (integrationEvents is null) return;
|
||||
|
||||
await _persistMessageProcessor.PublishMessageAsync(new MessageEnvelope(integrationEvents, SetHeaders()),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
private Task<IReadOnlyList<IIntegrationEvent>> MapDomainEventToIntegrationEventAsync(
|
||||
IReadOnlyList<IDomainEvent> events)
|
||||
|
||||
@ -4,9 +4,8 @@ namespace BuildingBlocks.Core;
|
||||
|
||||
public interface IEventDispatcher
|
||||
{
|
||||
public Task SendAsync(IReadOnlyList<IDomainEvent> domainEvents, CancellationToken cancellationToken = default);
|
||||
public Task SendAsync(IDomainEvent domainEvent, CancellationToken cancellationToken = default);
|
||||
|
||||
public Task SendAsync(IIntegrationEvent integrationEvent, CancellationToken cancellationToken = default);
|
||||
public Task SendAsync(IReadOnlyList<IIntegrationEvent> integrationEvents, CancellationToken cancellationToken = default);
|
||||
public Task SendAsync<T>(IReadOnlyList<T> events, CancellationToken cancellationToken = default)
|
||||
where T : IEvent;
|
||||
public Task SendAsync<T>(T @event, CancellationToken cancellationToken = default)
|
||||
where T : IEvent;
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
using System.Data;
|
||||
using System.Text.Json;
|
||||
using BuildingBlocks.Core;
|
||||
using BuildingBlocks.Core.Event;
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using BuildingBlocks.Core;
|
||||
using BuildingBlocks.Mongo;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Bson.Serialization.Conventions;
|
||||
using MongoDB.Driver;
|
||||
@ -13,12 +14,12 @@ public class MongoDbContext : IMongoDbContext
|
||||
public IMongoClient MongoClient { get; }
|
||||
protected readonly IList<Func<Task>> _commands;
|
||||
|
||||
public MongoDbContext(MongoOptions options)
|
||||
public MongoDbContext(IOptions<MongoOptions> options)
|
||||
{
|
||||
RegisterConventions();
|
||||
|
||||
MongoClient = new MongoClient(options.ConnectionString);
|
||||
var databaseName = options.DatabaseName;
|
||||
MongoClient = new MongoClient(options.Value.ConnectionString);
|
||||
var databaseName = options.Value.DatabaseName;
|
||||
Database = MongoClient.GetDatabase(databaseName);
|
||||
|
||||
// Every command will be stored and it'll be processed at SaveChanges
|
||||
|
||||
@ -9,7 +9,7 @@ public class BookingDbContext : AppDbContextBase
|
||||
{
|
||||
public const string DefaultSchema = "dbo";
|
||||
|
||||
public BookingDbContext(DbContextOptions options, IHttpContextAccessor httpContextAccessor) : base(options, httpContextAccessor)
|
||||
public BookingDbContext(DbContextOptions<BookingDbContext> options, IHttpContextAccessor httpContextAccessor) : base(options, httpContextAccessor)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@ -24,13 +24,6 @@ public class CreateBookingTests
|
||||
public CreateBookingTests(IntegrationTestFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
|
||||
_fixture.RegisterTestServices(services =>
|
||||
{
|
||||
MockFlightGrpcServices(services);
|
||||
MockPassengerGrpcServices(services);
|
||||
});
|
||||
|
||||
_testHarness = fixture.TestHarness;
|
||||
_channel = fixture.Channel;
|
||||
}
|
||||
@ -48,36 +41,4 @@ public class CreateBookingTests
|
||||
// Assert
|
||||
response.Should().BeGreaterOrEqualTo(0);
|
||||
}
|
||||
|
||||
private void MockPassengerGrpcServices(IServiceCollection services)
|
||||
{
|
||||
services.Replace(ServiceDescriptor.Singleton(x =>
|
||||
{
|
||||
var mock = Substitute.For<IPassengerGrpcService>();
|
||||
mock.GetById(Arg.Any<long>())
|
||||
.Returns(new UnaryResult<PassengerResponseDto>(new FakePassengerResponseDto().Generate()));
|
||||
|
||||
return mock;
|
||||
}));
|
||||
}
|
||||
|
||||
private void MockFlightGrpcServices(IServiceCollection services)
|
||||
{
|
||||
services.Replace(ServiceDescriptor.Singleton(x =>
|
||||
{
|
||||
var mock = Substitute.For<IFlightGrpcService>();
|
||||
|
||||
mock.GetById(Arg.Any<long>())
|
||||
.Returns(new UnaryResult<FlightResponseDto>(Task.FromResult(new FakeFlightResponseDto().Generate())));
|
||||
|
||||
mock.GetAvailableSeats(Arg.Any<long>())
|
||||
.Returns(
|
||||
new UnaryResult<IEnumerable<SeatResponseDto>>(Task.FromResult(FakeSeatsResponseDto.Generate())));
|
||||
|
||||
mock.ReserveSeat(new FakeReserveSeatRequestDto().Generate())
|
||||
.Returns(new UnaryResult<SeatResponseDto>(Task.FromResult(FakeSeatsResponseDto.Generate().First())));
|
||||
|
||||
return mock;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Booking.Data;
|
||||
using BuildingBlocks.Contracts.Grpc;
|
||||
using BuildingBlocks.Core.Model;
|
||||
using BuildingBlocks.MassTransit;
|
||||
using BuildingBlocks.Mongo;
|
||||
using BuildingBlocks.Web;
|
||||
using Grpc.Net.Client;
|
||||
using Integration.Test.Fakes;
|
||||
using MagicOnion;
|
||||
using MassTransit;
|
||||
using MassTransit.Testing;
|
||||
using MediatR;
|
||||
@ -16,6 +22,8 @@ using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Mongo2Go;
|
||||
using NSubstitute;
|
||||
using Respawn;
|
||||
using Serilog;
|
||||
@ -32,10 +40,11 @@ public class FixtureCollection : ICollectionFixture<IntegrationTestFixture>
|
||||
public class IntegrationTestFixture : IAsyncLifetime
|
||||
{
|
||||
private WebApplicationFactory<Program> _factory;
|
||||
public Checkpoint Checkpoint { get; set; }
|
||||
public Action<IServiceCollection>? TestRegistrationServices { get; set; }
|
||||
public IServiceProvider ServiceProvider => _factory.Services;
|
||||
public IConfiguration Configuration => _factory.Services.GetRequiredService<IConfiguration>();
|
||||
private Checkpoint _checkpoint;
|
||||
private MongoDbRunner _mongoRunner;
|
||||
private IServiceProvider _serviceProvider;
|
||||
private Action<IServiceCollection>? _testRegistrationServices;
|
||||
private IConfiguration _configuration;
|
||||
public HttpClient HttpClient => _factory.CreateClient();
|
||||
public ITestHarness TestHarness => CreateHarness();
|
||||
public GrpcChannel Channel => CreateChannel();
|
||||
@ -48,66 +57,78 @@ public class IntegrationTestFixture : IAsyncLifetime
|
||||
builder.UseEnvironment("test");
|
||||
builder.ConfigureServices(services =>
|
||||
{
|
||||
services.ReplaceSingleton(AddHttpContextAccessorMock);
|
||||
TestRegistrationServices?.Invoke(services);
|
||||
services.AddMassTransitTestHarness(x =>
|
||||
{
|
||||
x.UsingRabbitMq((context, cfg) =>
|
||||
{
|
||||
var rabbitMqOptions = services.GetOptions<RabbitMqOptions>("RabbitMq");
|
||||
var host = rabbitMqOptions.HostName;
|
||||
|
||||
cfg.Host(host, h =>
|
||||
{
|
||||
h.Username(rabbitMqOptions.UserName);
|
||||
h.Password(rabbitMqOptions.Password);
|
||||
});
|
||||
cfg.ConfigureEndpoints(context);
|
||||
});
|
||||
});
|
||||
|
||||
Checkpoint = new Checkpoint {TablesToIgnore = new[] {"__EFMigrationsHistory"}};
|
||||
|
||||
TestRegistrationServices?.Invoke(services);
|
||||
_testRegistrationServices?.Invoke(services);
|
||||
});
|
||||
});
|
||||
|
||||
RegisterServices(services =>
|
||||
{
|
||||
MockFlightGrpcServices(services);
|
||||
MockPassengerGrpcServices(services);
|
||||
services.ReplaceSingleton(AddHttpContextAccessorMock);
|
||||
services.AddMassTransitTestHarness(x =>
|
||||
{
|
||||
x.UsingRabbitMq((context, cfg) =>
|
||||
{
|
||||
var rabbitMqOptions = services.GetOptions<RabbitMqOptions>("RabbitMq");
|
||||
var host = rabbitMqOptions.HostName;
|
||||
|
||||
cfg.Host(host, h =>
|
||||
{
|
||||
h.Username(rabbitMqOptions.UserName);
|
||||
h.Password(rabbitMqOptions.Password);
|
||||
});
|
||||
cfg.ConfigureEndpoints(context);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
_serviceProvider = _factory.Services;
|
||||
_configuration = _factory.Services.GetRequiredService<IConfiguration>();
|
||||
|
||||
_checkpoint = new Checkpoint {TablesToIgnore = new[] {"__EFMigrationsHistory"}};
|
||||
|
||||
_mongoRunner = MongoDbRunner.Start();
|
||||
var mongoOptions = _factory.Services.GetRequiredService<IOptions<MongoOptions>>();
|
||||
if (mongoOptions.Value.ConnectionString != null)
|
||||
mongoOptions.Value.ConnectionString = _mongoRunner.ConnectionString;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void RegisterServices(Action<IServiceCollection> services) => _testRegistrationServices = services;
|
||||
|
||||
public virtual async Task DisposeAsync()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Configuration?.GetConnectionString("DefaultConnection")))
|
||||
await Checkpoint.Reset(Configuration?.GetConnectionString("DefaultConnection"));
|
||||
if (!string.IsNullOrEmpty(_configuration?.GetConnectionString("DefaultConnection")))
|
||||
await _checkpoint.Reset(_configuration?.GetConnectionString("DefaultConnection"));
|
||||
|
||||
await _factory.DisposeAsync();
|
||||
_mongoRunner.Dispose();
|
||||
}
|
||||
|
||||
// ref: https://github.com/trbenning/serilog-sinks-xunit
|
||||
public ILogger CreateLogger(ITestOutputHelper output)
|
||||
{
|
||||
if (output != null)
|
||||
{
|
||||
return new LoggerConfiguration()
|
||||
.WriteTo.TestOutput(output)
|
||||
.CreateLogger();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void RegisterTestServices(Action<IServiceCollection> services)
|
||||
{
|
||||
TestRegistrationServices = services;
|
||||
}
|
||||
|
||||
public async Task ExecuteScopeAsync(Func<IServiceProvider, Task> action)
|
||||
{
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
await action(scope.ServiceProvider);
|
||||
}
|
||||
|
||||
public async Task<T> ExecuteScopeAsync<T>(Func<IServiceProvider, Task<T>> action)
|
||||
{
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
|
||||
var result = await action(scope.ServiceProvider);
|
||||
|
||||
@ -238,7 +259,7 @@ public class IntegrationTestFixture : IAsyncLifetime
|
||||
|
||||
private ITestHarness CreateHarness()
|
||||
{
|
||||
var harness = ServiceProvider.GetTestHarness();
|
||||
var harness = _serviceProvider.GetTestHarness();
|
||||
harness.Start().GetAwaiter().GetResult();
|
||||
return harness;
|
||||
}
|
||||
@ -259,4 +280,36 @@ public class IntegrationTestFixture : IAsyncLifetime
|
||||
|
||||
return httpContextAccessorMock;
|
||||
}
|
||||
|
||||
private void MockPassengerGrpcServices(IServiceCollection services)
|
||||
{
|
||||
services.Replace(ServiceDescriptor.Singleton(x =>
|
||||
{
|
||||
var mock = Substitute.For<IPassengerGrpcService>();
|
||||
mock.GetById(Arg.Any<long>())
|
||||
.Returns(new UnaryResult<PassengerResponseDto>(new FakePassengerResponseDto().Generate()));
|
||||
|
||||
return mock;
|
||||
}));
|
||||
}
|
||||
|
||||
private void MockFlightGrpcServices(IServiceCollection services)
|
||||
{
|
||||
services.Replace(ServiceDescriptor.Singleton(x =>
|
||||
{
|
||||
var mock = Substitute.For<IFlightGrpcService>();
|
||||
|
||||
mock.GetById(Arg.Any<long>())
|
||||
.Returns(new UnaryResult<FlightResponseDto>(Task.FromResult(new FakeFlightResponseDto().Generate())));
|
||||
|
||||
mock.GetAvailableSeats(Arg.Any<long>())
|
||||
.Returns(
|
||||
new UnaryResult<IEnumerable<SeatResponseDto>>(Task.FromResult(FakeSeatsResponseDto.Generate())));
|
||||
|
||||
mock.ReserveSeat(new FakeReserveSeatRequestDto().Generate())
|
||||
.Returns(new UnaryResult<SeatResponseDto>(Task.FromResult(FakeSeatsResponseDto.Generate().First())));
|
||||
|
||||
return mock;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ namespace Flight.Data;
|
||||
|
||||
public class FlightReadDbContext : MongoDbContext
|
||||
{
|
||||
public FlightReadDbContext(IOptions<MongoOptions> options) : base(options.Value)
|
||||
public FlightReadDbContext(IOptions<MongoOptions> options) : base(options)
|
||||
{
|
||||
Flight = GetCollection<FlightReadModel>(nameof(Flight).Underscore());
|
||||
}
|
||||
|
||||
@ -1,11 +1,15 @@
|
||||
using System.Threading;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Ardalis.GuardClauses;
|
||||
using BuildingBlocks.Core.CQRS;
|
||||
using Flight.Data;
|
||||
using Flight.Flights.Exceptions;
|
||||
using Flight.Flights.Models.Reads;
|
||||
using MapsterMapper;
|
||||
using MediatR;
|
||||
using MongoDB.Driver;
|
||||
using MongoDB.Driver.Linq;
|
||||
|
||||
namespace Flight.Flights.Features.CreateFlight.Reads;
|
||||
|
||||
@ -28,6 +32,12 @@ public class CreateFlightMongoCommandHandler : ICommandHandler<CreateFlightMongo
|
||||
|
||||
var flightReadModel = _mapper.Map<FlightReadModel>(command);
|
||||
|
||||
var flight = await _flightReadDbContext.Flight.AsQueryable()
|
||||
.FirstOrDefaultAsync(x => x.Id == command.Id, cancellationToken);
|
||||
|
||||
if (flight is not null)
|
||||
throw new FlightAlreadyExistException();
|
||||
|
||||
await _flightReadDbContext.Flight.InsertOneAsync(flightReadModel, cancellationToken: cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
|
||||
@ -2,12 +2,10 @@
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using BuildingBlocks.Core.Model;
|
||||
using BuildingBlocks.EFCore;
|
||||
using BuildingBlocks.MassTransit;
|
||||
using BuildingBlocks.MessageProcessor;
|
||||
using BuildingBlocks.Mongo;
|
||||
using BuildingBlocks.Web;
|
||||
using Flight.Data;
|
||||
using FluentAssertions.Common;
|
||||
using Grpc.Net.Client;
|
||||
using MassTransit;
|
||||
using MassTransit.Testing;
|
||||
@ -15,11 +13,10 @@ using MediatR;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Mongo2Go;
|
||||
using NSubstitute;
|
||||
using Respawn;
|
||||
using Serilog;
|
||||
@ -35,15 +32,76 @@ public class FixtureCollection : ICollectionFixture<IntegrationTestFixture>
|
||||
|
||||
public class IntegrationTestFixture : IAsyncLifetime
|
||||
{
|
||||
private Checkpoint _checkpoint;
|
||||
private IConfiguration _configuration;
|
||||
private WebApplicationFactory<Program> _factory;
|
||||
public Checkpoint Checkpoint { get; set; }
|
||||
public Action<IServiceCollection>? TestRegistrationServices { get; set; }
|
||||
public IServiceProvider ServiceProvider => _factory.Services;
|
||||
public IConfiguration Configuration => _factory.Services.GetRequiredService<IConfiguration>();
|
||||
private MongoDbRunner _mongoRunner;
|
||||
private IServiceProvider _serviceProvider;
|
||||
private Action<IServiceCollection>? _testRegistrationServices;
|
||||
public HttpClient HttpClient => _factory.CreateClient();
|
||||
public ITestHarness TestHarness => CreateHarness();
|
||||
public GrpcChannel Channel => CreateChannel();
|
||||
|
||||
|
||||
public virtual Task InitializeAsync()
|
||||
{
|
||||
_factory = new WebApplicationFactory<Program>()
|
||||
.WithWebHostBuilder(builder =>
|
||||
{
|
||||
builder.UseEnvironment("test");
|
||||
builder.ConfigureServices(services =>
|
||||
{
|
||||
_testRegistrationServices?.Invoke(services);
|
||||
});
|
||||
});
|
||||
|
||||
RegisterServices(services =>
|
||||
{
|
||||
services.ReplaceSingleton(AddHttpContextAccessorMock);
|
||||
services.AddMassTransitTestHarness(x =>
|
||||
{
|
||||
x.UsingRabbitMq((context, cfg) =>
|
||||
{
|
||||
var rabbitMqOptions = services.GetOptions<RabbitMqOptions>("RabbitMq");
|
||||
var host = rabbitMqOptions.HostName;
|
||||
|
||||
cfg.Host(host, h =>
|
||||
{
|
||||
h.Username(rabbitMqOptions.UserName);
|
||||
h.Password(rabbitMqOptions.Password);
|
||||
});
|
||||
cfg.ConfigureEndpoints(context);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
_serviceProvider = _factory.Services;
|
||||
_configuration = _factory.Services.GetRequiredService<IConfiguration>();
|
||||
|
||||
_checkpoint = new Checkpoint {TablesToIgnore = new[] {"__EFMigrationsHistory"}};
|
||||
|
||||
_mongoRunner = MongoDbRunner.Start();
|
||||
var mongoOptions = _factory.Services.GetRequiredService<IOptions<MongoOptions>>();
|
||||
if (mongoOptions.Value.ConnectionString != null)
|
||||
mongoOptions.Value.ConnectionString = _mongoRunner.ConnectionString;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual async Task DisposeAsync()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_configuration?.GetConnectionString("DefaultConnection")))
|
||||
await _checkpoint.Reset(_configuration?.GetConnectionString("DefaultConnection"));
|
||||
|
||||
await _factory.DisposeAsync();
|
||||
_mongoRunner.Dispose();
|
||||
}
|
||||
|
||||
public void RegisterServices(Action<IServiceCollection> services)
|
||||
{
|
||||
_testRegistrationServices = services;
|
||||
}
|
||||
|
||||
// ref: https://github.com/trbenning/serilog-sinks-xunit
|
||||
public ILogger CreateLogger(ITestOutputHelper output)
|
||||
{
|
||||
@ -57,59 +115,15 @@ public class IntegrationTestFixture : IAsyncLifetime
|
||||
return null;
|
||||
}
|
||||
|
||||
public void RegisterTestServices(Action<IServiceCollection> services) => TestRegistrationServices = services;
|
||||
|
||||
public virtual Task InitializeAsync()
|
||||
{
|
||||
_factory = new WebApplicationFactory<Program>()
|
||||
.WithWebHostBuilder(builder =>
|
||||
{
|
||||
builder.UseEnvironment("test");
|
||||
builder.ConfigureServices(services =>
|
||||
{
|
||||
TestRegistrationServices?.Invoke(services);
|
||||
services.AddMassTransitTestHarness(x =>
|
||||
{
|
||||
x.UsingRabbitMq((context, cfg) =>
|
||||
{
|
||||
var rabbitMqOptions = services.GetOptions<RabbitMqOptions>("RabbitMq");
|
||||
var host = rabbitMqOptions.HostName;
|
||||
|
||||
cfg.Host(host, h =>
|
||||
{
|
||||
h.Username(rabbitMqOptions.UserName);
|
||||
h.Password(rabbitMqOptions.Password);
|
||||
});
|
||||
cfg.ConfigureEndpoints(context);
|
||||
});
|
||||
});
|
||||
|
||||
Checkpoint = new Checkpoint {TablesToIgnore = new[] {"__EFMigrationsHistory"}};
|
||||
|
||||
TestRegistrationServices?.Invoke(services);
|
||||
});
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual async Task DisposeAsync()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Configuration?.GetConnectionString("DefaultConnection")))
|
||||
await Checkpoint.Reset(Configuration?.GetConnectionString("DefaultConnection"));
|
||||
|
||||
await _factory.DisposeAsync();
|
||||
}
|
||||
|
||||
public async Task ExecuteScopeAsync(Func<IServiceProvider, Task> action)
|
||||
{
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
await action(scope.ServiceProvider);
|
||||
}
|
||||
|
||||
public async Task<T> ExecuteScopeAsync<T>(Func<IServiceProvider, Task<T>> action)
|
||||
{
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
|
||||
var result = await action(scope.ServiceProvider);
|
||||
|
||||
@ -240,7 +254,7 @@ public class IntegrationTestFixture : IAsyncLifetime
|
||||
|
||||
private ITestHarness CreateHarness()
|
||||
{
|
||||
var harness = ServiceProvider.GetTestHarness();
|
||||
var harness = _serviceProvider.GetTestHarness();
|
||||
harness.Start().GetAwaiter().GetResult();
|
||||
return harness;
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using BuildingBlocks.Core.Model;
|
||||
using BuildingBlocks.MassTransit;
|
||||
using BuildingBlocks.Mongo;
|
||||
using BuildingBlocks.Web;
|
||||
using Grpc.Net.Client;
|
||||
using Identity.Data;
|
||||
@ -14,8 +15,8 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Mongo2Go;
|
||||
using NSubstitute;
|
||||
using Respawn;
|
||||
using Serilog;
|
||||
@ -31,15 +32,17 @@ public class FixtureCollection : ICollectionFixture<IntegrationTestFixture>
|
||||
|
||||
public class IntegrationTestFixture : IAsyncLifetime
|
||||
{
|
||||
private Checkpoint _checkpoint;
|
||||
private IConfiguration _configuration;
|
||||
private WebApplicationFactory<Program> _factory;
|
||||
public Checkpoint Checkpoint { get; set; }
|
||||
public Action<IServiceCollection>? TestRegistrationServices { get; set; }
|
||||
public IServiceProvider ServiceProvider => _factory.Services;
|
||||
public IConfiguration Configuration => _factory.Services.GetRequiredService<IConfiguration>();
|
||||
private MongoDbRunner _mongoRunner;
|
||||
private IServiceProvider _serviceProvider;
|
||||
private Action<IServiceCollection>? _testRegistrationServices;
|
||||
public HttpClient HttpClient => _factory.CreateClient();
|
||||
public ITestHarness TestHarness => CreateHarness();
|
||||
public GrpcChannel Channel => CreateChannel();
|
||||
|
||||
|
||||
public virtual Task InitializeAsync()
|
||||
{
|
||||
_factory = new WebApplicationFactory<Program>()
|
||||
@ -48,66 +51,79 @@ public class IntegrationTestFixture : IAsyncLifetime
|
||||
builder.UseEnvironment("test");
|
||||
builder.ConfigureServices(services =>
|
||||
{
|
||||
services.ReplaceSingleton(AddHttpContextAccessorMock);
|
||||
TestRegistrationServices?.Invoke(services);
|
||||
services.AddMassTransitTestHarness(x =>
|
||||
{
|
||||
x.UsingRabbitMq((context, cfg) =>
|
||||
{
|
||||
var rabbitMqOptions = services.GetOptions<RabbitMqOptions>("RabbitMq");
|
||||
var host = rabbitMqOptions.HostName;
|
||||
|
||||
cfg.Host(host, h =>
|
||||
{
|
||||
h.Username(rabbitMqOptions.UserName);
|
||||
h.Password(rabbitMqOptions.Password);
|
||||
});
|
||||
cfg.ConfigureEndpoints(context);
|
||||
});
|
||||
});
|
||||
|
||||
Checkpoint = new Checkpoint {TablesToIgnore = new[] {"__EFMigrationsHistory"}};
|
||||
|
||||
TestRegistrationServices?.Invoke(services);
|
||||
_testRegistrationServices?.Invoke(services);
|
||||
});
|
||||
});
|
||||
|
||||
RegisterServices(services =>
|
||||
{
|
||||
services.ReplaceSingleton(AddHttpContextAccessorMock);
|
||||
services.AddMassTransitTestHarness(x =>
|
||||
{
|
||||
x.UsingRabbitMq((context, cfg) =>
|
||||
{
|
||||
var rabbitMqOptions = services.GetOptions<RabbitMqOptions>("RabbitMq");
|
||||
var host = rabbitMqOptions.HostName;
|
||||
|
||||
cfg.Host(host, h =>
|
||||
{
|
||||
h.Username(rabbitMqOptions.UserName);
|
||||
h.Password(rabbitMqOptions.Password);
|
||||
});
|
||||
cfg.ConfigureEndpoints(context);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
_serviceProvider = _factory.Services;
|
||||
_configuration = _factory.Services.GetRequiredService<IConfiguration>();
|
||||
|
||||
_checkpoint = new Checkpoint {TablesToIgnore = new[] {"__EFMigrationsHistory"}};
|
||||
|
||||
_mongoRunner = MongoDbRunner.Start();
|
||||
var mongoOptions = _factory.Services.GetRequiredService<IOptions<MongoOptions>>();
|
||||
if (mongoOptions.Value.ConnectionString != null)
|
||||
mongoOptions.Value.ConnectionString = _mongoRunner.ConnectionString;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual async Task DisposeAsync()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Configuration?.GetConnectionString("DefaultConnection")))
|
||||
await Checkpoint.Reset(Configuration?.GetConnectionString("DefaultConnection"));
|
||||
if (!string.IsNullOrEmpty(_configuration?.GetConnectionString("DefaultConnection")))
|
||||
await _checkpoint.Reset(_configuration?.GetConnectionString("DefaultConnection"));
|
||||
|
||||
await _factory.DisposeAsync();
|
||||
_mongoRunner.Dispose();
|
||||
}
|
||||
|
||||
public void RegisterServices(Action<IServiceCollection> services)
|
||||
{
|
||||
_testRegistrationServices = services;
|
||||
}
|
||||
|
||||
// ref: https://github.com/trbenning/serilog-sinks-xunit
|
||||
public ILogger CreateLogger(ITestOutputHelper output)
|
||||
{
|
||||
if (output != null)
|
||||
{
|
||||
return new LoggerConfiguration()
|
||||
.WriteTo.TestOutput(output)
|
||||
.CreateLogger();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void RegisterTestServices(Action<IServiceCollection> services)
|
||||
{
|
||||
TestRegistrationServices = services;
|
||||
}
|
||||
|
||||
public async Task ExecuteScopeAsync(Func<IServiceProvider, Task> action)
|
||||
{
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
await action(scope.ServiceProvider);
|
||||
}
|
||||
|
||||
public async Task<T> ExecuteScopeAsync<T>(Func<IServiceProvider, Task<T>> action)
|
||||
{
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
|
||||
var result = await action(scope.ServiceProvider);
|
||||
|
||||
@ -238,7 +254,7 @@ public class IntegrationTestFixture : IAsyncLifetime
|
||||
|
||||
private ITestHarness CreateHarness()
|
||||
{
|
||||
var harness = ServiceProvider.GetTestHarness();
|
||||
var harness = _serviceProvider.GetTestHarness();
|
||||
harness.Start().GetAwaiter().GetResult();
|
||||
return harness;
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ public sealed class PassengerDbContext : AppDbContextBase
|
||||
{
|
||||
public const string DefaultSchema = "dbo";
|
||||
|
||||
public PassengerDbContext(DbContextOptions options, IHttpContextAccessor httpContextAccessor) : base(options, httpContextAccessor)
|
||||
public PassengerDbContext(DbContextOptions<PassengerDbContext> options, IHttpContextAccessor httpContextAccessor) : base(options, httpContextAccessor)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using BuildingBlocks.Core.Model;
|
||||
using BuildingBlocks.MassTransit;
|
||||
using BuildingBlocks.Mongo;
|
||||
using BuildingBlocks.Web;
|
||||
using Grpc.Net.Client;
|
||||
using MassTransit;
|
||||
@ -13,8 +14,8 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Mongo2Go;
|
||||
using NSubstitute;
|
||||
using Passenger.Data;
|
||||
using Respawn;
|
||||
@ -31,15 +32,17 @@ public class FixtureCollection : ICollectionFixture<IntegrationTestFixture>
|
||||
|
||||
public class IntegrationTestFixture : IAsyncLifetime
|
||||
{
|
||||
private Checkpoint _checkpoint;
|
||||
private IConfiguration _configuration;
|
||||
private WebApplicationFactory<Program> _factory;
|
||||
public Checkpoint Checkpoint { get; set; }
|
||||
public Action<IServiceCollection>? TestRegistrationServices { get; set; }
|
||||
public IServiceProvider ServiceProvider => _factory.Services;
|
||||
public IConfiguration Configuration => _factory.Services.GetRequiredService<IConfiguration>();
|
||||
private MongoDbRunner _mongoRunner;
|
||||
private IServiceProvider _serviceProvider;
|
||||
private Action<IServiceCollection>? _testRegistrationServices;
|
||||
public HttpClient HttpClient => _factory.CreateClient();
|
||||
public ITestHarness TestHarness => CreateHarness();
|
||||
public GrpcChannel Channel => CreateChannel();
|
||||
|
||||
|
||||
public virtual Task InitializeAsync()
|
||||
{
|
||||
_factory = new WebApplicationFactory<Program>()
|
||||
@ -48,66 +51,79 @@ public class IntegrationTestFixture : IAsyncLifetime
|
||||
builder.UseEnvironment("test");
|
||||
builder.ConfigureServices(services =>
|
||||
{
|
||||
services.ReplaceSingleton(AddHttpContextAccessorMock);
|
||||
TestRegistrationServices?.Invoke(services);
|
||||
services.AddMassTransitTestHarness(x =>
|
||||
{
|
||||
x.UsingRabbitMq((context, cfg) =>
|
||||
{
|
||||
var rabbitMqOptions = services.GetOptions<RabbitMqOptions>("RabbitMq");
|
||||
var host = rabbitMqOptions.HostName;
|
||||
|
||||
cfg.Host(host, h =>
|
||||
{
|
||||
h.Username(rabbitMqOptions.UserName);
|
||||
h.Password(rabbitMqOptions.Password);
|
||||
});
|
||||
cfg.ConfigureEndpoints(context);
|
||||
});
|
||||
});
|
||||
|
||||
Checkpoint = new Checkpoint {TablesToIgnore = new[] {"__EFMigrationsHistory"}};
|
||||
|
||||
TestRegistrationServices?.Invoke(services);
|
||||
_testRegistrationServices?.Invoke(services);
|
||||
});
|
||||
});
|
||||
|
||||
RegisterServices(services =>
|
||||
{
|
||||
services.ReplaceSingleton(AddHttpContextAccessorMock);
|
||||
services.AddMassTransitTestHarness(x =>
|
||||
{
|
||||
x.UsingRabbitMq((context, cfg) =>
|
||||
{
|
||||
var rabbitMqOptions = services.GetOptions<RabbitMqOptions>("RabbitMq");
|
||||
var host = rabbitMqOptions.HostName;
|
||||
|
||||
cfg.Host(host, h =>
|
||||
{
|
||||
h.Username(rabbitMqOptions.UserName);
|
||||
h.Password(rabbitMqOptions.Password);
|
||||
});
|
||||
cfg.ConfigureEndpoints(context);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
_serviceProvider = _factory.Services;
|
||||
_configuration = _factory.Services.GetRequiredService<IConfiguration>();
|
||||
|
||||
_checkpoint = new Checkpoint {TablesToIgnore = new[] {"__EFMigrationsHistory"}};
|
||||
|
||||
_mongoRunner = MongoDbRunner.Start();
|
||||
var mongoOptions = _factory.Services.GetRequiredService<IOptions<MongoOptions>>();
|
||||
if (mongoOptions.Value.ConnectionString != null)
|
||||
mongoOptions.Value.ConnectionString = _mongoRunner.ConnectionString;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual async Task DisposeAsync()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Configuration?.GetConnectionString("DefaultConnection")))
|
||||
await Checkpoint.Reset(Configuration?.GetConnectionString("DefaultConnection"));
|
||||
if (!string.IsNullOrEmpty(_configuration?.GetConnectionString("DefaultConnection")))
|
||||
await _checkpoint.Reset(_configuration?.GetConnectionString("DefaultConnection"));
|
||||
|
||||
await _factory.DisposeAsync();
|
||||
_mongoRunner.Dispose();
|
||||
}
|
||||
|
||||
public void RegisterServices(Action<IServiceCollection> services)
|
||||
{
|
||||
_testRegistrationServices = services;
|
||||
}
|
||||
|
||||
// ref: https://github.com/trbenning/serilog-sinks-xunit
|
||||
public ILogger CreateLogger(ITestOutputHelper output)
|
||||
{
|
||||
if (output != null)
|
||||
{
|
||||
return new LoggerConfiguration()
|
||||
.WriteTo.TestOutput(output)
|
||||
.CreateLogger();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void RegisterTestServices(Action<IServiceCollection> services)
|
||||
{
|
||||
TestRegistrationServices = services;
|
||||
}
|
||||
|
||||
public async Task ExecuteScopeAsync(Func<IServiceProvider, Task> action)
|
||||
{
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
await action(scope.ServiceProvider);
|
||||
}
|
||||
|
||||
public async Task<T> ExecuteScopeAsync<T>(Func<IServiceProvider, Task<T>> action)
|
||||
{
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
|
||||
var result = await action(scope.ServiceProvider);
|
||||
|
||||
@ -238,7 +254,7 @@ public class IntegrationTestFixture : IAsyncLifetime
|
||||
|
||||
private ITestHarness CreateHarness()
|
||||
{
|
||||
var harness = ServiceProvider.GetTestHarness();
|
||||
var harness = _serviceProvider.GetTestHarness();
|
||||
harness.Start().GetAwaiter().GetResult();
|
||||
return harness;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user