Skip to content

Commit 51df37f

Browse files
author
Maxim Shoshin
committed
Allow to inject user code into initialization pipeline
1 parent 6ac80d9 commit 51df37f

File tree

5 files changed

+84
-57
lines changed

5 files changed

+84
-57
lines changed

ComposeTestEnvironment.xUnit/DockerComposeEnvironmentFixture.cs

+65-23
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ public class DockerComposeEnvironmentFixture<TDescriptor> : IAsyncLifetime
2525
private readonly IMessageSink _output;
2626
private readonly List<string> _outputStrings = new();
2727
private readonly DisposableList _disposables = new();
28-
private readonly TDescriptor _descriptor = new();
2928

3029
public DockerComposeEnvironmentFixture(IMessageSink output)
3130
{
@@ -36,7 +35,39 @@ public DockerComposeEnvironmentFixture(IMessageSink output)
3635

3736
public Discovery Discovery { get; private set; }
3837

39-
public async Task InitializeAsync()
38+
protected TDescriptor Descriptor { get; } = new();
39+
40+
protected virtual ValueTask AfterInitializeAsync()
41+
{
42+
return default;
43+
}
44+
45+
protected virtual ValueTask BeforeDisposeAsync()
46+
{
47+
return default;
48+
}
49+
50+
protected virtual ValueTask BeforeSingleTimeInitialize()
51+
{
52+
return default;
53+
}
54+
55+
protected virtual ValueTask AfterSingleTimeInitialize(Discovery discovery)
56+
{
57+
return default;
58+
}
59+
60+
protected void RegisterGlobalDisposable(IDisposable disposable)
61+
{
62+
_disposables.Add(disposable);
63+
}
64+
65+
protected ValueTask RegisterGlobalDisposableAsync(IAsyncDisposable disposable)
66+
{
67+
return _disposables.AddAsync(disposable);
68+
}
69+
70+
async Task IAsyncLifetime.InitializeAsync()
4071
{
4172
if (_initializeAsync == null)
4273
{
@@ -47,48 +78,59 @@ public async Task InitializeAsync()
4778
}
4879

4980
Discovery = await _initializeAsync;
81+
82+
await AfterInitializeAsync();
5083
}
5184

52-
public Task DisposeAsync()
85+
async Task IAsyncLifetime.DisposeAsync()
5386
{
54-
return Task.CompletedTask;
87+
await BeforeDisposeAsync();
5588
}
5689

5790
private async Task<Discovery> InitializeCoreAsync()
5891
{
59-
if (_descriptor.IsUnderCompose)
92+
await BeforeSingleTimeInitialize();
93+
94+
Discovery discovery;
95+
if (Descriptor.IsUnderCompose)
6096
{
61-
if (_descriptor.WaitForPortsListen)
97+
if (Descriptor.WaitForPortsListen)
6298
{
63-
var listening = _descriptor.Ports
99+
var listening = Descriptor.Ports
64100
.SelectMany(x => x.Value.Select(port => new UriBuilder("tcp://", x.Key, port).Uri))
65101
.ToList();
66102

67103
await WaitForListeningPorts(listening);
68104
}
69105

70-
return new Discovery(
71-
_descriptor.Ports.ToDictionary(
106+
discovery = new Discovery(
107+
Descriptor.Ports.ToDictionary(
72108
item => new HostSubstitution(item.Key, item.Key),
73109
item => (IReadOnlyList<PortSubstitution>)item.Value.Select(port => new PortSubstitution(port, port)).ToList()));
74110
}
111+
else
112+
{
113+
discovery = await InitializeComposeEnvironmentAsync();
114+
}
115+
116+
await AfterSingleTimeInitialize(discovery);
75117

76-
return await InitializeComposeEnvironmentAsync();
118+
return discovery;
77119
}
78120

79121
private async Task<Discovery> InitializeComposeEnvironmentAsync()
80122
{
81-
using var composeFileStream = File.OpenRead(FindFile(_descriptor.FileName));
123+
using var composeFileStream = File.OpenRead(FindFile(Descriptor.FileName));
82124

83125
var composeFile = ComposeFile.ParseAsync(composeFileStream);
84126

85127
await AssignExposedPorts(composeFile);
86128

87129
var generatedFilePath = GenerateComposeFileWithExposedPorts(composeFile);
88-
var projectName = _descriptor.ProjectName;
130+
var projectName = Descriptor.ProjectName;
89131
TestFramework.RegisterDisposable(_disposables);
90132

91-
if (_descriptor.DownOnComplete)
133+
if (Descriptor.DownOnComplete)
92134
{
93135
var downProcess = ComposeDown(generatedFilePath, projectName);
94136
_disposables.Add(downProcess);
@@ -97,7 +139,7 @@ await _disposables.AddAsync(async () =>
97139
{
98140
WriteMessage("Stopping compose...");
99141
await downProcess.Start(_startTimeout);
100-
await downProcess.WaitForExit().WithTimeout(_descriptor.StopTimeout);
142+
await downProcess.WaitForExit().WithTimeout(Descriptor.StopTimeout);
101143
});
102144
}
103145

@@ -117,7 +159,7 @@ await _disposables.AddAsync(async () =>
117159
.Argument("up")
118160
.CollectOutput(WriteMessage);
119161

120-
foreach (var message in _descriptor.StartedMessageMarkers)
162+
foreach (var message in Descriptor.StartedMessageMarkers)
121163
{
122164
process.WaitForMessageInOutput(message);
123165
}
@@ -126,7 +168,7 @@ await _disposables.AddAsync(async () =>
126168

127169
try
128170
{
129-
await process.Start(_descriptor.StartTimeout);
171+
await process.Start(Descriptor.StartTimeout);
130172
}
131173
catch (OperationCanceledException ex)
132174
{
@@ -143,10 +185,10 @@ await _disposables.AddAsync(async () =>
143185
var portMappings = composeFile.Services
144186
.Where(service =>
145187
service.Image != null &&
146-
_descriptor.Ports.ContainsKey(service.ServiceName))
188+
Descriptor.Ports.ContainsKey(service.ServiceName))
147189
.ToDictionary(x => x.ServiceName, x => x.PortMappings);
148190

149-
if (_descriptor.WaitForPortsListen)
191+
if (Descriptor.WaitForPortsListen)
150192
{
151193
var listening = portMappings.Values
152194
.SelectMany(x => x)
@@ -161,14 +203,14 @@ await _disposables.AddAsync(async () =>
161203
item => new HostSubstitution(item.Key, "localhost"),
162204
item => (IReadOnlyList<PortSubstitution>)item.Value.Select(port => new PortSubstitution(port.ExposedPort, port.PublicPort)).ToList()));
163205

164-
await _descriptor.WaitForReady(discovery);
206+
await Descriptor.WaitForReady(discovery);
165207

166208
return discovery;
167209
}
168210

169211
private async Task WaitForListeningPorts(IReadOnlyList<Uri> listening)
170212
{
171-
using var cancellationTokenSource = new CancellationTokenSource(_descriptor.StartTimeout);
213+
using var cancellationTokenSource = new CancellationTokenSource(Descriptor.StartTimeout);
172214

173215
var tasks = listening.Select(uri => Connect(uri, cancellationTokenSource.Token));
174216

@@ -252,7 +294,7 @@ private string GenerateComposeFileWithExposedPorts(ComposeFile composeFile)
252294
}
253295
});
254296

255-
if (_descriptor.GenerateImageBasedCompose)
297+
if (Descriptor.GenerateImageBasedCompose)
256298
{
257299
var nonImageServices = composeFile.Services
258300
.Where(service => service.Image == null)
@@ -262,7 +304,7 @@ private string GenerateComposeFileWithExposedPorts(ComposeFile composeFile)
262304
composeFile.RemoveServices(nonImageServices);
263305
}
264306

265-
composeFile.RemoveServices(_descriptor.ServicesToRemove);
307+
composeFile.RemoveServices(Descriptor.ServicesToRemove);
266308

267309
using (var tempStream = File.OpenWrite(generatedComposeFile))
268310
{
@@ -305,7 +347,7 @@ private string GetTempFile()
305347
do
306348
{
307349
var prefix = random.Next().ToString("x8");
308-
fileName = $"~{_descriptor.ProjectName}{prefix}.tmp.yml";
350+
fileName = $"~{Descriptor.ProjectName}{prefix}.tmp.yml";
309351
} while (File.Exists(fileName));
310352

311353
return fileName;

ComposeTestEnvironment.xUnit/LICENSE.txt

-21
This file was deleted.

Sample/SampleComposeFixture.cs

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using ComposeTestEnvironment.xUnit;
1+
using System.Threading.Tasks;
2+
using ComposeTestEnvironment.xUnit;
23
using Xunit.Abstractions;
34

45
namespace Sample
@@ -9,5 +10,16 @@ public SampleComposeFixture(IMessageSink output)
910
: base(output)
1011
{
1112
}
13+
14+
public string ConnectionString { get; private set; } = string.Empty;
15+
16+
// You can override various methods to inject your code in initialize/teardown pipeline
17+
protected override async ValueTask AfterInitializeAsync()
18+
{
19+
ConnectionString = Discovery.Substitute(
20+
"Server=$(sqlserver.host),$(sqlserver.1433);User Id=sa;Password=yourStrong(!)Password;");
21+
22+
await base.AfterInitializeAsync();
23+
}
1224
}
1325
}

Sample/SqlTest.cs

+3-6
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,17 @@ namespace Sample
66
{
77
public class SqlTest : IClassFixture<SampleComposeFixture>
88
{
9-
private readonly SampleComposeFixture _fixture;
9+
private readonly string _connectionString;
1010

1111
public SqlTest(SampleComposeFixture fixture)
1212
{
13-
_fixture = fixture;
13+
_connectionString = fixture.ConnectionString;
1414
}
1515

1616
[Fact]
1717
public async Task ShouldConnect()
1818
{
19-
var connectionString = _fixture.Discovery.Substitute(
20-
"Server=$(sqlserver.host),$(sqlserver.1433);User Id=sa;Password=yourStrong(!)Password;");
21-
22-
using var db = new SqlConnection(connectionString);
19+
using var db = new SqlConnection(_connectionString);
2320

2421
await db.OpenAsync();
2522
}

Sample/SqlTest2.cs

+3-6
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,17 @@ namespace Sample
66
{
77
public class SqlTest2 : IClassFixture<SampleComposeFixture>
88
{
9-
private readonly SampleComposeFixture _fixture;
9+
private readonly string _connectionString;
1010

1111
public SqlTest2(SampleComposeFixture fixture)
1212
{
13-
_fixture = fixture;
13+
_connectionString = fixture.ConnectionString;
1414
}
1515

1616
[Fact]
1717
public async Task ShouldConnect()
1818
{
19-
var connectionString = _fixture.Discovery.Substitute(
20-
"Server=$(sqlserver.host),$(sqlserver.1433);User Id=sa;Password=yourStrong(!)Password;");
21-
22-
using var db = new SqlConnection(connectionString);
19+
using var db = new SqlConnection(_connectionString);
2320

2421
await db.OpenAsync();
2522
}

0 commit comments

Comments
 (0)