Skip to content

Commit 0591160

Browse files
committed
Clean up WithResourceMapping
1 parent a253f4b commit 0591160

File tree

4 files changed

+464
-15
lines changed

4 files changed

+464
-15
lines changed

src/Testcontainers/Builders/ContainerBuilder`3.cs

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ namespace DotNet.Testcontainers.Builders
2222
/// <typeparam name="TContainerEntity">The resource entity.</typeparam>
2323
/// <typeparam name="TConfigurationEntity">The configuration entity.</typeparam>
2424
[PublicAPI]
25-
public abstract class ContainerBuilder<TBuilderEntity, TContainerEntity, TConfigurationEntity> : AbstractBuilder<TBuilderEntity, TContainerEntity, CreateContainerParameters, TConfigurationEntity>, IContainerBuilder<TBuilderEntity, TContainerEntity>
25+
public abstract class ContainerBuilder<TBuilderEntity, TContainerEntity, TConfigurationEntity> :
26+
AbstractBuilder<TBuilderEntity, TContainerEntity, CreateContainerParameters, TConfigurationEntity>,
27+
IContainerBuilder<TBuilderEntity, TContainerEntity>
2628
where TBuilderEntity : ContainerBuilder<TBuilderEntity, TContainerEntity, TConfigurationEntity>
2729
where TContainerEntity : IContainer
2830
where TConfigurationEntity : IContainerConfiguration
@@ -172,7 +174,8 @@ public TBuilderEntity WithPortBinding(int port, bool assignRandomHostPort = fals
172174
/// <inheritdoc />
173175
public TBuilderEntity WithPortBinding(int hostPort, int containerPort)
174176
{
175-
return WithPortBinding(hostPort.ToString(CultureInfo.InvariantCulture), containerPort.ToString(CultureInfo.InvariantCulture));
177+
return WithPortBinding(hostPort.ToString(CultureInfo.InvariantCulture),
178+
containerPort.ToString(CultureInfo.InvariantCulture));
176179
}
177180

178181
/// <inheritdoc />
@@ -201,15 +204,24 @@ public TBuilderEntity WithResourceMapping(IResourceMapping resourceMapping)
201204
}
202205

203206
/// <inheritdoc />
204-
public TBuilderEntity WithResourceMapping(byte[] resourceContent, string filePath, UnixFileModes fileMode = Unix.FileMode644)
207+
public TBuilderEntity WithResourceMapping(byte[] resourceContent, string filePath,
208+
UnixFileModes fileMode = Unix.FileMode644)
205209
{
206210
return WithResourceMapping(new BinaryResourceMapping(resourceContent, filePath, fileMode));
207211
}
208212

213+
/// <inheritdoc />
214+
public TBuilderEntity WithResourceMapping(byte[] resourceContent, FileInfo filePath,
215+
UnixFileModes fileMode = Unix.FileMode644)
216+
{
217+
return WithResourceMapping(new BinaryResourceMapping(resourceContent, filePath.FullName, fileMode));
218+
}
219+
209220
/// <inheritdoc />
210221
public TBuilderEntity WithResourceMapping(string source, string target, UnixFileModes fileMode = Unix.FileMode644)
211222
{
212-
if (Uri.IsWellFormedUriString(source, UriKind.Absolute) && Uri.TryCreate(source, UriKind.Absolute, out var uri) && new[] { Uri.UriSchemeHttp, Uri.UriSchemeHttps, Uri.UriSchemeFile }.Contains(uri.Scheme))
223+
if (Uri.IsWellFormedUriString(source, UriKind.Absolute) && Uri.TryCreate(source, UriKind.Absolute, out var uri) &&
224+
new[] { Uri.UriSchemeHttp, Uri.UriSchemeHttps, Uri.UriSchemeFile }.Contains(uri.Scheme))
213225
{
214226
return WithResourceMapping(uri, target, fileMode);
215227
}
@@ -227,19 +239,35 @@ public TBuilderEntity WithResourceMapping(string source, string target, UnixFile
227239
}
228240

229241
/// <inheritdoc />
230-
public TBuilderEntity WithResourceMapping(DirectoryInfo source, string target, UnixFileModes fileMode = Unix.FileMode644)
242+
public TBuilderEntity WithResourceMapping(DirectoryInfo source, string target,
243+
UnixFileModes fileMode = Unix.FileMode644)
231244
{
232245
return WithResourceMapping(new FileResourceMapping(source.FullName, target, fileMode));
233246
}
234247

248+
/// <inheritdoc />
249+
public TBuilderEntity WithResourceMapping(DirectoryInfo source, DirectoryInfo target,
250+
UnixFileModes fileMode = Unix.FileMode644)
251+
{
252+
return WithResourceMapping(new FileResourceMapping(source.FullName, target.FullName, fileMode));
253+
}
254+
235255
/// <inheritdoc />
236256
public TBuilderEntity WithResourceMapping(FileInfo source, string target, UnixFileModes fileMode = Unix.FileMode644)
237257
{
238258
return WithResourceMapping(new FileResourceMapping(source.FullName, target, fileMode));
239259
}
240260

241261
/// <inheritdoc />
242-
public TBuilderEntity WithResourceMapping(FileInfo source, FileInfo target, UnixFileModes fileMode = Unix.FileMode644)
262+
public TBuilderEntity WithResourceMapping(FileInfo source, DirectoryInfo target,
263+
UnixFileModes fileMode = Unix.FileMode644)
264+
{
265+
return WithResourceMapping(new FileResourceMapping(source.FullName, target.FullName, fileMode));
266+
}
267+
268+
/// <inheritdoc />
269+
public TBuilderEntity WithResourceMapping(FileInfo source, FileInfo target,
270+
UnixFileModes fileMode = Unix.FileMode644)
243271
{
244272
using (var fileStream = source.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
245273
{
@@ -253,15 +281,31 @@ public TBuilderEntity WithResourceMapping(FileInfo source, FileInfo target, Unix
253281

254282
/// <inheritdoc />
255283
public TBuilderEntity WithResourceMapping(Uri source, string target, UnixFileModes fileMode = Unix.FileMode644)
284+
{
285+
return WithResourceMapping(source, new DirectoryInfo(target), fileMode);
286+
}
287+
288+
/// <inheritdoc />
289+
public TBuilderEntity WithResourceMapping(Uri source, DirectoryInfo target,
290+
UnixFileModes fileMode = Unix.FileMode644)
256291
{
257292
if (source.IsFile)
258293
{
259-
return WithResourceMapping(new FileResourceMapping(source.AbsolutePath, target, fileMode));
294+
return WithResourceMapping(new FileResourceMapping(source.AbsolutePath, target.FullName, fileMode));
260295
}
261-
else
296+
297+
return WithResourceMapping(new UriResourceMapping(source, target.FullName, fileMode));
298+
}
299+
300+
/// <inheritdoc />
301+
public TBuilderEntity WithResourceMapping(Uri source, FileInfo target, UnixFileModes fileMode = Unix.FileMode644)
302+
{
303+
if (source.IsFile)
262304
{
263-
return WithResourceMapping(new UriResourceMapping(source, target, fileMode));
305+
return WithResourceMapping(new FileInfo(source.AbsolutePath), target, fileMode);
264306
}
307+
308+
return WithResourceMapping(new UriResourceMapping(source, target.FullName, fileMode));
265309
}
266310

267311
/// <inheritdoc />
@@ -380,13 +424,16 @@ public TBuilderEntity WithWaitStrategy(IWaitForContainerOS waitStrategy)
380424
/// <inheritdoc />
381425
public TBuilderEntity WithStartupCallback(Func<TContainerEntity, CancellationToken, Task> startupCallback)
382426
{
383-
return Clone(new ContainerConfiguration(startupCallback: (container, ct) => startupCallback((TContainerEntity)container, ct)));
427+
return Clone(new ContainerConfiguration(startupCallback: (container, ct) =>
428+
startupCallback((TContainerEntity)container, ct)));
384429
}
385430

386431
/// <inheritdoc />
387432
protected override TBuilderEntity Init()
388433
{
389-
return base.Init().WithImagePullPolicy(PullPolicy.Missing).WithPortForwarding().WithOutputConsumer(Consume.DoNotConsumeStdoutAndStderr()).WithWaitStrategy(Wait.ForUnixContainer()).WithStartupCallback((_, _) => Task.CompletedTask);
434+
return base.Init().WithImagePullPolicy(PullPolicy.Missing).WithPortForwarding()
435+
.WithOutputConsumer(Consume.DoNotConsumeStdoutAndStderr()).WithWaitStrategy(Wait.ForUnixContainer())
436+
.WithStartupCallback((_, _) => Task.CompletedTask);
390437
}
391438

392439
/// <inheritdoc />
@@ -396,7 +443,10 @@ protected override void Validate()
396443

397444
const string reuseNotSupported = "Reuse cannot be used in conjunction with WithAutoRemove(true).";
398445
_ = Guard.Argument(DockerResourceConfiguration, nameof(IContainerConfiguration.Reuse))
399-
.ThrowIf(argument => argument.Value.Reuse.HasValue && argument.Value.Reuse.Value && argument.Value.AutoRemove.HasValue && argument.Value.AutoRemove.Value, argument => new ArgumentException(reuseNotSupported, argument.Name));
446+
.ThrowIf(
447+
argument => argument.Value.Reuse.HasValue && argument.Value.Reuse.Value &&
448+
argument.Value.AutoRemove.HasValue && argument.Value.AutoRemove.Value,
449+
argument => new ArgumentException(reuseNotSupported, argument.Name));
400450

401451
_ = Guard.Argument(DockerResourceConfiguration.Image, nameof(IContainerConfiguration.Image))
402452
.NotNull();
@@ -411,10 +461,13 @@ protected virtual void ValidateLicenseAgreement()
411461
const string message = "The image '{0}' requires you to accept a license agreement.";
412462

413463
Predicate<TConfigurationEntity> licenseAgreementNotAccepted = value =>
414-
!value.Environments.TryGetValue(AcceptLicenseAgreementEnvVar, out var licenseAgreementValue) || !AcceptLicenseAgreement.Equals(licenseAgreementValue, StringComparison.Ordinal);
464+
!value.Environments.TryGetValue(AcceptLicenseAgreementEnvVar, out var licenseAgreementValue) ||
465+
!AcceptLicenseAgreement.Equals(licenseAgreementValue, StringComparison.Ordinal);
415466

416467
_ = Guard.Argument(DockerResourceConfiguration, nameof(DockerResourceConfiguration.Image))
417-
.ThrowIf(argument => licenseAgreementNotAccepted(argument.Value), argument => throw new ArgumentException(string.Format(message, DockerResourceConfiguration.Image.FullName), argument.Name));
468+
.ThrowIf(argument => licenseAgreementNotAccepted(argument.Value),
469+
argument => throw new ArgumentException(string.Format(message, DockerResourceConfiguration.Image.FullName),
470+
argument.Name));
418471
}
419472

420473
/// <summary>
@@ -427,7 +480,10 @@ protected virtual void ValidateLicenseAgreement()
427480
private TBuilderEntity WithPortForwarding()
428481
{
429482
const string hostname = "host.testcontainers.internal";
430-
return PortForwardingContainer.Instance != null && TestcontainersStates.Running.Equals(PortForwardingContainer.Instance.State) ? WithExtraHost(hostname, PortForwardingContainer.Instance.IpAddress) : Clone(new ContainerConfiguration());
483+
return PortForwardingContainer.Instance != null &&
484+
TestcontainersStates.Running.Equals(PortForwardingContainer.Instance.State)
485+
? WithExtraHost(hostname, PortForwardingContainer.Instance.IpAddress)
486+
: Clone(new ContainerConfiguration());
431487
}
432488

433489
/// <inheritdoc cref="NetworkBuilder" />

src/Testcontainers/Builders/IContainerBuilder`2.cs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,19 @@ public interface IContainerBuilder<out TBuilderEntity, out TContainerEntity> : I
228228
/// <param name="fileMode">The POSIX file mode permission.</param>
229229
/// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
230230
[PublicAPI]
231+
[Obsolete("Use WithResourceMapping(byte[], FileInfo, UnixFileModes) instead.")]
231232
TBuilderEntity WithResourceMapping(byte[] resourceContent, string filePath, UnixFileModes fileMode = Unix.FileMode644);
232233

234+
/// <summary>
235+
/// Copies the byte array content to the created container before it starts.
236+
/// </summary>
237+
/// <param name="resourceContent">The byte array content of the resource mapping.</param>
238+
/// <param name="filePath">The target file path to copy the file to.</param>
239+
/// <param name="fileMode">The POSIX file mode permission.</param>
240+
/// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
241+
[PublicAPI]
242+
TBuilderEntity WithResourceMapping(byte[] resourceContent, FileInfo filePath, UnixFileModes fileMode = Unix.FileMode644);
243+
233244
/// <summary>
234245
/// Copies the contents of a URL, a test host directory or file to the container before it starts.
235246
/// </summary>
@@ -246,6 +257,7 @@ public interface IContainerBuilder<out TBuilderEntity, out TContainerEntity> : I
246257
/// <param name="fileMode">The POSIX file mode permission.</param>
247258
/// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
248259
[PublicAPI]
260+
[Obsolete("Use one of the more specific WithResourceMapping(…) methods instead.")]
249261
TBuilderEntity WithResourceMapping(string source, string target, UnixFileModes fileMode = Unix.FileMode644);
250262

251263
/// <summary>
@@ -256,18 +268,40 @@ public interface IContainerBuilder<out TBuilderEntity, out TContainerEntity> : I
256268
/// <param name="fileMode">The POSIX file mode permission.</param>
257269
/// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
258270
[PublicAPI]
271+
[Obsolete("Use WithResourceMapping(DirectoryInfo, DirectoryInfo, UnixFileModes) instead.")]
259272
TBuilderEntity WithResourceMapping(DirectoryInfo source, string target, UnixFileModes fileMode = Unix.FileMode644);
260273

261274
/// <summary>
262275
/// Copies a test host directory or file to the container before it starts.
263276
/// </summary>
277+
/// <param name="source">The source directory to be copied.</param>
278+
/// <param name="target">The target directory path to copy the files to.</param>
279+
/// <param name="fileMode">The POSIX file mode permission.</param>
280+
/// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
281+
[PublicAPI]
282+
TBuilderEntity WithResourceMapping(DirectoryInfo source, DirectoryInfo target, UnixFileModes fileMode = Unix.FileMode644);
283+
284+
/// <summary>
285+
/// Copies a test host directory or file to the given directory in the container before it starts.
286+
/// </summary>
264287
/// <param name="source">The source file to be copied.</param>
265288
/// <param name="target">The target directory path to copy the file to.</param>
266289
/// <param name="fileMode">The POSIX file mode permission.</param>
267290
/// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
268291
[PublicAPI]
292+
[Obsolete("Use WithResourceMapping(FileInfo, DirectoryInfo, UnixFileModes) instead.")]
269293
TBuilderEntity WithResourceMapping(FileInfo source, string target, UnixFileModes fileMode = Unix.FileMode644);
270294

295+
/// <summary>
296+
/// Copies a test host directory or file to the given directory in the container before it starts.
297+
/// </summary>
298+
/// <param name="source">The source file to be copied.</param>
299+
/// <param name="target">The target directory path to copy the file to.</param>
300+
/// <param name="fileMode">The POSIX file mode permission.</param>
301+
/// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
302+
[PublicAPI]
303+
TBuilderEntity WithResourceMapping(FileInfo source, DirectoryInfo target, UnixFileModes fileMode = Unix.FileMode644);
304+
271305
/// <summary>
272306
/// Copies a test host file to the container before it starts.
273307
/// </summary>
@@ -295,8 +329,44 @@ public interface IContainerBuilder<out TBuilderEntity, out TContainerEntity> : I
295329
/// <param name="target">The target directory or file path to copy the file to.</param>
296330
/// <param name="fileMode">The POSIX file mode permission.</param>
297331
/// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
332+
[Obsolete("Use WithResourceMapping(Uri, FileInfo, UnixFileModes) or WithResourceMapping(Uri, DirectoryInfo, UnixFileModes) instead.")]
298333
TBuilderEntity WithResourceMapping(Uri source, string target, UnixFileModes fileMode = Unix.FileMode644);
299334

335+
/// <summary>
336+
/// Copies a file from a URL to the container before it starts.
337+
/// </summary>
338+
/// <remarks>
339+
/// If the Uri scheme corresponds to a file, the content is copied to the target
340+
/// directory path. If the Uri scheme corresponds to HTTP or HTTPS, the content is
341+
/// copied to the target file path.
342+
///
343+
/// The Uri scheme must be either <c>http</c>, <c>https</c> or <c>file</c>.
344+
///
345+
/// If you prefer to copy a file to a specific target file path instead of a
346+
/// directory, use: <see cref="WithResourceMapping(FileInfo, FileInfo, UnixFileModes)" />.
347+
/// </remarks>
348+
/// <param name="source">The source URL of the file to be copied.</param>
349+
/// <param name="target">The target directory path to copy the file to.</param>
350+
/// <param name="fileMode">The POSIX file mode permission.</param>
351+
/// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
352+
TBuilderEntity WithResourceMapping(Uri source, DirectoryInfo target, UnixFileModes fileMode = Unix.FileMode644);
353+
354+
/// <summary>
355+
/// Copies a file from a URL to the container before it starts.
356+
/// </summary>
357+
/// <remarks>
358+
/// If the Uri scheme corresponds to a file, the content is copied to the target
359+
/// directory path. If the Uri scheme corresponds to HTTP or HTTPS, the content is
360+
/// copied to the target file path.
361+
///
362+
/// The Uri scheme must be either <c>http</c>, <c>https</c> or <c>file</c>.
363+
/// </remarks>
364+
/// <param name="source">The source URL of the file to be copied.</param>
365+
/// <param name="target">The target file path to copy the file to.</param>
366+
/// <param name="fileMode">The POSIX file mode permission.</param>
367+
/// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
368+
TBuilderEntity WithResourceMapping(Uri source, FileInfo target, UnixFileModes fileMode = Unix.FileMode644);
369+
300370
/// <summary>
301371
/// Assigns the mount configuration to manage data in the container.
302372
/// </summary>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System.Collections.Generic;
2+
3+
namespace DotNet.Testcontainers.Tests.Fixtures
4+
{
5+
using System;
6+
using System.Threading.Tasks;
7+
using DotNet.Testcontainers.Builders;
8+
using DotNet.Testcontainers.Commons;
9+
using DotNet.Testcontainers.Containers;
10+
using JetBrains.Annotations;
11+
using Xunit;
12+
13+
[UsedImplicitly]
14+
public sealed class AlpineBuilderFixture : IAsyncLifetime
15+
{
16+
private readonly List<IContainer> _containers = [];
17+
18+
public IContainer Container(Func<ContainerBuilder, ContainerBuilder> builder)
19+
{
20+
var containerBuilder = builder(new ContainerBuilder());
21+
22+
var container = containerBuilder
23+
.WithImage(CommonImages.Alpine)
24+
.WithCommand(CommonCommands.SleepInfinity)
25+
.Build();
26+
27+
_containers.Add(container);
28+
29+
return container;
30+
}
31+
32+
public ValueTask InitializeAsync()
33+
{
34+
return ValueTask.CompletedTask;
35+
}
36+
37+
public async ValueTask DisposeAsync()
38+
{
39+
foreach (var container in _containers)
40+
{
41+
await container.DisposeAsync();
42+
}
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)