From cdd77694cf46b764b1bd83fa134d4c58745d8d11 Mon Sep 17 00:00:00 2001 From: Liam Wilson Date: Fri, 20 Sep 2024 17:04:18 +0100 Subject: [PATCH 01/13] Added a wait strategy using http request is succeeded for the health endpoint for Papercut WebUI Service --- Testcontainers.sln | 14 ++++ src/Testcontainers.Papercut/.editorconfig | 1 + .../PapercutBuilder.cs | 79 +++++++++++++++++++ .../PapercutConfiguration.cs | 53 +++++++++++++ .../PapercutContainer.cs | 29 +++++++ .../Testcontainers.Papercut.csproj | 15 ++++ src/Testcontainers.Papercut/Usings.cs | 6 ++ .../.editorconfig | 1 + .../PapercutContainerTest.cs | 72 +++++++++++++++++ .../Testcontainers.Papercut.Tests.csproj | 17 ++++ tests/Testcontainers.Papercut.Tests/Usings.cs | 8 ++ 11 files changed, 295 insertions(+) create mode 100644 src/Testcontainers.Papercut/.editorconfig create mode 100644 src/Testcontainers.Papercut/PapercutBuilder.cs create mode 100644 src/Testcontainers.Papercut/PapercutConfiguration.cs create mode 100644 src/Testcontainers.Papercut/PapercutContainer.cs create mode 100644 src/Testcontainers.Papercut/Testcontainers.Papercut.csproj create mode 100644 src/Testcontainers.Papercut/Usings.cs create mode 100644 tests/Testcontainers.Papercut.Tests/.editorconfig create mode 100644 tests/Testcontainers.Papercut.Tests/PapercutContainerTest.cs create mode 100644 tests/Testcontainers.Papercut.Tests/Testcontainers.Papercut.Tests.csproj create mode 100644 tests/Testcontainers.Papercut.Tests/Usings.cs diff --git a/Testcontainers.sln b/Testcontainers.sln index aacb19742..a4fba1261 100644 --- a/Testcontainers.sln +++ b/Testcontainers.sln @@ -191,6 +191,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Tests", "tes EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.WebDriver.Tests", "tests\Testcontainers.WebDriver.Tests\Testcontainers.WebDriver.Tests.csproj", "{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Papercut", "src\Testcontainers.Papercut\Testcontainers.Papercut.csproj", "{B2608563-8EE4-49AA-A9A0-B1614486AEEF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Papercut.Tests", "tests\Testcontainers.Papercut.Tests\Testcontainers.Papercut.Tests.csproj", "{F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -556,6 +560,14 @@ Global {EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}.Debug|Any CPU.Build.0 = Debug|Any CPU {EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}.Release|Any CPU.ActiveCfg = Release|Any CPU {EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}.Release|Any CPU.Build.0 = Release|Any CPU + {B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Release|Any CPU.Build.0 = Release|Any CPU + {F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {5365F780-0E6C-41F0-B1B9-7DC34368F80C} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} @@ -647,5 +659,7 @@ Global {9E8E6AA5-65D1-498F-BEAB-BA34723A0050} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {27CDB869-A150-4593-958F-6F26E5391E7C} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} + {B2608563-8EE4-49AA-A9A0-B1614486AEEF} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} + {F03FA970-BE2B-4AE2-96FE-7E1F805CEA20} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} EndGlobalSection EndGlobal diff --git a/src/Testcontainers.Papercut/.editorconfig b/src/Testcontainers.Papercut/.editorconfig new file mode 100644 index 000000000..6f066619d --- /dev/null +++ b/src/Testcontainers.Papercut/.editorconfig @@ -0,0 +1 @@ +root = true \ No newline at end of file diff --git a/src/Testcontainers.Papercut/PapercutBuilder.cs b/src/Testcontainers.Papercut/PapercutBuilder.cs new file mode 100644 index 000000000..5a6208b91 --- /dev/null +++ b/src/Testcontainers.Papercut/PapercutBuilder.cs @@ -0,0 +1,79 @@ +using System.Net; + +namespace Testcontainers.Papercut; + +/// +[PublicAPI] +public sealed class PapercutBuilder : ContainerBuilder +{ + public const string PapercutImage = "jijiechen/papercut:latest"; + + public const ushort HttpPort = 37408; + + public const ushort SmtpPort = 25; + + /// + /// Initializes a new instance of the class. + /// + public PapercutBuilder() + : this(new PapercutConfiguration()) + { + DockerResourceConfiguration = Init().DockerResourceConfiguration; + } + + /// + /// Initializes a new instance of the class. + /// + /// The Docker resource configuration. + private PapercutBuilder(PapercutConfiguration resourceConfiguration) + : base(resourceConfiguration) + { + DockerResourceConfiguration = resourceConfiguration; + } + + /// + protected override PapercutConfiguration DockerResourceConfiguration { get; } + + /// + public override PapercutContainer Build() + { + Validate(); + return new PapercutContainer(DockerResourceConfiguration); + } + + /// + protected override PapercutBuilder Init() + { + return base.Init() + .WithImage(PapercutImage) + .WithPortBinding(HttpPort, true) + .WithPortBinding(SmtpPort, true) + .WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged("Now listening on")) + .WithWaitStrategy(Wait.ForUnixContainer() + .UntilHttpRequestIsSucceeded(strategy => + strategy.ForPath("/health") + .ForPort(HttpPort) + .ForStatusCode(HttpStatusCode.OK) + .ForResponseMessageMatching(async message => await message.Content.ReadAsStringAsync() == "Papercut WebUI server started successfully.") + ) + ); + } + + /// + protected override PapercutBuilder Clone(IResourceConfiguration resourceConfiguration) + { + return Merge(DockerResourceConfiguration, new PapercutConfiguration(resourceConfiguration)); + } + + /// + protected override PapercutBuilder Clone(IContainerConfiguration resourceConfiguration) + { + return Merge(DockerResourceConfiguration, new PapercutConfiguration(resourceConfiguration)); + } + + /// + protected override PapercutBuilder Merge(PapercutConfiguration oldValue, PapercutConfiguration newValue) + { + return new PapercutBuilder(new PapercutConfiguration(oldValue, newValue)); + } +} \ No newline at end of file diff --git a/src/Testcontainers.Papercut/PapercutConfiguration.cs b/src/Testcontainers.Papercut/PapercutConfiguration.cs new file mode 100644 index 000000000..6582a0276 --- /dev/null +++ b/src/Testcontainers.Papercut/PapercutConfiguration.cs @@ -0,0 +1,53 @@ +namespace Testcontainers.Papercut; + +/// +[PublicAPI] +public sealed class PapercutConfiguration : ContainerConfiguration +{ + /// + /// Initializes a new instance of the class. + /// + public PapercutConfiguration() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The Docker resource configuration. + public PapercutConfiguration(IResourceConfiguration resourceConfiguration) + : base(resourceConfiguration) + { + // Passes the configuration upwards to the base implementations to create an updated immutable copy. + } + + /// + /// Initializes a new instance of the class. + /// + /// The Docker resource configuration. + public PapercutConfiguration(IContainerConfiguration resourceConfiguration) + : base(resourceConfiguration) + { + // Passes the configuration upwards to the base implementations to create an updated immutable copy. + } + + /// + /// Initializes a new instance of the class. + /// + /// The Docker resource configuration. + public PapercutConfiguration(PapercutConfiguration resourceConfiguration) + : this(new PapercutConfiguration(), resourceConfiguration) + { + // Passes the configuration upwards to the base implementations to create an updated immutable copy. + } + + /// + /// Initializes a new instance of the class. + /// + /// The old Docker resource configuration. + /// The new Docker resource configuration. + public PapercutConfiguration(PapercutConfiguration oldValue, PapercutConfiguration newValue) + : base(oldValue, newValue) + { + } +} \ No newline at end of file diff --git a/src/Testcontainers.Papercut/PapercutContainer.cs b/src/Testcontainers.Papercut/PapercutContainer.cs new file mode 100644 index 000000000..2ad934865 --- /dev/null +++ b/src/Testcontainers.Papercut/PapercutContainer.cs @@ -0,0 +1,29 @@ +namespace Testcontainers.Papercut; + +/// +[PublicAPI] +public sealed class PapercutContainer : DockerContainer +{ + /// + /// Initializes a new instance of the class. + /// + /// The container configuration. + public PapercutContainer(PapercutConfiguration configuration) + : base(configuration) + { + } + + /// + /// Gets the SMTP port. + /// + public ushort SmtpPort => GetMappedPublicPort(PapercutBuilder.SmtpPort); + + /// + /// Gets the Papercut base address. + /// + /// The Papercut base address. + public string GetBaseAddress() + { + return new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(PapercutBuilder.HttpPort)).ToString(); + } +} \ No newline at end of file diff --git a/src/Testcontainers.Papercut/Testcontainers.Papercut.csproj b/src/Testcontainers.Papercut/Testcontainers.Papercut.csproj new file mode 100644 index 000000000..b57207a66 --- /dev/null +++ b/src/Testcontainers.Papercut/Testcontainers.Papercut.csproj @@ -0,0 +1,15 @@ + + + net6.0;net8.0;netstandard2.0;netstandard2.1 + latest + 4.0.1 + 4.0.0 - First release +4.0.1 - Wait stretagy for Papercut WebUI server started successfully + + + + + + + + \ No newline at end of file diff --git a/src/Testcontainers.Papercut/Usings.cs b/src/Testcontainers.Papercut/Usings.cs new file mode 100644 index 000000000..79fd3af9b --- /dev/null +++ b/src/Testcontainers.Papercut/Usings.cs @@ -0,0 +1,6 @@ +global using System; +global using Docker.DotNet.Models; +global using DotNet.Testcontainers.Builders; +global using DotNet.Testcontainers.Configurations; +global using DotNet.Testcontainers.Containers; +global using JetBrains.Annotations; \ No newline at end of file diff --git a/tests/Testcontainers.Papercut.Tests/.editorconfig b/tests/Testcontainers.Papercut.Tests/.editorconfig new file mode 100644 index 000000000..6f066619d --- /dev/null +++ b/tests/Testcontainers.Papercut.Tests/.editorconfig @@ -0,0 +1 @@ +root = true \ No newline at end of file diff --git a/tests/Testcontainers.Papercut.Tests/PapercutContainerTest.cs b/tests/Testcontainers.Papercut.Tests/PapercutContainerTest.cs new file mode 100644 index 000000000..6feba9c73 --- /dev/null +++ b/tests/Testcontainers.Papercut.Tests/PapercutContainerTest.cs @@ -0,0 +1,72 @@ +namespace Testcontainers.Papercut; + +public sealed class PapercutContainerTest : IAsyncLifetime +{ + private readonly PapercutContainer _papercutContainer = new PapercutBuilder().Build(); + + public Task InitializeAsync() + { + return _papercutContainer.StartAsync(); + } + + public Task DisposeAsync() + { + return _papercutContainer.DisposeAsync().AsTask(); + } + + [Fact] + [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))] + public async Task ReceivesSentMessage() + { + // Given + const string subject = "Test"; + + Message[] messages; + + using var httpClient = new HttpClient(); + httpClient.BaseAddress = new Uri(_papercutContainer.GetBaseAddress()); + + using var smtpClient = new SmtpClient(_papercutContainer.Hostname, _papercutContainer.SmtpPort); + + // When + smtpClient.Send("from@example.com", "to@example.com", subject, "A test message"); + + do + { + var messagesJson = await httpClient.GetStringAsync("/api/messages") + .ConfigureAwait(true); + + var jsonDocument = JsonDocument.Parse(messagesJson); + messages = jsonDocument.RootElement.GetProperty("messages").Deserialize(); + } + while (messages.Length == 0); + + // Then + Assert.NotEmpty(messages); + Assert.Equal(subject, messages[0].Subject); + } + + private readonly struct Message + { + [JsonConstructor] + public Message(string id, string subject, string size, DateTime createdAt) + { + Id = id; + Subject = subject; + Size = size; + CreatedAt = createdAt; + } + + [JsonPropertyName("id")] + public string Id { get; } + + [JsonPropertyName("subject")] + public string Subject { get; } + + [JsonPropertyName("size")] + public string Size { get; } + + [JsonPropertyName("createdAt")] + public DateTime CreatedAt { get; } + } +} \ No newline at end of file diff --git a/tests/Testcontainers.Papercut.Tests/Testcontainers.Papercut.Tests.csproj b/tests/Testcontainers.Papercut.Tests/Testcontainers.Papercut.Tests.csproj new file mode 100644 index 000000000..485fcc0f8 --- /dev/null +++ b/tests/Testcontainers.Papercut.Tests/Testcontainers.Papercut.Tests.csproj @@ -0,0 +1,17 @@ + + + net8.0 + false + false + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Testcontainers.Papercut.Tests/Usings.cs b/tests/Testcontainers.Papercut.Tests/Usings.cs new file mode 100644 index 000000000..fd8f22f9b --- /dev/null +++ b/tests/Testcontainers.Papercut.Tests/Usings.cs @@ -0,0 +1,8 @@ +global using System; +global using System.Net.Http; +global using System.Net.Mail; +global using System.Text.Json; +global using System.Text.Json.Serialization; +global using System.Threading.Tasks; +global using DotNet.Testcontainers.Commons; +global using Xunit; From e2f55a3628dae85120841dfe973f1b56e6697551 Mon Sep 17 00:00:00 2001 From: Liam Wilson Date: Fri, 20 Sep 2024 21:45:03 +0100 Subject: [PATCH 02/13] Added retry mechanic to HTTP client check for Papercut test --- .../PapercutContainerTest.cs | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/tests/Testcontainers.Papercut.Tests/PapercutContainerTest.cs b/tests/Testcontainers.Papercut.Tests/PapercutContainerTest.cs index 6feba9c73..07e95ac49 100644 --- a/tests/Testcontainers.Papercut.Tests/PapercutContainerTest.cs +++ b/tests/Testcontainers.Papercut.Tests/PapercutContainerTest.cs @@ -21,7 +21,7 @@ public async Task ReceivesSentMessage() // Given const string subject = "Test"; - Message[] messages; + Message[] messages = []; using var httpClient = new HttpClient(); httpClient.BaseAddress = new Uri(_papercutContainer.GetBaseAddress()); @@ -31,13 +31,26 @@ public async Task ReceivesSentMessage() // When smtpClient.Send("from@example.com", "to@example.com", subject, "A test message"); + var tries = 0; do { - var messagesJson = await httpClient.GetStringAsync("/api/messages") - .ConfigureAwait(true); - - var jsonDocument = JsonDocument.Parse(messagesJson); - messages = jsonDocument.RootElement.GetProperty("messages").Deserialize(); + try + { + var messagesJson = await httpClient.GetStringAsync("/api/messages") + .ConfigureAwait(true); + + var jsonDocument = JsonDocument.Parse(messagesJson); + messages = jsonDocument.RootElement.GetProperty("messages").Deserialize(); + } + catch + { + tries++; + if (tries >= 5) + { + throw; + } + await Task.Delay(25 + Random.Shared.Next(-10, 10)); + } } while (messages.Length == 0); From e6eb084ee47c706b7ca7420432cb157d24837e69 Mon Sep 17 00:00:00 2001 From: Liam Wilson Date: Fri, 20 Sep 2024 22:02:34 +0100 Subject: [PATCH 03/13] Added documentation back --- docs/modules/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/modules/index.md b/docs/modules/index.md index 00de47323..a3042326f 100644 --- a/docs/modules/index.md +++ b/docs/modules/index.md @@ -53,6 +53,7 @@ await moduleNameContainer.StartAsync(); | NATS | `nats:2.9` | [NuGet](https://www.nuget.org/packages/Testcontainers.Nats) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Nats) | | Neo4j | `neo4j:5.4` | [NuGet](https://www.nuget.org/packages/Testcontainers.Neo4j) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Neo4j) | | Oracle | `gvenzl/oracle-xe:21.3.0-slim-faststart` | [NuGet](https://www.nuget.org/packages/Testcontainers.Oracle) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Oracle) | +| Papercut | `jijiechen/papercut:latest` | [NuGet](https://www.nuget.org/packages/Testcontainers.Papercut) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Papercut) | | PostgreSQL | `postgres:15.1` | [NuGet](https://www.nuget.org/packages/Testcontainers.PostgreSql) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.PostgreSql) | | PubSub | `gcr.io/google.com/cloudsdktool/google-cloud-cli:446.0.1-emulators` | [NuGet](https://www.nuget.org/packages/Testcontainers.PubSub) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.PubSub) | | Pulsar | `apachepulsar/pulsar:3.0.6` | [NuGet](https://www.nuget.org/packages/Testcontainers.Pulsar) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Pulsar) | From 71cd80151a38c86f81f890417afff546430d10a2 Mon Sep 17 00:00:00 2001 From: Liam Wilson Date: Sat, 21 Sep 2024 12:36:39 +0100 Subject: [PATCH 04/13] Introduced batching of test runs so we are not spinning up to many containers all at once fighting over resources reduction --- build.cake | 48 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/build.cake b/build.cake index 7ce01ac0c..9896dbdfb 100644 --- a/build.cake +++ b/build.cake @@ -71,20 +71,46 @@ Task("Build") }); }); +void RunTestsInBatches(IEnumerable testProjects, int batchSize) +{ + var batches = testProjects + .Select((project, index) => new { project, index }) + .GroupBy(x => x.index / batchSize) + .Select(group => group.Select(g => g.project)); + + int batchNumber = 1; + + foreach (var batch in batches) + { + Information($"Running batch {batchNumber++}"); + + foreach (var project in batch) + { + Information($"Running tests for project: {project.FullPath}"); + DotNetTest(project.FullPath, new DotNetTestSettings + { + Configuration = param.Configuration, + Verbosity = param.Verbosity, + NoRestore = true, + NoBuild = true, + Collectors = new[] { "XPlat Code Coverage;Format=opencover" }, + ResultsDirectory = param.Paths.Directories.TestResultsDirectoryPath, + ArgumentCustomization = args => args + }); + } + } +} + Task("Tests") .Does(() => { - DotNetTest(param.Solution, new DotNetTestSettings - { - Configuration = param.Configuration, - Verbosity = param.Verbosity, - NoRestore = true, - NoBuild = true, - Collectors = new[] { "XPlat Code Coverage;Format=opencover" }, - Filter = param.TestFilter, - ResultsDirectory = param.Paths.Directories.TestResultsDirectoryPath, - ArgumentCustomization = args => args - }); + var testProjects = param.Projects.All + .Where(p => p.Name.Contains("Test")) + .Select(p => p.Path); + + var batchSize = 5; + + RunTestsInBatches(testProjects, batchSize); }); Task("Sonar-Begin") From d7809e18f9bb894fd9d84b4b59e1a9d4a41d3c7e Mon Sep 17 00:00:00 2001 From: Liam Wilson Date: Sat, 21 Sep 2024 13:03:57 +0100 Subject: [PATCH 05/13] Now lets run the batches in Parallel --- build.cake | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/build.cake b/build.cake index 9896dbdfb..daf9d0016 100644 --- a/build.cake +++ b/build.cake @@ -84,9 +84,11 @@ void RunTestsInBatches(IEnumerable testProjects, int batchSize) { Information($"Running batch {batchNumber++}"); - foreach (var project in batch) + // Parallel execution within each batch + Parallel.ForEach(batch, new ParallelOptions { MaxDegreeOfParallelism = batchSize }, project => { Information($"Running tests for project: {project.FullPath}"); + DotNetTest(project.FullPath, new DotNetTestSettings { Configuration = param.Configuration, @@ -97,7 +99,7 @@ void RunTestsInBatches(IEnumerable testProjects, int batchSize) ResultsDirectory = param.Paths.Directories.TestResultsDirectoryPath, ArgumentCustomization = args => args }); - } + }); } } @@ -108,7 +110,7 @@ Task("Tests") .Where(p => p.Name.Contains("Test")) .Select(p => p.Path); - var batchSize = 5; + var batchSize = 10; RunTestsInBatches(testProjects, batchSize); }); From ae74b7b947d0721d2373c5506ff4075c60749cb7 Mon Sep 17 00:00:00 2001 From: Liam Wilson Date: Sat, 21 Sep 2024 13:24:50 +0100 Subject: [PATCH 06/13] Added batch count for better output message --- build.cake | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build.cake b/build.cake index daf9d0016..06fb4f0e3 100644 --- a/build.cake +++ b/build.cake @@ -76,13 +76,15 @@ void RunTestsInBatches(IEnumerable testProjects, int batchSize) var batches = testProjects .Select((project, index) => new { project, index }) .GroupBy(x => x.index / batchSize) - .Select(group => group.Select(g => g.project)); + .Select(group => group.Select(g => g.project)) + .ToArray(); int batchNumber = 1; + int batchCount = batches.Count(); foreach (var batch in batches) { - Information($"Running batch {batchNumber++}"); + Information($"Running batch {batchNumber++} / {batchCount}"); // Parallel execution within each batch Parallel.ForEach(batch, new ParallelOptions { MaxDegreeOfParallelism = batchSize }, project => From 1f7d1877c431151c7646855d04e0fc8d48c9b049 Mon Sep 17 00:00:00 2001 From: Liam Wilson Date: Sat, 21 Sep 2024 14:15:30 +0100 Subject: [PATCH 07/13] Added missing bits form DotNetTestSettings --- build.cake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.cake b/build.cake index 06fb4f0e3..7693a0bbe 100644 --- a/build.cake +++ b/build.cake @@ -98,8 +98,10 @@ void RunTestsInBatches(IEnumerable testProjects, int batchSize) NoRestore = true, NoBuild = true, Collectors = new[] { "XPlat Code Coverage;Format=opencover" }, + Filter = param.TestFilter, ResultsDirectory = param.Paths.Directories.TestResultsDirectoryPath, ArgumentCustomization = args => args + .AppendSwitchQuoted("--blame-hang-timeout", "5m") }); }); } From 369dccaf4b25f600c21d047a04265ac67063fd0a Mon Sep 17 00:00:00 2001 From: Liam Wilson Date: Sat, 21 Sep 2024 14:41:28 +0100 Subject: [PATCH 08/13] Removed retry around Papercut http API request --- .../PapercutContainerTest.cs | 27 ++++--------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/tests/Testcontainers.Papercut.Tests/PapercutContainerTest.cs b/tests/Testcontainers.Papercut.Tests/PapercutContainerTest.cs index 07e95ac49..96bcaec1b 100644 --- a/tests/Testcontainers.Papercut.Tests/PapercutContainerTest.cs +++ b/tests/Testcontainers.Papercut.Tests/PapercutContainerTest.cs @@ -31,28 +31,11 @@ public async Task ReceivesSentMessage() // When smtpClient.Send("from@example.com", "to@example.com", subject, "A test message"); - var tries = 0; - do - { - try - { - var messagesJson = await httpClient.GetStringAsync("/api/messages") - .ConfigureAwait(true); - - var jsonDocument = JsonDocument.Parse(messagesJson); - messages = jsonDocument.RootElement.GetProperty("messages").Deserialize(); - } - catch - { - tries++; - if (tries >= 5) - { - throw; - } - await Task.Delay(25 + Random.Shared.Next(-10, 10)); - } - } - while (messages.Length == 0); + var messagesJson = await httpClient.GetStringAsync("/api/messages") + .ConfigureAwait(true); + + var jsonDocument = JsonDocument.Parse(messagesJson); + messages = jsonDocument.RootElement.GetProperty("messages").Deserialize(); // Then Assert.NotEmpty(messages); From 6b668d6bca763e32df5663dff859dc4dd1fd6a5f Mon Sep 17 00:00:00 2001 From: Liam Wilson Date: Sat, 21 Sep 2024 15:29:21 +0100 Subject: [PATCH 09/13] Updated to offical image from Papercut which we should be using --- src/Testcontainers.Papercut/PapercutBuilder.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Testcontainers.Papercut/PapercutBuilder.cs b/src/Testcontainers.Papercut/PapercutBuilder.cs index 5a6208b91..f312247c6 100644 --- a/src/Testcontainers.Papercut/PapercutBuilder.cs +++ b/src/Testcontainers.Papercut/PapercutBuilder.cs @@ -6,10 +6,9 @@ namespace Testcontainers.Papercut; [PublicAPI] public sealed class PapercutBuilder : ContainerBuilder { - public const string PapercutImage = "jijiechen/papercut:latest"; - - public const ushort HttpPort = 37408; + public const string PapercutImage = "changemakerstudiosus/papercut-smtp:latest"; + public const ushort HttpPort = 80; public const ushort SmtpPort = 25; /// From 47d4083785c9ad9da4544dec46f2146eed59e401 Mon Sep 17 00:00:00 2001 From: Liam Wilson Date: Sat, 21 Sep 2024 16:44:17 +0100 Subject: [PATCH 10/13] Added removal of docker images after every test project only for CICD pipelines though so we don't destroy developer boxes with images we didn't create --- .cake-scripts/parameters.cake | 4 +++- .github/workflows/cicd.yml | 2 +- build.cake | 9 +++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.cake-scripts/parameters.cake b/.cake-scripts/parameters.cake index 320489de1..e9d70d697 100644 --- a/.cake-scripts/parameters.cake +++ b/.cake-scripts/parameters.cake @@ -29,6 +29,7 @@ internal sealed class BuildParameters public NuGetCredentials NuGetCredentials { get; private set; } public BuildProjects Projects { get; private set; } public BuildPaths Paths { get; private set; } + public bool EnableDockerImageRemoval { get; private set; } public static BuildParameters Instance(ICakeContext context) { @@ -58,7 +59,8 @@ internal sealed class BuildParameters SonarQubeCredentials = SonarQubeCredentials.GetSonarQubeCredentials(context), NuGetCredentials = NuGetCredentials.GetNuGetCredentials(context), Projects = BuildProjects.Instance(context, solutionFilePath), - Paths = BuildPaths.Instance(context, buildInformation.Version) + Paths = BuildPaths.Instance(context, buildInformation.Version), + EnableDockerImageRemoval = context.Argument("enable-docker-image-removal", false) }; } } diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index 29deb471b..1768b3c62 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -76,7 +76,7 @@ jobs: run: dotnet cake --target=Build - name: Run Tests - run: dotnet cake --target=Tests --test-filter=${{ startsWith(matrix.os, 'ubuntu') && 'FullyQualifiedName~Testcontainers' || 'DockerPlatform=Windows' }} + run: dotnet cake --target=Tests --test-filter=${{ startsWith(matrix.os, 'ubuntu') && 'FullyQualifiedName~Testcontainers' || 'DockerPlatform=Windows' }} --enable-docker-image-removal=true # The Test Reporter GH Action is not compatible with the recent # actions/upload-artifact@v4 updates: https://github.com/dorny/test-reporter/issues/363. diff --git a/build.cake b/build.cake index 7693a0bbe..97b113fee 100644 --- a/build.cake +++ b/build.cake @@ -104,6 +104,15 @@ void RunTestsInBatches(IEnumerable testProjects, int batchSize) .AppendSwitchQuoted("--blame-hang-timeout", "5m") }); }); + + if (param.EnableDockerImageRemoval) + { + Information($"Cleaning up Docker images and containers after batch {batchNumber - 1}"); + StartProcess("docker", new ProcessSettings + { + Arguments = "system prune -a -f" + }); + } } } From d7bb3264cae0f59b36b5e2cb1632f51cc00df1bd Mon Sep 17 00:00:00 2001 From: Liam Wilson Date: Sun, 6 Oct 2024 13:27:10 +0100 Subject: [PATCH 11/13] Final bit of clean up of cake script changes --- .cake-scripts/parameters.cake | 3 +-- .github/workflows/cicd.yml | 2 +- docs/modules/index.md | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.cake-scripts/parameters.cake b/.cake-scripts/parameters.cake index e9d70d697..96a7736bd 100644 --- a/.cake-scripts/parameters.cake +++ b/.cake-scripts/parameters.cake @@ -59,8 +59,7 @@ internal sealed class BuildParameters SonarQubeCredentials = SonarQubeCredentials.GetSonarQubeCredentials(context), NuGetCredentials = NuGetCredentials.GetNuGetCredentials(context), Projects = BuildProjects.Instance(context, solutionFilePath), - Paths = BuildPaths.Instance(context, buildInformation.Version), - EnableDockerImageRemoval = context.Argument("enable-docker-image-removal", false) + Paths = BuildPaths.Instance(context, buildInformation.Version) }; } } diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index 92456f811..9f221c5aa 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -76,7 +76,7 @@ jobs: run: dotnet cake --target=Build - name: Run Tests - run: dotnet cake --target=Tests --test-filter=${{ startsWith(matrix.os, 'ubuntu') && 'FullyQualifiedName~Testcontainers' || 'DockerPlatform=Windows' }} --enable-docker-image-removal=true + run: dotnet cake --target=Tests --test-filter=${{ startsWith(matrix.os, 'ubuntu') && 'FullyQualifiedName~Testcontainers' || 'DockerPlatform=Windows' }} - name: Upload Test And Coverage Results uses: actions/upload-artifact@v4 diff --git a/docs/modules/index.md b/docs/modules/index.md index a3042326f..3295e6d7a 100644 --- a/docs/modules/index.md +++ b/docs/modules/index.md @@ -53,7 +53,7 @@ await moduleNameContainer.StartAsync(); | NATS | `nats:2.9` | [NuGet](https://www.nuget.org/packages/Testcontainers.Nats) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Nats) | | Neo4j | `neo4j:5.4` | [NuGet](https://www.nuget.org/packages/Testcontainers.Neo4j) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Neo4j) | | Oracle | `gvenzl/oracle-xe:21.3.0-slim-faststart` | [NuGet](https://www.nuget.org/packages/Testcontainers.Oracle) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Oracle) | -| Papercut | `jijiechen/papercut:latest` | [NuGet](https://www.nuget.org/packages/Testcontainers.Papercut) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Papercut) | +| Papercut | `changemakerstudiosus/papercut-smtp:latest` | [NuGet](https://www.nuget.org/packages/Testcontainers.Papercut) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Papercut) | | PostgreSQL | `postgres:15.1` | [NuGet](https://www.nuget.org/packages/Testcontainers.PostgreSql) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.PostgreSql) | | PubSub | `gcr.io/google.com/cloudsdktool/google-cloud-cli:446.0.1-emulators` | [NuGet](https://www.nuget.org/packages/Testcontainers.PubSub) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.PubSub) | | Pulsar | `apachepulsar/pulsar:3.0.6` | [NuGet](https://www.nuget.org/packages/Testcontainers.Pulsar) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Pulsar) | From 466ccf5ede9d9d593f4b8a5e87f57c868dd20752 Mon Sep 17 00:00:00 2001 From: Liam Wilson Date: Sun, 6 Oct 2024 13:27:10 +0100 Subject: [PATCH 12/13] Final bit of clean up of cake script changes --- .cake-scripts/parameters.cake | 4 +--- .github/workflows/cicd.yml | 2 +- docs/modules/index.md | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.cake-scripts/parameters.cake b/.cake-scripts/parameters.cake index e9d70d697..320489de1 100644 --- a/.cake-scripts/parameters.cake +++ b/.cake-scripts/parameters.cake @@ -29,7 +29,6 @@ internal sealed class BuildParameters public NuGetCredentials NuGetCredentials { get; private set; } public BuildProjects Projects { get; private set; } public BuildPaths Paths { get; private set; } - public bool EnableDockerImageRemoval { get; private set; } public static BuildParameters Instance(ICakeContext context) { @@ -59,8 +58,7 @@ internal sealed class BuildParameters SonarQubeCredentials = SonarQubeCredentials.GetSonarQubeCredentials(context), NuGetCredentials = NuGetCredentials.GetNuGetCredentials(context), Projects = BuildProjects.Instance(context, solutionFilePath), - Paths = BuildPaths.Instance(context, buildInformation.Version), - EnableDockerImageRemoval = context.Argument("enable-docker-image-removal", false) + Paths = BuildPaths.Instance(context, buildInformation.Version) }; } } diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index 92456f811..9f221c5aa 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -76,7 +76,7 @@ jobs: run: dotnet cake --target=Build - name: Run Tests - run: dotnet cake --target=Tests --test-filter=${{ startsWith(matrix.os, 'ubuntu') && 'FullyQualifiedName~Testcontainers' || 'DockerPlatform=Windows' }} --enable-docker-image-removal=true + run: dotnet cake --target=Tests --test-filter=${{ startsWith(matrix.os, 'ubuntu') && 'FullyQualifiedName~Testcontainers' || 'DockerPlatform=Windows' }} - name: Upload Test And Coverage Results uses: actions/upload-artifact@v4 diff --git a/docs/modules/index.md b/docs/modules/index.md index a3042326f..3295e6d7a 100644 --- a/docs/modules/index.md +++ b/docs/modules/index.md @@ -53,7 +53,7 @@ await moduleNameContainer.StartAsync(); | NATS | `nats:2.9` | [NuGet](https://www.nuget.org/packages/Testcontainers.Nats) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Nats) | | Neo4j | `neo4j:5.4` | [NuGet](https://www.nuget.org/packages/Testcontainers.Neo4j) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Neo4j) | | Oracle | `gvenzl/oracle-xe:21.3.0-slim-faststart` | [NuGet](https://www.nuget.org/packages/Testcontainers.Oracle) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Oracle) | -| Papercut | `jijiechen/papercut:latest` | [NuGet](https://www.nuget.org/packages/Testcontainers.Papercut) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Papercut) | +| Papercut | `changemakerstudiosus/papercut-smtp:latest` | [NuGet](https://www.nuget.org/packages/Testcontainers.Papercut) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Papercut) | | PostgreSQL | `postgres:15.1` | [NuGet](https://www.nuget.org/packages/Testcontainers.PostgreSql) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.PostgreSql) | | PubSub | `gcr.io/google.com/cloudsdktool/google-cloud-cli:446.0.1-emulators` | [NuGet](https://www.nuget.org/packages/Testcontainers.PubSub) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.PubSub) | | Pulsar | `apachepulsar/pulsar:3.0.6` | [NuGet](https://www.nuget.org/packages/Testcontainers.Pulsar) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Pulsar) | From eb05e63b9a797e794487e67997de224ae37a908d Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Thu, 10 Oct 2024 18:25:40 +0200 Subject: [PATCH 13/13] chore: Clean up usings, consider default TC config --- Testcontainers.sln | 28 ++++++++--------- docs/modules/index.md | 2 +- src/Testcontainers.Neo4j/Usings.cs | 1 - .../PapercutBuilder.cs | 31 +++++++++++-------- .../Testcontainers.Papercut.csproj | 3 -- src/Testcontainers.Papercut/Usings.cs | 2 ++ .../PapercutContainerTest.cs | 9 ++---- tests/Testcontainers.Papercut.Tests/Usings.cs | 2 +- 8 files changed, 39 insertions(+), 39 deletions(-) diff --git a/Testcontainers.sln b/Testcontainers.sln index a4fba1261..10cae3fc2 100644 --- a/Testcontainers.sln +++ b/Testcontainers.sln @@ -79,6 +79,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Neo4j", "src EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Oracle", "src\Testcontainers.Oracle\Testcontainers.Oracle.csproj", "{596EAFC1-0496-495C-B382-D57415FA456A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Papercut", "src\Testcontainers.Papercut\Testcontainers.Papercut.csproj", "{B2608563-8EE4-49AA-A9A0-B1614486AEEF}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.PostgreSql", "src\Testcontainers.PostgreSql\Testcontainers.PostgreSql.csproj", "{8AB91636-9055-4900-A72A-7CFFACDFDBF0}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.PubSub", "src\Testcontainers.PubSub\Testcontainers.PubSub.csproj", "{E6642255-667D-476B-B584-089AA5E6C0B1}" @@ -167,6 +169,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Neo4j.Tests" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Oracle.Tests", "tests\Testcontainers.Oracle.Tests\Testcontainers.Oracle.Tests.csproj", "{4AC1088B-9965-4497-AC8E-570F1AD5631F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Papercut.Tests", "tests\Testcontainers.Papercut.Tests\Testcontainers.Papercut.Tests.csproj", "{F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Platform.Linux.Tests", "tests\Testcontainers.Platform.Linux.Tests\Testcontainers.Platform.Linux.Tests.csproj", "{DA1D7ADE-452C-4369-83CC-56289176EACD}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Platform.Windows.Tests", "tests\Testcontainers.Platform.Windows.Tests\Testcontainers.Platform.Windows.Tests.csproj", "{3E55CBE8-AFE8-426D-9470-49D63CD1051C}" @@ -191,10 +195,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Tests", "tes EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.WebDriver.Tests", "tests\Testcontainers.WebDriver.Tests\Testcontainers.WebDriver.Tests.csproj", "{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Papercut", "src\Testcontainers.Papercut\Testcontainers.Papercut.csproj", "{B2608563-8EE4-49AA-A9A0-B1614486AEEF}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Papercut.Tests", "tests\Testcontainers.Papercut.Tests\Testcontainers.Papercut.Tests.csproj", "{F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -336,6 +336,10 @@ Global {596EAFC1-0496-495C-B382-D57415FA456A}.Debug|Any CPU.Build.0 = Debug|Any CPU {596EAFC1-0496-495C-B382-D57415FA456A}.Release|Any CPU.ActiveCfg = Release|Any CPU {596EAFC1-0496-495C-B382-D57415FA456A}.Release|Any CPU.Build.0 = Release|Any CPU + {B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Release|Any CPU.Build.0 = Release|Any CPU {8AB91636-9055-4900-A72A-7CFFACDFDBF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8AB91636-9055-4900-A72A-7CFFACDFDBF0}.Debug|Any CPU.Build.0 = Debug|Any CPU {8AB91636-9055-4900-A72A-7CFFACDFDBF0}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -512,6 +516,10 @@ Global {4AC1088B-9965-4497-AC8E-570F1AD5631F}.Debug|Any CPU.Build.0 = Debug|Any CPU {4AC1088B-9965-4497-AC8E-570F1AD5631F}.Release|Any CPU.ActiveCfg = Release|Any CPU {4AC1088B-9965-4497-AC8E-570F1AD5631F}.Release|Any CPU.Build.0 = Release|Any CPU + {F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}.Release|Any CPU.Build.0 = Release|Any CPU {DA1D7ADE-452C-4369-83CC-56289176EACD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DA1D7ADE-452C-4369-83CC-56289176EACD}.Debug|Any CPU.Build.0 = Debug|Any CPU {DA1D7ADE-452C-4369-83CC-56289176EACD}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -560,14 +568,6 @@ Global {EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}.Debug|Any CPU.Build.0 = Debug|Any CPU {EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}.Release|Any CPU.ActiveCfg = Release|Any CPU {EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}.Release|Any CPU.Build.0 = Release|Any CPU - {B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Release|Any CPU.Build.0 = Release|Any CPU - {F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {5365F780-0E6C-41F0-B1B9-7DC34368F80C} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} @@ -603,6 +603,7 @@ Global {BF37BEA1-0816-4326-B1E0-E82290F8FCE0} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} {ADC2372B-6FE0-421D-8277-BB628E8EFC22} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} {596EAFC1-0496-495C-B382-D57415FA456A} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} + {B2608563-8EE4-49AA-A9A0-B1614486AEEF} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} {8AB91636-9055-4900-A72A-7CFFACDFDBF0} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} {E6642255-667D-476B-B584-089AA5E6C0B1} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} {27D46863-65B9-4934-B3C8-2383B217A477} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} @@ -647,6 +648,7 @@ Global {87A3F137-6DC3-4CE5-91E6-01797D076086} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {D3F63405-C0FA-4F83-8B79-E30BFF5FF5BF} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {4AC1088B-9965-4497-AC8E-570F1AD5631F} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} + {F03FA970-BE2B-4AE2-96FE-7E1F805CEA20} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {DA1D7ADE-452C-4369-83CC-56289176EACD} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {3E55CBE8-AFE8-426D-9470-49D63CD1051C} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {56D0DCA5-567F-4B3B-8B79-CB108F8EB8A6} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} @@ -659,7 +661,5 @@ Global {9E8E6AA5-65D1-498F-BEAB-BA34723A0050} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {27CDB869-A150-4593-958F-6F26E5391E7C} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} - {B2608563-8EE4-49AA-A9A0-B1614486AEEF} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} - {F03FA970-BE2B-4AE2-96FE-7E1F805CEA20} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} EndGlobalSection EndGlobal diff --git a/docs/modules/index.md b/docs/modules/index.md index 3295e6d7a..cec9c0e32 100644 --- a/docs/modules/index.md +++ b/docs/modules/index.md @@ -53,7 +53,7 @@ await moduleNameContainer.StartAsync(); | NATS | `nats:2.9` | [NuGet](https://www.nuget.org/packages/Testcontainers.Nats) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Nats) | | Neo4j | `neo4j:5.4` | [NuGet](https://www.nuget.org/packages/Testcontainers.Neo4j) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Neo4j) | | Oracle | `gvenzl/oracle-xe:21.3.0-slim-faststart` | [NuGet](https://www.nuget.org/packages/Testcontainers.Oracle) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Oracle) | -| Papercut | `changemakerstudiosus/papercut-smtp:latest` | [NuGet](https://www.nuget.org/packages/Testcontainers.Papercut) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Papercut) | +| Papercut | `changemakerstudiosus/papercut-smtp:latest` | [NuGet](https://www.nuget.org/packages/Testcontainers.Papercut) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Papercut) | | PostgreSQL | `postgres:15.1` | [NuGet](https://www.nuget.org/packages/Testcontainers.PostgreSql) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.PostgreSql) | | PubSub | `gcr.io/google.com/cloudsdktool/google-cloud-cli:446.0.1-emulators` | [NuGet](https://www.nuget.org/packages/Testcontainers.PubSub) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.PubSub) | | Pulsar | `apachepulsar/pulsar:3.0.6` | [NuGet](https://www.nuget.org/packages/Testcontainers.Pulsar) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Pulsar) | diff --git a/src/Testcontainers.Neo4j/Usings.cs b/src/Testcontainers.Neo4j/Usings.cs index adef2193a..271ad97d9 100644 --- a/src/Testcontainers.Neo4j/Usings.cs +++ b/src/Testcontainers.Neo4j/Usings.cs @@ -1,5 +1,4 @@ global using System; -global using System.Linq; global using System.Text.RegularExpressions; global using Docker.DotNet.Models; global using DotNet.Testcontainers; diff --git a/src/Testcontainers.Papercut/PapercutBuilder.cs b/src/Testcontainers.Papercut/PapercutBuilder.cs index f312247c6..69293818d 100644 --- a/src/Testcontainers.Papercut/PapercutBuilder.cs +++ b/src/Testcontainers.Papercut/PapercutBuilder.cs @@ -1,5 +1,3 @@ -using System.Net; - namespace Testcontainers.Papercut; /// @@ -8,9 +6,10 @@ public sealed class PapercutBuilder : ContainerBuilder /// Initializes a new instance of the class. /// @@ -45,17 +44,10 @@ protected override PapercutBuilder Init() { return base.Init() .WithImage(PapercutImage) - .WithPortBinding(HttpPort, true) .WithPortBinding(SmtpPort, true) - .WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged("Now listening on")) - .WithWaitStrategy(Wait.ForUnixContainer() - .UntilHttpRequestIsSucceeded(strategy => - strategy.ForPath("/health") - .ForPort(HttpPort) - .ForStatusCode(HttpStatusCode.OK) - .ForResponseMessageMatching(async message => await message.Content.ReadAsStringAsync() == "Papercut WebUI server started successfully.") - ) - ); + .WithPortBinding(HttpPort, true) + .WithWaitStrategy(Wait.ForUnixContainer().UntilHttpRequestIsSucceeded(request => + request.ForPath("/health").ForPort(HttpPort).ForResponseMessageMatching(IsInstanceHealthyAsync))); } /// @@ -75,4 +67,17 @@ protected override PapercutBuilder Merge(PapercutConfiguration oldValue, Papercu { return new PapercutBuilder(new PapercutConfiguration(oldValue, newValue)); } + + /// + /// Determines whether the instance is healthy or not. + /// + /// The HTTP response that contains the health information. + /// A value indicating whether the instance is healthy or not. + private static async Task IsInstanceHealthyAsync(HttpResponseMessage response) + { + var body = await response.Content.ReadAsStringAsync() + .ConfigureAwait(false); + + return "Papercut WebUI server started successfully.".Equals(body, StringComparison.OrdinalIgnoreCase); + } } \ No newline at end of file diff --git a/src/Testcontainers.Papercut/Testcontainers.Papercut.csproj b/src/Testcontainers.Papercut/Testcontainers.Papercut.csproj index b57207a66..8b2ed72c6 100644 --- a/src/Testcontainers.Papercut/Testcontainers.Papercut.csproj +++ b/src/Testcontainers.Papercut/Testcontainers.Papercut.csproj @@ -2,9 +2,6 @@ net6.0;net8.0;netstandard2.0;netstandard2.1 latest - 4.0.1 - 4.0.0 - First release -4.0.1 - Wait stretagy for Papercut WebUI server started successfully diff --git a/src/Testcontainers.Papercut/Usings.cs b/src/Testcontainers.Papercut/Usings.cs index 79fd3af9b..2dfa21a9b 100644 --- a/src/Testcontainers.Papercut/Usings.cs +++ b/src/Testcontainers.Papercut/Usings.cs @@ -1,4 +1,6 @@ global using System; +global using System.Net.Http; +global using System.Threading.Tasks; global using Docker.DotNet.Models; global using DotNet.Testcontainers.Builders; global using DotNet.Testcontainers.Configurations; diff --git a/tests/Testcontainers.Papercut.Tests/PapercutContainerTest.cs b/tests/Testcontainers.Papercut.Tests/PapercutContainerTest.cs index 96bcaec1b..5b749ea9e 100644 --- a/tests/Testcontainers.Papercut.Tests/PapercutContainerTest.cs +++ b/tests/Testcontainers.Papercut.Tests/PapercutContainerTest.cs @@ -21,13 +21,11 @@ public async Task ReceivesSentMessage() // Given const string subject = "Test"; - Message[] messages = []; + using var smtpClient = new SmtpClient(_papercutContainer.Hostname, _papercutContainer.SmtpPort); using var httpClient = new HttpClient(); httpClient.BaseAddress = new Uri(_papercutContainer.GetBaseAddress()); - using var smtpClient = new SmtpClient(_papercutContainer.Hostname, _papercutContainer.SmtpPort); - // When smtpClient.Send("from@example.com", "to@example.com", subject, "A test message"); @@ -35,11 +33,10 @@ public async Task ReceivesSentMessage() .ConfigureAwait(true); var jsonDocument = JsonDocument.Parse(messagesJson); - messages = jsonDocument.RootElement.GetProperty("messages").Deserialize(); + var messages = jsonDocument.RootElement.GetProperty("messages").Deserialize(); // Then - Assert.NotEmpty(messages); - Assert.Equal(subject, messages[0].Subject); + Assert.Single(messages, message => subject.Equals(message.Subject)); } private readonly struct Message diff --git a/tests/Testcontainers.Papercut.Tests/Usings.cs b/tests/Testcontainers.Papercut.Tests/Usings.cs index fd8f22f9b..763582fff 100644 --- a/tests/Testcontainers.Papercut.Tests/Usings.cs +++ b/tests/Testcontainers.Papercut.Tests/Usings.cs @@ -5,4 +5,4 @@ global using System.Text.Json.Serialization; global using System.Threading.Tasks; global using DotNet.Testcontainers.Commons; -global using Xunit; +global using Xunit; \ No newline at end of file