Skip to content

Commit 835e7bf

Browse files
authored
fix: Preserve builder options when selecting transport (#87)
1 parent 8600cdc commit 835e7bf

5 files changed

Lines changed: 105 additions & 23 deletions

File tree

src/Docker.DotNet/DockerClient.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ internal DockerClient(
2020
HttpMessageHandler handler,
2121
ClientOptions clientOptions,
2222
Uri effectiveEndpoint,
23-
IStreamHijacker hijack,
24-
ILogger logger)
23+
IStreamHijacker hijack)
2524
{
2625
_client = new HttpClient(handler, true);
2726
_client.Timeout = Timeout.InfiniteTimeSpan;

src/Docker.DotNet/DockerClientBuilder.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@ public DockerClientBuilder()
2222
_ = WithEndpoint(LocalDockerEndpoint);
2323
}
2424

25+
/// <summary>
26+
/// Initializes a new instance of the <see cref="DockerClientBuilder"/> class.
27+
/// </summary>
28+
/// <param name="clientOptions">The client options to preserve.</param>
29+
/// <param name="logger">The logger to preserve.</param>
30+
protected DockerClientBuilder(
31+
ClientOptions clientOptions,
32+
ILogger logger)
33+
{
34+
ClientOptions = clientOptions;
35+
Logger = logger;
36+
}
37+
2538
/// <summary>
2639
/// Gets the client options.
2740
/// </summary>
@@ -140,7 +153,7 @@ public DockerClientBuilder WithLogger(ILogger logger)
140153
/// <returns>A typed builder that uses the legacy HTTP transport.</returns>
141154
public DockerClientBuilder<LegacyHttpTransportOptions> WithTransportOptions(LegacyHttpTransportOptions transportOptions)
142155
{
143-
return new DockerClientBuilder<LegacyHttpTransportOptions>(LegacyHttp.DockerHandlerFactory.Instance, transportOptions);
156+
return new DockerClientBuilder<LegacyHttpTransportOptions>(LegacyHttp.DockerHandlerFactory.Instance, transportOptions, ClientOptions, Logger);
144157
}
145158

146159
/// <summary>
@@ -150,7 +163,7 @@ public DockerClientBuilder<LegacyHttpTransportOptions> WithTransportOptions(Lega
150163
/// <returns>A typed builder that uses the native HTTP transport.</returns>
151164
public DockerClientBuilder<NativeHttpTransportOptions> WithTransportOptions(NativeHttpTransportOptions transportOptions)
152165
{
153-
return new DockerClientBuilder<NativeHttpTransportOptions>(NativeHttp.DockerHandlerFactory.Instance, transportOptions);
166+
return new DockerClientBuilder<NativeHttpTransportOptions>(NativeHttp.DockerHandlerFactory.Instance, transportOptions, ClientOptions, Logger);
154167
}
155168

156169
/// <summary>
@@ -160,7 +173,7 @@ public DockerClientBuilder<NativeHttpTransportOptions> WithTransportOptions(Nati
160173
/// <returns>A typed builder that uses the named pipe transport.</returns>
161174
public DockerClientBuilder<NPipeTransportOptions> WithTransportOptions(NPipeTransportOptions transportOptions)
162175
{
163-
return new DockerClientBuilder<NPipeTransportOptions>(NPipe.DockerHandlerFactory.Instance, transportOptions);
176+
return new DockerClientBuilder<NPipeTransportOptions>(NPipe.DockerHandlerFactory.Instance, transportOptions, ClientOptions, Logger);
164177
}
165178

166179
/// <summary>
@@ -170,7 +183,7 @@ public DockerClientBuilder<NPipeTransportOptions> WithTransportOptions(NPipeTran
170183
/// <returns>A typed builder that uses the Unix socket transport.</returns>
171184
public DockerClientBuilder<UnixSocketTransportOptions> WithTransportOptions(UnixSocketTransportOptions transportOptions)
172185
{
173-
return new DockerClientBuilder<UnixSocketTransportOptions>(Unix.DockerHandlerFactory.Instance, transportOptions);
186+
return new DockerClientBuilder<UnixSocketTransportOptions>(Unix.DockerHandlerFactory.Instance, transportOptions, ClientOptions, Logger);
174187
}
175188

176189
/// <summary>
@@ -182,7 +195,7 @@ public DockerClientBuilder<UnixSocketTransportOptions> WithTransportOptions(Unix
182195
/// <returns>A typed builder that uses the provided custom transport.</returns>
183196
public DockerClientBuilder<TTransportOptions> WithTransportOptions<TTransportOptions>(IDockerHandlerFactory<TTransportOptions> transportFactory, TTransportOptions transportOptions)
184197
{
185-
return new DockerClientBuilder<TTransportOptions>(transportFactory, transportOptions);
198+
return new DockerClientBuilder<TTransportOptions>(transportFactory, transportOptions, ClientOptions, Logger);
186199
}
187200

188201
/// <summary>
@@ -200,7 +213,7 @@ public virtual DockerClient Build()
200213

201214
var authenticatedHandler = ClientOptions.AuthProvider.ConfigureHandler(resolvedTransport.Handler);
202215

203-
return new DockerClient(authenticatedHandler, ClientOptions, resolvedTransport.EffectiveEndpoint, transportFactory, Logger);
216+
return new DockerClient(authenticatedHandler, ClientOptions, resolvedTransport.EffectiveEndpoint, transportFactory);
204217
}
205218

206219
/// <summary>

src/Docker.DotNet/DockerClientBuilder`1.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,24 @@ public DockerClientBuilder(
2323
_transportOptions = transportOptions;
2424
}
2525

26+
/// <summary>
27+
/// Initializes a new instance of the <see cref="DockerClientBuilder{TTransportOptions}"/> class.
28+
/// </summary>
29+
/// <param name="transportFactory">The transport handler factory.</param>
30+
/// <param name="transportOptions">The transport options.</param>
31+
/// <param name="clientOptions">The client options to preserve.</param>
32+
/// <param name="logger">The logger to preserve.</param>
33+
public DockerClientBuilder(
34+
IDockerHandlerFactory<TTransportOptions> transportFactory,
35+
TTransportOptions transportOptions,
36+
ClientOptions clientOptions,
37+
ILogger logger)
38+
: base(clientOptions, logger)
39+
{
40+
_transportFactory = transportFactory;
41+
_transportOptions = transportOptions;
42+
}
43+
2644
/// <summary>
2745
/// Builds a <see cref="DockerClient"/> using the explicitly selected transport handler.
2846
/// </summary>
@@ -33,6 +51,6 @@ public override DockerClient Build()
3351

3452
var authenticatedHandler = ClientOptions.AuthProvider.ConfigureHandler(resolvedTransport.Handler);
3553

36-
return new DockerClient(authenticatedHandler, ClientOptions, resolvedTransport.EffectiveEndpoint, _transportFactory, Logger);
54+
return new DockerClient(authenticatedHandler, ClientOptions, resolvedTransport.EffectiveEndpoint, _transportFactory);
3755
}
3856
}

test/Docker.DotNet.TestsV2/DockerClientBuilderTests.cs

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public void Build_WithUnsupportedScheme_ThrowsNotSupportedException()
119119
[Theory]
120120
[InlineData("npipe://./pipe/docker_engine", typeof(NPipe.DockerHandlerFactory))]
121121
[InlineData("unix:/var/run/docker.sock", typeof(Unix.DockerHandlerFactory))]
122-
public void ResolveTransportFactory_UsesExpectedFactory_ForSocketSchemes(string endpoint, Type expectedFactoryType)
122+
public void ResolveTransportFactory_UsesExpectedFactory_WhenSocketSchemeIsProvided(string endpoint, Type expectedFactoryType)
123123
{
124124
var builder = new TestDockerClientBuilder();
125125

@@ -129,7 +129,7 @@ public void ResolveTransportFactory_UsesExpectedFactory_ForSocketSchemes(string
129129
}
130130

131131
[Fact]
132-
public void ResolveTransportFactory_WithHttpScheme_UsesConfiguredDefaultHttpFactory()
132+
public void ResolveTransportFactory_UsesExpectedFactory_WhenHttpSchemeIsProvided()
133133
{
134134
var builder = new TestDockerClientBuilder();
135135

@@ -143,30 +143,79 @@ public void ResolveTransportFactory_WithHttpScheme_UsesConfiguredDefaultHttpFact
143143
}
144144

145145
[Fact]
146-
public void Build_WithExplicitTransport_UsesProvidedFactoryAndOptions()
146+
public void Build_PreservesClientOptionsAndLogger_WhenSetBeforeTransportSelection()
147147
{
148148
var transportFactory = new FakeTransportFactory();
149149

150150
var transportOptions = new FakeTransportOptions();
151151

152+
const string headerName = "x-test";
153+
const string headerValue = "value";
154+
155+
var apiVersion = new Version(1, 52);
156+
var endpoint = new Uri("http://localhost:2375");
157+
var authProvider = new PassThroughAuthProvider(true);
158+
var timeout = TimeSpan.FromSeconds(1);
159+
var logger = NullLogger.Instance;
160+
161+
_ = new DockerClientBuilder()
162+
.WithApiVersion(apiVersion)
163+
.WithEndpoint(endpoint)
164+
.WithAuthProvider(authProvider)
165+
.WithHeader(headerName, headerValue)
166+
.WithTimeout(timeout)
167+
.WithLogger(logger)
168+
.WithTransportOptions(transportFactory, transportOptions)
169+
.Build();
170+
171+
Assert.Equal(apiVersion, transportFactory.LastClientOptions.ApiVersion);
172+
Assert.Equal(endpoint, transportFactory.LastClientOptions.Endpoint);
173+
Assert.Same(authProvider, transportFactory.LastClientOptions.AuthProvider);
174+
Assert.Equal(headerValue, transportFactory.LastClientOptions.Headers[headerName]);
175+
Assert.Equal(timeout, transportFactory.LastClientOptions.Timeout);
176+
Assert.Same(logger, transportFactory.LastLogger);
177+
Assert.Equal(1, transportFactory.TypedCreateHandlerCallCount);
178+
Assert.Same(transportOptions, transportFactory.LastTransportOptions);
179+
}
180+
181+
[Fact]
182+
public void Build_PreservesClientOptionsAndLogger_WhenSetAfterTransportSelection()
183+
{
184+
var transportFactory = new FakeTransportFactory();
185+
186+
var transportOptions = new FakeTransportOptions();
187+
188+
const string headerName = "x-test";
189+
const string headerValue = "value";
190+
191+
var apiVersion = new Version(1, 52);
192+
var endpoint = new Uri("http://localhost:2375");
193+
var authProvider = new PassThroughAuthProvider(true);
194+
var timeout = TimeSpan.FromSeconds(5);
195+
var logger = NullLogger.Instance;
196+
152197
_ = new DockerClientBuilder()
153198
.WithTransportOptions(transportFactory, transportOptions)
154-
.WithEndpoint(new Uri("http://localhost:2375"))
155-
.WithApiVersion(new Version(1, 52))
156-
.WithHeader("x-test", "value")
157-
.WithTimeout(TimeSpan.FromSeconds(1))
199+
.WithApiVersion(apiVersion)
200+
.WithEndpoint(endpoint)
201+
.WithAuthProvider(authProvider)
202+
.WithHeader(headerName, headerValue)
203+
.WithTimeout(timeout)
204+
.WithLogger(logger)
158205
.Build();
159206

207+
Assert.Equal(apiVersion, transportFactory.LastClientOptions.ApiVersion);
208+
Assert.Equal(endpoint, transportFactory.LastClientOptions.Endpoint);
209+
Assert.Same(authProvider, transportFactory.LastClientOptions.AuthProvider);
210+
Assert.Equal(headerValue, transportFactory.LastClientOptions.Headers[headerName]);
211+
Assert.Equal(timeout, transportFactory.LastClientOptions.Timeout);
212+
Assert.Same(logger, transportFactory.LastLogger);
160213
Assert.Equal(1, transportFactory.TypedCreateHandlerCallCount);
161214
Assert.Same(transportOptions, transportFactory.LastTransportOptions);
162-
Assert.Equal("http", transportFactory.LastClientOptions.Endpoint.Scheme);
163-
Assert.Equal("value", transportFactory.LastClientOptions.Headers["x-test"]);
164-
Assert.Equal(new Version(1, 52), transportFactory.LastClientOptions.ApiVersion);
165-
Assert.Equal(TimeSpan.FromSeconds(1), transportFactory.LastClientOptions.Timeout);
166215
}
167216

168217
[Fact]
169-
public void Build_PreservesOriginalEndpointInClientOptions_WhenTransportNormalizesEndpoint()
218+
public void Build_PreservesEndpointInClientOptions_WhenTransportNormalizesEndpoint()
170219
{
171220
var transportFactory = new FakeTransportFactory();
172221

@@ -183,7 +232,7 @@ public void Build_PreservesOriginalEndpointInClientOptions_WhenTransportNormaliz
183232
}
184233

185234
[Fact]
186-
public void WithTransportOptions_ReturnsTypedBuilder_ForBuiltInTransports()
235+
public void WithTransportOptions_ReturnsTypedBuilder_WhenBuiltInTransportIsSelected()
187236
{
188237
var builder = new DockerClientBuilder();
189238

@@ -229,11 +278,14 @@ private sealed class FakeTransportFactory : IDockerHandlerFactory<FakeTransportO
229278

230279
public ClientOptions LastClientOptions { get; private set; } = null!;
231280

281+
public ILogger LastLogger { get; private set; } = null!;
282+
232283
public ResolvedTransport CreateHandler(FakeTransportOptions transportOptions, ClientOptions clientOptions, ILogger logger)
233284
{
234285
TypedCreateHandlerCallCount++;
235286
LastTransportOptions = transportOptions;
236287
LastClientOptions = clientOptions;
288+
LastLogger = logger;
237289

238290
return new ResolvedTransport(new HttpClientHandler(), clientOptions.Endpoint);
239291
}

version.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
3-
"version": "4.0.1",
3+
"version": "4.0.2",
44
"nugetPackageVersion": {
55
"semVer": 2
66
},

0 commit comments

Comments
 (0)