147 lines
5.7 KiB
C#
147 lines
5.7 KiB
C#
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Options;
|
|
using NSubstitute;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
|
|
using ZB.MOM.WW.ScadaBridge.NotificationOutbox.Delivery;
|
|
using ZB.MOM.WW.ScadaBridge.NotificationService;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.NotificationOutbox.Tests;
|
|
|
|
/// <summary>
|
|
/// Task 17: Tests for <see cref="ServiceCollectionExtensions.AddNotificationOutbox"/> — the
|
|
/// DI registration extension for the Notification Outbox component. The extension binds
|
|
/// <see cref="NotificationOutboxOptions"/> from the <c>ScadaBridge:NotificationOutbox</c>
|
|
/// configuration section and registers the channel delivery adapter(s).
|
|
///
|
|
/// The Host wires both <c>AddNotificationService</c> and <c>AddNotificationOutbox</c> on the
|
|
/// central node; these tests do the same so the
|
|
/// adapter's SMTP dependencies (<c>Func<ISmtpClientWrapper></c>, <c>OAuth2TokenService</c>,
|
|
/// <c>NotificationOptions</c>) are satisfied. <see cref="INotificationRepository"/> — which the
|
|
/// <see cref="EmailNotificationDeliveryAdapter"/> takes directly and is registered scoped by the
|
|
/// Configuration Database component — is supplied here by a lightweight stub.
|
|
/// </summary>
|
|
public class ServiceRegistrationTests
|
|
{
|
|
private static ServiceProvider BuildProvider()
|
|
{
|
|
var services = new ServiceCollection();
|
|
|
|
// Empty configuration: the options binding must still succeed and yield the
|
|
// documented NotificationOutboxOptions defaults.
|
|
var configuration = new ConfigurationBuilder().Build();
|
|
services.AddSingleton<IConfiguration>(configuration);
|
|
services.AddLogging();
|
|
|
|
// INotificationRepository is registered scoped by the Configuration Database
|
|
// component in production; a no-op stub stands in for it here.
|
|
services.AddScoped<INotificationRepository>(_ => Substitute.For<INotificationRepository>());
|
|
|
|
services.AddNotificationService();
|
|
services.AddNotificationOutbox();
|
|
|
|
return services.BuildServiceProvider();
|
|
}
|
|
|
|
[Fact]
|
|
public void AddNotificationOutbox_RegistersNotificationOutboxOptions_WithDefaults()
|
|
{
|
|
using var provider = BuildProvider();
|
|
|
|
var options = provider.GetRequiredService<IOptions<NotificationOutboxOptions>>().Value;
|
|
|
|
Assert.NotNull(options);
|
|
Assert.Equal(TimeSpan.FromSeconds(10), options.DispatchInterval);
|
|
Assert.Equal(100, options.DispatchBatchSize);
|
|
}
|
|
|
|
[Fact]
|
|
public void AddNotificationOutbox_OptionsSection_IsTheNotificationOutboxConfigPath()
|
|
{
|
|
Assert.Equal(
|
|
"ScadaBridge:NotificationOutbox",
|
|
NotificationOutbox.ServiceCollectionExtensions.OptionsSection);
|
|
}
|
|
|
|
[Fact]
|
|
public void AddNotificationOutbox_BindsNotificationOutboxOptions_FromConfiguration()
|
|
{
|
|
var services = new ServiceCollection();
|
|
var configuration = new ConfigurationBuilder()
|
|
.AddInMemoryCollection(new Dictionary<string, string?>
|
|
{
|
|
["ScadaBridge:NotificationOutbox:DispatchBatchSize"] = "250",
|
|
})
|
|
.Build();
|
|
services.AddSingleton<IConfiguration>(configuration);
|
|
services.AddLogging();
|
|
services.AddScoped<INotificationRepository>(_ => Substitute.For<INotificationRepository>());
|
|
services.AddNotificationService();
|
|
services.AddNotificationOutbox();
|
|
|
|
using var provider = services.BuildServiceProvider();
|
|
var options = provider.GetRequiredService<IOptions<NotificationOutboxOptions>>().Value;
|
|
|
|
Assert.Equal(250, options.DispatchBatchSize);
|
|
}
|
|
|
|
[Fact]
|
|
public void AddNotificationOutbox_RegistersEmailDeliveryAdapter()
|
|
{
|
|
using var provider = BuildProvider();
|
|
using var scope = provider.CreateScope();
|
|
|
|
var adapter = scope.ServiceProvider.GetRequiredService<EmailNotificationDeliveryAdapter>();
|
|
|
|
Assert.NotNull(adapter);
|
|
Assert.Equal(NotificationType.Email, adapter.Type);
|
|
}
|
|
|
|
[Fact]
|
|
public void AddNotificationOutbox_RegistersSmsDeliveryAdapter()
|
|
{
|
|
using var provider = BuildProvider();
|
|
using var scope = provider.CreateScope();
|
|
|
|
var adapter = scope.ServiceProvider.GetRequiredService<SmsNotificationDeliveryAdapter>();
|
|
|
|
Assert.NotNull(adapter);
|
|
Assert.Equal(NotificationType.Sms, adapter.Type);
|
|
}
|
|
|
|
[Fact]
|
|
public void AddNotificationOutbox_RegistersBothAdapters_AsINotificationDeliveryAdapter()
|
|
{
|
|
using var provider = BuildProvider();
|
|
using var scope = provider.CreateScope();
|
|
|
|
var adapters = scope.ServiceProvider.GetServices<INotificationDeliveryAdapter>().ToList();
|
|
|
|
// Both the Email and SMS channel adapters must resolve from the enumerable so the
|
|
// dispatch sweep can route a notification to the adapter matching its Type.
|
|
Assert.Equal(2, adapters.Count);
|
|
|
|
// The set of advertised channel Types is exactly {Email, Sms}.
|
|
Assert.Equal(
|
|
new[] { NotificationType.Email, NotificationType.Sms },
|
|
adapters.Select(a => a.Type).OrderBy(t => t).ToArray());
|
|
|
|
// And the concrete adapter implementations are the expected pair.
|
|
Assert.Contains(adapters, a => a is EmailNotificationDeliveryAdapter);
|
|
Assert.Contains(adapters, a => a is SmsNotificationDeliveryAdapter);
|
|
}
|
|
|
|
[Fact]
|
|
public void AddNotificationOutbox_RegistersSmsOptions_WithDefaults()
|
|
{
|
|
using var provider = BuildProvider();
|
|
|
|
var options = provider.GetRequiredService<IOptions<SmsOptions>>().Value;
|
|
|
|
Assert.NotNull(options);
|
|
Assert.Equal(1600, options.MaxMessageLength);
|
|
Assert.Equal(30, options.ConnectionTimeoutSeconds);
|
|
}
|
|
}
|