Skip to content

Commit 159e4bf

Browse files
feat: Reintroduce Papercut module (#1268)
Co-authored-by: Andre Hofmeister <[email protected]>
1 parent f4966d8 commit 159e4bf

File tree

13 files changed

+292
-1
lines changed

13 files changed

+292
-1
lines changed

Testcontainers.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Neo4j", "src
7979
EndProject
8080
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Oracle", "src\Testcontainers.Oracle\Testcontainers.Oracle.csproj", "{596EAFC1-0496-495C-B382-D57415FA456A}"
8181
EndProject
82+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Papercut", "src\Testcontainers.Papercut\Testcontainers.Papercut.csproj", "{B2608563-8EE4-49AA-A9A0-B1614486AEEF}"
83+
EndProject
8284
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.PostgreSql", "src\Testcontainers.PostgreSql\Testcontainers.PostgreSql.csproj", "{8AB91636-9055-4900-A72A-7CFFACDFDBF0}"
8385
EndProject
8486
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"
167169
EndProject
168170
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Oracle.Tests", "tests\Testcontainers.Oracle.Tests\Testcontainers.Oracle.Tests.csproj", "{4AC1088B-9965-4497-AC8E-570F1AD5631F}"
169171
EndProject
172+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Papercut.Tests", "tests\Testcontainers.Papercut.Tests\Testcontainers.Papercut.Tests.csproj", "{F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}"
173+
EndProject
170174
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}"
171175
EndProject
172176
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}"
@@ -332,6 +336,10 @@ Global
332336
{596EAFC1-0496-495C-B382-D57415FA456A}.Debug|Any CPU.Build.0 = Debug|Any CPU
333337
{596EAFC1-0496-495C-B382-D57415FA456A}.Release|Any CPU.ActiveCfg = Release|Any CPU
334338
{596EAFC1-0496-495C-B382-D57415FA456A}.Release|Any CPU.Build.0 = Release|Any CPU
339+
{B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
340+
{B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
341+
{B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
342+
{B2608563-8EE4-49AA-A9A0-B1614486AEEF}.Release|Any CPU.Build.0 = Release|Any CPU
335343
{8AB91636-9055-4900-A72A-7CFFACDFDBF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
336344
{8AB91636-9055-4900-A72A-7CFFACDFDBF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
337345
{8AB91636-9055-4900-A72A-7CFFACDFDBF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -508,6 +516,10 @@ Global
508516
{4AC1088B-9965-4497-AC8E-570F1AD5631F}.Debug|Any CPU.Build.0 = Debug|Any CPU
509517
{4AC1088B-9965-4497-AC8E-570F1AD5631F}.Release|Any CPU.ActiveCfg = Release|Any CPU
510518
{4AC1088B-9965-4497-AC8E-570F1AD5631F}.Release|Any CPU.Build.0 = Release|Any CPU
519+
{F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
520+
{F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}.Debug|Any CPU.Build.0 = Debug|Any CPU
521+
{F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}.Release|Any CPU.ActiveCfg = Release|Any CPU
522+
{F03FA970-BE2B-4AE2-96FE-7E1F805CEA20}.Release|Any CPU.Build.0 = Release|Any CPU
511523
{DA1D7ADE-452C-4369-83CC-56289176EACD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
512524
{DA1D7ADE-452C-4369-83CC-56289176EACD}.Debug|Any CPU.Build.0 = Debug|Any CPU
513525
{DA1D7ADE-452C-4369-83CC-56289176EACD}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -591,6 +603,7 @@ Global
591603
{BF37BEA1-0816-4326-B1E0-E82290F8FCE0} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
592604
{ADC2372B-6FE0-421D-8277-BB628E8EFC22} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
593605
{596EAFC1-0496-495C-B382-D57415FA456A} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
606+
{B2608563-8EE4-49AA-A9A0-B1614486AEEF} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
594607
{8AB91636-9055-4900-A72A-7CFFACDFDBF0} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
595608
{E6642255-667D-476B-B584-089AA5E6C0B1} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
596609
{27D46863-65B9-4934-B3C8-2383B217A477} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
@@ -635,6 +648,7 @@ Global
635648
{87A3F137-6DC3-4CE5-91E6-01797D076086} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
636649
{D3F63405-C0FA-4F83-8B79-E30BFF5FF5BF} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
637650
{4AC1088B-9965-4497-AC8E-570F1AD5631F} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
651+
{F03FA970-BE2B-4AE2-96FE-7E1F805CEA20} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
638652
{DA1D7ADE-452C-4369-83CC-56289176EACD} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
639653
{3E55CBE8-AFE8-426D-9470-49D63CD1051C} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
640654
{56D0DCA5-567F-4B3B-8B79-CB108F8EB8A6} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}

docs/modules/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ await moduleNameContainer.StartAsync();
5353
| NATS | `nats:2.9` | [NuGet](https://www.nuget.org/packages/Testcontainers.Nats) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Nats) |
5454
| Neo4j | `neo4j:5.4` | [NuGet](https://www.nuget.org/packages/Testcontainers.Neo4j) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Neo4j) |
5555
| 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) |
56+
| 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) |
5657
| PostgreSQL | `postgres:15.1` | [NuGet](https://www.nuget.org/packages/Testcontainers.PostgreSql) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.PostgreSql) |
5758
| 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) |
5859
| 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) |

src/Testcontainers.Neo4j/Usings.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
global using System;
2-
global using System.Linq;
32
global using System.Text.RegularExpressions;
43
global using Docker.DotNet.Models;
54
global using DotNet.Testcontainers;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
root = true
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
namespace Testcontainers.Papercut;
2+
3+
/// <inheritdoc cref="ContainerBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}" />
4+
[PublicAPI]
5+
public sealed class PapercutBuilder : ContainerBuilder<PapercutBuilder, PapercutContainer, PapercutConfiguration>
6+
{
7+
public const string PapercutImage = "changemakerstudiosus/papercut-smtp:latest";
8+
9+
public const ushort SmtpPort = 25;
10+
11+
public const ushort HttpPort = 80;
12+
13+
/// <summary>
14+
/// Initializes a new instance of the <see cref="PapercutBuilder" /> class.
15+
/// </summary>
16+
public PapercutBuilder()
17+
: this(new PapercutConfiguration())
18+
{
19+
DockerResourceConfiguration = Init().DockerResourceConfiguration;
20+
}
21+
22+
/// <summary>
23+
/// Initializes a new instance of the <see cref="PapercutBuilder" /> class.
24+
/// </summary>
25+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
26+
private PapercutBuilder(PapercutConfiguration resourceConfiguration)
27+
: base(resourceConfiguration)
28+
{
29+
DockerResourceConfiguration = resourceConfiguration;
30+
}
31+
32+
/// <inheritdoc />
33+
protected override PapercutConfiguration DockerResourceConfiguration { get; }
34+
35+
/// <inheritdoc />
36+
public override PapercutContainer Build()
37+
{
38+
Validate();
39+
return new PapercutContainer(DockerResourceConfiguration);
40+
}
41+
42+
/// <inheritdoc />
43+
protected override PapercutBuilder Init()
44+
{
45+
return base.Init()
46+
.WithImage(PapercutImage)
47+
.WithPortBinding(SmtpPort, true)
48+
.WithPortBinding(HttpPort, true)
49+
.WithWaitStrategy(Wait.ForUnixContainer().UntilHttpRequestIsSucceeded(request =>
50+
request.ForPath("/health").ForPort(HttpPort).ForResponseMessageMatching(IsInstanceHealthyAsync)));
51+
}
52+
53+
/// <inheritdoc />
54+
protected override PapercutBuilder Clone(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
55+
{
56+
return Merge(DockerResourceConfiguration, new PapercutConfiguration(resourceConfiguration));
57+
}
58+
59+
/// <inheritdoc />
60+
protected override PapercutBuilder Clone(IContainerConfiguration resourceConfiguration)
61+
{
62+
return Merge(DockerResourceConfiguration, new PapercutConfiguration(resourceConfiguration));
63+
}
64+
65+
/// <inheritdoc />
66+
protected override PapercutBuilder Merge(PapercutConfiguration oldValue, PapercutConfiguration newValue)
67+
{
68+
return new PapercutBuilder(new PapercutConfiguration(oldValue, newValue));
69+
}
70+
71+
/// <summary>
72+
/// Determines whether the instance is healthy or not.
73+
/// </summary>
74+
/// <param name="response">The HTTP response that contains the health information.</param>
75+
/// <returns>A value indicating whether the instance is healthy or not.</returns>
76+
private static async Task<bool> IsInstanceHealthyAsync(HttpResponseMessage response)
77+
{
78+
var body = await response.Content.ReadAsStringAsync()
79+
.ConfigureAwait(false);
80+
81+
return "Papercut WebUI server started successfully.".Equals(body, StringComparison.OrdinalIgnoreCase);
82+
}
83+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
namespace Testcontainers.Papercut;
2+
3+
/// <inheritdoc cref="ContainerConfiguration" />
4+
[PublicAPI]
5+
public sealed class PapercutConfiguration : ContainerConfiguration
6+
{
7+
/// <summary>
8+
/// Initializes a new instance of the <see cref="PapercutConfiguration" /> class.
9+
/// </summary>
10+
public PapercutConfiguration()
11+
{
12+
}
13+
14+
/// <summary>
15+
/// Initializes a new instance of the <see cref="PapercutConfiguration" /> class.
16+
/// </summary>
17+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
18+
public PapercutConfiguration(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
19+
: base(resourceConfiguration)
20+
{
21+
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
22+
}
23+
24+
/// <summary>
25+
/// Initializes a new instance of the <see cref="PapercutConfiguration" /> class.
26+
/// </summary>
27+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
28+
public PapercutConfiguration(IContainerConfiguration resourceConfiguration)
29+
: base(resourceConfiguration)
30+
{
31+
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
32+
}
33+
34+
/// <summary>
35+
/// Initializes a new instance of the <see cref="PapercutConfiguration" /> class.
36+
/// </summary>
37+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
38+
public PapercutConfiguration(PapercutConfiguration resourceConfiguration)
39+
: this(new PapercutConfiguration(), resourceConfiguration)
40+
{
41+
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
42+
}
43+
44+
/// <summary>
45+
/// Initializes a new instance of the <see cref="PapercutConfiguration" /> class.
46+
/// </summary>
47+
/// <param name="oldValue">The old Docker resource configuration.</param>
48+
/// <param name="newValue">The new Docker resource configuration.</param>
49+
public PapercutConfiguration(PapercutConfiguration oldValue, PapercutConfiguration newValue)
50+
: base(oldValue, newValue)
51+
{
52+
}
53+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
namespace Testcontainers.Papercut;
2+
3+
/// <inheritdoc cref="DockerContainer" />
4+
[PublicAPI]
5+
public sealed class PapercutContainer : DockerContainer
6+
{
7+
/// <summary>
8+
/// Initializes a new instance of the <see cref="PapercutContainer" /> class.
9+
/// </summary>
10+
/// <param name="configuration">The container configuration.</param>
11+
public PapercutContainer(PapercutConfiguration configuration)
12+
: base(configuration)
13+
{
14+
}
15+
16+
/// <summary>
17+
/// Gets the SMTP port.
18+
/// </summary>
19+
public ushort SmtpPort => GetMappedPublicPort(PapercutBuilder.SmtpPort);
20+
21+
/// <summary>
22+
/// Gets the Papercut base address.
23+
/// </summary>
24+
/// <returns>The Papercut base address.</returns>
25+
public string GetBaseAddress()
26+
{
27+
return new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(PapercutBuilder.HttpPort)).ToString();
28+
}
29+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFrameworks>net6.0;net8.0;netstandard2.0;netstandard2.1</TargetFrameworks>
4+
<LangVersion>latest</LangVersion>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<PackageReference Include="JetBrains.Annotations" VersionOverride="2023.3.0" PrivateAssets="All"/>
8+
</ItemGroup>
9+
<ItemGroup>
10+
<ProjectReference Include="../Testcontainers/Testcontainers.csproj"/>
11+
</ItemGroup>
12+
</Project>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
global using System;
2+
global using System.Net.Http;
3+
global using System.Threading.Tasks;
4+
global using Docker.DotNet.Models;
5+
global using DotNet.Testcontainers.Builders;
6+
global using DotNet.Testcontainers.Configurations;
7+
global using DotNet.Testcontainers.Containers;
8+
global using JetBrains.Annotations;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
root = true

0 commit comments

Comments
 (0)