-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added options for subscriber (pull model) (#80)
Extension/Builder was used to follow what was already done for publisher / push model subscriber. Added options plus validation for Subscriber (pull model) Named options are supported so that we can register multiple subscribers to different topics Added extension method and builder to register those options
- Loading branch information
Showing
9 changed files
with
328 additions
and
1 deletion.
There are no files selected for viewing
48 changes: 48 additions & 0 deletions
48
...tion.Subscription.PullDelivery.Tests/EventPropagationSubscriptionOptionsValidatorTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
#nullable disable // To reproduce users that don't have nullable enabled | ||
|
||
using Azure.Identity; | ||
|
||
namespace Workleap.DomainEventPropagation.Subscription.PullDelivery.Tests; | ||
|
||
public class EventPropagationSubscriptionOptionsValidatorTests | ||
{ | ||
[Theory] | ||
|
||
// Valid options | ||
[InlineData("accessKey", false, "http://topicurl.com", "topicName", "subName", true)] | ||
|
||
// Access key | ||
[InlineData(" ", false, "http://topicurl.com", "topicName", "subName", false)] | ||
[InlineData(null, false, "http://topicurl.com", "topicName", "subName", false)] | ||
|
||
// Token credential | ||
[InlineData("accessKey", true, "http://topicurl.com", "topicName", "subName", true)] | ||
|
||
// Topic endpoint | ||
[InlineData("accessKey", false, "invalid-url", "topicName", "subName", false)] | ||
[InlineData("accessKey", false, null, "topicName", "subName", false)] | ||
[InlineData("accessKey", false, " ", "topicName", "subName", false)] | ||
|
||
// Topic name | ||
[InlineData("accessKey", false, "http://topicurl.com", " ", "subName", false)] | ||
[InlineData("accessKey", false, "http://topicurl.com", null, "subName", false)] | ||
|
||
// Subscription name | ||
[InlineData("accessKey", false, "http://topicurl.com", "topicName", "", false)] | ||
[InlineData("accessKey", false, "http://topicurl.com", "topicName", null, false)] | ||
public void GivenNamedConfiguration_WhenValidate_ThenOptionsAreValidated(string topicAccessKey, bool useTokenCredential, string topicEndpoint, string topicName, string subName, bool validationSucceeded) | ||
{ | ||
var validator = new EventPropagationSubscriptionOptionsValidator(); | ||
|
||
var result = validator.Validate("namedOptions", new EventPropagationSubscriptionOptions | ||
{ | ||
TokenCredential = useTokenCredential ? new DefaultAzureCredential() : default, | ||
TopicEndpoint = topicEndpoint, | ||
TopicAccessKey = topicAccessKey, | ||
TopicName = topicName, | ||
SubscriptionName = subName, | ||
}); | ||
|
||
Assert.Equal(validationSucceeded, result.Succeeded); | ||
} | ||
} |
129 changes: 129 additions & 0 deletions
129
...tion.Subscription.PullDelivery.Tests/ServiceCollectionEventSubscriptionExtensionsTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Options; | ||
|
||
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 GivenUnnamedConfiguration_WhenAddSubscriber_ThenOptionsAreRegistered() | ||
{ | ||
// Given | ||
var services = new ServiceCollection(); | ||
GivenConfigurations(services, EventPropagationSubscriptionOptions.DefaultSectionName); | ||
|
||
// When | ||
services.AddPullDeliverySubscription().AddSubscriber(); | ||
var serviceProvider = services.BuildServiceProvider(); | ||
var options = serviceProvider.GetRequiredService<IOptionsMonitor<EventPropagationSubscriptionOptions>>().Get(EventPropagationSubscriptionOptions.DefaultSectionName); | ||
|
||
// Then | ||
Assert.Equal(AccessKey, options.TopicAccessKey); | ||
Assert.Equal(TopicEndPoint, options.TopicEndpoint); | ||
Assert.Equal(TopicName, options.TopicName); | ||
Assert.Equal(SubscriptionName, options.SubscriptionName); | ||
} | ||
|
||
[Fact] | ||
public void GivenUnnamedConfiguration_WhenAddSubscriber_CanOverrideConfiguration() | ||
{ | ||
// Given | ||
var services = new ServiceCollection(); | ||
GivenConfigurations(services, EventPropagationSubscriptionOptions.DefaultSectionName); | ||
|
||
// When | ||
services.AddPullDeliverySubscription().AddSubscriber(options => { options.TopicEndpoint = "http://ovewrite.io"; }); | ||
var serviceProvider = services.BuildServiceProvider(); | ||
var options = serviceProvider.GetRequiredService<IOptionsMonitor<EventPropagationSubscriptionOptions>>().Get(EventPropagationSubscriptionOptions.DefaultSectionName); | ||
|
||
// Then | ||
Assert.Equal("http://ovewrite.io", options.TopicEndpoint); | ||
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.AddPullDeliverySubscription() | ||
.AddSubscriber(sectionName1) | ||
.AddSubscriber(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.AddPullDeliverySubscription() | ||
.AddSubscriber(options => { options.TopicEndpoint = "http://ovewrite1.io"; }, sectionName1) | ||
.AddSubscriber(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); | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
...eap.DomainEventPropagation.Subscription.PullDelivery/EventPropagationSubscriberBuilder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.DependencyInjection.Extensions; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Workleap.DomainEventPropagation; | ||
|
||
internal sealed class EventPropagationSubscriberBuilder : IEventPropagationSubscriberBuilder | ||
{ | ||
public EventPropagationSubscriberBuilder(IServiceCollection services) | ||
{ | ||
this.Services = services; | ||
} | ||
|
||
public IServiceCollection Services { get; } | ||
} |
18 changes: 18 additions & 0 deletions
18
...p.DomainEventPropagation.Subscription.PullDelivery/EventPropagationSubscriptionOptions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using Azure.Core; | ||
|
||
namespace Workleap.DomainEventPropagation; | ||
|
||
public class EventPropagationSubscriptionOptions | ||
{ | ||
internal const string DefaultSectionName = "EventPropagation:Subscription"; | ||
|
||
public string TopicAccessKey { get; set; } = string.Empty; | ||
|
||
public TokenCredential? TokenCredential { get; set; } | ||
|
||
public string TopicEndpoint { get; set; } = string.Empty; | ||
|
||
public string TopicName { get; set; } = string.Empty; | ||
|
||
public string SubscriptionName { get; set; } = string.Empty; | ||
} |
36 changes: 36 additions & 0 deletions
36
...ventPropagation.Subscription.PullDelivery/EventPropagationSubscriptionOptionsValidator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Workleap.DomainEventPropagation; | ||
|
||
public class EventPropagationSubscriptionOptionsValidator : IValidateOptions<EventPropagationSubscriptionOptions> | ||
{ | ||
public ValidateOptionsResult Validate(string name, EventPropagationSubscriptionOptions options) | ||
{ | ||
if (options.TokenCredential is null && string.IsNullOrWhiteSpace(options.TopicAccessKey)) | ||
{ | ||
return ValidateOptionsResult.Fail("A token credential or an access key is required"); | ||
} | ||
|
||
if (string.IsNullOrWhiteSpace(options.TopicEndpoint)) | ||
{ | ||
return ValidateOptionsResult.Fail("A topic endpoint is required"); | ||
} | ||
|
||
if (!Uri.TryCreate(options.TopicEndpoint, UriKind.Absolute, out _)) | ||
{ | ||
return ValidateOptionsResult.Fail("The topic endpoint must be an absolute URI"); | ||
} | ||
|
||
if (string.IsNullOrWhiteSpace(options.TopicName)) | ||
{ | ||
return ValidateOptionsResult.Fail("A topic endpoint is required"); | ||
} | ||
|
||
if (string.IsNullOrWhiteSpace(options.SubscriptionName)) | ||
{ | ||
return ValidateOptionsResult.Fail("A topic endpoint is required"); | ||
} | ||
|
||
return ValidateOptionsResult.Success; | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
...ap.DomainEventPropagation.Subscription.PullDelivery/IEventPropagationSubscriberBuilder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace Workleap.DomainEventPropagation; | ||
|
||
public interface IEventPropagationSubscriberBuilder | ||
{ | ||
IServiceCollection Services { get; } | ||
} |
24 changes: 23 additions & 1 deletion
24
src/Workleap.DomainEventPropagation.Subscription.PullDelivery/PublicAPI.Unshipped.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,23 @@ | ||
#nullable enable | ||
#nullable enable | ||
static Workleap.DomainEventPropagation.ServiceCollectionEventSubscriptionExtensions.AddPullDeliverySubscription(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Workleap.DomainEventPropagation.IEventPropagationSubscriberBuilder! | ||
static Workleap.DomainEventPropagation.ServiceCollectionEventSubscriptionExtensions.AddSubscriber(this Workleap.DomainEventPropagation.IEventPropagationSubscriberBuilder! builder) -> Workleap.DomainEventPropagation.IEventPropagationSubscriberBuilder! | ||
static Workleap.DomainEventPropagation.ServiceCollectionEventSubscriptionExtensions.AddSubscriber(this Workleap.DomainEventPropagation.IEventPropagationSubscriberBuilder! builder, string! optionsSectionName) -> Workleap.DomainEventPropagation.IEventPropagationSubscriberBuilder! | ||
static Workleap.DomainEventPropagation.ServiceCollectionEventSubscriptionExtensions.AddSubscriber(this Workleap.DomainEventPropagation.IEventPropagationSubscriberBuilder! builder, 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! | ||
Workleap.DomainEventPropagation.EventPropagationSubscriptionOptions.SubscriptionName.set -> void | ||
Workleap.DomainEventPropagation.EventPropagationSubscriptionOptions.TokenCredential.get -> Azure.Core.TokenCredential? | ||
Workleap.DomainEventPropagation.EventPropagationSubscriptionOptions.TokenCredential.set -> void | ||
Workleap.DomainEventPropagation.EventPropagationSubscriptionOptions.TopicAccessKey.get -> string! | ||
Workleap.DomainEventPropagation.EventPropagationSubscriptionOptions.TopicAccessKey.set -> void | ||
Workleap.DomainEventPropagation.EventPropagationSubscriptionOptions.TopicEndpoint.get -> string! | ||
Workleap.DomainEventPropagation.EventPropagationSubscriptionOptions.TopicEndpoint.set -> void | ||
Workleap.DomainEventPropagation.EventPropagationSubscriptionOptions.TopicName.get -> string! | ||
Workleap.DomainEventPropagation.EventPropagationSubscriptionOptions.TopicName.set -> void | ||
Workleap.DomainEventPropagation.EventPropagationSubscriptionOptionsValidator | ||
Workleap.DomainEventPropagation.EventPropagationSubscriptionOptionsValidator.EventPropagationSubscriptionOptionsValidator() -> void | ||
Workleap.DomainEventPropagation.EventPropagationSubscriptionOptionsValidator.Validate(string! name, Workleap.DomainEventPropagation.EventPropagationSubscriptionOptions! options) -> Microsoft.Extensions.Options.ValidateOptionsResult! | ||
Workleap.DomainEventPropagation.IEventPropagationSubscriberBuilder | ||
Workleap.DomainEventPropagation.IEventPropagationSubscriberBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection! | ||
Workleap.DomainEventPropagation.ServiceCollectionEventSubscriptionExtensions |
47 changes: 47 additions & 0 deletions
47
...ventPropagation.Subscription.PullDelivery/ServiceCollectionEventSubscriptionExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.DependencyInjection.Extensions; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Workleap.DomainEventPropagation; | ||
|
||
public static class ServiceCollectionEventSubscriptionExtensions | ||
{ | ||
public static IEventPropagationSubscriberBuilder AddPullDeliverySubscription(this IServiceCollection services) | ||
{ | ||
return new EventPropagationSubscriberBuilder(services); | ||
} | ||
|
||
public static IEventPropagationSubscriberBuilder AddSubscriber(this IEventPropagationSubscriberBuilder builder) | ||
=> builder.AddSubscriber(_ => { }); | ||
|
||
public static IEventPropagationSubscriberBuilder AddSubscriber(this IEventPropagationSubscriberBuilder builder, string optionsSectionName) | ||
=> builder.AddSubscriber(_ => { }, optionsSectionName); | ||
|
||
public static IEventPropagationSubscriberBuilder AddSubscriber(this IEventPropagationSubscriberBuilder builder, Action<EventPropagationSubscriptionOptions> configure, string optionsSectionName = EventPropagationSubscriptionOptions.DefaultSectionName) | ||
{ | ||
if (builder == null) | ||
{ | ||
throw new ArgumentNullException(nameof(builder)); | ||
} | ||
|
||
if (configure == null) | ||
{ | ||
throw new ArgumentNullException(nameof(configure)); | ||
} | ||
|
||
builder.Services.AddOptions<EventPropagationSubscriptionOptions>(optionsSectionName) | ||
.Configure<IConfiguration>((opt, cfg) => BindFromWellKnownConfigurationSection(opt, cfg, optionsSectionName)) | ||
.Configure(configure); | ||
|
||
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IValidateOptions<EventPropagationSubscriptionOptions>, EventPropagationSubscriptionOptionsValidator>()); | ||
|
||
return builder; | ||
} | ||
|
||
private static void BindFromWellKnownConfigurationSection(EventPropagationSubscriptionOptions options, IConfiguration configuration, string optionsSectionName) | ||
{ | ||
var section = configuration.GetSection(optionsSectionName); | ||
section.Bind(options); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters