Skip to content

Commit

Permalink
Added support for multiple subscribers with named options
Browse files Browse the repository at this point in the history
  • Loading branch information
DArdouin committed Jan 3, 2024
1 parent b5a9989 commit f98e532
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class EventPropagationSubscriptionOptionsValidatorTests
// Subscription name
[InlineData("accessKey", false, "http://topicurl.com", "topicName", "", false)]
[InlineData("accessKey", false, "http://topicurl.com", "topicName", null, false)]
public void GivenEventPropagationConfigurations_WhenValidateOptions_ThenAccessCredentialsValidated(string topicAccessKey, bool useTokenCredential, string topicEndpoint, string topicName, string subName, bool validationSucceeded)
public void GivenNamedConfiguration_WhenValidate_ThenOptionsAreValidated(string topicAccessKey, bool useTokenCredential, string topicEndpoint, string topicName, string subName, bool validationSucceeded)
{
var validator = new EventPropagationSubscriptionOptionsValidator();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,63 +6,122 @@ namespace Workleap.DomainEventPropagation.Subscription.PullDelivery.Tests;

public class ServiceCollectionEventSubscriptionExtensionsTests
{
private const string AccessKey = "accessKey";
private const string TopicEndPoint = "http://topicurl.com";
private const string TopicName = "topic-name";
private const string SubscriptionName = "sub-name";

[Fact]
public void GivenIConfiguration_WhenAddSubscriber_ThenOptionsAreRegistered()
public void GivenUnnamedConfiguration_WhenAddSubscriber_ThenOptionsAreRegistered()
{
// Given
var myConfiguration = new Dictionary<string, string>
{
[$"{EventPropagationSubscriptionOptions.SectionName}:{nameof(EventPropagationSubscriptionOptions.TopicAccessKey)}"] = "accessKey",
[$"{EventPropagationSubscriptionOptions.SectionName}:{nameof(EventPropagationSubscriptionOptions.TopicEndpoint)}"] = "http://topicurl.com",
[$"{EventPropagationSubscriptionOptions.SectionName}:{nameof(EventPropagationSubscriptionOptions.SubscriptionName)}"] = "sub-name",
[$"{EventPropagationSubscriptionOptions.SectionName}:{nameof(EventPropagationSubscriptionOptions.TopicName)}"] = "topic-name",
};

var services = new ServiceCollection();
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(myConfiguration)
.Build();
services.AddSingleton<IConfiguration>(configuration);
GivenConfigurations(services, EventPropagationSubscriptionOptions.DefaultSectionName);

// When
services.AddEventPropagationSubscriber();
var serviceProvider = services.BuildServiceProvider();
var options = serviceProvider.GetRequiredService<IOptions<EventPropagationSubscriptionOptions>>().Value;
var options = serviceProvider.GetRequiredService<IOptionsMonitor<EventPropagationSubscriptionOptions>>().Get(EventPropagationSubscriptionOptions.DefaultSectionName);

// Then
Assert.Equal(myConfiguration[$"{EventPropagationSubscriptionOptions.SectionName}:{nameof(EventPropagationSubscriptionOptions.TopicEndpoint)}"], options.TopicEndpoint);
Assert.Equal(myConfiguration[$"{EventPropagationSubscriptionOptions.SectionName}:{nameof(EventPropagationSubscriptionOptions.TopicAccessKey)}"], options.TopicAccessKey);
Assert.Equal(myConfiguration[$"{EventPropagationSubscriptionOptions.SectionName}:{nameof(EventPropagationSubscriptionOptions.SubscriptionName)}"], options.SubscriptionName);
Assert.Equal(myConfiguration[$"{EventPropagationSubscriptionOptions.SectionName}:{nameof(EventPropagationSubscriptionOptions.TopicName)}"], options.TopicName);
Assert.Equal(AccessKey, options.TopicAccessKey);
Assert.Equal(TopicEndPoint, options.TopicEndpoint);
Assert.Equal(TopicName, options.TopicName);
Assert.Equal(SubscriptionName, options.SubscriptionName);
}

[Fact]
public void GivenIConfiguration_WhenAddSubscriber_CanOverrideConfiguration()
public void GivenUnnamedConfiguration_WhenAddSubscriber_CanOverrideConfiguration()
{
// Given
var myConfiguration = new Dictionary<string, string>
{
[$"{EventPropagationSubscriptionOptions.SectionName}:{nameof(EventPropagationSubscriptionOptions.TopicAccessKey)}"] = "accessKey",
[$"{EventPropagationSubscriptionOptions.SectionName}:{nameof(EventPropagationSubscriptionOptions.TopicEndpoint)}"] = "http://topicurl.com",
[$"{EventPropagationSubscriptionOptions.SectionName}:{nameof(EventPropagationSubscriptionOptions.SubscriptionName)}"] = "sub-name",
[$"{EventPropagationSubscriptionOptions.SectionName}:{nameof(EventPropagationSubscriptionOptions.TopicName)}"] = "topic-name",
};

var services = new ServiceCollection();
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(myConfiguration)
.Build();
services.AddSingleton<IConfiguration>(configuration);
GivenConfigurations(services, EventPropagationSubscriptionOptions.DefaultSectionName);

// When
services.AddEventPropagationSubscriber(options => { options.TopicEndpoint = "http://ovewrite.io"; });
var serviceProvider = services.BuildServiceProvider();
var options = serviceProvider.GetRequiredService<IOptions<EventPropagationSubscriptionOptions>>().Value;
var options = serviceProvider.GetRequiredService<IOptionsMonitor<EventPropagationSubscriptionOptions>>().Get(EventPropagationSubscriptionOptions.DefaultSectionName);

// Then
Assert.Equal("http://ovewrite.io", options.TopicEndpoint);
Assert.Equal(myConfiguration[$"{EventPropagationSubscriptionOptions.SectionName}:{nameof(EventPropagationSubscriptionOptions.TopicAccessKey)}"], options.TopicAccessKey);
Assert.Equal(myConfiguration[$"{EventPropagationSubscriptionOptions.SectionName}:{nameof(EventPropagationSubscriptionOptions.SubscriptionName)}"], options.SubscriptionName);
Assert.Equal(myConfiguration[$"{EventPropagationSubscriptionOptions.SectionName}:{nameof(EventPropagationSubscriptionOptions.TopicName)}"], options.TopicName);
Assert.Equal(AccessKey, options.TopicAccessKey);
Assert.Equal(SubscriptionName, options.SubscriptionName);
Assert.Equal(TopicName, options.TopicName);
}

[Fact]
public void GivenNamedConfigurations_WhenAddSubscribers_ThenOptionsAreRegistered()
{
// Given
var services = new ServiceCollection();
const string sectionName1 = "EventPropagation:Sub1";
const string sectionName2 = "EventPropagation:Sub2";
GivenConfigurations(services, sectionName1, sectionName2);

// When
services.AddEventPropagationSubscriber(sectionName1);
services.AddEventPropagationSubscriber(sectionName2);
var serviceProvider = services.BuildServiceProvider();
var monitor = serviceProvider.GetRequiredService<IOptionsMonitor<EventPropagationSubscriptionOptions>>();
var options1 = monitor.Get(sectionName1);
var options2 = monitor.Get(sectionName2);

// Then
Assert.Equal(AccessKey, options1.TopicAccessKey);
Assert.Equal(TopicEndPoint, options1.TopicEndpoint);
Assert.Equal(TopicName, options1.TopicName);
Assert.Equal(SubscriptionName, options1.SubscriptionName);

Assert.Equal(AccessKey, options2.TopicAccessKey);
Assert.Equal(TopicEndPoint, options2.TopicEndpoint);
Assert.Equal(TopicName, options2.TopicName);
Assert.Equal(SubscriptionName, options2.SubscriptionName);
}

[Fact]
public void GivenNamedConfigurations_WhenAddSubscribers_CanOverrideConfigurations()
{
// Given
var services = new ServiceCollection();
const string sectionName1 = "EventPropagation:Sub1";
const string sectionName2 = "EventPropagation:Sub2";
GivenConfigurations(services, sectionName1, sectionName2);

// When
services.AddEventPropagationSubscriber(options => { options.TopicEndpoint = "http://ovewrite1.io"; }, sectionName1);
services.AddEventPropagationSubscriber(options => { options.TopicEndpoint = "http://ovewrite2.io"; }, sectionName2);
var serviceProvider = services.BuildServiceProvider();
var monitor = serviceProvider.GetRequiredService<IOptionsMonitor<EventPropagationSubscriptionOptions>>();
var options1 = monitor.Get(sectionName1);
var options2 = monitor.Get(sectionName2);

// Then
Assert.Equal("http://ovewrite1.io", options1.TopicEndpoint);
Assert.Equal(AccessKey, options1.TopicAccessKey);
Assert.Equal(TopicName, options1.TopicName);
Assert.Equal(SubscriptionName, options1.SubscriptionName);

Assert.Equal("http://ovewrite2.io", options2.TopicEndpoint);
Assert.Equal(AccessKey, options2.TopicAccessKey);
Assert.Equal(TopicName, options2.TopicName);
Assert.Equal(SubscriptionName, options2.SubscriptionName);
}

private static void GivenConfigurations(IServiceCollection services, params string[] sections)
{
var dictionnary = new Dictionary<string, string>();

foreach (var section in sections)
{
dictionnary[$"{section}:{nameof(EventPropagationSubscriptionOptions.TopicAccessKey)}"] = AccessKey;
dictionnary[$"{section}:{nameof(EventPropagationSubscriptionOptions.TopicEndpoint)}"] = TopicEndPoint;
dictionnary[$"{section}:{nameof(EventPropagationSubscriptionOptions.TopicName)}"] = TopicName;
dictionnary[$"{section}:{nameof(EventPropagationSubscriptionOptions.SubscriptionName)}"] = SubscriptionName;
}

var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(dictionnary)
.Build();
services.AddSingleton<IConfiguration>(configuration);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,27 @@ namespace Workleap.DomainEventPropagation;

internal sealed class EventPropagationSubscriberBuilder : IEventPropagationSubscriberBuilder
{
public EventPropagationSubscriberBuilder(IServiceCollection services, Action<EventPropagationSubscriptionOptions> configure)
public EventPropagationSubscriberBuilder(IServiceCollection services, Action<EventPropagationSubscriptionOptions> configure, string optionsSectionName)
{
this.Services = services;
this.AddRegistrations(configure);
this.AddRegistrations(configure, optionsSectionName);
}

public IServiceCollection Services { get; }

private void AddRegistrations(Action<EventPropagationSubscriptionOptions> configure)
private void AddRegistrations(Action<EventPropagationSubscriptionOptions> configure, string optionsSectionName)
{
this.Services
.AddOptions<EventPropagationSubscriptionOptions>()
.Configure<IConfiguration>(BindFromWellKnownConfigurationSection)
.AddOptions<EventPropagationSubscriptionOptions>(optionsSectionName)
.Configure<IConfiguration>((opt, cfg) => BindFromWellKnownConfigurationSection(opt, cfg, optionsSectionName))
.Configure(configure);

this.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IValidateOptions<EventPropagationSubscriptionOptions>, EventPropagationSubscriptionOptionsValidator>());
}

private static void BindFromWellKnownConfigurationSection(EventPropagationSubscriptionOptions options, IConfiguration configuration)
private static void BindFromWellKnownConfigurationSection(EventPropagationSubscriptionOptions options, IConfiguration configuration, string optionsSectionName)
{
configuration.GetSection(EventPropagationSubscriptionOptions.SectionName).Bind(options);
var section = configuration.GetSection(optionsSectionName);
section.Bind(options);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace Workleap.DomainEventPropagation;

public class EventPropagationSubscriptionOptions
{
internal const string SectionName = "EventPropagation:Subscription";
internal const string DefaultSectionName = "EventPropagation:Subscription";

public string TopicAccessKey { get; set; } = string.Empty;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#nullable enable
static Workleap.DomainEventPropagation.ServiceCollectionEventSubscriptionExtensions.AddEventPropagationSubscriber(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Workleap.DomainEventPropagation.IEventPropagationSubscriberBuilder!
static Workleap.DomainEventPropagation.ServiceCollectionEventSubscriptionExtensions.AddEventPropagationSubscriber(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action<Workleap.DomainEventPropagation.EventPropagationSubscriptionOptions!>! configure) -> Workleap.DomainEventPropagation.IEventPropagationSubscriberBuilder!
static Workleap.DomainEventPropagation.ServiceCollectionEventSubscriptionExtensions.AddEventPropagationSubscriber(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, string! optionsSectionName) -> Workleap.DomainEventPropagation.IEventPropagationSubscriberBuilder!
static Workleap.DomainEventPropagation.ServiceCollectionEventSubscriptionExtensions.AddEventPropagationSubscriber(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action<Workleap.DomainEventPropagation.EventPropagationSubscriptionOptions!>! configure, string! optionsSectionName = "EventPropagation:Subscription") -> Workleap.DomainEventPropagation.IEventPropagationSubscriberBuilder!
Workleap.DomainEventPropagation.EventPropagationSubscriptionOptions
Workleap.DomainEventPropagation.EventPropagationSubscriptionOptions.EventPropagationSubscriptionOptions() -> void
Workleap.DomainEventPropagation.EventPropagationSubscriptionOptions.SubscriptionName.get -> string!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ public static class ServiceCollectionEventSubscriptionExtensions
public static IEventPropagationSubscriberBuilder AddEventPropagationSubscriber(this IServiceCollection services)
=> services.AddEventPropagationSubscriber(_ => { });

public static IEventPropagationSubscriberBuilder AddEventPropagationSubscriber(this IServiceCollection services, Action<EventPropagationSubscriptionOptions> configure)
public static IEventPropagationSubscriberBuilder AddEventPropagationSubscriber(this IServiceCollection services, string optionsSectionName)
=> services.AddEventPropagationSubscriber(_ => { }, optionsSectionName);

public static IEventPropagationSubscriberBuilder AddEventPropagationSubscriber(this IServiceCollection services, Action<EventPropagationSubscriptionOptions> configure, string optionsSectionName = EventPropagationSubscriptionOptions.DefaultSectionName)
{
if (services == null)
{
Expand All @@ -19,6 +22,6 @@ public static IEventPropagationSubscriberBuilder AddEventPropagationSubscriber(t
throw new ArgumentNullException(nameof(configure));
}

return new EventPropagationSubscriberBuilder(services, configure);
return new EventPropagationSubscriberBuilder(services, configure, optionsSectionName);
}
}

0 comments on commit f98e532

Please sign in to comment.