Skip to content

Commit f7f3c49

Browse files
authored
feat: Add support for copying directories and files to a container (#913)
1 parent de410de commit f7f3c49

File tree

27 files changed

+611
-48
lines changed

27 files changed

+611
-48
lines changed

src/Testcontainers.Kafka/KafkaBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ protected override KafkaBuilder Init()
8484
startupScript.Append("echo '' > /etc/confluent/docker/ensure");
8585
startupScript.Append(lf);
8686
startupScript.Append("/etc/confluent/docker/run");
87-
return container.CopyFileAsync(StartupScriptFilePath, Encoding.Default.GetBytes(startupScript.ToString()), 493, ct: ct);
87+
return container.CopyAsync(Encoding.Default.GetBytes(startupScript.ToString()), StartupScriptFilePath, Unix.FileMode755, ct);
8888
});
8989
}
9090

src/Testcontainers.MariaDb/MariaDbContainer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public async Task<ExecResult> ExecScriptAsync(string scriptContent, Cancellation
4242
{
4343
var scriptFilePath = string.Join("/", string.Empty, "tmp", Guid.NewGuid().ToString("D"), Path.GetRandomFileName());
4444

45-
await CopyFileAsync(scriptFilePath, Encoding.Default.GetBytes(scriptContent), 493, 0, 0, ct)
45+
await CopyAsync(Encoding.Default.GetBytes(scriptContent), scriptFilePath, Unix.FileMode644, ct)
4646
.ConfigureAwait(false);
4747

4848
return await ExecAsync(new[] { "mysql", "--protocol=TCP", $"--port={MariaDbBuilder.MariaDbPort}", $"--user={_configuration.Username}", $"--password={_configuration.Password}", _configuration.Database, $"--execute=source {scriptFilePath};" }, ct)

src/Testcontainers.MongoDb/MongoDbContainer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public async Task<ExecResult> ExecScriptAsync(string scriptContent, Cancellation
4040
{
4141
var scriptFilePath = string.Join("/", string.Empty, "tmp", Guid.NewGuid().ToString("D"), Path.GetRandomFileName());
4242

43-
await CopyFileAsync(scriptFilePath, Encoding.Default.GetBytes(scriptContent), 493, 0, 0, ct)
43+
await CopyAsync(Encoding.Default.GetBytes(scriptContent), scriptFilePath, Unix.FileMode644, ct)
4444
.ConfigureAwait(false);
4545

4646
return await ExecAsync(new MongoDbShellCommand($"load('{scriptFilePath}')", _configuration.Username, _configuration.Password), ct)

src/Testcontainers.MsSql/MsSqlContainer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public async Task<ExecResult> ExecScriptAsync(string scriptContent, Cancellation
4242
{
4343
var scriptFilePath = string.Join("/", string.Empty, "tmp", Guid.NewGuid().ToString("D"), Path.GetRandomFileName());
4444

45-
await CopyFileAsync(scriptFilePath, Encoding.Default.GetBytes(scriptContent), 493, 0, 0, ct)
45+
await CopyAsync(Encoding.Default.GetBytes(scriptContent), scriptFilePath, Unix.FileMode644, ct)
4646
.ConfigureAwait(false);
4747

4848
return await ExecAsync(new[] { "/opt/mssql-tools/bin/sqlcmd", "-b", "-r", "1", "-U", _configuration.Username, "-P", _configuration.Password, "-i", scriptFilePath }, ct)

src/Testcontainers.MySql/MySqlContainer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public async Task<ExecResult> ExecScriptAsync(string scriptContent, Cancellation
4242
{
4343
var scriptFilePath = string.Join("/", string.Empty, "tmp", Guid.NewGuid().ToString("D"), Path.GetRandomFileName());
4444

45-
await CopyFileAsync(scriptFilePath, Encoding.Default.GetBytes(scriptContent), 493, 0, 0, ct)
45+
await CopyAsync(Encoding.Default.GetBytes(scriptContent), scriptFilePath, Unix.FileMode644, ct)
4646
.ConfigureAwait(false);
4747

4848
return await ExecAsync(new[] { "mysql", "--protocol=TCP", $"--port={MySqlBuilder.MySqlPort}", $"--user={_configuration.Username}", $"--password={_configuration.Password}", _configuration.Database, $"--execute=source {scriptFilePath};" }, ct)

src/Testcontainers.Oracle/OracleContainer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public async Task<ExecResult> ExecScriptAsync(string scriptContent, Cancellation
3737
{
3838
var scriptFilePath = string.Join("/", string.Empty, "tmp", Guid.NewGuid().ToString("D"), Path.GetRandomFileName());
3939

40-
await CopyFileAsync(scriptFilePath, Encoding.Default.GetBytes(scriptContent), 493, 0, 0, ct)
40+
await CopyAsync(Encoding.Default.GetBytes(scriptContent), scriptFilePath, Unix.FileMode644, ct)
4141
.ConfigureAwait(false);
4242

4343
return await ExecAsync(new[] { "/bin/sh", "-c", $"exit | sqlplus -LOGON -SILENT {_configuration.Username}/{_configuration.Password}@localhost:1521/{_configuration.Database} @{scriptFilePath}" }, ct)

src/Testcontainers.PostgreSql/PostgreSqlContainer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public async Task<ExecResult> ExecScriptAsync(string scriptContent, Cancellation
4242
{
4343
var scriptFilePath = string.Join("/", string.Empty, "tmp", Guid.NewGuid().ToString("D"), Path.GetRandomFileName());
4444

45-
await CopyFileAsync(scriptFilePath, Encoding.Default.GetBytes(scriptContent), 493, 0, 0, ct)
45+
await CopyAsync(Encoding.Default.GetBytes(scriptContent), scriptFilePath, Unix.FileMode644, ct)
4646
.ConfigureAwait(false);
4747

4848
return await ExecAsync(new[] { "psql", "--username", _configuration.Username, "--dbname", _configuration.Database, "--file", scriptFilePath }, ct)

src/Testcontainers.Redis/RedisContainer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public async Task<ExecResult> ExecScriptAsync(string scriptContent, Cancellation
3333
{
3434
var scriptFilePath = string.Join("/", string.Empty, "tmp", Guid.NewGuid().ToString("D"), Path.GetRandomFileName());
3535

36-
await CopyFileAsync(scriptFilePath, Encoding.Default.GetBytes(scriptContent), 493, 0, 0, ct)
36+
await CopyAsync(Encoding.Default.GetBytes(scriptContent), scriptFilePath, Unix.FileMode644, ct)
3737
.ConfigureAwait(false);
3838

3939
return await ExecAsync(new[] { "redis-cli", "--eval", scriptFilePath, "0" }, ct)

src/Testcontainers.Redpanda/RedpandaBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ protected override RedpandaBuilder Init()
6161
startupScript.Append("--mode dev-container ");
6262
startupScript.Append("--kafka-addr PLAINTEXT://0.0.0.0:29092,OUTSIDE://0.0.0.0:9092 ");
6363
startupScript.Append("--advertise-kafka-addr PLAINTEXT://127.0.0.1:29092,OUTSIDE://" + container.Hostname + ":" + container.GetMappedPublicPort(RedpandaPort));
64-
return container.CopyFileAsync(StartupScriptFilePath, Encoding.Default.GetBytes(startupScript.ToString()), 493, ct: ct);
64+
return container.CopyAsync(Encoding.Default.GetBytes(startupScript.ToString()), StartupScriptFilePath, Unix.FileMode755, ct);
6565
});
6666
}
6767

src/Testcontainers/Clients/ITestcontainersClient.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ namespace DotNet.Testcontainers.Clients
22
{
33
using System;
44
using System.Collections.Generic;
5+
using System.IO;
56
using System.Threading;
67
using System.Threading.Tasks;
78
using Docker.DotNet.Models;
@@ -103,6 +104,37 @@ internal interface ITestcontainersClient
103104
/// <returns>Task that completes when the shell command has been executed.</returns>
104105
Task<ExecResult> ExecAsync(string id, IList<string> command, CancellationToken ct = default);
105106

107+
/// <summary>
108+
/// Copies the content of an implementation of <see cref="IResourceMapping" /> to the container.
109+
/// </summary>
110+
/// <param name="id">The container id.</param>
111+
/// <param name="resourceMapping">The resource mapping to add to the archive.</param>
112+
/// <param name="ct">Cancellation token.</param>
113+
/// <returns>A task that completes when the content has been copied.</returns>
114+
Task CopyAsync(string id, IResourceMapping resourceMapping, CancellationToken ct = default);
115+
116+
/// <summary>
117+
/// Copies a test host directory to the container.
118+
/// </summary>
119+
/// <param name="id">The container id.</param>
120+
/// <param name="source">The source directory to be copied.</param>
121+
/// <param name="target">The target directory path to copy the files to.</param>
122+
/// <param name="fileMode">The POSIX file mode permission.</param>
123+
/// <param name="ct">Cancellation token.</param>
124+
/// <returns>A task that completes when the directory has been copied.</returns>
125+
Task CopyAsync(string id, DirectoryInfo source, string target, UnixFileMode fileMode, CancellationToken ct = default);
126+
127+
/// <summary>
128+
/// Copies a test host file to the container.
129+
/// </summary>
130+
/// <param name="id">The container id.</param>
131+
/// <param name="source">The source file to be copied.</param>
132+
/// <param name="target">The target directory path to copy the file to.</param>
133+
/// <param name="fileMode">The POSIX file mode permission.</param>
134+
/// <param name="ct">Cancellation token.</param>
135+
/// <returns>A task that completes when the file has been copied.</returns>
136+
Task CopyAsync(string id, FileInfo source, string target, UnixFileMode fileMode, CancellationToken ct = default);
137+
106138
/// <summary>
107139
/// Copies a file to the container.
108140
/// </summary>

0 commit comments

Comments
 (0)