mirror of
https://github.com/alex289/CleanArchitecture.git
synced 2025-07-06 05:53:55 +00:00
feat: Add rabbit and redis to integration tests
This commit is contained in:
parent
dca566cbf6
commit
4a8c102d00
@ -72,7 +72,7 @@ builder.Services.AddLogging(x => x.AddSimpleConsole(console =>
|
|||||||
console.IncludeScopes = true;
|
console.IncludeScopes = true;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (builder.Environment.IsProduction())
|
if (builder.Environment.IsProduction() || !string.IsNullOrWhiteSpace(builder.Configuration["RedisHostName"]))
|
||||||
{
|
{
|
||||||
builder.Services.AddStackExchangeRedisCache(options =>
|
builder.Services.AddStackExchangeRedisCache(options =>
|
||||||
{
|
{
|
||||||
@ -95,12 +95,8 @@ using (var scope = app.Services.CreateScope())
|
|||||||
var domainStoreDbContext = services.GetRequiredService<DomainNotificationStoreDbContext>();
|
var domainStoreDbContext = services.GetRequiredService<DomainNotificationStoreDbContext>();
|
||||||
|
|
||||||
appDbContext.EnsureMigrationsApplied();
|
appDbContext.EnsureMigrationsApplied();
|
||||||
|
storeDbContext.EnsureMigrationsApplied();
|
||||||
if (app.Environment.EnvironmentName != "Integration")
|
domainStoreDbContext.EnsureMigrationsApplied();
|
||||||
{
|
|
||||||
storeDbContext.EnsureMigrationsApplied();
|
|
||||||
domainStoreDbContext.EnsureMigrationsApplied();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (app.Environment.IsDevelopment())
|
if (app.Environment.IsDevelopment())
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
"Audience": "CleanArchitectureClient",
|
"Audience": "CleanArchitectureClient",
|
||||||
"Secret": "sD3v061gf8BxXgmxcHssasjdlkasjd87439284)@#(*"
|
"Secret": "sD3v061gf8BxXgmxcHssasjdlkasjd87439284)@#(*"
|
||||||
},
|
},
|
||||||
|
"RedisHostName": "",
|
||||||
"RabbitMQ": {
|
"RabbitMQ": {
|
||||||
"Host": "localhost",
|
"Host": "localhost",
|
||||||
"Username": "guest",
|
"Username": "guest",
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"RedisHostName": "",
|
||||||
"RabbitMQ": {
|
"RabbitMQ": {
|
||||||
"Host": "localhost",
|
"Host": "localhost",
|
||||||
"Username": "guest",
|
"Username": "guest",
|
||||||
|
@ -5,7 +5,7 @@ using Xunit;
|
|||||||
|
|
||||||
namespace CleanArchitecture.IntegrationTests.Fixtures;
|
namespace CleanArchitecture.IntegrationTests.Fixtures;
|
||||||
|
|
||||||
public sealed class DatabaseFixture : IAsyncLifetime
|
public sealed class AccessorFixture : IAsyncLifetime
|
||||||
{
|
{
|
||||||
public static string TestRunDbName { get; } = $"CleanArchitecture-Integration-{Guid.NewGuid()}";
|
public static string TestRunDbName { get; } = $"CleanArchitecture-Integration-{Guid.NewGuid()}";
|
||||||
|
|
||||||
@ -13,11 +13,23 @@ public sealed class DatabaseFixture : IAsyncLifetime
|
|||||||
{
|
{
|
||||||
var db = DatabaseAccessor.GetOrCreateAsync(TestRunDbName);
|
var db = DatabaseAccessor.GetOrCreateAsync(TestRunDbName);
|
||||||
await db.DisposeAsync();
|
await db.DisposeAsync();
|
||||||
|
|
||||||
|
var redis = RedisAccessor.GetOrCreateAsync();
|
||||||
|
await redis.DisposeAsync();
|
||||||
|
|
||||||
|
var rabbit = RabbitmqAccessor.GetOrCreateAsync();
|
||||||
|
await rabbit.DisposeAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task InitializeAsync()
|
public async Task InitializeAsync()
|
||||||
{
|
{
|
||||||
var db = DatabaseAccessor.GetOrCreateAsync(TestRunDbName);
|
var db = DatabaseAccessor.GetOrCreateAsync(TestRunDbName);
|
||||||
await db.InitializeAsync();
|
await db.InitializeAsync();
|
||||||
|
|
||||||
|
var redis = RedisAccessor.GetOrCreateAsync();
|
||||||
|
await redis.InitializeAsync();
|
||||||
|
|
||||||
|
var rabbit = RabbitmqAccessor.GetOrCreateAsync();
|
||||||
|
await rabbit.InitializeAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,7 +22,7 @@ public class TestFixtureBase : IAsyncLifetime
|
|||||||
Factory = new CleanArchitectureWebApplicationFactory(
|
Factory = new CleanArchitectureWebApplicationFactory(
|
||||||
RegisterCustomServicesHandler,
|
RegisterCustomServicesHandler,
|
||||||
useTestAuthentication,
|
useTestAuthentication,
|
||||||
DatabaseFixture.TestRunDbName);
|
AccessorFixture.TestRunDbName);
|
||||||
|
|
||||||
ServerClient = Factory.CreateClient();
|
ServerClient = Factory.CreateClient();
|
||||||
ServerClient.Timeout = TimeSpan.FromMinutes(5);
|
ServerClient.Timeout = TimeSpan.FromMinutes(5);
|
||||||
|
@ -40,18 +40,31 @@ public sealed class CleanArchitectureWebApplicationFactory : WebApplicationFacto
|
|||||||
|
|
||||||
base.ConfigureWebHost(builder);
|
base.ConfigureWebHost(builder);
|
||||||
|
|
||||||
|
var configuration = new ConfigurationBuilder()
|
||||||
|
.Build();
|
||||||
|
|
||||||
builder.ConfigureAppConfiguration(configurationBuilder =>
|
builder.ConfigureAppConfiguration(configurationBuilder =>
|
||||||
{
|
{
|
||||||
configurationBuilder.AddEnvironmentVariables();
|
configurationBuilder.AddEnvironmentVariables();
|
||||||
|
|
||||||
var accessor = DatabaseAccessor.GetOrCreateAsync(_instanceDatabaseName);
|
var dbAccessor = DatabaseAccessor.GetOrCreateAsync(_instanceDatabaseName);
|
||||||
|
var redisAccessor = RedisAccessor.GetOrCreateAsync();
|
||||||
|
var rabbitAccessor = RabbitmqAccessor.GetOrCreateAsync();
|
||||||
|
|
||||||
// Overwrite default connection string to our test instance db
|
// Overwrite default connection strings
|
||||||
configurationBuilder.AddInMemoryCollection([
|
configurationBuilder.AddInMemoryCollection([
|
||||||
new KeyValuePair<string, string?>(
|
new KeyValuePair<string, string?>(
|
||||||
"ConnectionStrings:DefaultConnection",
|
"ConnectionStrings:DefaultConnection",
|
||||||
accessor.GetConnectionString())
|
dbAccessor.GetConnectionString()),
|
||||||
|
new KeyValuePair<string, string?>(
|
||||||
|
"RedisHostName",
|
||||||
|
redisAccessor.GetConnectionString()),
|
||||||
|
new KeyValuePair<string, string?>(
|
||||||
|
"RabbitMQ:Host",
|
||||||
|
rabbitAccessor.GetConnectionString())
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
configuration = configurationBuilder.Build();
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.ConfigureServices(services =>
|
builder.ConfigureServices(services =>
|
||||||
@ -70,8 +83,14 @@ public sealed class CleanArchitectureWebApplicationFactory : WebApplicationFacto
|
|||||||
using var scope = sp.CreateScope();
|
using var scope = sp.CreateScope();
|
||||||
var scopedServices = scope.ServiceProvider;
|
var scopedServices = scope.ServiceProvider;
|
||||||
|
|
||||||
var accessor = DatabaseAccessor.GetOrCreateAsync(_instanceDatabaseName);
|
var dbAccessor = DatabaseAccessor.GetOrCreateAsync(_instanceDatabaseName);
|
||||||
var applicationDbContext = accessor.CreateDatabase(scopedServices);
|
dbAccessor.CreateDatabase(scopedServices);
|
||||||
|
|
||||||
|
var redisAccessor = RedisAccessor.GetOrCreateAsync();
|
||||||
|
redisAccessor.RegisterRedis(services, configuration);
|
||||||
|
|
||||||
|
var rabbitAccessor = RabbitmqAccessor.GetOrCreateAsync();
|
||||||
|
rabbitAccessor.RegisterRabbitmq(services, configuration);
|
||||||
|
|
||||||
_registerCustomServicesHandler?.Invoke(services, sp, scopedServices);
|
_registerCustomServicesHandler?.Invoke(services, sp, scopedServices);
|
||||||
});
|
});
|
||||||
@ -85,7 +104,13 @@ public sealed class CleanArchitectureWebApplicationFactory : WebApplicationFacto
|
|||||||
|
|
||||||
public override async ValueTask DisposeAsync()
|
public override async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
var accessor = DatabaseAccessor.GetOrCreateAsync(_instanceDatabaseName);
|
var dbAccessor = DatabaseAccessor.GetOrCreateAsync(_instanceDatabaseName);
|
||||||
await accessor.DisposeAsync();
|
await dbAccessor.DisposeAsync();
|
||||||
|
|
||||||
|
var redisAccessor = RedisAccessor.GetOrCreateAsync();
|
||||||
|
await redisAccessor.DisposeAsync();
|
||||||
|
|
||||||
|
var rabbitAccessor = RabbitmqAccessor.GetOrCreateAsync();
|
||||||
|
await rabbitAccessor.DisposeAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -18,7 +18,7 @@ public sealed class DatabaseAccessor
|
|||||||
private bool _databaseCreated = false;
|
private bool _databaseCreated = false;
|
||||||
private readonly object _databaseCreationLock = new();
|
private readonly object _databaseCreationLock = new();
|
||||||
|
|
||||||
private const string _dbPassword = "12345678##as";
|
private const string _dbPassword = "234#AD224fD#ss";
|
||||||
private static readonly MsSqlContainer s_dbContainer = new MsSqlBuilder()
|
private static readonly MsSqlContainer s_dbContainer = new MsSqlBuilder()
|
||||||
.WithPassword(_dbPassword)
|
.WithPassword(_dbPassword)
|
||||||
.WithPortBinding(1433)
|
.WithPortBinding(1433)
|
||||||
@ -61,6 +61,7 @@ public sealed class DatabaseAccessor
|
|||||||
|
|
||||||
public async ValueTask DisposeAsync()
|
public async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
|
// Reset the database to its original state
|
||||||
var dropScript = $@"
|
var dropScript = $@"
|
||||||
USE MASTER;
|
USE MASTER;
|
||||||
|
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CleanArchitecture.Domain.Rabbitmq;
|
||||||
|
using CleanArchitecture.Domain.Rabbitmq.Extensions;
|
||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Testcontainers.RabbitMq;
|
||||||
|
using RabbitMqConfiguration = CleanArchitecture.Domain.Rabbitmq.RabbitMqConfiguration;
|
||||||
|
|
||||||
|
namespace CleanArchitecture.IntegrationTests.Infrastructure;
|
||||||
|
|
||||||
|
public sealed class RabbitmqAccessor
|
||||||
|
{
|
||||||
|
private static readonly ConcurrentDictionary<string, RabbitmqAccessor> s_accessors = new();
|
||||||
|
|
||||||
|
private static readonly RabbitMqContainer s_rabbitContainer = new RabbitMqBuilder()
|
||||||
|
.WithPortBinding(5672)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
public async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
await s_rabbitContainer.StartAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
await s_rabbitContainer.DisposeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetConnectionString()
|
||||||
|
{
|
||||||
|
return s_rabbitContainer.GetConnectionString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterRabbitmq(IServiceCollection serviceCollection, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var rabbitService = serviceCollection.FirstOrDefault(x =>
|
||||||
|
x.ServiceType == typeof(RabbitMqHandler));
|
||||||
|
|
||||||
|
if (rabbitService != null)
|
||||||
|
{
|
||||||
|
serviceCollection.Remove(rabbitService);
|
||||||
|
}
|
||||||
|
|
||||||
|
var rabbitConfig = serviceCollection.FirstOrDefault(x =>
|
||||||
|
x.ServiceType == typeof(RabbitMqConfiguration));
|
||||||
|
|
||||||
|
if (rabbitConfig != null)
|
||||||
|
{
|
||||||
|
serviceCollection.Remove(rabbitConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceCollection.AddRabbitMqHandler(
|
||||||
|
configuration,
|
||||||
|
"RabbitMQ");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RabbitmqAccessor GetOrCreateAsync()
|
||||||
|
{
|
||||||
|
return s_accessors.GetOrAdd("rabbimq", _ => new RabbitmqAccessor());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Testcontainers.Redis;
|
||||||
|
|
||||||
|
namespace CleanArchitecture.IntegrationTests.Infrastructure;
|
||||||
|
|
||||||
|
public sealed class RedisAccessor
|
||||||
|
{
|
||||||
|
private static readonly ConcurrentDictionary<string, RedisAccessor> s_accessors = new();
|
||||||
|
|
||||||
|
private static readonly RedisContainer s_redisContainer = new RedisBuilder()
|
||||||
|
.WithPortBinding(6379)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
public async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
await s_redisContainer.StartAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
await s_redisContainer.DisposeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetConnectionString()
|
||||||
|
{
|
||||||
|
return s_redisContainer.GetConnectionString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterRedis(IServiceCollection serviceCollection, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var distributedCache = serviceCollection.FirstOrDefault(x =>
|
||||||
|
x.ServiceType == typeof(IDistributedCache));
|
||||||
|
|
||||||
|
if (distributedCache != null)
|
||||||
|
{
|
||||||
|
serviceCollection.Remove(distributedCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceCollection.AddStackExchangeRedisCache(options =>
|
||||||
|
{
|
||||||
|
options.Configuration = configuration["RedisHostName"];
|
||||||
|
options.InstanceName = "clean-architecture";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RedisAccessor GetOrCreateAsync()
|
||||||
|
{
|
||||||
|
return s_accessors.GetOrAdd("redis", _ => new RedisAccessor());
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,6 @@ namespace CleanArchitecture.IntegrationTests;
|
|||||||
|
|
||||||
[CollectionDefinition("IntegrationTests", DisableParallelization = true)]
|
[CollectionDefinition("IntegrationTests", DisableParallelization = true)]
|
||||||
public sealed class IntegrationTestsCollection :
|
public sealed class IntegrationTestsCollection :
|
||||||
ICollectionFixture<DatabaseFixture>
|
ICollectionFixture<AccessorFixture>
|
||||||
{
|
{
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user