Implements outbox pattern for reliable message delivery Adds email verification flow with Postmark integration Enhances account registration with secure token generation Introduces background processing for asynchronous email sending Implements database-level notification mechanism for message processing
130 lines
4 KiB
C#
130 lines
4 KiB
C#
using System.Diagnostics;
|
|
using Autofac;
|
|
using LightBDD.MsTest3;
|
|
using Microsoft.ApplicationInsights;
|
|
using PlanTempus.Components;
|
|
using PlanTempus.Components.ModuleRegistry;
|
|
using PlanTempus.Components.Outbox;
|
|
using PlanTempus.Core.Configurations;
|
|
using PlanTempus.Core.Configurations.JsonConfigProvider;
|
|
using PlanTempus.Core.Email;
|
|
using PlanTempus.Core.ModuleRegistry;
|
|
using PlanTempus.Core.Outbox;
|
|
using PlanTempus.Core.SeqLogging;
|
|
using PlanTempus.Database.ModuleRegistry;
|
|
using CrypticWizard.RandomWordGenerator;
|
|
|
|
namespace PlanTempus.X.BDD;
|
|
|
|
/// <summary>
|
|
/// Base class for BDD tests. Combines LightBDD FeatureFixture with Autofac DI.
|
|
/// </summary>
|
|
public abstract class BddTestFixture : FeatureFixture
|
|
{
|
|
private readonly string _configurationFilePath;
|
|
private OutboxListener _outboxListener;
|
|
private SeqBackgroundService _seqBackgroundService;
|
|
private CancellationTokenSource _cts;
|
|
|
|
protected BddTestFixture() : this(null)
|
|
{
|
|
}
|
|
|
|
public BddTestFixture(string configurationFilePath)
|
|
{
|
|
if (configurationFilePath is not null)
|
|
_configurationFilePath = configurationFilePath.TrimEnd('/') + "/";
|
|
}
|
|
|
|
protected IContainer Container { get; private set; }
|
|
protected ContainerBuilder ContainerBuilder { get; private set; }
|
|
protected ICommandHandler CommandHandler { get; private set; }
|
|
|
|
public string GetRandomWord()
|
|
{
|
|
var myWordGenerator = new WordGenerator();
|
|
return myWordGenerator.GetWord(WordGenerator.PartOfSpeech.verb);
|
|
}
|
|
|
|
public virtual IConfigurationRoot Configuration()
|
|
{
|
|
var configuration = new ConfigurationBuilder()
|
|
.AddJsonFile($"{_configurationFilePath}appconfiguration.dev.json")
|
|
.Build();
|
|
|
|
return configuration;
|
|
}
|
|
|
|
[TestInitialize]
|
|
public void SetupContainer()
|
|
{
|
|
var configuration = Configuration();
|
|
var builder = new ContainerBuilder();
|
|
|
|
builder.RegisterModule(new DbPostgreSqlModule
|
|
{
|
|
ConnectionString = configuration.GetConnectionString("DefaultConnection")
|
|
});
|
|
|
|
builder.RegisterModule(new TelemetryModule
|
|
{
|
|
TelemetryConfig = configuration.GetSection("ApplicationInsights").ToObject<TelemetryConfig>()
|
|
});
|
|
|
|
builder.RegisterModule(new SeqLoggingModule
|
|
{
|
|
SeqConfiguration = configuration.GetSection("SeqConfiguration").ToObject<SeqConfiguration>()
|
|
});
|
|
|
|
builder.RegisterModule<CommandModule>();
|
|
builder.RegisterModule<SecurityModule>();
|
|
builder.RegisterModule<OutboxModule>();
|
|
builder.RegisterModule(new EmailModule
|
|
{
|
|
PostmarkConfiguration = configuration.GetSection("Postmark").ToObject<PostmarkConfiguration>()
|
|
});
|
|
|
|
builder.RegisterType<OutboxListener>().SingleInstance();
|
|
builder.RegisterType<SeqBackgroundService>().SingleInstance();
|
|
|
|
ContainerBuilder = builder;
|
|
Container = builder.Build();
|
|
CommandHandler = Container.Resolve<ICommandHandler>();
|
|
|
|
_cts = new CancellationTokenSource();
|
|
|
|
_seqBackgroundService = Container.Resolve<SeqBackgroundService>();
|
|
_seqBackgroundService.StartAsync(_cts.Token);
|
|
|
|
_outboxListener = Container.Resolve<OutboxListener>();
|
|
_outboxListener.StartAsync(_cts.Token);
|
|
|
|
}
|
|
|
|
[TestCleanup]
|
|
public void CleanupContainer()
|
|
{
|
|
_cts?.Cancel();
|
|
_outboxListener?.StopAsync(CancellationToken.None).Wait();
|
|
_seqBackgroundService?.StopAsync(CancellationToken.None).Wait();
|
|
|
|
Trace.Flush();
|
|
|
|
if (Container is not null)
|
|
{
|
|
var telemetryClient = Container.Resolve<TelemetryClient>();
|
|
telemetryClient.Flush();
|
|
|
|
try
|
|
{
|
|
Container.Dispose();
|
|
}
|
|
catch (System.Threading.Channels.ChannelClosedException)
|
|
{
|
|
// Channel already closed by SeqBackgroundService.StopAsync
|
|
}
|
|
|
|
Container = null;
|
|
}
|
|
}
|
|
}
|