|
4 | 4 | using Azure.Core;
|
5 | 5 | using Azure.Identity;
|
6 | 6 | using FluentAssertions;
|
| 7 | +using Grpc.Core; |
7 | 8 | using Microsoft.DurableTask.Client.Grpc;
|
8 | 9 | using Microsoft.Extensions.DependencyInjection;
|
9 | 10 | using Microsoft.Extensions.Options;
|
@@ -109,7 +110,7 @@ public void UseDurableTaskScheduler_WithNullParameters_ShouldThrowOptionsValidat
|
109 | 110 | // Assert
|
110 | 111 | var action = () => provider.GetRequiredService<IOptions<DurableTaskSchedulerClientOptions>>().Value;
|
111 | 112 | action.Should().Throw<OptionsValidationException>()
|
112 |
| - .WithMessage(endpoint == null |
| 113 | + .WithMessage(endpoint == null |
113 | 114 | ? "DataAnnotation validation failed for 'DurableTaskSchedulerClientOptions' members: 'EndpointAddress' with the error: 'Endpoint address is required'."
|
114 | 115 | : "DataAnnotation validation failed for 'DurableTaskSchedulerClientOptions' members: 'TaskHubName' with the error: 'Task hub name is required'.");
|
115 | 116 | }
|
@@ -193,4 +194,90 @@ public void UseDurableTaskScheduler_WithNamedOptions_ShouldConfigureCorrectly()
|
193 | 194 | options.ResourceId.Should().Be("https://durabletask.io");
|
194 | 195 | options.AllowInsecureCredentials.Should().BeFalse();
|
195 | 196 | }
|
| 197 | + |
| 198 | + [Fact] |
| 199 | + public void UseDurableTaskScheduler_WithEndpointAndCredentialAndRetryOptions_ShouldConfigureCorrectly() |
| 200 | + { |
| 201 | + // Arrange |
| 202 | + ServiceCollection services = new ServiceCollection(); |
| 203 | + Mock<IDurableTaskClientBuilder> mockBuilder = new Mock<IDurableTaskClientBuilder>(); |
| 204 | + mockBuilder.Setup(b => b.Services).Returns(services); |
| 205 | + DefaultAzureCredential credential = new DefaultAzureCredential(); |
| 206 | + |
| 207 | + // Act |
| 208 | + mockBuilder.Object.UseDurableTaskScheduler(ValidEndpoint, ValidTaskHub, credential, options => |
| 209 | + options.RetryOptions = new DurableTaskSchedulerClientOptions.ClientRetryOptions |
| 210 | + { |
| 211 | + MaxRetries = 5, |
| 212 | + InitialBackoffMs = 100, |
| 213 | + MaxBackoffMs = 1000, |
| 214 | + BackoffMultiplier = 2.0, |
| 215 | + RetryableStatusCodes = new List<StatusCode> { StatusCode.Unknown } |
| 216 | + } |
| 217 | + ); |
| 218 | + |
| 219 | + // Assert |
| 220 | + ServiceProvider provider = services.BuildServiceProvider(); |
| 221 | + IOptions<GrpcDurableTaskClientOptions>? options = provider.GetService<IOptions<GrpcDurableTaskClientOptions>>(); |
| 222 | + options.Should().NotBeNull(); |
| 223 | + |
| 224 | + // Validate the configured options |
| 225 | + DurableTaskSchedulerClientOptions clientOptions = provider.GetRequiredService<IOptions<DurableTaskSchedulerClientOptions>>().Value; |
| 226 | + clientOptions.EndpointAddress.Should().Be(ValidEndpoint); |
| 227 | + clientOptions.TaskHubName.Should().Be(ValidTaskHub); |
| 228 | + clientOptions.Credential.Should().BeOfType<DefaultAzureCredential>(); |
| 229 | + clientOptions.RetryOptions.Should().NotBeNull(); |
| 230 | + // The assert not null doesn't clear the syntax warning about null checks. |
| 231 | + if (clientOptions.RetryOptions != null) |
| 232 | + { |
| 233 | + clientOptions.RetryOptions.MaxRetries.Should().Be(5); |
| 234 | + clientOptions.RetryOptions.InitialBackoffMs.Should().Be(100); |
| 235 | + clientOptions.RetryOptions.MaxBackoffMs.Should().Be(1000); |
| 236 | + clientOptions.RetryOptions.BackoffMultiplier.Should().Be(2.0); |
| 237 | + clientOptions.RetryOptions.RetryableStatusCodes.Should().Contain(StatusCode.Unknown); |
| 238 | + } |
| 239 | + } |
| 240 | + |
| 241 | + [Fact] |
| 242 | + public void UseDurableTaskScheduler_WithConnectionStringAndRetryOptions_ShouldConfigureCorrectly() |
| 243 | + { |
| 244 | + // Arrange |
| 245 | + ServiceCollection services = new ServiceCollection(); |
| 246 | + Mock<IDurableTaskClientBuilder> mockBuilder = new Mock<IDurableTaskClientBuilder>(); |
| 247 | + mockBuilder.Setup(b => b.Services).Returns(services); |
| 248 | + string connectionString = $"Endpoint={ValidEndpoint};Authentication=DefaultAzure;TaskHub={ValidTaskHub}"; |
| 249 | + |
| 250 | + // Act |
| 251 | + mockBuilder.Object.UseDurableTaskScheduler(connectionString, options => |
| 252 | + options.RetryOptions = new DurableTaskSchedulerClientOptions.ClientRetryOptions |
| 253 | + { |
| 254 | + MaxRetries = 5, |
| 255 | + InitialBackoffMs = 100, |
| 256 | + MaxBackoffMs = 1000, |
| 257 | + BackoffMultiplier = 2.0, |
| 258 | + RetryableStatusCodes = new List<StatusCode> { StatusCode.Unknown } |
| 259 | + } |
| 260 | + ); |
| 261 | + |
| 262 | + // Assert |
| 263 | + ServiceProvider provider = services.BuildServiceProvider(); |
| 264 | + IOptions<GrpcDurableTaskClientOptions>? options = provider.GetService<IOptions<GrpcDurableTaskClientOptions>>(); |
| 265 | + options.Should().NotBeNull(); |
| 266 | + |
| 267 | + // Validate the configured options |
| 268 | + DurableTaskSchedulerClientOptions clientOptions = provider.GetRequiredService<IOptions<DurableTaskSchedulerClientOptions>>().Value; |
| 269 | + clientOptions.EndpointAddress.Should().Be(ValidEndpoint); |
| 270 | + clientOptions.TaskHubName.Should().Be(ValidTaskHub); |
| 271 | + clientOptions.Credential.Should().BeOfType<DefaultAzureCredential>(); |
| 272 | + clientOptions.RetryOptions.Should().NotBeNull(); |
| 273 | + // The assert not null doesn't clear the syntax warning about null checks. |
| 274 | + if (clientOptions.RetryOptions != null) |
| 275 | + { |
| 276 | + clientOptions.RetryOptions.MaxRetries.Should().Be(5); |
| 277 | + clientOptions.RetryOptions.InitialBackoffMs.Should().Be(100); |
| 278 | + clientOptions.RetryOptions.MaxBackoffMs.Should().Be(1000); |
| 279 | + clientOptions.RetryOptions.BackoffMultiplier.Should().Be(2.0); |
| 280 | + clientOptions.RetryOptions.RetryableStatusCodes.Should().Contain(StatusCode.Unknown); |
| 281 | + } |
| 282 | + } |
196 | 283 | }
|
0 commit comments