From 54db49253ed75ea07fb0a04117ba4d194307e3fd Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Thu, 20 Oct 2022 10:39:24 +0200 Subject: [PATCH 1/4] fix(#610): Do not deny all files in the Docker image tarball when a .dockerignore entry ends with /* --- CHANGELOG.md | 1 + src/Testcontainers/Images/IgnoreFile.cs | 10 ++++++++++ .../Fixtures/Images/IgnoreFileFixture.cs | 8 ++++---- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2fafefb0..b64b68b5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ - 525 Read ServerURL, Username and Secret field from CredsStore response to pull private Docker images - 595 Implement `TestcontainersContainer.DisposeAsync` thread safe (rename `TestcontainersState` to `TestcontainersStates`) - 604 Do not deny all files in the Docker image tarball when a `.dockerignore` entry ends with `/` +- 610 Do not deny all files in the Docker image tarball when a `.dockerignore` entry ends with `/*` ## [2.1.0] diff --git a/src/Testcontainers/Images/IgnoreFile.cs b/src/Testcontainers/Images/IgnoreFile.cs index 293f156e3..732fc8d8f 100644 --- a/src/Testcontainers/Images/IgnoreFile.cs +++ b/src/Testcontainers/Images/IgnoreFile.cs @@ -32,6 +32,16 @@ public IgnoreFile(IEnumerable patterns, ILogger logger) // Trim each line. .Select(line => line.Trim()) + // Exclude files and directories. + .Select(line => line.TrimEnd('/')) + + // Exclude files and directories. + .Select(line => + { + const string filesAndDirectories = "/*"; + return line.EndsWith(filesAndDirectories, StringComparison.InvariantCulture) ? line.Substring(0, line.Length - filesAndDirectories.Length) : line; + }) + // Remove empty line. .Where(line => !string.IsNullOrEmpty(line)) diff --git a/tests/Testcontainers.Tests/Fixtures/Images/IgnoreFileFixture.cs b/tests/Testcontainers.Tests/Fixtures/Images/IgnoreFileFixture.cs index 341531726..ce2e5b6e1 100644 --- a/tests/Testcontainers.Tests/Fixtures/Images/IgnoreFileFixture.cs +++ b/tests/Testcontainers.Tests/Fixtures/Images/IgnoreFileFixture.cs @@ -9,15 +9,15 @@ public sealed class IgnoreFileFixture : TheoryData public IgnoreFileFixture() { var logger = TestcontainersSettings.Logger; - var ignoreDirectory = new IgnoreFile(new[] { "bin/", "obj/" }, logger); + var ignoreFilesAndDirectories = new IgnoreFile(new[] { "bin/", "obj/*" }, logger); var ignoreNonRecursiveFiles = new IgnoreFile(new[] { "*/temp*" }, logger); var ignoreNonRecursiveNestedFiles = new IgnoreFile(new[] { "*/*/temp*" }, logger); var ignoreRecursiveFiles = new IgnoreFile(new[] { "**/*.txt" }, logger); var ignoreSingleCharacterFiles = new IgnoreFile(new[] { "temp?" }, logger); var ignoreExceptionFiles = new IgnoreFile(new[] { "*.md", "!README*.md", "README-secret.md" }, logger); - this.Add(ignoreDirectory, "Testcontainers.sln", true); - this.Add(ignoreDirectory, "bin/Debug/net6.0", false); - this.Add(ignoreDirectory, "obj/Debug/net6.0", false); + this.Add(ignoreFilesAndDirectories, "bin/Debug/net6.0", false); + this.Add(ignoreFilesAndDirectories, "obj/Debug/net6.0", false); + this.Add(ignoreFilesAndDirectories, "Testcontainers.sln", true); this.Add(ignoreNonRecursiveFiles, "lipsum/temp", false); this.Add(ignoreNonRecursiveFiles, "lipsum/temp.txt", false); this.Add(ignoreNonRecursiveFiles, "lipsum/lorem/temp", true); From c11cad2bad38fce090ce0db9f33078e9d4d354b2 Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Thu, 20 Oct 2022 10:42:24 +0200 Subject: [PATCH 2/4] refactor: Resolve containers hostname equivalent to tc-java --- .../Containers/TestcontainersContainer.cs | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/Testcontainers/Containers/TestcontainersContainer.cs b/src/Testcontainers/Containers/TestcontainersContainer.cs index 3a1ae1b13..2b2a199d9 100644 --- a/src/Testcontainers/Containers/TestcontainersContainer.cs +++ b/src/Testcontainers/Containers/TestcontainersContainer.cs @@ -4,7 +4,6 @@ namespace DotNet.Testcontainers.Containers using System.Collections.Generic; using System.Globalization; using System.Linq; - using System.Net; using System.Threading; using System.Threading.Tasks; using Docker.DotNet; @@ -20,8 +19,6 @@ public class TestcontainersContainer : ITestcontainersContainer { private const TestcontainersStates ContainerHasBeenCreatedStates = TestcontainersStates.Created | TestcontainersStates.Running | TestcontainersStates.Exited; - private static readonly string[] DockerDesktopGateways = { "host.docker.internal", "gateway.docker.internal" }; - private readonly SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1); private readonly ITestcontainersClient client; @@ -379,30 +376,31 @@ private void ThrowIfContainerHasNotBeenCreated() private string GetContainerGateway() { - if (!this.client.IsRunningInsideDocker || !ContainerHasBeenCreatedStates.HasFlag(this.State)) + const string localhost = "localhost"; + + if (!ContainerHasBeenCreatedStates.HasFlag(this.State)) { - return "localhost"; + return localhost; } - string GetDockerDesktopGateway(string dockerDesktopGateway) + if (!this.client.IsRunningInsideDocker) { - try - { - _ = Dns.GetHostEntry(dockerDesktopGateway); - return dockerDesktopGateway; - } - catch - { - return null; - } + return localhost; + } + + var endpointSettings = this.container.NetworkSettings.Networks.TryGetValue("bridge", out var network) ? network : new EndpointSettings(); + if (!string.IsNullOrWhiteSpace(endpointSettings.Gateway)) + { + return endpointSettings.Gateway; } - var hostname = DockerDesktopGateways - .AsParallel() - .Select(GetDockerDesktopGateway) - .FirstOrDefault(dockerDesktopGateway => dockerDesktopGateway != null); + var networkSettings = this.container.NetworkSettings; + if (!string.IsNullOrWhiteSpace(networkSettings.Gateway)) + { + return networkSettings.Gateway; + } - return hostname ?? this.container.NetworkSettings.Networks.First().Value.Gateway; + return localhost; } } } From daf39a2b7a1631644bb78a06a53eb339cae03cc5 Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Thu, 20 Oct 2022 10:44:32 +0200 Subject: [PATCH 3/4] docs: Get WeatherForecast service from in-process DI container --- .../WeatherForecastTest.cs | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/examples/WeatherForecast/tests/WeatherForecast.InProcess.Test/WeatherForecastTest.cs b/examples/WeatherForecast/tests/WeatherForecast.InProcess.Test/WeatherForecastTest.cs index 1527d7743..ad14881f6 100644 --- a/examples/WeatherForecast/tests/WeatherForecast.InProcess.Test/WeatherForecastTest.cs +++ b/examples/WeatherForecast/tests/WeatherForecast.InProcess.Test/WeatherForecastTest.cs @@ -10,7 +10,9 @@ using DotNet.Testcontainers.Containers; using JetBrains.Annotations; using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.Extensions.DependencyInjection; using WeatherForecast.Entities; +using WeatherForecast.Repositories; using Xunit; namespace WeatherForecast.InProcess.Test; @@ -41,8 +43,12 @@ public Task DisposeAsync() return _mssqlContainer.DisposeAsync().AsTask(); } - public sealed class Api : IClassFixture + public sealed class Api : IClassFixture, IDisposable { + private readonly WebApplicationFactory _webApplicationFactory; + + private readonly IServiceScope _serviceScope; + private readonly HttpClient _httpClient; public Api(WeatherForecastTest weatherForecastTest) @@ -51,7 +57,16 @@ public Api(WeatherForecastTest weatherForecastTest) Environment.SetEnvironmentVariable("ASPNETCORE_Kestrel__Certificates__Default__Path", "certificate.crt"); Environment.SetEnvironmentVariable("ASPNETCORE_Kestrel__Certificates__Default__Password", "password"); Environment.SetEnvironmentVariable("ConnectionStrings__DefaultConnection", weatherForecastTest._mssqlContainer.ConnectionString); - _httpClient = new WebApplicationFactory().CreateClient(); + _webApplicationFactory = new WebApplicationFactory(); + _serviceScope = _webApplicationFactory.Services.GetRequiredService().CreateScope(); + _httpClient = _webApplicationFactory.CreateClient(); + } + + public void Dispose() + { + _httpClient.Dispose(); + _serviceScope.Dispose(); + _webApplicationFactory.Dispose(); } [Fact] @@ -75,5 +90,22 @@ public async Task Get_WeatherForecast_ReturnsSevenDays() Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(7, weatherForecast!.Count()); } + + [Fact] + [Trait("Category", nameof(Api))] + public async Task Get_WeatherForecast_ReturnsThreeDays() + { + // Given + const int threeDays = 3; + + var weatherDataReadOnlyRepository = _serviceScope.ServiceProvider.GetRequiredService(); + + // When + var weatherForecast = await weatherDataReadOnlyRepository.GetAllAsync(string.Empty, string.Empty, DateTime.Today, DateTime.Today.AddDays(threeDays)) + .ConfigureAwait(false); + + // Then + Assert.Equal(threeDays, weatherForecast.Count()); + } } } From 08e7fa5a6e1d08c02bf249db79ac57e097276ba6 Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Thu, 20 Oct 2022 11:21:53 +0200 Subject: [PATCH 4/4] refactor: DockerfileArchive always write files (into the tarball) --- src/Testcontainers/Images/DockerfileArchive.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Testcontainers/Images/DockerfileArchive.cs b/src/Testcontainers/Images/DockerfileArchive.cs index d3ba508ef..e4ebc7d70 100644 --- a/src/Testcontainers/Images/DockerfileArchive.cs +++ b/src/Testcontainers/Images/DockerfileArchive.cs @@ -86,7 +86,7 @@ public string Tar() var tarEntry = TarEntry.CreateEntryFromFile(file); tarEntry.Name = relativePath; - tarArchive.WriteEntry(tarEntry, true); + tarArchive.WriteEntry(tarEntry, false); } } }