Skip to content

Commit 8923128

Browse files
committed
Add OrchestrationServiceShim unit tests
1 parent 742f912 commit 8923128

File tree

6 files changed

+260
-11
lines changed

6 files changed

+260
-11
lines changed

Microsoft.DurableTask.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleAppMinimal", "sample
8787
EndProject
8888
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Worker.OrchestrationServiceShim", "src\Worker\OrchestrationServiceShim\Worker.OrchestrationServiceShim.csproj", "{361E87D2-5CF6-4BB2-8B11-0BE736F88EB8}"
8989
EndProject
90+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Worker.OrchestrationServiceShim.Tests", "test\Worker\OrchestrationServiceShim.Tests\Worker.OrchestrationServiceShim.Tests.csproj", "{14822652-388B-4521-924A-2834B75F783C}"
91+
EndProject
9092
Global
9193
GlobalSection(SolutionConfigurationPlatforms) = preSolution
9294
Debug|Any CPU = Debug|Any CPU
@@ -229,6 +231,10 @@ Global
229231
{361E87D2-5CF6-4BB2-8B11-0BE736F88EB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
230232
{361E87D2-5CF6-4BB2-8B11-0BE736F88EB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
231233
{361E87D2-5CF6-4BB2-8B11-0BE736F88EB8}.Release|Any CPU.Build.0 = Release|Any CPU
234+
{14822652-388B-4521-924A-2834B75F783C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
235+
{14822652-388B-4521-924A-2834B75F783C}.Debug|Any CPU.Build.0 = Debug|Any CPU
236+
{14822652-388B-4521-924A-2834B75F783C}.Release|Any CPU.ActiveCfg = Release|Any CPU
237+
{14822652-388B-4521-924A-2834B75F783C}.Release|Any CPU.Build.0 = Release|Any CPU
232238
EndGlobalSection
233239
GlobalSection(SolutionProperties) = preSolution
234240
HideSolutionNode = FALSE
@@ -272,6 +278,7 @@ Global
272278
{3272C041-F81D-4C85-A4FB-2A700B5A7A9D} = {CECADDB5-E30A-4CE2-8604-9AC596D4A2DC}
273279
{B48FACA9-A328-452A-BFAE-C4F60F9C7024} = {EFF7632B-821E-4CFC-B4A0-ED4B24296B17}
274280
{361E87D2-5CF6-4BB2-8B11-0BE736F88EB8} = {5B448FF6-EC42-491D-A22E-1DC8B618E6D5}
281+
{14822652-388B-4521-924A-2834B75F783C} = {51DC98A3-0193-4C66-964B-C26C748E25B6}
275282
EndGlobalSection
276283
GlobalSection(ExtensibilityGlobals) = postSolution
277284
SolutionGuid = {AB41CB55-35EA-4986-A522-387AB3402E71}

src/Worker/OrchestrationServiceShim/ShimDurableTaskWorker.cs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ class ShimDurableTaskWorker : DurableTaskWorker
2727
readonly IServiceProvider services;
2828
readonly DurableTaskShimFactory shimFactory;
2929
readonly ILogger logger;
30-
readonly TaskHubWorker worker;
3130

3231
/// <summary>
3332
/// Initializes a new instance of the <see cref="ShimDurableTaskWorker" /> class.
@@ -51,22 +50,27 @@ public ShimDurableTaskWorker(
5150

5251
// This should already be validated by options.
5352
IOrchestrationService service = Verify.NotNull(this.options.Service);
54-
this.worker = service is IEntityOrchestrationService entity
53+
this.Worker = service is IEntityOrchestrationService entity
5554
? this.CreateWorker(entity, loggerFactory) : this.CreateWorker(service, loggerFactory);
5655
}
5756

57+
/// <summary>
58+
/// Gets the inner <see cref="TaskHubWorker"/>.
59+
/// </summary>
60+
/// <remarks>
61+
/// For internal test verification.
62+
/// </remarks>
63+
internal TaskHubWorker Worker { get; }
64+
5865
/// <inheritdoc/>
59-
public override async Task StopAsync(CancellationToken cancellationToken)
60-
{
61-
await base.StopAsync(cancellationToken);
62-
await this.worker.StopAsync();
63-
}
66+
public override Task StopAsync(CancellationToken cancellationToken) => this.Worker.StopAsync();
6467

6568
/// <inheritdoc/>
66-
protected override Task ExecuteAsync(CancellationToken stoppingToken)
67-
{
68-
return this.worker.StartAsync().WaitAsync(stoppingToken);
69-
}
69+
public override Task StartAsync(CancellationToken cancellationToken) => this.Worker.StartAsync();
70+
71+
/// <inheritdoc/>
72+
/// <remarks>Not actually called.</remarks>
73+
protected override Task ExecuteAsync(CancellationToken stoppingToken) => Task.CompletedTask;
7074

7175
TaskHubWorker CreateWorker(IOrchestrationService service, ILoggerFactory loggerFactory)
7276
{
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using DurableTask.Core;
5+
using Microsoft.Extensions.DependencyInjection;
6+
using Microsoft.Extensions.Options;
7+
8+
namespace Microsoft.DurableTask.Worker.OrchestrationServiceShim.Tests;
9+
10+
public class DurableTaskWorkerBuilderExtensionsTests
11+
{
12+
[Fact]
13+
public void UseOrchestrationService_NotSet_Throws()
14+
{
15+
ServiceCollection services = new();
16+
DefaultDurableTaskWorkerBuilder builder = new(null, services);
17+
Action act = () => builder.UseOrchestrationService();
18+
act.Should().NotThrow();
19+
builder.BuildTarget.Should().Be(typeof(ShimDurableTaskWorker));
20+
21+
IServiceProvider provider = services.BuildServiceProvider();
22+
act = () => provider.GetOptions<ShimDurableTaskWorkerOptions>();
23+
24+
act.Should().ThrowExactly<OptionsValidationException>()
25+
.WithMessage("ShimDurableTaskWorkerOptions.Service must not be null.");
26+
}
27+
28+
[Fact]
29+
public void UseOrchestrationService_Service_Sets()
30+
{
31+
ServiceCollection services = new();
32+
IOrchestrationService service = Mock.Of<IOrchestrationService>();
33+
DefaultDurableTaskWorkerBuilder builder = new(null, services);
34+
builder.UseOrchestrationService(service);
35+
36+
IServiceProvider provider = services.BuildServiceProvider();
37+
ShimDurableTaskWorkerOptions options = provider.GetOptions<ShimDurableTaskWorkerOptions>();
38+
39+
options.Service.Should().Be(service);
40+
}
41+
42+
[Fact]
43+
public void UseOrchestrationService_FromServices1()
44+
{
45+
ServiceCollection services = new();
46+
IOrchestrationService service = Mock.Of<IOrchestrationService>();
47+
services.AddSingleton(service);
48+
DefaultDurableTaskWorkerBuilder builder = new(null, services);
49+
50+
builder.UseOrchestrationService();
51+
52+
IServiceProvider provider = services.BuildServiceProvider();
53+
ShimDurableTaskWorkerOptions options = provider.GetOptions<ShimDurableTaskWorkerOptions>();
54+
55+
options.Service.Should().Be(service);
56+
}
57+
58+
[Fact]
59+
public void UseOrchestrationService_FromServices2()
60+
{
61+
ServiceCollection services = new();
62+
Mock<IOrchestrationService> mock = new();
63+
mock.As<IOrchestrationService>();
64+
services.AddSingleton(mock.As<IOrchestrationService>().Object);
65+
DefaultDurableTaskWorkerBuilder builder = new(null, services);
66+
67+
builder.UseOrchestrationService();
68+
69+
IServiceProvider provider = services.BuildServiceProvider();
70+
ShimDurableTaskWorkerOptions options = provider.GetOptions<ShimDurableTaskWorkerOptions>();
71+
72+
options.Service.Should().Be(mock.Object);
73+
}
74+
75+
[Fact]
76+
public void UseOrchestrationService_Callback_Sets()
77+
{
78+
ServiceCollection services = new();
79+
IOrchestrationService service = Mock.Of<IOrchestrationService>();
80+
DefaultDurableTaskWorkerBuilder builder = new(null, services);
81+
builder.UseOrchestrationService(opt => opt.Service = service);
82+
83+
IServiceProvider provider = services.BuildServiceProvider();
84+
ShimDurableTaskWorkerOptions options = provider.GetOptions<ShimDurableTaskWorkerOptions>();
85+
86+
options.Service.Should().Be(service);
87+
}
88+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using DurableTask.Core;
5+
using DurableTask.Core.Entities;
6+
using Microsoft.DurableTask.Worker.OrchestrationServiceShim.Core;
7+
using Microsoft.Extensions.Logging.Abstractions;
8+
using Microsoft.Extensions.Options;
9+
10+
namespace Microsoft.DurableTask.Worker.OrchestrationServiceShim.Tests;
11+
12+
public class ShimDurableTaskWorkerTests
13+
{
14+
readonly Mock<IOrchestrationService> orchestrationService = new(MockBehavior.Strict);
15+
readonly Mock<IDurableTaskFactory> durableTaskFactory = new(MockBehavior.Strict);
16+
readonly Mock<IServiceProvider> serviceProvider = new(MockBehavior.Strict);
17+
readonly ShimDurableTaskWorkerOptions options = new();
18+
19+
[Fact]
20+
public void Ctor_WithEntityService_EntitiesEnabled()
21+
{
22+
// Arrange
23+
this.durableTaskFactory.As<IDurableTaskFactory2>();
24+
Mock<IEntityOrchestrationService> entities = this.AddEntitiesToOrchestrationService();
25+
this.options.EnableEntitySupport = true;
26+
27+
// Act
28+
ShimDurableTaskWorker worker = this.CreateWorker();
29+
30+
// Assert
31+
worker.Worker.orchestrationService.Should().BeSameAs(this.orchestrationService.Object);
32+
entities.Verify(m => m.EntityBackendProperties, Times.Once);
33+
}
34+
35+
[Fact]
36+
public void Ctor_WithEntityService_EntitiesDisabled()
37+
{
38+
// Arrange
39+
this.durableTaskFactory.As<IDurableTaskFactory2>();
40+
this.AddEntitiesToOrchestrationService();
41+
this.options.EnableEntitySupport = false;
42+
43+
// Act
44+
ShimDurableTaskWorker worker = this.CreateWorker();
45+
46+
// Assert
47+
worker.Worker.orchestrationService.Should().BeOfType<OrchestrationServiceNoEntities>();
48+
}
49+
50+
[Fact]
51+
public void Ctor_FactoryNoEntitySupport_EntitiesDisabled()
52+
{
53+
// Arrange
54+
this.AddEntitiesToOrchestrationService();
55+
this.options.EnableEntitySupport = true;
56+
57+
// Act
58+
ShimDurableTaskWorker worker = this.CreateWorker();
59+
60+
// Assert
61+
worker.Worker.orchestrationService.Should().BeOfType<OrchestrationServiceNoEntities>();
62+
}
63+
64+
[Fact]
65+
public void Ctor_NoEntityService_EntitiesDisabled()
66+
{
67+
// Arrange
68+
this.durableTaskFactory.As<IDurableTaskFactory2>();
69+
this.options.EnableEntitySupport = true;
70+
71+
// Act
72+
ShimDurableTaskWorker worker = this.CreateWorker();
73+
74+
// Assert
75+
worker.Worker.orchestrationService.Should().BeSameAs(this.orchestrationService.Object);
76+
}
77+
78+
[Fact]
79+
public async Task Start_StartsInnerWorker()
80+
{
81+
// Arrange
82+
this.orchestrationService.Setup(m => m.TaskOrchestrationDispatcherCount).Returns(1);
83+
this.orchestrationService.Setup(m => m.MaxConcurrentTaskOrchestrationWorkItems).Returns(1);
84+
this.orchestrationService.Setup(m => m.TaskActivityDispatcherCount).Returns(1);
85+
this.orchestrationService.Setup(m => m.MaxConcurrentTaskActivityWorkItems).Returns(1);
86+
this.orchestrationService.Setup(m => m.StartAsync()).Returns(Task.CompletedTask);
87+
ShimDurableTaskWorker worker = this.CreateWorker();
88+
89+
// Act
90+
await worker.StartAsync(default);
91+
92+
// Assert
93+
this.orchestrationService.Verify(m => m.StartAsync(), Times.Once);
94+
}
95+
96+
[Fact]
97+
public async Task Stop_StopsInnerWorker()
98+
{
99+
// Arrange
100+
this.orchestrationService.Setup(m => m.TaskOrchestrationDispatcherCount).Returns(1);
101+
this.orchestrationService.Setup(m => m.MaxConcurrentTaskOrchestrationWorkItems).Returns(1);
102+
this.orchestrationService.Setup(m => m.TaskActivityDispatcherCount).Returns(1);
103+
this.orchestrationService.Setup(m => m.MaxConcurrentTaskActivityWorkItems).Returns(1);
104+
this.orchestrationService.Setup(m => m.StartAsync()).Returns(Task.CompletedTask);
105+
this.orchestrationService.Setup(m => m.StopAsync(false)).Returns(Task.CompletedTask);
106+
ShimDurableTaskWorker worker = this.CreateWorker();
107+
await worker.StartAsync(default);
108+
109+
// Act
110+
await worker.StopAsync(default);
111+
112+
// Assert
113+
this.orchestrationService.Verify(m => m.StopAsync(false), Times.Once);
114+
}
115+
116+
Mock<IEntityOrchestrationService> AddEntitiesToOrchestrationService()
117+
{
118+
Mock<IEntityOrchestrationService> mock = this.orchestrationService.As<IEntityOrchestrationService>();
119+
mock.Setup(m => m.EntityBackendProperties).Returns(new EntityBackendProperties());
120+
return mock;
121+
}
122+
123+
ShimDurableTaskWorker CreateWorker()
124+
{
125+
this.options.Service = this.orchestrationService.Object;
126+
return new(
127+
"test",
128+
this.durableTaskFactory.Object,
129+
Mock.Of<IOptionsMonitor<ShimDurableTaskWorkerOptions>>(m => m.Get("test") == this.options),
130+
this.serviceProvider.Object,
131+
NullLoggerFactory.Instance);
132+
}
133+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
global using FluentAssertions;
5+
global using Moq;
6+
global using Xunit;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<ItemGroup>
4+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
5+
</ItemGroup>
6+
7+
<ItemGroup>
8+
<ProjectReference Include="$(SrcRoot)Worker/OrchestrationServiceShim/Worker.OrchestrationServiceShim.csproj" />
9+
</ItemGroup>
10+
11+
</Project>

0 commit comments

Comments
 (0)