feat(sms): Twilio SmsNotificationDeliveryAdapter + classifier + options + DI (S3)

This commit is contained in:
Joseph Doherty
2026-06-19 10:14:52 -04:00
parent 609bdb37ef
commit a1d484a5ff
7 changed files with 1069 additions and 7 deletions
@@ -99,15 +99,48 @@ public class ServiceRegistrationTests
}
[Fact]
public void AddNotificationOutbox_RegistersEmailAdapter_AsINotificationDeliveryAdapter()
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();
var email = Assert.Single(adapters);
Assert.IsType<EmailNotificationDeliveryAdapter>(email);
Assert.Equal(NotificationType.Email, email.Type);
// 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);
}
}