diff --git a/src/Testcontainers/Configurations/FileSystem.cs b/src/Testcontainers/Configurations/FileSystem.cs new file mode 100644 index 000000000..d32ba92fd --- /dev/null +++ b/src/Testcontainers/Configurations/FileSystem.cs @@ -0,0 +1,21 @@ +namespace DotNet.Testcontainers.Configurations +{ + using JetBrains.Annotations; + + /// + /// Indicates the file system for file operations. + /// + [PublicAPI] + public enum FileSystem + { + /// + /// The test host file system. + /// + Host = 0, + + /// + /// The container file system. + /// + Container = 1, + } +} diff --git a/src/Testcontainers/Configurations/WaitStrategies/IWaitForContainerOS.cs b/src/Testcontainers/Configurations/WaitStrategies/IWaitForContainerOS.cs index 400558577..f4e3d2df5 100644 --- a/src/Testcontainers/Configurations/WaitStrategies/IWaitForContainerOS.cs +++ b/src/Testcontainers/Configurations/WaitStrategies/IWaitForContainerOS.cs @@ -52,10 +52,11 @@ public interface IWaitForContainerOS /// /// Waits until the file exists. /// - /// The file to be checked. + /// The file path to be checked. + /// The file system to be checked. /// A configured instance of . [PublicAPI] - IWaitForContainerOS UntilFileExists(string file); + IWaitForContainerOS UntilFileExists(string filePath, FileSystem fileSystem = FileSystem.Host); /// /// Waits until the message is logged. diff --git a/src/Testcontainers/Configurations/WaitStrategies/UntilFileExistsInContainer.cs b/src/Testcontainers/Configurations/WaitStrategies/UntilFileExistsInContainer.cs new file mode 100644 index 000000000..63b410ada --- /dev/null +++ b/src/Testcontainers/Configurations/WaitStrategies/UntilFileExistsInContainer.cs @@ -0,0 +1,31 @@ +namespace DotNet.Testcontainers.Configurations +{ + using System.IO; + using System.Threading.Tasks; + using DotNet.Testcontainers.Containers; + + internal class UntilFileExistsInContainer : IWaitUntil + { + private readonly string _file; + + public UntilFileExistsInContainer(string file) + { + _file = file; + } + + public async Task UntilAsync(IContainer container) + { + try + { + _ = await container.ReadFileAsync(_file) + .ConfigureAwait(false); + + return true; + } + catch (FileNotFoundException) + { + return false; + } + } + } +} diff --git a/src/Testcontainers/Configurations/WaitStrategies/UntilFilesExists.cs b/src/Testcontainers/Configurations/WaitStrategies/UntilFileExistsOnHost.cs similarity index 77% rename from src/Testcontainers/Configurations/WaitStrategies/UntilFilesExists.cs rename to src/Testcontainers/Configurations/WaitStrategies/UntilFileExistsOnHost.cs index 70ab4fd27..10362752e 100644 --- a/src/Testcontainers/Configurations/WaitStrategies/UntilFilesExists.cs +++ b/src/Testcontainers/Configurations/WaitStrategies/UntilFileExistsOnHost.cs @@ -4,11 +4,11 @@ namespace DotNet.Testcontainers.Configurations using System.Threading.Tasks; using DotNet.Testcontainers.Containers; - internal class UntilFilesExists : IWaitUntil + internal class UntilFileExistsOnHost : IWaitUntil { private readonly string _file; - public UntilFilesExists(string file) + public UntilFileExistsOnHost(string file) { _file = file; } diff --git a/src/Testcontainers/Configurations/WaitStrategies/WaitForContainerOS.cs b/src/Testcontainers/Configurations/WaitStrategies/WaitForContainerOS.cs index 88b2161d2..669c5e062 100644 --- a/src/Testcontainers/Configurations/WaitStrategies/WaitForContainerOS.cs +++ b/src/Testcontainers/Configurations/WaitStrategies/WaitForContainerOS.cs @@ -34,9 +34,16 @@ public virtual IWaitForContainerOS AddCustomWaitStrategy(IWaitUntil waitStrategy } /// - public virtual IWaitForContainerOS UntilFileExists(string file) + public virtual IWaitForContainerOS UntilFileExists(string filePath, FileSystem fileSystem = FileSystem.Host) { - return AddCustomWaitStrategy(new UntilFilesExists(file)); + switch (fileSystem) + { + case FileSystem.Container: + return AddCustomWaitStrategy(new UntilFileExistsInContainer(filePath)); + case FileSystem.Host: + default: + return AddCustomWaitStrategy(new UntilFileExistsOnHost(filePath)); + } } /// diff --git a/tests/Testcontainers.Tests/Unit/Configurations/WaitUntilFileExistsInContainerTest.cs b/tests/Testcontainers.Tests/Unit/Configurations/WaitUntilFileExistsInContainerTest.cs new file mode 100644 index 000000000..007b2ad3e --- /dev/null +++ b/tests/Testcontainers.Tests/Unit/Configurations/WaitUntilFileExistsInContainerTest.cs @@ -0,0 +1,50 @@ +namespace DotNet.Testcontainers.Tests.Unit +{ + using System; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + using DotNet.Testcontainers.Builders; + using DotNet.Testcontainers.Commons; + using DotNet.Testcontainers.Configurations; + using DotNet.Testcontainers.Containers; + using Xunit; + + public sealed class WaitUntilFileExistsInContainerTest : IAsyncLifetime, IDisposable + { + private const string ContainerFilePath = "/tmp/hostname"; + + private readonly CancellationTokenSource _cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + + private readonly IContainer _container = new ContainerBuilder() + .WithImage(CommonImages.Alpine) + .WithEntrypoint("/bin/sh", "-c") + .WithCommand("hostname > " + ContainerFilePath + "; trap : TERM INT; sleep infinity & wait") + .WithWaitStrategy(Wait.ForUnixContainer().UntilFileExists(ContainerFilePath, FileSystem.Container)) + .Build(); + + public Task InitializeAsync() + { + return _container.StartAsync(_cts.Token); + } + + public Task DisposeAsync() + { + return _container.DisposeAsync().AsTask(); + } + + public void Dispose() + { + _cts.Dispose(); + } + + [Fact] + public async Task ContainerIsRunning() + { + var execResult = await _container.ExecAsync(new List { "test", "-f", ContainerFilePath }) + .ConfigureAwait(false); + + Assert.Equal(0, execResult.ExitCode); + } + } +}