using System; using System.Net.Http; using System.Threading.Tasks; using Booking.Data; using BuildingBlocks.Domain.Model; using Grpc.Net.Client; using MassTransit.Testing; using MediatR; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Serilog; using Xunit; using Xunit.Abstractions; namespace Integration.Test; [CollectionDefinition(nameof(IntegrationTestFixture))] public class SliceFixtureCollection : ICollectionFixture { } public class IntegrationTestFixture : IAsyncLifetime { private readonly CustomWebApplicationFactory _factory; public IntegrationTestFixture() { // Ref: https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-6.0#basic-tests-with-the-default-webapplicationfactory _factory = new CustomWebApplicationFactory(); } public IServiceProvider ServiceProvider => _factory.Services; public IConfiguration Configuration => _factory.Configuration; public HttpClient HttpClient => _factory.CreateClient(); public ITestHarness TestHarness => CreateHarness(); public GrpcChannel Channel => CreateChannel(); public virtual Task InitializeAsync() { return Task.CompletedTask; } public virtual async Task DisposeAsync() { if (!string.IsNullOrEmpty(Configuration?.GetConnectionString("DefaultConnection"))) await _factory.Checkpoint.Reset(Configuration?.GetConnectionString("DefaultConnection")); await _factory.DisposeAsync(); } // 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 services) { _factory.TestRegistrationServices = services; } public async Task ExecuteScopeAsync(Func action) { using var scope = ServiceProvider.CreateScope(); await action(scope.ServiceProvider); } public async Task ExecuteScopeAsync(Func> action) { using var scope = ServiceProvider.CreateScope(); var result = await action(scope.ServiceProvider); return result; } public Task ExecuteDbContextAsync(Func action) { return ExecuteScopeAsync(sp => action(sp.GetService())); } public Task ExecuteDbContextAsync(Func action) { return ExecuteScopeAsync(sp => action(sp.GetService()).AsTask()); } public Task ExecuteDbContextAsync(Func action) { return ExecuteScopeAsync(sp => action(sp.GetService(), sp.GetService())); } public Task ExecuteDbContextAsync(Func> action) { return ExecuteScopeAsync(sp => action(sp.GetService())); } public Task ExecuteDbContextAsync(Func> action) { return ExecuteScopeAsync(sp => action(sp.GetService()).AsTask()); } public Task ExecuteDbContextAsync(Func> action) { return ExecuteScopeAsync(sp => action(sp.GetService(), sp.GetService())); } public Task InsertAsync(params T[] entities) where T : class { return ExecuteDbContextAsync(db => { foreach (var entity in entities) db.Set().Add(entity); return db.SaveChangesAsync(); }); } public Task InsertAsync(TEntity entity) where TEntity : class { return ExecuteDbContextAsync(db => { db.Set().Add(entity); return db.SaveChangesAsync(); }); } public Task InsertAsync(TEntity entity, TEntity2 entity2) where TEntity : class where TEntity2 : class { return ExecuteDbContextAsync(db => { db.Set().Add(entity); db.Set().Add(entity2); return db.SaveChangesAsync(); }); } public Task InsertAsync(TEntity entity, TEntity2 entity2, TEntity3 entity3) where TEntity : class where TEntity2 : class where TEntity3 : class { return ExecuteDbContextAsync(db => { db.Set().Add(entity); db.Set().Add(entity2); db.Set().Add(entity3); return db.SaveChangesAsync(); }); } public Task InsertAsync(TEntity entity, TEntity2 entity2, TEntity3 entity3, TEntity4 entity4) where TEntity : class where TEntity2 : class where TEntity3 : class where TEntity4 : class { return ExecuteDbContextAsync(db => { db.Set().Add(entity); db.Set().Add(entity2); db.Set().Add(entity3); db.Set().Add(entity4); return db.SaveChangesAsync(); }); } public Task FindAsync(long id) where T : class, IEntity { return ExecuteDbContextAsync(db => db.Set().FindAsync(id).AsTask()); } public Task SendAsync(IRequest request) { return ExecuteScopeAsync(sp => { var mediator = sp.GetRequiredService(); return mediator.Send(request); }); } public Task SendAsync(IRequest request) { return ExecuteScopeAsync(sp => { var mediator = sp.GetRequiredService(); return mediator.Send(request); }); } private ITestHarness CreateHarness() { var harness = ServiceProvider.GetTestHarness(); harness.Start().GetAwaiter().GetResult(); return harness; } private GrpcChannel CreateChannel() { return GrpcChannel.ForAddress(HttpClient.BaseAddress!, new GrpcChannelOptions {HttpClient = HttpClient}); } }