Skip to content

Commit 7715969

Browse files
feat: Add Db2 module (#1237)
Co-authored-by: Andre Hofmeister <[email protected]>
1 parent 13dcbe4 commit 7715969

17 files changed

+465
-0
lines changed

.github/workflows/cicd.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ jobs:
4848
{ name: "Testcontainers.CosmosDb", runs-on: "ubuntu-22.04" },
4949
{ name: "Testcontainers.Couchbase", runs-on: "ubuntu-22.04" },
5050
{ name: "Testcontainers.CouchDb", runs-on: "ubuntu-22.04" },
51+
{ name: "Testcontainers.Db2", runs-on: "ubuntu-22.04" },
5152
{ name: "Testcontainers.DynamoDb", runs-on: "ubuntu-22.04" },
5253
{ name: "Testcontainers.Elasticsearch", runs-on: "ubuntu-22.04" },
5354
{ name: "Testcontainers.EventStoreDb", runs-on: "ubuntu-22.04" },

Directory.Packages.props

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
<PackageVersion Include="Confluent.SchemaRegistry" Version="2.8.0"/>
4242
<PackageVersion Include="Consul" Version="1.6.10.9"/>
4343
<PackageVersion Include="CouchbaseNetClient" Version="3.6.4"/>
44+
<PackageVersion Include="Net.IBM.Data.Db2-lnx" Version="9.0.0.100"/>
45+
<PackageVersion Include="Net.IBM.Data.Db2" Version="9.0.0.100"/>
4446
<PackageVersion Include="DotPulsar" Version="3.3.2"/>
4547
<PackageVersion Include="Elastic.Clients.Elasticsearch" Version="8.16.3"/>
4648
<PackageVersion Include="EventStore.Client.Grpc.Streams" Version="22.0.0"/>

Testcontainers.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Couchbase",
3535
EndProject
3636
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.CouchDb", "src\Testcontainers.CouchDb\Testcontainers.CouchDb.csproj", "{DCECB1F6-D9AA-431F-AE42-25D56B9E7DFC}"
3737
EndProject
38+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Db2", "src\Testcontainers.Db2\Testcontainers.Db2.csproj", "{ED3C611F-DFE2-4AB7-A323-B500E95B4FF9}"
39+
EndProject
3840
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.DynamoDb", "src\Testcontainers.DynamoDb\Testcontainers.DynamoDb.csproj", "{2EAFA567-9F68-4C52-9DBC-8F3EC11BB2CE}"
3941
EndProject
4042
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Elasticsearch", "src\Testcontainers.Elasticsearch\Testcontainers.Elasticsearch.csproj", "{641DDEA5-B6E0-41E6-BA11-7A28C0913127}"
@@ -135,6 +137,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.CouchDb.Test
135137
EndProject
136138
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Databases.Tests", "tests\Testcontainers.Databases.Tests\Testcontainers.Databases.Tests.csproj", "{DA54916E-1128-4200-B6AE-9F5BF02D832D}"
137139
EndProject
140+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Db2.Tests", "tests\Testcontainers.Db2.Tests\Testcontainers.Db2.Tests.csproj", "{AF9853AB-86E7-49DE-8DF8-454838E90D6F}"
141+
EndProject
138142
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.DynamoDb.Tests", "tests\Testcontainers.DynamoDb.Tests\Testcontainers.DynamoDb.Tests.csproj", "{101515E6-74C1-40F9-85C8-871F742A378D}"
139143
EndProject
140144
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Elasticsearch.Tests", "tests\Testcontainers.Elasticsearch.Tests\Testcontainers.Elasticsearch.Tests.csproj", "{DD5B3678-468F-4D73-AECE-705E3D66CD43}"
@@ -266,6 +270,10 @@ Global
266270
{DCECB1F6-D9AA-431F-AE42-25D56B9E7DFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
267271
{DCECB1F6-D9AA-431F-AE42-25D56B9E7DFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
268272
{DCECB1F6-D9AA-431F-AE42-25D56B9E7DFC}.Release|Any CPU.Build.0 = Release|Any CPU
273+
{ED3C611F-DFE2-4AB7-A323-B500E95B4FF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
274+
{ED3C611F-DFE2-4AB7-A323-B500E95B4FF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
275+
{ED3C611F-DFE2-4AB7-A323-B500E95B4FF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
276+
{ED3C611F-DFE2-4AB7-A323-B500E95B4FF9}.Release|Any CPU.Build.0 = Release|Any CPU
269277
{2EAFA567-9F68-4C52-9DBC-8F3EC11BB2CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
270278
{2EAFA567-9F68-4C52-9DBC-8F3EC11BB2CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
271279
{2EAFA567-9F68-4C52-9DBC-8F3EC11BB2CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -466,6 +474,10 @@ Global
466474
{DA54916E-1128-4200-B6AE-9F5BF02D832D}.Debug|Any CPU.Build.0 = Debug|Any CPU
467475
{DA54916E-1128-4200-B6AE-9F5BF02D832D}.Release|Any CPU.ActiveCfg = Release|Any CPU
468476
{DA54916E-1128-4200-B6AE-9F5BF02D832D}.Release|Any CPU.Build.0 = Release|Any CPU
477+
{AF9853AB-86E7-49DE-8DF8-454838E90D6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
478+
{AF9853AB-86E7-49DE-8DF8-454838E90D6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
479+
{AF9853AB-86E7-49DE-8DF8-454838E90D6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
480+
{AF9853AB-86E7-49DE-8DF8-454838E90D6F}.Release|Any CPU.Build.0 = Release|Any CPU
469481
{101515E6-74C1-40F9-85C8-871F742A378D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
470482
{101515E6-74C1-40F9-85C8-871F742A378D}.Debug|Any CPU.Build.0 = Debug|Any CPU
471483
{101515E6-74C1-40F9-85C8-871F742A378D}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -635,6 +647,7 @@ Global
635647
{A724806F-8C94-4438-8011-04A9A1575318} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
636648
{58E94721-2681-4D82-8D94-0B2F9DB0D575} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
637649
{DCECB1F6-D9AA-431F-AE42-25D56B9E7DFC} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
650+
{ED3C611F-DFE2-4AB7-A323-B500E95B4FF9} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
638651
{2EAFA567-9F68-4C52-9DBC-8F3EC11BB2CE} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
639652
{641DDEA5-B6E0-41E6-BA11-7A28C0913127} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
640653
{84D707E0-C9FA-4327-85DC-0AFEBEA73572} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
@@ -685,6 +698,7 @@ Global
685698
{809322BA-D690-4F2B-B884-23F895663963} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
686699
{E4520FB1-4466-4DCA-AD08-4075102C68D3} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
687700
{DA54916E-1128-4200-B6AE-9F5BF02D832D} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
701+
{AF9853AB-86E7-49DE-8DF8-454838E90D6F} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
688702
{101515E6-74C1-40F9-85C8-871F742A378D} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
689703
{DD5B3678-468F-4D73-AECE-705E3D66CD43} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
690704
{64F8E9B9-78FD-4E13-BDDF-0340E2D4E1D0} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}

docs/modules/db2.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Db2
2+
3+
[Db2](https://www.ibm.com/db2) is a relational database engine developed by IBM.
4+
5+
Add the following dependency to your project file:
6+
7+
```shell title="NuGet"
8+
dotnet add package Testcontainers.Db2
9+
```
10+
11+
!!! warning
12+
13+
The Linux client dependency, [Net.IBM.Data.Db2-lnx](https://www.nuget.org/packages/Net.IBM.Data.Db2-lnx), requires additional configurations. We use the [Testcontainers.Db2.Tests.targets](https://github.com/testcontainers/testcontainers-dotnet/blob/develop/tests/Testcontainers.Db2.Tests/Testcontainers.Db2.Tests.targets) file to configure the environment variables: `LD_LIBRARY_PATH`, `PATH`, `DB2_CLI_DRIVER_INSTALL_PATH`, at runtime.
14+
15+
You can start an Db2 container instance from any .NET application. This example uses xUnit.net's `IAsyncLifetime` interface to manage the lifecycle of the container. The container is started in the `InitializeAsync` method before the test method runs, ensuring that the environment is ready for testing. After the test completes, the container is removed in the `DisposeAsync` method.
16+
17+
=== "Usage Example"
18+
```csharp
19+
--8<-- "tests/Testcontainers.Db2.Tests/Db2ContainerTest.cs:UseDb2Container"
20+
```
21+
22+
The test example uses the following NuGet dependencies:
23+
24+
=== "Package References"
25+
```xml
26+
--8<-- "tests/Testcontainers.Db2.Tests/Testcontainers.Db2.Tests.csproj:PackageReferences"
27+
```
28+
29+
To execute the tests, use the command `dotnet test` from a terminal.
30+
31+
--8<-- "docs/modules/_call_out_test_projects.txt"

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ nav:
4747
- examples/aspnet.md
4848
- Modules:
4949
- modules/index.md
50+
- modules/db2.md
5051
- modules/elasticsearch.md
5152
- modules/mongodb.md
5253
- modules/mssql.md

src/Testcontainers.Db2/.editorconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
root = true

src/Testcontainers.Db2/Db2Builder.cs

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
namespace Testcontainers.Db2;
2+
3+
/// <inheritdoc cref="ContainerBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}" />
4+
[PublicAPI]
5+
public sealed class Db2Builder : ContainerBuilder<Db2Builder, Db2Container, Db2Configuration>
6+
{
7+
public const string Db2Image = "icr.io/db2_community/db2:12.1.0.0";
8+
9+
public const ushort Db2Port = 50000;
10+
11+
public const string DefaultDatabase = "test";
12+
13+
public const string DefaultUsername = "db2inst1";
14+
15+
public const string DefaultPassword = "db2inst1";
16+
17+
private const string AcceptLicenseAgreementEnvVar = "LICENSE";
18+
19+
private const string AcceptLicenseAgreement = "accept";
20+
21+
private const string DeclineLicenseAgreement = "decline";
22+
23+
/// <summary>
24+
/// Initializes a new instance of the <see cref="Db2Builder" /> class.
25+
/// </summary>
26+
public Db2Builder()
27+
: this(new Db2Configuration())
28+
{
29+
DockerResourceConfiguration = Init().DockerResourceConfiguration;
30+
}
31+
32+
/// <summary>
33+
/// Initializes a new instance of the <see cref="Db2Builder" /> class.
34+
/// </summary>
35+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
36+
private Db2Builder(Db2Configuration resourceConfiguration)
37+
: base(resourceConfiguration)
38+
{
39+
DockerResourceConfiguration = resourceConfiguration;
40+
}
41+
42+
/// <inheritdoc />
43+
protected override Db2Configuration DockerResourceConfiguration { get; }
44+
45+
/// <summary>
46+
/// Accepts the license agreement.
47+
/// </summary>
48+
/// <remarks>
49+
/// When <paramref name="acceptLicenseAgreement" /> is set to <c>true</c>, the Db2 <see href="www.ibm.com/terms/?id=L-SNMD-UVTL8R">license</see> is accepted.
50+
/// </remarks>
51+
/// <param name="acceptLicenseAgreement">A boolean value indicating whether the Db2 license agreement is accepted.</param>
52+
/// <returns>A configured instance of <see cref="Db2Builder" />.</returns>
53+
public Db2Builder WithAcceptLicenseAgreement(bool acceptLicenseAgreement)
54+
{
55+
var licenseAgreement = acceptLicenseAgreement ? AcceptLicenseAgreement : DeclineLicenseAgreement;
56+
return WithEnvironment(AcceptLicenseAgreementEnvVar, licenseAgreement);
57+
}
58+
59+
/// <summary>
60+
/// Sets the Db2 database name.
61+
/// </summary>
62+
/// <param name="database">The Db2 database.</param>
63+
/// <returns>A configured instance of <see cref="Db2Builder" />.</returns>
64+
public Db2Builder WithDatabase(string database)
65+
{
66+
return Merge(DockerResourceConfiguration, new Db2Configuration(database: database))
67+
.WithEnvironment("DBNAME", database);
68+
}
69+
70+
/// <summary>
71+
/// Sets the Db2 username.
72+
/// </summary>
73+
/// <param name="username">The Db2 username.</param>
74+
/// <returns>A configured instance of <see cref="Db2Builder" />.</returns>
75+
public Db2Builder WithUsername(string username)
76+
{
77+
return Merge(DockerResourceConfiguration, new Db2Configuration(username: username))
78+
.WithEnvironment("DB2INSTANCE", username)
79+
.WithTmpfsMount(string.Join("/", string.Empty, "home", username, "data"));
80+
}
81+
82+
/// <summary>
83+
/// Sets the Db2 password.
84+
/// </summary>
85+
/// <param name="password">The Db2 password.</param>
86+
/// <returns>A configured instance of <see cref="Db2Builder" />.</returns>
87+
public Db2Builder WithPassword(string password)
88+
{
89+
return Merge(DockerResourceConfiguration, new Db2Configuration(password: password))
90+
.WithEnvironment("DB2INST1_PASSWORD", password);
91+
}
92+
93+
/// <inheritdoc />
94+
public override Db2Container Build()
95+
{
96+
Validate();
97+
return new Db2Container(DockerResourceConfiguration);
98+
}
99+
100+
/// <inheritdoc />
101+
protected override Db2Builder Init() => base.Init()
102+
.WithImage(Db2Image)
103+
.WithPortBinding(Db2Port, true)
104+
.WithDatabase(DefaultDatabase)
105+
.WithUsername(DefaultUsername)
106+
.WithPassword(DefaultPassword)
107+
.WithPrivileged(true)
108+
.WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged("Setup has completed."));
109+
110+
/// <inheritdoc />
111+
protected override void Validate()
112+
{
113+
const string message = "The image '{0}' requires you to accept a license agreement.";
114+
115+
base.Validate();
116+
117+
Predicate<Db2Configuration> licenseAgreementNotAccepted = value =>
118+
!value.Environments.TryGetValue(AcceptLicenseAgreementEnvVar, out var licenseAgreementValue) || !AcceptLicenseAgreement.Equals(licenseAgreementValue, StringComparison.Ordinal);
119+
120+
_ = Guard.Argument(DockerResourceConfiguration, nameof(DockerResourceConfiguration.Image))
121+
.ThrowIf(argument => licenseAgreementNotAccepted(argument.Value), argument => throw new ArgumentException(string.Format(message, DockerResourceConfiguration.Image.FullName), argument.Name));
122+
123+
_ = Guard.Argument(DockerResourceConfiguration.Username, nameof(DockerResourceConfiguration.Username))
124+
.NotNull()
125+
.NotEmpty();
126+
127+
_ = Guard.Argument(DockerResourceConfiguration.Password, nameof(DockerResourceConfiguration.Password))
128+
.NotNull()
129+
.NotEmpty();
130+
}
131+
132+
/// <inheritdoc />
133+
protected override Db2Builder Clone(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
134+
{
135+
return Merge(DockerResourceConfiguration, new Db2Configuration(resourceConfiguration));
136+
}
137+
138+
/// <inheritdoc />
139+
protected override Db2Builder Clone(IContainerConfiguration resourceConfiguration)
140+
{
141+
return Merge(DockerResourceConfiguration, new Db2Configuration(resourceConfiguration));
142+
}
143+
144+
/// <inheritdoc />
145+
protected override Db2Builder Merge(Db2Configuration oldValue, Db2Configuration newValue)
146+
{
147+
return new Db2Builder(new Db2Configuration(oldValue, newValue));
148+
}
149+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
namespace Testcontainers.Db2;
2+
3+
/// <inheritdoc cref="ContainerConfiguration" />
4+
[PublicAPI]
5+
public sealed class Db2Configuration : ContainerConfiguration
6+
{
7+
/// <summary>
8+
/// Initializes a new instance of the <see cref="Db2Configuration" /> class.
9+
/// </summary>
10+
/// <param name="database">The Db2 database.</param>
11+
/// <param name="username">The Db2 username.</param>
12+
/// <param name="password">The Db2 password.</param>
13+
public Db2Configuration(
14+
string database = null,
15+
string username = null,
16+
string password = null)
17+
{
18+
Database = database;
19+
Username = username;
20+
Password = password;
21+
}
22+
23+
/// <summary>
24+
/// Initializes a new instance of the <see cref="Db2Configuration" /> class.
25+
/// </summary>
26+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
27+
public Db2Configuration(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
28+
: base(resourceConfiguration)
29+
{
30+
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
31+
}
32+
33+
/// <summary>
34+
/// Initializes a new instance of the <see cref="Db2Configuration" /> class.
35+
/// </summary>
36+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
37+
public Db2Configuration(IContainerConfiguration resourceConfiguration)
38+
: base(resourceConfiguration)
39+
{
40+
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
41+
}
42+
43+
/// <summary>
44+
/// Initializes a new instance of the <see cref="Db2Configuration" /> class.
45+
/// </summary>
46+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
47+
public Db2Configuration(Db2Configuration resourceConfiguration)
48+
: this(new Db2Configuration(), resourceConfiguration)
49+
{
50+
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
51+
}
52+
53+
/// <summary>
54+
/// Initializes a new instance of the <see cref="Db2Configuration" /> class.
55+
/// </summary>
56+
/// <param name="oldValue">The old Docker resource configuration.</param>
57+
/// <param name="newValue">The new Docker resource configuration.</param>
58+
public Db2Configuration(Db2Configuration oldValue, Db2Configuration newValue)
59+
: base(oldValue, newValue)
60+
{
61+
Database = BuildConfiguration.Combine(oldValue.Database, newValue.Database);
62+
Username = BuildConfiguration.Combine(oldValue.Username, newValue.Username);
63+
Password = BuildConfiguration.Combine(oldValue.Password, newValue.Password);
64+
}
65+
66+
/// <summary>
67+
/// Gets the Db2 database.
68+
/// </summary>
69+
public string Database { get; }
70+
71+
/// <summary>
72+
/// Gets the Db2 username.
73+
/// </summary>
74+
public string Username { get; }
75+
76+
/// <summary>
77+
/// Gets the Db2 password.
78+
/// </summary>
79+
public string Password { get; }
80+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
namespace Testcontainers.Db2;
2+
3+
/// <inheritdoc cref="DockerContainer" />
4+
[PublicAPI]
5+
public sealed class Db2Container : DockerContainer, IDatabaseContainer
6+
{
7+
private readonly Db2Configuration _configuration;
8+
9+
public Db2Container(Db2Configuration configuration) : base(configuration)
10+
{
11+
_configuration = configuration;
12+
}
13+
14+
/// <summary>
15+
/// Gets the Db2 connection string.
16+
/// </summary>
17+
/// <returns>The Db2 connection string.</returns>
18+
public string GetConnectionString()
19+
{
20+
var properties = new Dictionary<string, string>();
21+
properties.Add("Server", Hostname + ":" + GetMappedPublicPort(Db2Builder.Db2Port));
22+
properties.Add("Database", _configuration.Database);
23+
properties.Add("UID", _configuration.Username);
24+
properties.Add("PWD", _configuration.Password);
25+
return string.Join(";", properties.Select(property => string.Join("=", property.Key, property.Value)));
26+
}
27+
28+
/// <summary>
29+
/// Executes the SQL script in the Db2 container.
30+
/// </summary>
31+
/// <param name="scriptContent">The content of the SQL script to execute.</param>
32+
/// <param name="ct">Cancellation token.</param>
33+
/// <returns>Task that completes when the SQL script has been executed.</returns>
34+
public async Task<ExecResult> ExecScriptAsync(string scriptContent, CancellationToken ct = default)
35+
{
36+
const string db2ShellCommandFormat = "su - {1} -c \"db2 connect to {0} && db2 -tvf '{2}'\"";
37+
38+
var scriptFilePath = string.Join("/", string.Empty, "tmp", Guid.NewGuid().ToString("D"), Path.GetRandomFileName());
39+
40+
var db2ShellCommand = string.Format(db2ShellCommandFormat, _configuration.Database, _configuration.Username, scriptFilePath);
41+
42+
await CopyAsync(Encoding.Default.GetBytes(scriptContent), scriptFilePath, Unix.FileMode644, ct)
43+
.ConfigureAwait(false);
44+
45+
return await ExecAsync(new [] { "/bin/sh", "-c", db2ShellCommand}, ct)
46+
.ConfigureAwait(false);
47+
}
48+
}

0 commit comments

Comments
 (0)