Skip to content

Commit 70bece4

Browse files
Xor-elHofmeisterAn
andauthored
feat: Add Lowkey Vault module (#1344)
Co-authored-by: Andre Hofmeister <[email protected]>
1 parent 5638c05 commit 70bece4

File tree

14 files changed

+482
-3
lines changed

14 files changed

+482
-3
lines changed

.github/workflows/cicd.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ jobs:
6464
{ name: "Testcontainers.Keycloak", runs-on: "ubuntu-22.04" },
6565
{ name: "Testcontainers.Kusto", runs-on: "ubuntu-22.04" },
6666
{ name: "Testcontainers.LocalStack", runs-on: "ubuntu-22.04" },
67+
{ name: "Testcontainers.LowkeyVault", runs-on: "ubuntu-22.04" },
6768
{ name: "Testcontainers.MariaDb", runs-on: "ubuntu-22.04" },
6869
{ name: "Testcontainers.Milvus", runs-on: "ubuntu-22.04" },
6970
{ name: "Testcontainers.Minio", runs-on: "ubuntu-22.04" },

Directory.Packages.props

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,8 @@
7575
<PackageVersion Include="RavenDB.Client" Version="5.4.100"/>
7676
<PackageVersion Include="Selenium.WebDriver" Version="4.8.1"/>
7777
<PackageVersion Include="StackExchange.Redis" Version="2.6.90"/>
78+
<PackageVersion Include="Azure.Identity" Version="1.13.2" />
79+
<PackageVersion Include="Azure.Security.KeyVault.Certificates" Version="4.7.0" />
80+
<PackageVersion Include="Azure.Security.KeyVault.Secrets" Version="4.7.0" />
7881
</ItemGroup>
7982
</Project>

Testcontainers.sln

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Kusto", "src
6969
EndProject
7070
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.LocalStack", "src\Testcontainers.LocalStack\Testcontainers.LocalStack.csproj", "{3792268A-EF08-4569-8118-991E08FD61C4}"
7171
EndProject
72+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.LowkeyVault", "src\Testcontainers.LowkeyVault\Testcontainers.LowkeyVault.csproj", "{436486CE-E855-43DA-A2C7-9832E98BD86E}"
73+
EndProject
7274
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.MariaDb", "src\Testcontainers.MariaDb\Testcontainers.MariaDb.csproj", "{4B204EB3-C478-422E-9B6F-62DF3871291A}"
7375
EndProject
7476
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Milvus", "src\Testcontainers.Milvus\Testcontainers.Milvus.csproj", "{B024E315-831F-429D-92AA-44B839AC10F4}"
@@ -177,6 +179,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Kusto.Tests"
177179
EndProject
178180
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.LocalStack.Tests", "tests\Testcontainers.LocalStack.Tests\Testcontainers.LocalStack.Tests.csproj", "{728CBE16-1D52-4F84-AF01-7229E6013512}"
179181
EndProject
182+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.LowkeyVault.Tests", "tests\Testcontainers.LowkeyVault.Tests\Testcontainers.LowkeyVault.Tests.csproj", "{CB4F241B-EB79-49D5-A45F-050BEE2191B8}"
183+
EndProject
180184
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.MariaDb.Tests", "tests\Testcontainers.MariaDb.Tests\Testcontainers.MariaDb.Tests.csproj", "{7F0AE083-9DB8-4BD4-91F7-C199DCC7301D}"
181185
EndProject
182186
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Milvus.Tests", "tests\Testcontainers.Milvus.Tests\Testcontainers.Milvus.Tests.csproj", "{5247DF94-32F3-4ED6-AE71-6AB4F4078E6D}"
@@ -244,9 +248,6 @@ Global
244248
Debug|Any CPU = Debug|Any CPU
245249
Release|Any CPU = Release|Any CPU
246250
EndGlobalSection
247-
GlobalSection(SolutionProperties) = preSolution
248-
HideSolutionNode = FALSE
249-
EndGlobalSection
250251
GlobalSection(ProjectConfigurationPlatforms) = postSolution
251252
{5365F780-0E6C-41F0-B1B9-7DC34368F80C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
252253
{5365F780-0E6C-41F0-B1B9-7DC34368F80C}.Debug|Any CPU.Build.0 = Debug|Any CPU
@@ -448,6 +449,10 @@ Global
448449
{64A87DE5-29B0-4A54-9E74-560484D8C7C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
449450
{64A87DE5-29B0-4A54-9E74-560484D8C7C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
450451
{64A87DE5-29B0-4A54-9E74-560484D8C7C0}.Release|Any CPU.Build.0 = Release|Any CPU
452+
{436486CE-E855-43DA-A2C7-9832E98BD86E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
453+
{436486CE-E855-43DA-A2C7-9832E98BD86E}.Debug|Any CPU.Build.0 = Debug|Any CPU
454+
{436486CE-E855-43DA-A2C7-9832E98BD86E}.Release|Any CPU.ActiveCfg = Release|Any CPU
455+
{436486CE-E855-43DA-A2C7-9832E98BD86E}.Release|Any CPU.Build.0 = Release|Any CPU
451456
{380BB29B-F556-404D-B13B-CA250599C565}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
452457
{380BB29B-F556-404D-B13B-CA250599C565}.Debug|Any CPU.Build.0 = Debug|Any CPU
453458
{380BB29B-F556-404D-B13B-CA250599C565}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -696,11 +701,18 @@ Global
696701
{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
697702
{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
698703
{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}.Release|Any CPU.Build.0 = Release|Any CPU
704+
{CB4F241B-EB79-49D5-A45F-050BEE2191B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
705+
{CB4F241B-EB79-49D5-A45F-050BEE2191B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
706+
{CB4F241B-EB79-49D5-A45F-050BEE2191B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
707+
{CB4F241B-EB79-49D5-A45F-050BEE2191B8}.Release|Any CPU.Build.0 = Release|Any CPU
699708
{E901DF14-6F05-4FC2-825A-3055FAD33561}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
700709
{E901DF14-6F05-4FC2-825A-3055FAD33561}.Debug|Any CPU.Build.0 = Debug|Any CPU
701710
{E901DF14-6F05-4FC2-825A-3055FAD33561}.Release|Any CPU.ActiveCfg = Release|Any CPU
702711
{E901DF14-6F05-4FC2-825A-3055FAD33561}.Release|Any CPU.Build.0 = Release|Any CPU
703712
EndGlobalSection
713+
GlobalSection(SolutionProperties) = preSolution
714+
HideSolutionNode = FALSE
715+
EndGlobalSection
704716
GlobalSection(NestedProjects) = preSolution
705717
{5365F780-0E6C-41F0-B1B9-7DC34368F80C} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
706718
{AB9C1563-07C7-4685-BACD-BB1FF64B3611} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
@@ -752,6 +764,7 @@ Global
752764
{7D5C6816-0DD2-4E13-A585-033B5D3C80D5} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
753765
{68F8600D-24E9-4E03-9E25-5F6EB338EAC1} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
754766
{64A87DE5-29B0-4A54-9E74-560484D8C7C0} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
767+
{436486CE-E855-43DA-A2C7-9832E98BD86E} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
755768
{380BB29B-F556-404D-B13B-CA250599C565} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
756769
{84911C93-C2A9-46E9-AE5E-D567306589E5} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
757770
{EC76857B-A3B8-4B7A-A1B0-8D867A4D1733} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
@@ -814,6 +827,7 @@ Global
814827
{27CDB869-A150-4593-958F-6F26E5391E7C} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
815828
{DDB41BC8-5826-4D97-9C5F-001151E3FFD6} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
816829
{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
830+
{CB4F241B-EB79-49D5-A45F-050BEE2191B8} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
817831
{E901DF14-6F05-4FC2-825A-3055FAD33561} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
818832
EndGlobalSection
819833
EndGlobal

docs/modules/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ await moduleNameContainer.StartAsync();
4949
| Keycloak | `quay.io/keycloak/keycloak:21.1` | [NuGet](https://www.nuget.org/packages/Testcontainers.Keycloak) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Keycloak) |
5050
| Kusto emulator | `mcr.microsoft.com/azuredataexplorer/kustainer-linux:latest` | [NuGet](https://www.nuget.org/packages/Testcontainers.Kusto) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Kusto) |
5151
| LocalStack | `localstack/localstack:2.0` | [NuGet](https://www.nuget.org/packages/Testcontainers.LocalStack) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.LocalStack) |
52+
| Lowkey Vault | `nagyesta/lowkey-vault:2.7.1-ubi9-minimal` | [NuGet](https://www.nuget.org/packages/Testcontainers.LowkeyVault) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.LowkeyVault) |
5253
| MariaDB | `mariadb:10.10` | [NuGet](https://www.nuget.org/packages/Testcontainers.MariaDb) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.MariaDb) |
5354
| Milvus | `milvusdb/milvus:v2.3.10` | [NuGet](https://www.nuget.org/packages/Testcontainers.Milvus) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Milvus) |
5455
| MinIO | `minio/minio:RELEASE.2023-01-31T02-24-19Z` | [NuGet](https://www.nuget.org/packages/Testcontainers.Minio) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Minio) |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
root = true
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
namespace Testcontainers.LowkeyVault;
2+
3+
/// <inheritdoc cref="ContainerBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}" />
4+
[PublicAPI]
5+
public sealed class LowkeyVaultBuilder : ContainerBuilder<LowkeyVaultBuilder, LowkeyVaultContainer, LowkeyVaultConfiguration>
6+
{
7+
public const string LowkeyVaultImage = "nagyesta/lowkey-vault:2.7.1-ubi9-minimal";
8+
9+
public const ushort LowkeyVaultPort = 8443;
10+
11+
public const ushort LowkeyVaultTokenPort = 8080;
12+
13+
/// <summary>
14+
/// Initializes a new instance of the <see cref="LowkeyVaultBuilder" /> class.
15+
/// </summary>
16+
public LowkeyVaultBuilder()
17+
: this(new LowkeyVaultConfiguration())
18+
{
19+
DockerResourceConfiguration = Init().DockerResourceConfiguration;
20+
}
21+
22+
/// <summary>
23+
/// Initializes a new instance of the <see cref="LowkeyVaultBuilder" /> class.
24+
/// </summary>
25+
/// <param name="dockerResourceConfiguration">The Docker resource configuration.</param>
26+
private LowkeyVaultBuilder(LowkeyVaultConfiguration dockerResourceConfiguration)
27+
: base(dockerResourceConfiguration)
28+
{
29+
DockerResourceConfiguration = dockerResourceConfiguration;
30+
}
31+
32+
/// <inheritdoc />
33+
protected override LowkeyVaultConfiguration DockerResourceConfiguration { get; }
34+
35+
/// <summary>
36+
/// Collects and appends Lowkey Vault arguments to the container start.
37+
/// </summary>
38+
/// <remarks>
39+
/// The method adds the provided arguments to the <c>LOWKEY_ARGS</c> environment variable.
40+
/// E.g. <c>--LOWKEY_DEBUG_REQUEST_LOG=true</c>.
41+
/// </remarks>
42+
/// <param name="arguments">The arguments to add to the <c>LOWKEY_ARGS</c> environment variable.</param>
43+
/// <returns>A configured instance of <see cref="LowkeyVaultBuilder" />.</returns>
44+
public LowkeyVaultBuilder WithArguments(IEnumerable<string> arguments)
45+
{
46+
return Merge(DockerResourceConfiguration, new LowkeyVaultConfiguration(arguments: arguments));
47+
}
48+
49+
/// <inheritdoc />
50+
public override LowkeyVaultContainer Build()
51+
{
52+
Validate();
53+
54+
var lowkeyVaultBusBuilder = WithEnvironment("LOWKEY_ARGS", string.Join(" ", DockerResourceConfiguration.Arguments));
55+
return new LowkeyVaultContainer(lowkeyVaultBusBuilder.DockerResourceConfiguration);
56+
}
57+
58+
/// <inheritdoc />
59+
protected override LowkeyVaultBuilder Init()
60+
{
61+
return base.Init()
62+
.WithImage(LowkeyVaultImage)
63+
.WithPortBinding(LowkeyVaultPort, true)
64+
.WithPortBinding(LowkeyVaultTokenPort, true)
65+
.WithArguments(new[] { "--LOWKEY_VAULT_RELAXED_PORTS=true" })
66+
.WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged("(?s).*Started LowkeyVaultApp.*$"));
67+
}
68+
69+
/// <inheritdoc />
70+
protected override LowkeyVaultBuilder Clone(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
71+
{
72+
return Merge(DockerResourceConfiguration, new LowkeyVaultConfiguration(resourceConfiguration));
73+
}
74+
75+
/// <inheritdoc />
76+
protected override LowkeyVaultBuilder Clone(IContainerConfiguration resourceConfiguration)
77+
{
78+
return Merge(DockerResourceConfiguration, new LowkeyVaultConfiguration(resourceConfiguration));
79+
}
80+
81+
/// <inheritdoc />
82+
protected override LowkeyVaultBuilder Merge(LowkeyVaultConfiguration oldValue, LowkeyVaultConfiguration newValue)
83+
{
84+
return new LowkeyVaultBuilder(new LowkeyVaultConfiguration(oldValue, newValue));
85+
}
86+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
namespace Testcontainers.LowkeyVault;
2+
3+
/// <inheritdoc cref="ContainerConfiguration" />
4+
[PublicAPI]
5+
public sealed class LowkeyVaultConfiguration : ContainerConfiguration
6+
{
7+
/// <summary>
8+
/// Initializes a new instance of the <see cref="LowkeyVaultConfiguration" /> class.
9+
/// </summary>
10+
/// <param name="arguments">The arguments to add to the <c>LOWKEY_ARGS</c> environment variable.</param>
11+
public LowkeyVaultConfiguration(IEnumerable<string> arguments = null)
12+
{
13+
Arguments = arguments;
14+
}
15+
16+
/// <summary>
17+
/// Initializes a new instance of the <see cref="LowkeyVaultConfiguration" /> class.
18+
/// </summary>
19+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
20+
public LowkeyVaultConfiguration(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
21+
: base(resourceConfiguration)
22+
{
23+
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
24+
}
25+
26+
/// <summary>
27+
/// Initializes a new instance of the <see cref="LowkeyVaultConfiguration" /> class.
28+
/// </summary>
29+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
30+
public LowkeyVaultConfiguration(IContainerConfiguration resourceConfiguration)
31+
: base(resourceConfiguration)
32+
{
33+
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
34+
}
35+
36+
/// <summary>
37+
/// Initializes a new instance of the <see cref="LowkeyVaultConfiguration" /> class.
38+
/// </summary>
39+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
40+
public LowkeyVaultConfiguration(LowkeyVaultConfiguration resourceConfiguration)
41+
: this(new LowkeyVaultConfiguration(), resourceConfiguration)
42+
{
43+
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
44+
}
45+
46+
/// <summary>
47+
/// Initializes a new instance of the <see cref="LowkeyVaultConfiguration" /> class.
48+
/// </summary>
49+
/// <param name="oldValue">The old Docker resource configuration.</param>
50+
/// <param name="newValue">The new Docker resource configuration.</param>
51+
public LowkeyVaultConfiguration(LowkeyVaultConfiguration oldValue, LowkeyVaultConfiguration newValue)
52+
: base(oldValue, newValue)
53+
{
54+
Arguments = BuildConfiguration.Combine(oldValue.Arguments, newValue.Arguments);
55+
}
56+
57+
/// <summary>
58+
/// Gets the arguments that are added to the <c>LOWKEY_ARGS</c> environment variable.
59+
/// </summary>
60+
public IEnumerable<string> Arguments { get; }
61+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
namespace Testcontainers.LowkeyVault;
2+
3+
/// <inheritdoc cref="DockerContainer" />
4+
[PublicAPI]
5+
public sealed class LowkeyVaultContainer : DockerContainer
6+
{
7+
/// <summary>
8+
/// Initializes a new instance of the <see cref="LowkeyVaultContainer" /> class.
9+
/// </summary>
10+
/// <param name="configuration">The container configuration.</param>
11+
public LowkeyVaultContainer(LowkeyVaultConfiguration configuration)
12+
: base(configuration)
13+
{
14+
}
15+
16+
/// <summary>
17+
/// Gets the base HTTPS address for the Lowkey Vault service.
18+
/// </summary>
19+
/// <returns>The base address URL.</returns>
20+
public string GetBaseAddress()
21+
{
22+
return new UriBuilder(Uri.UriSchemeHttps, Hostname, GetMappedPublicPort(LowkeyVaultBuilder.LowkeyVaultPort)).ToString();
23+
}
24+
25+
/// <summary>
26+
/// Gets the URL used to request the authentication token.
27+
/// </summary>
28+
/// <returns>The authentication token URL.</returns>
29+
public string GetAuthTokenUrl()
30+
{
31+
const string identityAuthTokenUriPath = "/metadata/identity/oauth2/token";
32+
return new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(LowkeyVaultBuilder.LowkeyVaultTokenPort), identityAuthTokenUriPath).ToString();
33+
}
34+
35+
/// <summary>
36+
/// Gets the default certificate from the Lowkey Vault service.
37+
/// </summary>
38+
/// <returns>A collection containing the default <see cref="X509Certificate2" />.</returns>
39+
public async Task<X509Certificate2Collection> GetCertificateAsync()
40+
{
41+
const string defaultCertFilePathUriPath = "/metadata/default-cert/lowkey-vault.p12";
42+
43+
var requestUri = new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(LowkeyVaultBuilder.LowkeyVaultTokenPort), defaultCertFilePathUriPath).Uri;
44+
45+
using var httpClient = new HttpClient();
46+
47+
using var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri);
48+
49+
using var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage)
50+
.ConfigureAwait(false);
51+
52+
httpResponseMessage.EnsureSuccessStatusCode();
53+
54+
var certificateBytes = await httpResponseMessage.Content.ReadAsByteArrayAsync()
55+
.ConfigureAwait(false);
56+
57+
var certificatePassword = await GetCertificatePasswordAsync()
58+
.ConfigureAwait(false);
59+
60+
#if NET9_0_OR_GREATER
61+
return X509CertificateLoader.LoadPkcs12Collection(certificateBytes, certificatePassword);
62+
#else
63+
var certificate = new X509Certificate2(certificateBytes, certificatePassword);
64+
return new X509Certificate2Collection(certificate);
65+
#endif
66+
}
67+
68+
/// <summary>
69+
/// Gets the password for the default certificate from the Lowkey Vault service.
70+
/// </summary>
71+
/// <returns>The default certificate password.</returns>
72+
public async Task<string> GetCertificatePasswordAsync()
73+
{
74+
const string defaultCertPasswordUriPath = "/metadata/default-cert/password";
75+
76+
var requestUri = new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(LowkeyVaultBuilder.LowkeyVaultTokenPort), defaultCertPasswordUriPath).Uri;
77+
78+
using var httpClient = new HttpClient();
79+
80+
using var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri);
81+
82+
using var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage)
83+
.ConfigureAwait(false);
84+
85+
httpResponseMessage.EnsureSuccessStatusCode();
86+
87+
return await httpResponseMessage.Content.ReadAsStringAsync()
88+
.ConfigureAwait(false);
89+
}
90+
}
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>net8.0;net9.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: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
global using System;
2+
global using System.Collections.Generic;
3+
global using System.Net.Http;
4+
global using System.Security.Cryptography.X509Certificates;
5+
global using System.Threading.Tasks;
6+
global using Docker.DotNet.Models;
7+
global using DotNet.Testcontainers.Builders;
8+
global using DotNet.Testcontainers.Configurations;
9+
global using DotNet.Testcontainers.Containers;
10+
global using JetBrains.Annotations;

0 commit comments

Comments
 (0)