Skip to content

Commit 8bcd493

Browse files
committed
Added intetgration scenarios to test IoC scope for MS IoC container and the AutoFac IoC container
1 parent b25f3f0 commit 8bcd493

File tree

3 files changed

+257
-1
lines changed

3 files changed

+257
-1
lines changed
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
using System;
2+
using WorkflowCore.Interface;
3+
using WorkflowCore.Models;
4+
using Xunit;
5+
using FluentAssertions;
6+
using WorkflowCore.Testing;
7+
using Microsoft.Extensions.DependencyInjection;
8+
using Autofac.Extensions.DependencyInjection;
9+
using Autofac;
10+
using System.Diagnostics;
11+
12+
namespace WorkflowCore.IntegrationTests.Scenarios
13+
{
14+
public class DiWorkflow : IWorkflow<DiData>
15+
{
16+
public string Id => "DiWorkflow";
17+
public int Version => 1;
18+
19+
public void Build(IWorkflowBuilder<DiData> builder)
20+
{
21+
builder
22+
.StartWith<DiStep1>()
23+
.Output(_ => _.instance1, _ => _.dependency1.Instance)
24+
.Output(_ => _.instance2, _ => _.dependency2.dependency1.Instance)
25+
.Then(context =>
26+
{
27+
return ExecutionResult.Next();
28+
});
29+
}
30+
}
31+
32+
public class DiData
33+
{
34+
public int instance1 { get; set; } = -1;
35+
public int instance2 { get; set; } = -1;
36+
}
37+
38+
public class Dependency1
39+
{
40+
public static int InstanceCounter = 0;
41+
42+
public int Instance { get; set; } = ++InstanceCounter;
43+
}
44+
45+
public class Dependency2
46+
{
47+
public readonly Dependency1 dependency1;
48+
49+
public Dependency2(Dependency1 dependency1)
50+
{
51+
this.dependency1 = dependency1;
52+
}
53+
}
54+
55+
public class DiStep1 : StepBody
56+
{
57+
public readonly Dependency1 dependency1;
58+
public readonly Dependency2 dependency2;
59+
60+
public DiStep1(Dependency1 dependency1, Dependency2 dependency2)
61+
{
62+
this.dependency1 = dependency1;
63+
this.dependency2 = dependency2;
64+
}
65+
66+
public override ExecutionResult Run(IStepExecutionContext context)
67+
{
68+
return ExecutionResult.Next();
69+
}
70+
}
71+
72+
/// <summary>
73+
/// The DI scenarios are design to test whether the scoped / transient dependecies are honoured with
74+
/// various IoC container implementations. The basic premise is that a step has a dependency on
75+
/// two services, one of which has a dependency on the other.
76+
///
77+
/// We then use the instance numbers of the services to determine whether the container has created a
78+
/// transient instance or a scoped instance
79+
///
80+
/// if step.dependency2.dependency1.instance == step.dependency1.instance then
81+
/// we can be assured that dependency1 was created in the same scope as dependency 2
82+
///
83+
/// otherwise if the instances are different, they were created as transient
84+
///
85+
/// </summary>
86+
public abstract class DiScenario : WorkflowTest<DiWorkflow, DiData>
87+
{
88+
protected void ConfigureHost(IServiceProvider serviceProvider)
89+
{
90+
PersistenceProvider = serviceProvider.GetService<IPersistenceProvider>();
91+
Host = serviceProvider.GetService<IWorkflowHost>();
92+
Host.RegisterWorkflow<DiWorkflow, DiData>();
93+
Host.OnStepError += Host_OnStepError;
94+
Host.Start();
95+
}
96+
}
97+
98+
/// <summary>
99+
/// Because of the static InMemory Persistence provider, this test must run in issolation
100+
/// to prevent other hosts from picking up steps intended for this host and incorrectly
101+
/// cross-referencing the scoped / transient IoC container for step constrcution
102+
/// </summary>
103+
[CollectionDefinition("DiMsTransientScenario", DisableParallelization = true)]
104+
[Collection("DiMsTransientScenario")]
105+
public class DiMsTransientScenario : DiScenario
106+
{
107+
public DiMsTransientScenario()
108+
{
109+
//setup dependency injection
110+
IServiceCollection services = new ServiceCollection();
111+
services.AddTransient<Dependency1>();
112+
services.AddTransient<Dependency2>();
113+
services.AddTransient<DiStep1>();
114+
services.AddLogging();
115+
ConfigureServices(services);
116+
117+
var serviceProvider = services.BuildServiceProvider();
118+
ConfigureHost(serviceProvider);
119+
}
120+
121+
[Fact]
122+
public void Scenario()
123+
{
124+
var workflowId = StartWorkflow(new DiData());
125+
WaitForWorkflowToComplete(workflowId, TimeSpan.FromSeconds(5));
126+
var data = GetData(workflowId);
127+
128+
// DI provider should have created two transient instances, with different instance ids
129+
data.instance1.Should().NotBe(-1);
130+
data.instance2.Should().NotBe(-1);
131+
data.instance1.Should().NotBe(data.instance2);
132+
}
133+
}
134+
135+
/// <summary>
136+
/// Because of the static InMemory Persistence provider, this test must run in issolation
137+
/// to prevent other hosts from picking up steps intended for this host and incorrectly
138+
/// cross-referencing the scoped / transient IoC container for step constrcution
139+
/// </summary>
140+
[CollectionDefinition("DiMsScopedScenario", DisableParallelization = true)]
141+
[Collection("DiMsScopedScenario")]
142+
public class DiMsScopedScenario : DiScenario
143+
{
144+
public DiMsScopedScenario()
145+
{
146+
//setup dependency injection
147+
IServiceCollection services = new ServiceCollection();
148+
services.AddScoped<Dependency1>();
149+
services.AddScoped<Dependency2>();
150+
services.AddTransient<DiStep1>();
151+
services.AddLogging();
152+
ConfigureServices(services);
153+
154+
var serviceProvider = services.BuildServiceProvider();
155+
ConfigureHost(serviceProvider);
156+
}
157+
158+
[Fact]
159+
public void Scenario()
160+
{
161+
var workflowId = StartWorkflow(new DiData());
162+
WaitForWorkflowToComplete(workflowId, TimeSpan.FromSeconds(5));
163+
var data = GetData(workflowId);
164+
165+
// scope provider should have created one scoped instance, with the same instance ids
166+
data.instance1.Should().NotBe(-1);
167+
data.instance2.Should().NotBe(-1);
168+
data.instance1.Should().Be(data.instance2);
169+
}
170+
}
171+
172+
/// <summary>
173+
/// Because of the static InMemory Persistence provider, this test must run in issolation
174+
/// to prevent other hosts from picking up steps intended for this host and incorrectly
175+
/// cross-referencing the scoped / transient IoC container for step constrcution
176+
/// </summary>
177+
[CollectionDefinition("DiAutoFacTransientScenario", DisableParallelization = true)]
178+
[Collection("DiAutoFacTransientScenario")]
179+
public class DiAutoFacTransientScenario : DiScenario
180+
{
181+
public DiAutoFacTransientScenario()
182+
{
183+
//setup dependency injection
184+
IServiceCollection services = new ServiceCollection();
185+
services.AddLogging();
186+
ConfigureServices(services);
187+
188+
//setup dependency injection
189+
var builder = new ContainerBuilder();
190+
builder.Populate(services);
191+
builder.RegisterType<Dependency1>().InstancePerDependency();
192+
builder.RegisterType<Dependency2>().InstancePerDependency();
193+
builder.RegisterType<DiStep1>().InstancePerDependency();
194+
var container = builder.Build();
195+
196+
var serviceProvider = new AutofacServiceProvider(container);
197+
ConfigureHost(serviceProvider);
198+
}
199+
200+
[Fact]
201+
public void Scenario()
202+
{
203+
var workflowId = StartWorkflow(new DiData());
204+
WaitForWorkflowToComplete(workflowId, TimeSpan.FromSeconds(5));
205+
var data = GetData(workflowId);
206+
207+
// scope provider should have created one scoped instance, with the same instance ids
208+
data.instance1.Should().NotBe(-1);
209+
data.instance2.Should().NotBe(-1);
210+
data.instance1.Should().NotBe(data.instance2);
211+
}
212+
}
213+
214+
/// <summary>
215+
/// Because of the static InMemory Persistence provider, this test must run in issolation
216+
/// to prevent other hosts from picking up steps intended for this host and incorrectly
217+
/// cross-referencing the scoped / transient IoC container for step constrcution
218+
/// </summary>
219+
[CollectionDefinition("DiAutoFacScopedScenario", DisableParallelization = true)]
220+
[Collection("DiAutoFacScopedScenario")]
221+
public class DiAutoFacScopedScenario : DiScenario
222+
{
223+
public DiAutoFacScopedScenario()
224+
{
225+
//setup dependency injection
226+
IServiceCollection services = new ServiceCollection();
227+
services.AddLogging();
228+
ConfigureServices(services);
229+
230+
//setup dependency injection
231+
var builder = new ContainerBuilder();
232+
builder.Populate(services);
233+
builder.RegisterType<Dependency1>().InstancePerLifetimeScope();
234+
builder.RegisterType<Dependency2>().InstancePerLifetimeScope();
235+
builder.RegisterType<DiStep1>().InstancePerLifetimeScope();
236+
var container = builder.Build();
237+
238+
var serviceProvider = new AutofacServiceProvider(container);
239+
ConfigureHost(serviceProvider);
240+
}
241+
242+
[Fact]
243+
public void Scenario()
244+
{
245+
var workflowId = StartWorkflow(null);
246+
WaitForWorkflowToComplete(workflowId, TimeSpan.FromSeconds(5));
247+
var data = GetData(workflowId);
248+
249+
// scope provider should have created one scoped instance, with the same instance ids
250+
data.instance1.Should().NotBe(-1);
251+
data.instance2.Should().NotBe(-1);
252+
data.instance1.Should().Be(data.instance2);
253+
}
254+
}
255+
}

test/WorkflowCore.IntegrationTests/WorkflowCore.IntegrationTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
</ItemGroup>
1919

2020
<ItemGroup>
21+
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.3.1" />
2122
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
2223
<PackageReference Include="FluentAssertions" Version="4.19.4" />
2324
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.1.0" />

test/WorkflowCore.Testing/WorkflowTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ protected virtual void Setup()
3939
Host.Start();
4040
}
4141

42-
private void Host_OnStepError(WorkflowInstance workflow, WorkflowStep step, Exception exception)
42+
protected void Host_OnStepError(WorkflowInstance workflow, WorkflowStep step, Exception exception)
4343
{
4444
UnhandledStepErrors.Add(new StepError()
4545
{

0 commit comments

Comments
 (0)