Skip to content

Commit 9fa0862

Browse files
Merge pull request #276 from Avanade/feat/newcartridges
fix: Added null checks and configuration validation
2 parents 2f4ac17 + 9688559 commit 9fa0862

File tree

5 files changed

+172
-11
lines changed

5 files changed

+172
-11
lines changed

src/Liquid.Messaging.ServiceBus/Liquid.Messaging.ServiceBus.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<Copyright>Avanade 2019</Copyright>
1111
<PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl>
1212
<PackageIcon>logo.png</PackageIcon>
13-
<Version>8.0.0</Version>
13+
<Version>8.0.1</Version>
1414
<GenerateDocumentationFile>true</GenerateDocumentationFile>
1515
<Description>
1616
The Liquid.Messaging.ServiceBus provides producer and consumer patterns to allow the send and consumption of Messaging inside your microservice.

src/Liquid.Messaging.ServiceBus/ServiceBusConsumer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class ServiceBusConsumer<TEntity> : ILiquidConsumer<TEntity>
3434
public ServiceBusConsumer(IServiceBusFactory factory, string settingsName)
3535
{
3636
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
37-
_settingsName = settingsName;
37+
_settingsName = settingsName ?? throw new ArgumentNullException(nameof(settingsName));
3838
}
3939

4040
///<inheritdoc/>

src/Liquid.Messaging.ServiceBus/ServiceBusFactory.cs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ public ServiceBusProcessor GetProcessor(string settingsName)
2828
{
2929
var config = _options.Settings.FirstOrDefault(x => x.EntityPath == settingsName);
3030

31+
if (config == null)
32+
{
33+
throw new ArgumentOutOfRangeException(nameof(settingsName), $"The settings name '{settingsName}' is not found in the configuration.");
34+
}
35+
3136
var options = new ServiceBusProcessorOptions();
3237

3338
options.ReceiveMode = config.PeekLockMode ? ServiceBusReceiveMode.PeekLock : ServiceBusReceiveMode.ReceiveAndDelete;
@@ -42,7 +47,7 @@ public ServiceBusProcessor GetProcessor(string settingsName)
4247
processor = serviceBusClient.CreateProcessor(config.EntityPath, options);
4348
}
4449
else
45-
{
50+
{
4651
processor = serviceBusClient.CreateProcessor(config.EntityPath, config.Subscription, options);
4752
}
4853

@@ -59,6 +64,11 @@ public ServiceBusSender GetSender(string settingsName)
5964
{
6065
var config = _options.Settings.FirstOrDefault(x => x.EntityPath == settingsName);
6166

67+
if (config == null)
68+
{
69+
throw new ArgumentOutOfRangeException(nameof(settingsName), $"The settings name '{settingsName}' is not found in the configuration.");
70+
}
71+
6272
try
6373
{
6474
var serviceBusClient = new ServiceBusClient(config.ConnectionString);
@@ -77,15 +87,20 @@ public ServiceBusReceiver GetReceiver(string settingsName)
7787
{
7888
var config = _options.Settings.FirstOrDefault(x => x.EntityPath == settingsName);
7989

90+
if (config == null)
91+
{
92+
throw new ArgumentOutOfRangeException(nameof(settingsName), $"The settings name '{settingsName}' is not found in the configuration.");
93+
}
94+
8095
try
8196
{
8297
var options = new ServiceBusReceiverOptions();
8398

8499
options.ReceiveMode = config.PeekLockMode ? ServiceBusReceiveMode.PeekLock : ServiceBusReceiveMode.ReceiveAndDelete;
85-
86-
var serviceBusClient = new ServiceBusClient(config.ConnectionString);
87-
88-
var receiver = serviceBusClient.CreateReceiver(config.EntityPath, options);
100+
101+
var serviceBusClient = new ServiceBusClient(config.ConnectionString);
102+
103+
var receiver = serviceBusClient.CreateReceiver(config.EntityPath, options);
89104

90105
return receiver;
91106
}

test/Liquid.Messaging.ServiceBus.Tests/ServiceBusConsumerTest.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,16 @@ public ServiceBusConsumerTest() : base(_factory, "test")
2525
}
2626

2727
[Fact]
28-
public void RegisterMessageHandler_WhenRegisteredSucessfully_StartProcessingReceivedCall()
28+
public async Task RegisterMessageHandler_WhenRegisteredSucessfully_StartProcessingReceivedCall()
2929
{
3030
var messageReceiver = Substitute.For<ServiceBusProcessor>();
3131
_factory.GetProcessor(Arg.Any<string>()).Returns(messageReceiver);
3232

3333
ConsumeMessageAsync += ProcessMessageAsyncMock;
3434

35-
RegisterMessageHandler();
35+
await RegisterMessageHandler();
3636

37-
messageReceiver.Received(1).StartProcessingAsync();
37+
await messageReceiver.Received(1).StartProcessingAsync();
3838
}
3939

4040
[Fact]
@@ -46,7 +46,6 @@ public async Task RegisterMessageHandler_WhenConsumeMessageAssyncIsNull_ThrowNot
4646
await Assert.ThrowsAsync<NotImplementedException>(() => RegisterMessageHandler());
4747
}
4848

49-
5049
[Fact]
5150
public async Task MessageHandler_WhenProcessExecutedSucessfully()
5251
{
@@ -85,6 +84,17 @@ public async Task ErrorHandler_WhenProcessErrorExecuted_ThrowsMessagingConsumerE
8584
await Assert.ThrowsAsync<MessagingConsumerException>(() => ErrorHandler(processError));
8685
}
8786

87+
[Fact]
88+
public void Constructor_WhenFactoryIsNull_ThrowsArgumentNullException()
89+
{
90+
Assert.Throws<ArgumentNullException>(() => new ServiceBusConsumer<EntityMock>(null, "test"));
91+
}
92+
93+
[Fact]
94+
public void Constructor_WhenSettingsNameIsNull_ThrowsArgumentNullException()
95+
{
96+
Assert.Throws<ArgumentNullException>(() => new ServiceBusConsumer<EntityMock>(_factory, null));
97+
}
8898

8999
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
90100
private async Task ProcessMessageAsyncMock(ConsumerMessageEventArgs<EntityMock> args, CancellationToken cancellationToken)
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Azure.Messaging.ServiceBus;
5+
using Liquid.Core.Exceptions;
6+
using Liquid.Messaging.ServiceBus;
7+
using Liquid.Messaging.ServiceBus.Settings;
8+
using Microsoft.Extensions.Options;
9+
using NSubstitute;
10+
using Xunit;
11+
12+
namespace Liquid.Messaging.ServiceBus.Tests
13+
{
14+
public class ServiceBusFactoryTests
15+
{
16+
private readonly ServiceBusSettings _settings;
17+
private readonly IOptions<ServiceBusSettings> _options;
18+
19+
public ServiceBusFactoryTests()
20+
{
21+
_settings = new ServiceBusSettings
22+
{
23+
Settings = new List<ServiceBusEntitySettings>
24+
{
25+
new ServiceBusEntitySettings
26+
{
27+
EntityPath = "queue1",
28+
ConnectionString = "Endpoint=sb://test.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=key",
29+
PeekLockMode = true,
30+
MaxConcurrentCalls = 5,
31+
Subscription = null
32+
},
33+
new ServiceBusEntitySettings
34+
{
35+
EntityPath = "topic1",
36+
ConnectionString = "Endpoint=sb://test.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=key",
37+
PeekLockMode = false,
38+
MaxConcurrentCalls = 2,
39+
Subscription = "sub1"
40+
}
41+
}
42+
};
43+
_options = Substitute.For<IOptions<ServiceBusSettings>>();
44+
_options.Value.Returns(_settings);
45+
}
46+
47+
[Fact]
48+
public void GetSender_ReturnsSender_WhenConfigExists()
49+
{
50+
// Arrange
51+
var factory = new ServiceBusFactory(_options);
52+
53+
// Act
54+
var sender = factory.GetSender("queue1");
55+
56+
// Assert
57+
Assert.NotNull(sender);
58+
Assert.IsType<ServiceBusSender>(sender);
59+
}
60+
61+
[Fact]
62+
public void GetSender_ThrowsArgumentOutOfRangeException_WhenConfigMissing()
63+
{
64+
// Arrange
65+
var factory = new ServiceBusFactory(_options);
66+
67+
// Act & Assert
68+
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => factory.GetSender("notfound"));
69+
Assert.Contains("notfound", ex.Message);
70+
}
71+
72+
[Fact]
73+
public void GetProcessor_ReturnsProcessor_WhenQueueConfigExists()
74+
{
75+
// Arrange
76+
var factory = new ServiceBusFactory(_options);
77+
78+
// Act
79+
var processor = factory.GetProcessor("queue1");
80+
81+
// Assert
82+
Assert.NotNull(processor);
83+
Assert.IsType<ServiceBusProcessor>(processor);
84+
}
85+
86+
[Fact]
87+
public void GetProcessor_ReturnsProcessor_WhenTopicConfigExists()
88+
{
89+
// Arrange
90+
var factory = new ServiceBusFactory(_options);
91+
92+
// Act
93+
var processor = factory.GetProcessor("topic1");
94+
95+
// Assert
96+
Assert.NotNull(processor);
97+
Assert.IsType<ServiceBusProcessor>(processor);
98+
}
99+
100+
[Fact]
101+
public void GetProcessor_ThrowsMessagingMissingConfigurationException_WhenConfigMissing()
102+
{
103+
// Arrange
104+
var factory = new ServiceBusFactory(_options);
105+
106+
// Act & Assert
107+
var ex = Assert.Throws<MessagingMissingConfigurationException>(() => factory.GetProcessor("notfound"));
108+
Assert.Contains("notfound", ex.Message);
109+
}
110+
111+
[Fact]
112+
public void GetReceiver_ReturnsReceiver_WhenConfigExists()
113+
{
114+
// Arrange
115+
var factory = new ServiceBusFactory(_options);
116+
117+
// Act
118+
var receiver = factory.GetReceiver("queue1");
119+
120+
// Assert
121+
Assert.NotNull(receiver);
122+
Assert.IsType<ServiceBusReceiver>(receiver);
123+
}
124+
125+
[Fact]
126+
public void GetReceiver_ThrowsArgumentOutOfRangeException_WhenConfigMissing()
127+
{
128+
// Arrange
129+
var factory = new ServiceBusFactory(_options);
130+
131+
// Act & Assert
132+
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => factory.GetReceiver("notfound"));
133+
Assert.Contains("notfound", ex.Message);
134+
}
135+
}
136+
}

0 commit comments

Comments
 (0)