@@ -25,7 +25,6 @@ public class DockerComposeEnvironmentFixture<TDescriptor> : IAsyncLifetime
25
25
private readonly IMessageSink _output ;
26
26
private readonly List < string > _outputStrings = new ( ) ;
27
27
private readonly DisposableList _disposables = new ( ) ;
28
- private readonly TDescriptor _descriptor = new ( ) ;
29
28
30
29
public DockerComposeEnvironmentFixture ( IMessageSink output )
31
30
{
@@ -36,7 +35,39 @@ public DockerComposeEnvironmentFixture(IMessageSink output)
36
35
37
36
public Discovery Discovery { get ; private set ; }
38
37
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 ( )
40
71
{
41
72
if ( _initializeAsync == null )
42
73
{
@@ -47,48 +78,59 @@ public async Task InitializeAsync()
47
78
}
48
79
49
80
Discovery = await _initializeAsync ;
81
+
82
+ await AfterInitializeAsync ( ) ;
50
83
}
51
84
52
- public Task DisposeAsync ( )
85
+ async Task IAsyncLifetime . DisposeAsync ( )
53
86
{
54
- return Task . CompletedTask ;
87
+ await BeforeDisposeAsync ( ) ;
55
88
}
56
89
57
90
private async Task < Discovery > InitializeCoreAsync ( )
58
91
{
59
- if ( _descriptor . IsUnderCompose )
92
+ await BeforeSingleTimeInitialize ( ) ;
93
+
94
+ Discovery discovery ;
95
+ if ( Descriptor . IsUnderCompose )
60
96
{
61
- if ( _descriptor . WaitForPortsListen )
97
+ if ( Descriptor . WaitForPortsListen )
62
98
{
63
- var listening = _descriptor . Ports
99
+ var listening = Descriptor . Ports
64
100
. SelectMany ( x => x . Value . Select ( port => new UriBuilder ( "tcp://" , x . Key , port ) . Uri ) )
65
101
. ToList ( ) ;
66
102
67
103
await WaitForListeningPorts ( listening ) ;
68
104
}
69
105
70
- return new Discovery (
71
- _descriptor . Ports . ToDictionary (
106
+ discovery = new Discovery (
107
+ Descriptor . Ports . ToDictionary (
72
108
item => new HostSubstitution ( item . Key , item . Key ) ,
73
109
item => ( IReadOnlyList < PortSubstitution > ) item . Value . Select ( port => new PortSubstitution ( port , port ) ) . ToList ( ) ) ) ;
74
110
}
111
+ else
112
+ {
113
+ discovery = await InitializeComposeEnvironmentAsync ( ) ;
114
+ }
115
+
116
+ await AfterSingleTimeInitialize ( discovery ) ;
75
117
76
- return await InitializeComposeEnvironmentAsync ( ) ;
118
+ return discovery ;
77
119
}
78
120
79
121
private async Task < Discovery > InitializeComposeEnvironmentAsync ( )
80
122
{
81
- using var composeFileStream = File . OpenRead ( FindFile ( _descriptor . FileName ) ) ;
123
+ using var composeFileStream = File . OpenRead ( FindFile ( Descriptor . FileName ) ) ;
82
124
83
125
var composeFile = ComposeFile . ParseAsync ( composeFileStream ) ;
84
126
85
127
await AssignExposedPorts ( composeFile ) ;
86
128
87
129
var generatedFilePath = GenerateComposeFileWithExposedPorts ( composeFile ) ;
88
- var projectName = _descriptor . ProjectName ;
130
+ var projectName = Descriptor . ProjectName ;
89
131
TestFramework . RegisterDisposable ( _disposables ) ;
90
132
91
- if ( _descriptor . DownOnComplete )
133
+ if ( Descriptor . DownOnComplete )
92
134
{
93
135
var downProcess = ComposeDown ( generatedFilePath , projectName ) ;
94
136
_disposables . Add ( downProcess ) ;
@@ -97,7 +139,7 @@ await _disposables.AddAsync(async () =>
97
139
{
98
140
WriteMessage ( "Stopping compose..." ) ;
99
141
await downProcess . Start ( _startTimeout ) ;
100
- await downProcess . WaitForExit ( ) . WithTimeout ( _descriptor . StopTimeout ) ;
142
+ await downProcess . WaitForExit ( ) . WithTimeout ( Descriptor . StopTimeout ) ;
101
143
} ) ;
102
144
}
103
145
@@ -117,7 +159,7 @@ await _disposables.AddAsync(async () =>
117
159
. Argument ( "up" )
118
160
. CollectOutput ( WriteMessage ) ;
119
161
120
- foreach ( var message in _descriptor . StartedMessageMarkers )
162
+ foreach ( var message in Descriptor . StartedMessageMarkers )
121
163
{
122
164
process . WaitForMessageInOutput ( message ) ;
123
165
}
@@ -126,7 +168,7 @@ await _disposables.AddAsync(async () =>
126
168
127
169
try
128
170
{
129
- await process . Start ( _descriptor . StartTimeout ) ;
171
+ await process . Start ( Descriptor . StartTimeout ) ;
130
172
}
131
173
catch ( OperationCanceledException ex )
132
174
{
@@ -143,10 +185,10 @@ await _disposables.AddAsync(async () =>
143
185
var portMappings = composeFile . Services
144
186
. Where ( service =>
145
187
service . Image != null &&
146
- _descriptor . Ports . ContainsKey ( service . ServiceName ) )
188
+ Descriptor . Ports . ContainsKey ( service . ServiceName ) )
147
189
. ToDictionary ( x => x . ServiceName , x => x . PortMappings ) ;
148
190
149
- if ( _descriptor . WaitForPortsListen )
191
+ if ( Descriptor . WaitForPortsListen )
150
192
{
151
193
var listening = portMappings . Values
152
194
. SelectMany ( x => x )
@@ -161,14 +203,14 @@ await _disposables.AddAsync(async () =>
161
203
item => new HostSubstitution ( item . Key , "localhost" ) ,
162
204
item => ( IReadOnlyList < PortSubstitution > ) item . Value . Select ( port => new PortSubstitution ( port . ExposedPort , port . PublicPort ) ) . ToList ( ) ) ) ;
163
205
164
- await _descriptor . WaitForReady ( discovery ) ;
206
+ await Descriptor . WaitForReady ( discovery ) ;
165
207
166
208
return discovery ;
167
209
}
168
210
169
211
private async Task WaitForListeningPorts ( IReadOnlyList < Uri > listening )
170
212
{
171
- using var cancellationTokenSource = new CancellationTokenSource ( _descriptor . StartTimeout ) ;
213
+ using var cancellationTokenSource = new CancellationTokenSource ( Descriptor . StartTimeout ) ;
172
214
173
215
var tasks = listening . Select ( uri => Connect ( uri , cancellationTokenSource . Token ) ) ;
174
216
@@ -252,7 +294,7 @@ private string GenerateComposeFileWithExposedPorts(ComposeFile composeFile)
252
294
}
253
295
} ) ;
254
296
255
- if ( _descriptor . GenerateImageBasedCompose )
297
+ if ( Descriptor . GenerateImageBasedCompose )
256
298
{
257
299
var nonImageServices = composeFile . Services
258
300
. Where ( service => service . Image == null )
@@ -262,7 +304,7 @@ private string GenerateComposeFileWithExposedPorts(ComposeFile composeFile)
262
304
composeFile . RemoveServices ( nonImageServices ) ;
263
305
}
264
306
265
- composeFile . RemoveServices ( _descriptor . ServicesToRemove ) ;
307
+ composeFile . RemoveServices ( Descriptor . ServicesToRemove ) ;
266
308
267
309
using ( var tempStream = File . OpenWrite ( generatedComposeFile ) )
268
310
{
@@ -305,7 +347,7 @@ private string GetTempFile()
305
347
do
306
348
{
307
349
var prefix = random . Next ( ) . ToString ( "x8" ) ;
308
- fileName = $ "~{ _descriptor . ProjectName } { prefix } .tmp.yml";
350
+ fileName = $ "~{ Descriptor . ProjectName } { prefix } .tmp.yml";
309
351
} while ( File . Exists ( fileName ) ) ;
310
352
311
353
return fileName ;
0 commit comments