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
This commit is contained in:
parent
88812177a9
commit
54b057886c
35 changed files with 1174 additions and 358 deletions
130
PlanTempus.X.BDD/BddTestFixture.cs
Normal file
130
PlanTempus.X.BDD/BddTestFixture.cs
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue