PlanTempusApp/PlanTempus.X.BDD/BddTestFixture.cs
Janus C. H. Knudsen 54b057886c Adds transactional outbox and email verification
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
2026-01-10 11:13:33 +01:00

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;
}
}
}