Skip to content

Commit abea539

Browse files
authored
Merge branch 'develop' into ThrowIfExited
2 parents 8c41cee + b0b0cbc commit abea539

File tree

92 files changed

+2650
-269
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+2650
-269
lines changed

.github/FUNDING.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
github: HofmeisterAn
1+
github: [testcontainers, HofmeisterAn]
22
ko_fi: hofmeister

.github/workflows/cicd.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ jobs:
5252
{ name: "Testcontainers.Db2", runs-on: "ubuntu-22.04" },
5353
{ name: "Testcontainers.DynamoDb", runs-on: "ubuntu-22.04" },
5454
{ name: "Testcontainers.Elasticsearch", runs-on: "ubuntu-22.04" },
55-
{ name: "Testcontainers.EventStoreDb", runs-on: "ubuntu-22.04" },
5655
{ name: "Testcontainers.EventHubs", runs-on: "ubuntu-22.04" },
56+
{ name: "Testcontainers.EventStoreDb", runs-on: "ubuntu-22.04" },
5757
{ name: "Testcontainers.FakeGcsServer", runs-on: "ubuntu-22.04" },
5858
{ name: "Testcontainers.FirebirdSql", runs-on: "ubuntu-22.04" },
5959
{ name: "Testcontainers.Firestore", runs-on: "ubuntu-22.04" },
@@ -74,6 +74,7 @@ jobs:
7474
{ name: "Testcontainers.Nats", runs-on: "ubuntu-22.04" },
7575
{ name: "Testcontainers.Neo4j", runs-on: "ubuntu-22.04" },
7676
{ name: "Testcontainers.Ollama", runs-on: "ubuntu-22.04" },
77+
{ name: "Testcontainers.OpenSearch", runs-on: "ubuntu-22.04" },
7778
{ name: "Testcontainers.Oracle", runs-on: "ubuntu-22.04" },
7879
{ name: "Testcontainers.Oracle11", runs-on: "ubuntu-22.04" },
7980
{ name: "Testcontainers.Oracle18", runs-on: "ubuntu-22.04" },
@@ -119,7 +120,7 @@ jobs:
119120
shell: bash
120121

121122
- name: Run Build
122-
run: ./build.sh --target=Build
123+
run: ./build.sh --target=Build --test-project=${{ matrix.test-projects.name }}
123124
shell: bash
124125

125126
- name: Run Tests

Directory.Build.props

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<Project>
33
<PropertyGroup>
44
<PackageId>$(AssemblyName)</PackageId>
5-
<Version>4.5.0</Version>
5+
<Version>4.7.0</Version>
66
<AssemblyVersion>$(Version)</AssemblyVersion>
77
<FileVersion>$(Version)</FileVersion>
88
<Product>Testcontainers</Product>
@@ -26,12 +26,15 @@
2626
<DebugType>embedded</DebugType>
2727
</PropertyGroup>
2828
<PropertyGroup>
29-
<NoWarn>CS0618,CS1591,SA0001,SA1600,SA1633,SA1649,CA1859,CA1861</NoWarn>
29+
<NoWarn>CA1859,CA1861,CS0618,CS1591,xUnit1044,xUnit1045</NoWarn>
3030
</PropertyGroup>
3131
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
3232
<GenerateDocumentationFile>true</GenerateDocumentationFile>
3333
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
3434
</PropertyGroup>
35+
<ItemGroup>
36+
<GlobalPackageReference Include="SauceControl.InheritDoc" VersionOverride="2.0.2" />
37+
</ItemGroup>
3538
<ItemGroup>
3639
<None Include="$(MSBuildThisFileDirectory)docs/banner.png" Visible="false" Pack="true" PackagePath="docs/" />
3740
<None Include="$(MSBuildThisFileDirectory)docs/logo.png" Visible="false" Pack="true" PackagePath="docs/" />

Directory.Packages.props

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
55
</PropertyGroup>
66
<ItemGroup>
7-
<PackageVersion Include="BouncyCastle.Cryptography" Version="2.5.1"/>
8-
<PackageVersion Include="Docker.DotNet.Enhanced.X509" Version="3.128.1"/>
9-
<PackageVersion Include="Docker.DotNet.Enhanced" Version="3.128.1"/>
7+
<PackageVersion Include="BouncyCastle.Cryptography" Version="2.6.1"/>
8+
<PackageVersion Include="Docker.DotNet.Enhanced.X509" Version="3.128.5"/>
9+
<PackageVersion Include="Docker.DotNet.Enhanced" Version="3.128.5"/>
1010
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0"/>
1111
<PackageVersion Include="Microsoft.Bcl.HashCode" Version="1.1.1"/>
1212
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.3"/>
@@ -51,7 +51,7 @@
5151
<PackageVersion Include="Confluent.SchemaRegistry.Serdes.Json" Version="2.8.0"/>
5252
<PackageVersion Include="Confluent.SchemaRegistry" Version="2.8.0"/>
5353
<PackageVersion Include="Consul" Version="1.6.10.9"/>
54-
<PackageVersion Include="CouchbaseNetClient" Version="3.6.4"/>
54+
<PackageVersion Include="CouchbaseNetClient" Version="3.7.2"/>
5555
<PackageVersion Include="DotPulsar" Version="3.6.0"/>
5656
<PackageVersion Include="Elastic.Clients.Elasticsearch" Version="8.16.3"/>
5757
<PackageVersion Include="EventStore.Client.Grpc.Streams" Version="22.0.0"/>
@@ -79,6 +79,7 @@
7979
<PackageVersion Include="Net.IBM.Data.Db2" Version="9.0.0.100"/>
8080
<PackageVersion Include="Npgsql" Version="6.0.11"/>
8181
<PackageVersion Include="OllamaSharp" Version="5.1.13"/>
82+
<PackageVersion Include="OpenSearch.Client" Version="1.8.0"/>
8283
<PackageVersion Include="Oracle.ManagedDataAccess.Core" Version="23.7.0"/>
8384
<PackageVersion Include="Qdrant.Client" Version="1.13.0"/>
8485
<PackageVersion Include="RabbitMQ.Client" Version="6.4.0"/>

Testcontainers.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Neo4j", "src
8989
EndProject
9090
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Ollama", "src\Testcontainers.Ollama\Testcontainers.Ollama.csproj", "{0DB0075D-42EC-4438-93F7-630CF5BCCAF0}"
9191
EndProject
92+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.OpenSearch", "src\Testcontainers.OpenSearch\Testcontainers.OpenSearch.csproj", "{49051DBC-6B80-4412-8505-BC2764A877BD}"
93+
EndProject
9294
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Oracle", "src\Testcontainers.Oracle\Testcontainers.Oracle.csproj", "{596EAFC1-0496-495C-B382-D57415FA456A}"
9395
EndProject
9496
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Papercut", "src\Testcontainers.Papercut\Testcontainers.Papercut.csproj", "{B2608563-8EE4-49AA-A9A0-B1614486AEEF}"
@@ -203,6 +205,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Neo4j.Tests"
203205
EndProject
204206
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Ollama.Tests", "tests\Testcontainers.Ollama.Tests\Testcontainers.Ollama.Tests.csproj", "{D3AD7D72-510C-43A4-A401-DB3C2594508E}"
205207
EndProject
208+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.OpenSearch.Tests", "tests\Testcontainers.OpenSearch.Tests\Testcontainers.OpenSearch.Tests.csproj", "{04A7AF65-2E02-4E20-8056-2AAC0705B0BC}"
209+
EndProject
206210
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Oracle.Tests", "tests\Testcontainers.Oracle.Tests\Testcontainers.Oracle.Tests.csproj", "{4AC1088B-9965-4497-AC8E-570F1AD5631F}"
207211
EndProject
208212
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Oracle11.Tests", "tests\Testcontainers.Oracle11.Tests\Testcontainers.Oracle11.Tests.csproj", "{0A0AC20D-226B-46F9-B267-0D00964A7601}"
@@ -411,6 +415,10 @@ Global
411415
{0DB0075D-42EC-4438-93F7-630CF5BCCAF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
412416
{0DB0075D-42EC-4438-93F7-630CF5BCCAF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
413417
{0DB0075D-42EC-4438-93F7-630CF5BCCAF0}.Release|Any CPU.Build.0 = Release|Any CPU
418+
{49051DBC-6B80-4412-8505-BC2764A877BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
419+
{49051DBC-6B80-4412-8505-BC2764A877BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
420+
{49051DBC-6B80-4412-8505-BC2764A877BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
421+
{49051DBC-6B80-4412-8505-BC2764A877BD}.Release|Any CPU.Build.0 = Release|Any CPU
414422
{596EAFC1-0496-495C-B382-D57415FA456A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
415423
{596EAFC1-0496-495C-B382-D57415FA456A}.Debug|Any CPU.Build.0 = Debug|Any CPU
416424
{596EAFC1-0496-495C-B382-D57415FA456A}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -639,6 +647,10 @@ Global
639647
{D3AD7D72-510C-43A4-A401-DB3C2594508E}.Debug|Any CPU.Build.0 = Debug|Any CPU
640648
{D3AD7D72-510C-43A4-A401-DB3C2594508E}.Release|Any CPU.ActiveCfg = Release|Any CPU
641649
{D3AD7D72-510C-43A4-A401-DB3C2594508E}.Release|Any CPU.Build.0 = Release|Any CPU
650+
{04A7AF65-2E02-4E20-8056-2AAC0705B0BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
651+
{04A7AF65-2E02-4E20-8056-2AAC0705B0BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
652+
{04A7AF65-2E02-4E20-8056-2AAC0705B0BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
653+
{04A7AF65-2E02-4E20-8056-2AAC0705B0BC}.Release|Any CPU.Build.0 = Release|Any CPU
642654
{4AC1088B-9965-4497-AC8E-570F1AD5631F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
643655
{4AC1088B-9965-4497-AC8E-570F1AD5631F}.Debug|Any CPU.Build.0 = Debug|Any CPU
644656
{4AC1088B-9965-4497-AC8E-570F1AD5631F}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -782,6 +794,7 @@ Global
782794
{BF37BEA1-0816-4326-B1E0-E82290F8FCE0} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
783795
{ADC2372B-6FE0-421D-8277-BB628E8EFC22} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
784796
{0DB0075D-42EC-4438-93F7-630CF5BCCAF0} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
797+
{49051DBC-6B80-4412-8505-BC2764A877BD} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
785798
{596EAFC1-0496-495C-B382-D57415FA456A} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
786799
{B2608563-8EE4-49AA-A9A0-B1614486AEEF} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
787800
{8AB91636-9055-4900-A72A-7CFFACDFDBF0} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
@@ -839,6 +852,7 @@ Global
839852
{87A3F137-6DC3-4CE5-91E6-01797D076086} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
840853
{D3F63405-C0FA-4F83-8B79-E30BFF5FF5BF} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
841854
{D3AD7D72-510C-43A4-A401-DB3C2594508E} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
855+
{04A7AF65-2E02-4E20-8056-2AAC0705B0BC} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
842856
{4AC1088B-9965-4497-AC8E-570F1AD5631F} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
843857
{0A0AC20D-226B-46F9-B267-0D00964A7601} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
844858
{E4C887A9-A44A-4641-BB9B-0664CC4C362F} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}

build/Tasks.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,14 @@ public sealed class BuildTask : FrostingTask<BuildContext>
8787
public override void Run(BuildContext context)
8888
{
8989
var param = context.Parameters;
90-
context.DotNetBuild(param.Solution, new DotNetBuildSettings
90+
91+
// If a test project is specified, just build the project and its dependent projects to
92+
// save build time.
93+
var solutionOrProjectFilePath = string.IsNullOrEmpty(param.TestProject)
94+
? param.Solution
95+
: param.Projects.OnlyTests.Single(testProject => testProject.Path.FullPath.EndsWith(param.TestProject + ".Tests.csproj")).Path.FullPath;
96+
97+
context.DotNetBuild(solutionOrProjectFilePath, new DotNetBuildSettings
9198
{
9299
Configuration = param.Configuration,
93100
Verbosity = param.Verbosity,
@@ -193,7 +200,7 @@ public override void Run(BuildContext context)
193200
public sealed class SignNuGetPackagesTask : FrostingTask<BuildContext>
194201
{
195202
// We do not have access to a valid code signing certificate anymore.
196-
public override bool ShouldRun(BuildContext context) => context.Parameters.ShouldPublish && false;
203+
public override bool ShouldRun(BuildContext context) => /* context.Parameters.ShouldPublish */ false;
197204

198205
public override void Run(BuildContext context)
199206
{

docs/api/create_docker_container.md

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ _ = new ContainerBuilder()
4545

4646
```csharp title="Copying a file"
4747
_ = new ContainerBuilder()
48-
.WithResourceMapping(new FileInfo("appsettings.json"), "/app/");
48+
# Copy 'appsettings.json' into the '/app' directory.
49+
.WithResourceMapping(new FileInfo("appsettings.json"), "/app/")
50+
# Copy 'appsettings.Container.json' to '/app/appsettings.Developer.json'.
51+
.WithResourceMapping(new FileInfo("appsettings.Container.json"), new FileInfo("/app/appsettings.Developer.json"));
4952
```
5053

5154
Another overloaded member of the container builder API allows you to copy the contents of a byte array to a specific file path within the container. This can be useful when you already have the file content stored in memory or when you need to dynamically generate the file content before copying it.
@@ -97,6 +100,37 @@ _ = new ContainerBuilder()
97100

98101
The static class `Consume` offers pre-configured implementations of the `IOutputConsumer` interface for common use cases. If you need additional functionalities beyond those provided by the default implementations, you can create your own implementations of `IOutputConsumer`.
99102

103+
## Composing command arguments
104+
105+
Testcontainers for .NET provides the `WithCommand(ComposableEnumerable<string>)` API to give you flexible control over container command arguments. While currently used for container commands, the `ComposableEnumerable<T>` abstraction is designed to support other builder APIs in the future, allowing similar composition and override functionality.
106+
107+
Because our builders are immutable, this feature allows you to extend or override pre-configured configurations, such as those in Testcontainers [modules](../modules/index.md), without modifying the original builder.
108+
109+
`ComposableEnumerable<T>` lets you decide how new API arguments should be combined with existing ones. You can choose to append, overwrite, or apply other strategies based on your needs.
110+
111+
If a module applies default commands and you need to override or remove them entirely, you can do this e.g. by explicitly resetting the command list:
112+
113+
```csharp title="Resetting command arguments"
114+
// Default PostgreSQL builder configuration:
115+
//
116+
// base.Init()
117+
// ...
118+
// .WithCommand("-c", "fsync=off")
119+
// .WithCommand("-c", "full_page_writes=off")
120+
// .WithCommand("-c", "synchronous_commit=off")
121+
// ...
122+
123+
var postgreSqlContainer = new PostgreSqlBuilder()
124+
.WithCommand(new OverwriteEnumerable<string>(Array.Empty<string>()))
125+
.Build();
126+
```
127+
128+
Using `OverwriteEnumerable<string>(Array.Empty<string>())` removes all default command configurations. This is useful when you want full control over the PostgreSQL startup or when the default configurations do not match your requirements.
129+
130+
!!!tip
131+
132+
You can create your own `ComposableEnumerable<T>` implementation to control exactly how configuration values are composed or modified.
133+
100134
## Examples
101135

102136
An NGINX container that binds the HTTP port to a random host port and hosts static content. The example connects to the web server and checks the HTTP status code.

docs/api/wait_strategies.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Wait strategies are useful to detect if a container is ready for testing (i.e.,
44

55
```csharp
66
_ = Wait.ForUnixContainer()
7-
.UntilPortIsAvailable(80)
7+
.UntilInternalTcpPortIsAvailable(80)
88
.UntilFileExists("/tmp/foo")
99
.UntilFileExists("/tmp/bar")
1010
.UntilOperationIsSucceeded(() => true, 1)
@@ -51,6 +51,36 @@ _ = Wait.ForUnixContainer()
5151
.ForStatusCodeMatching(statusCode => statusCode >= HttpStatusCode.OK && statusCode < HttpStatusCode.MultipleChoices));
5252
```
5353

54+
## Wait until a TCP port is available
55+
56+
Testcontainers provides two distinct strategies for waiting until a TCP port becomes available, each serving different purposes depending on your testing needs.
57+
58+
### Wait until an internal TCP port is available
59+
60+
`UntilInternalTcpPortIsAvailable(int)` checks if a service inside the container is listening on the specified port by testing connectivity from within the container itself. This strategy verifies that your application or service has actually started and is ready to accept connections.
61+
62+
```csharp
63+
_ = Wait.ForUnixContainer()
64+
.UntilInternalTcpPortIsAvailable(8080);
65+
```
66+
67+
!!!note
68+
69+
Just because a service is listening on the internal TCP port does not necessarily mean it is fully ready to handle requests. Often, wait strategies such as checking for specific log messages or verifying a health endpoint provide more reliable confirmation that the service is operational.
70+
71+
### Wait until an external TCP port is available
72+
73+
`UntilExternalTcpPortIsAvailable(int)` checks if the port is accessible from the test host to the container. This verifies that the port mapping has been established and the port is reachable externally.
74+
75+
```csharp
76+
_ = Wait.ForUnixContainer()
77+
.UntilExternalTcpPortIsAvailable(8080);
78+
```
79+
80+
!!!note
81+
82+
External TCP port availability doesn't guarantee that the actual service inside the container is ready to handle requests. It only confirms that the port mapping is established and a connection can be made to the host-side proxy.
83+
5484
## Wait until the container is healthy
5585

5686
If the Docker image supports Dockers's [HEALTHCHECK][docker-docs-healthcheck] feature, like the following configuration:

0 commit comments

Comments
 (0)