Skip to content

Commit 9995d5e

Browse files
author
Anders Tøgersen (Delegate)
committed
Extended ServiceCollectionExtensions configuration
Added tests
1 parent ad4d288 commit 9995d5e

File tree

7 files changed

+286
-46
lines changed

7 files changed

+286
-46
lines changed

Atc.Azure.Messaging.sln

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,36 @@
1-
2-
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio Version 17
4-
VisualStudioVersion = 17.0.31903.59
5-
MinimumVisualStudioVersion = 15.0.26124.0
6-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Atc.Azure.Messaging", "src\Atc.Azure.Messaging\Atc.Azure.Messaging.csproj", "{2F7702F2-A407-41FB-8C88-7C066237BC75}"
7-
EndProject
8-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Atc.Azure.Messaging.Tests", "test\Atc.Azure.Messaging.Tests\Atc.Azure.Messaging.Tests.csproj", "{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}"
9-
EndProject
10-
Global
11-
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12-
Debug|Any CPU = Debug|Any CPU
13-
Release|Any CPU = Release|Any CPU
14-
EndGlobalSection
15-
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16-
{2F7702F2-A407-41FB-8C88-7C066237BC75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17-
{2F7702F2-A407-41FB-8C88-7C066237BC75}.Debug|Any CPU.Build.0 = Debug|Any CPU
18-
{2F7702F2-A407-41FB-8C88-7C066237BC75}.Release|Any CPU.ActiveCfg = Release|Any CPU
19-
{2F7702F2-A407-41FB-8C88-7C066237BC75}.Release|Any CPU.Build.0 = Release|Any CPU
20-
{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21-
{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
22-
{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
23-
{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}.Release|Any CPU.Build.0 = Release|Any CPU
24-
EndGlobalSection
25-
GlobalSection(SolutionProperties) = preSolution
26-
HideSolutionNode = FALSE
27-
EndGlobalSection
28-
GlobalSection(ExtensibilityGlobals) = postSolution
29-
SolutionGuid = {1EC093F7-1E03-4088-BA72-0DEB39AFEE82}
30-
EndGlobalSection
31-
EndGlobal
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.0.31903.59
5+
MinimumVisualStudioVersion = 15.0.26124.0
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Atc.Azure.Messaging", "src\Atc.Azure.Messaging\Atc.Azure.Messaging.csproj", "{2F7702F2-A407-41FB-8C88-7C066237BC75}"
7+
EndProject
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Atc.Azure.Messaging.Tests", "test\Atc.Azure.Messaging.Tests\Atc.Azure.Messaging.Tests.csproj", "{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}"
9+
EndProject
10+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5F9CEB97-F31C-493F-9FF4-EF94F8169B80}"
11+
ProjectSection(SolutionItems) = preProject
12+
version.json = version.json
13+
EndProjectSection
14+
EndProject
15+
Global
16+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
17+
Debug|Any CPU = Debug|Any CPU
18+
Release|Any CPU = Release|Any CPU
19+
EndGlobalSection
20+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
21+
{2F7702F2-A407-41FB-8C88-7C066237BC75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22+
{2F7702F2-A407-41FB-8C88-7C066237BC75}.Debug|Any CPU.Build.0 = Debug|Any CPU
23+
{2F7702F2-A407-41FB-8C88-7C066237BC75}.Release|Any CPU.ActiveCfg = Release|Any CPU
24+
{2F7702F2-A407-41FB-8C88-7C066237BC75}.Release|Any CPU.Build.0 = Release|Any CPU
25+
{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26+
{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
27+
{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
28+
{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}.Release|Any CPU.Build.0 = Release|Any CPU
29+
EndGlobalSection
30+
GlobalSection(SolutionProperties) = preSolution
31+
HideSolutionNode = FALSE
32+
EndGlobalSection
33+
GlobalSection(ExtensibilityGlobals) = postSolution
34+
SolutionGuid = {1EC093F7-1E03-4088-BA72-0DEB39AFEE82}
35+
EndGlobalSection
36+
EndGlobal

src/Atc.Azure.Messaging/Atc.Azure.Messaging.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
</PropertyGroup>
1212

1313
<ItemGroup>
14-
<None Include="..\..\README.md" Pack="true" PackagePath="\"/>
14+
<None Include="..\..\README.md" Pack="true" PackagePath="\" />
1515
</ItemGroup>
1616

1717
<ItemGroup>
18-
<PackageReference Include="Atc.Azure.Options" Version="3.0.14" />
18+
<PackageReference Include="Atc.Azure.Options" Version="3.0.18" />
1919
<PackageReference Include="Azure.Messaging.EventHubs" Version="5.7.0" />
2020
<PackageReference Include="Azure.Messaging.ServiceBus" Version="7.8.1" />
2121
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />

src/Atc.Azure.Messaging/ServiceCollectionExtensions.cs

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,68 @@
1-
using System.Diagnostics.CodeAnalysis;
1+
using System.Diagnostics.CodeAnalysis;
22
using Atc.Azure.Messaging.EventHub;
33
using Atc.Azure.Messaging.ServiceBus;
4+
using Atc.Azure.Options.Authorization;
5+
using Atc.Azure.Options.Environment;
46
using Atc.Azure.Options.EventHub;
7+
using Atc.Azure.Options.Providers;
58
using Atc.Azure.Options.ServiceBus;
9+
using Azure.Identity;
610
using Microsoft.Extensions.Configuration;
7-
11+
using Microsoft.Extensions.DependencyInjection.Extensions;
12+
813
namespace Microsoft.Extensions.DependencyInjection;
914

1015
[ExcludeFromCodeCoverage]
1116
public static class ServiceCollectionExtensions
1217
{
13-
public static void ConfigureMessagingServices(
14-
this IServiceCollection services,
15-
IConfiguration configuration)
16-
{
17-
services.AddOptions<EventHubOptions>(configuration);
18-
services.AddOptions<ServiceBusOptions>(configuration);
19-
20-
services.AddSingleton<IEventHubPublisherFactory, EventHubPublisherFactory>();
21-
services.AddSingleton<IServiceBusClientFactory, ServiceBusClientFactory>();
22-
services.AddSingleton<IServiceBusSenderProvider, ServiceBusSenderProvider>();
23-
services.AddSingleton<IServiceBusPublisher, ServiceBusPublisher>();
18+
/// <summary>
19+
/// Adds messaging services from the configuration.
20+
/// </summary>
21+
/// <param name="services">The service collection</param>
22+
/// <param name="configuration">The application configurations</param>
23+
/// <param name="useAzureCredentials">
24+
/// Flag indicating whether to use managed identity with azure credentials or
25+
/// connection strings for the messaging service configuration.
26+
/// <para>
27+
/// Defaults to using connection strings.
28+
/// </para>
29+
/// </param>
30+
/// <param name="credentialOptionsProvider">
31+
/// The <see cref="IAzureCredentialOptionsProvider"/> to be used for configuring
32+
/// the <see cref="DefaultAzureCredential"/>.
33+
/// <para>
34+
/// Defaults to <see cref="AzureCredentialOptionsProvider"/> if
35+
/// <paramref name="credentialOptionsProvider"/> is null.
36+
/// </para>
37+
/// <para>
38+
/// Parameter is only considered if <paramref name="useAzureCredentials"/> is set to true.
39+
/// </para>
40+
/// </param>
41+
public static void ConfigureMessagingServices(
42+
this IServiceCollection services,
43+
IConfiguration configuration,
44+
bool useAzureCredentials = false,
45+
IAzureCredentialOptionsProvider? credentialOptionsProvider = null)
46+
{
47+
services.AddOptions<EventHubOptions>(configuration);
48+
services.AddOptions<ServiceBusOptions>(configuration);
49+
50+
if (useAzureCredentials)
51+
{
52+
services.AddOptions<EnvironmentOptions>(configuration);
53+
services.AddOptions<ClientAuthorizationOptions>(configuration);
54+
55+
credentialOptionsProvider ??= new AzureCredentialOptionsProvider();
56+
services.AddSingleton<IAzureCredentialOptionsProvider>(credentialOptionsProvider);
57+
58+
services.AddSingleton<IEventHubPublisherFactory, EventHubCredentialsPublisherFactory>();
59+
services.AddSingleton<IServiceBusClientFactory, ServiceBusCredentialsClientFactory>();
60+
}
61+
62+
services.TryAddSingleton<IEventHubPublisherFactory, EventHubPublisherFactory>();
63+
services.TryAddSingleton<IServiceBusClientFactory, ServiceBusClientFactory>();
64+
services.AddSingleton<IServiceBusSenderProvider, ServiceBusSenderProvider>();
65+
services.AddSingleton<IServiceBusPublisher, ServiceBusPublisher>();
2466
}
2567

2668
private static T AddOptions<T>(

test/Atc.Azure.Messaging.Tests/Atc.Azure.Messaging.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
</PropertyGroup>
1010

1111
<ItemGroup>
12+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
1213
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
1314
<PackageReference Include="xunit" Version="2.4.1" />
1415
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using Atc.Azure.Messaging.EventHub;
2+
using Atc.Azure.Options.Authorization;
3+
using Atc.Azure.Options.Environment;
4+
using Atc.Azure.Options.EventHub;
5+
using Atc.Azure.Options.Providers;
6+
7+
namespace Atc.Azure.Messaging.Tests.EventHub;
8+
9+
public class EventHubCredentialsPublisherFactoryTests
10+
{
11+
private const string FullyQualifiedNamespace = "eventHubNamespace.servicebus.windows.net";
12+
13+
[Theory, AutoNSubstituteData]
14+
public void Create_Returns_NotNull(
15+
[Frozen] IAzureCredentialOptionsProvider credentialOptionsProvider,
16+
EnvironmentOptions environmentOptions,
17+
ClientAuthorizationOptions authorizationOptions,
18+
string eventHubName)
19+
=> new EventHubCredentialsPublisherFactory(
20+
new EventHubOptions { FullyQualifiedNamespace = FullyQualifiedNamespace },
21+
environmentOptions,
22+
authorizationOptions,
23+
credentialOptionsProvider)
24+
.Create(eventHubName)
25+
.Should()
26+
.NotBeNull();
27+
28+
[Theory, AutoNSubstituteData]
29+
public void Create_Returns_IEventHubPublisher(
30+
[Frozen] IAzureCredentialOptionsProvider credentialOptionsProvider,
31+
EnvironmentOptions environmentOptions,
32+
ClientAuthorizationOptions authorizationOptions,
33+
string eventHubName)
34+
=> new EventHubCredentialsPublisherFactory(
35+
new EventHubOptions { FullyQualifiedNamespace = FullyQualifiedNamespace },
36+
environmentOptions,
37+
authorizationOptions,
38+
credentialOptionsProvider)
39+
.Create(eventHubName)
40+
.Should()
41+
.BeAssignableTo<IEventHubPublisher>();
42+
43+
[Theory, AutoNSubstituteData]
44+
public void Constructor_Calls_AzureCredentialsOptionsProvider(
45+
[Frozen] IAzureCredentialOptionsProvider credentialOptionsProvider,
46+
EventHubOptions eventHubOptions,
47+
EnvironmentOptions environmentOptions,
48+
ClientAuthorizationOptions authorizationOptions)
49+
{
50+
_ = new EventHubCredentialsPublisherFactory(
51+
eventHubOptions,
52+
environmentOptions,
53+
authorizationOptions,
54+
credentialOptionsProvider);
55+
56+
credentialOptionsProvider
57+
.Received(1)
58+
.GetAzureCredentialOptions(environmentOptions, authorizationOptions);
59+
}
60+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using Atc.Azure.Messaging.ServiceBus;
2+
using Atc.Azure.Options.Authorization;
3+
using Atc.Azure.Options.Environment;
4+
using Atc.Azure.Options.Providers;
5+
using Atc.Azure.Options.ServiceBus;
6+
7+
namespace Atc.Azure.Messaging.Tests.ServiceBus;
8+
9+
public class ServiceBusCredentialsClientFactoryTests
10+
{
11+
private const string FullyQualifiedNamespace = "serviceBusNamespace.servicebus.windows.net";
12+
13+
[Theory, AutoNSubstituteData]
14+
public void Create_Returns_Not_Null(
15+
[Frozen] IAzureCredentialOptionsProvider credentialOptionsProvider,
16+
EnvironmentOptions environmentOptions,
17+
ClientAuthorizationOptions authorizationOptions) =>
18+
new ServiceBusCredentialsClientFactory(
19+
new ServiceBusOptions { FullyQualifiedNamespace = FullyQualifiedNamespace },
20+
environmentOptions,
21+
authorizationOptions,
22+
credentialOptionsProvider)
23+
.Create()
24+
.Should()
25+
.NotBeNull();
26+
27+
[Theory, AutoNSubstituteData]
28+
public void Create_Returns_Client_With_FullyQualifiedNamespace(
29+
[Frozen] IAzureCredentialOptionsProvider credentialOptionsProvider,
30+
EnvironmentOptions environmentOptions,
31+
ClientAuthorizationOptions authorizationOptions) =>
32+
new ServiceBusCredentialsClientFactory(
33+
new ServiceBusOptions { FullyQualifiedNamespace = FullyQualifiedNamespace },
34+
environmentOptions,
35+
authorizationOptions,
36+
credentialOptionsProvider)
37+
.Create()
38+
.FullyQualifiedNamespace
39+
.Should()
40+
.Be(FullyQualifiedNamespace);
41+
42+
[Theory, AutoNSubstituteData]
43+
public void Constructor_Calls_AzureCredentialsOptionsProvider(
44+
[Frozen] IAzureCredentialOptionsProvider credentialOptionsProvider,
45+
ServiceBusOptions serviceBusOptions,
46+
EnvironmentOptions environmentOptions,
47+
ClientAuthorizationOptions authorizationOptions)
48+
{
49+
_ = new ServiceBusCredentialsClientFactory(
50+
serviceBusOptions,
51+
environmentOptions,
52+
authorizationOptions,
53+
credentialOptionsProvider);
54+
55+
credentialOptionsProvider
56+
.Received(1)
57+
.GetAzureCredentialOptions(environmentOptions, authorizationOptions);
58+
}
59+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using Atc.Azure.Messaging.EventHub;
2+
using Atc.Azure.Messaging.ServiceBus;
3+
using Atc.Azure.Options.Providers;
4+
using Microsoft.Extensions.Configuration;
5+
using Microsoft.Extensions.DependencyInjection;
6+
7+
namespace Atc.Azure.Messaging.Tests;
8+
9+
public class ServiceCollectionExtensionsTests
10+
{
11+
private readonly IServiceCollection services = new ServiceCollection();
12+
13+
[Theory]
14+
[InlineAutoNSubstituteData(false, typeof(IEventHubPublisherFactory), typeof(EventHubPublisherFactory))]
15+
[InlineAutoNSubstituteData(false, typeof(IServiceBusClientFactory), typeof(ServiceBusClientFactory))]
16+
[InlineAutoNSubstituteData(false, typeof(IServiceBusPublisher), typeof(ServiceBusPublisher))]
17+
[InlineAutoNSubstituteData(false, typeof(IServiceBusSenderProvider), typeof(ServiceBusSenderProvider))]
18+
[InlineAutoNSubstituteData(true, typeof(IEventHubPublisherFactory), typeof(EventHubCredentialsPublisherFactory))]
19+
[InlineAutoNSubstituteData(true, typeof(IServiceBusClientFactory), typeof(ServiceBusCredentialsClientFactory))]
20+
[InlineAutoNSubstituteData(true, typeof(IServiceBusPublisher), typeof(ServiceBusPublisher))]
21+
[InlineAutoNSubstituteData(true, typeof(IServiceBusSenderProvider), typeof(ServiceBusSenderProvider))]
22+
public void ConfigureMessagingServices_Adds_Messaging_Dependencies(
23+
bool useAzureCredentials,
24+
Type serviceType,
25+
Type implementationType,
26+
[Frozen] IConfiguration configuration)
27+
{
28+
services.ConfigureMessagingServices(configuration, useAzureCredentials);
29+
30+
services
31+
.Should()
32+
.ContainSingle(s =>
33+
s.Lifetime == ServiceLifetime.Singleton &&
34+
s.ServiceType == serviceType &&
35+
s.ImplementationType == implementationType);
36+
}
37+
38+
[Theory, AutoNSubstituteData]
39+
public void ConfigureMessagingServices_Adds_AzureCredentialOptionsProvider_Default_Dependency(
40+
[Frozen] IConfiguration configuration)
41+
{
42+
services.ConfigureMessagingServices(configuration, true, null);
43+
44+
services
45+
.Should()
46+
.ContainSingle(s =>
47+
s.Lifetime == ServiceLifetime.Singleton &&
48+
s.ServiceType == typeof(IAzureCredentialOptionsProvider))
49+
.Which
50+
.ImplementationInstance
51+
.Should()
52+
.BeOfType<AzureCredentialOptionsProvider>();
53+
}
54+
55+
[Theory, AutoNSubstituteData]
56+
public void ConfigureMessagingServices_Adds_AzureCredentialOptionsProvider_Instance_Dependency(
57+
[Frozen] IConfiguration configuration)
58+
{
59+
var azureCredentialOptionsProviderInstance = new AzureCredentialOptionsProvider();
60+
61+
services.ConfigureMessagingServices(configuration, true, azureCredentialOptionsProviderInstance);
62+
63+
services
64+
.Should()
65+
.ContainSingle(s =>
66+
s.Lifetime == ServiceLifetime.Singleton &&
67+
s.ServiceType == typeof(IAzureCredentialOptionsProvider))
68+
.Which
69+
.ImplementationInstance
70+
.Should()
71+
.BeSameAs(azureCredentialOptionsProviderInstance);
72+
}
73+
}

0 commit comments

Comments
 (0)