From 5b9de6d1839fe6fefcfafb8767d23281c9432757 Mon Sep 17 00:00:00 2001 From: Gavin de Kock Date: Sat, 8 Feb 2025 23:29:27 +0000 Subject: [PATCH 1/6] Adding cassandra (#1) * Added support for Cassandra 5.0.3 TestConainer --- .github/workflows/cicd.yml | 1 + Directory.Packages.props | 3 +- Testcontainers.sln | 14 ++++ docs/modules/index.md | 1 + src/Testcontainers.Cassandra/.editorconfig | 1 + .../CassandraBuilder.cs | 77 +++++++++++++++++++ .../CassandraConfiguration.cs | 54 +++++++++++++ .../CassandraContainer.cs | 43 +++++++++++ .../Testcontainers.Cassandra.csproj | 12 +++ src/Testcontainers.Cassandra/Usings.cs | 11 +++ .../CassandraContainerTest.cs | 73 ++++++++++++++++++ .../Testcontainers.Cassandra.Tests.csproj | 18 +++++ .../Testcontainers.Cassandra.Tests/Usings.cs | 5 ++ 13 files changed, 312 insertions(+), 1 deletion(-) create mode 100644 src/Testcontainers.Cassandra/.editorconfig create mode 100644 src/Testcontainers.Cassandra/CassandraBuilder.cs create mode 100644 src/Testcontainers.Cassandra/CassandraConfiguration.cs create mode 100644 src/Testcontainers.Cassandra/CassandraContainer.cs create mode 100644 src/Testcontainers.Cassandra/Testcontainers.Cassandra.csproj create mode 100644 src/Testcontainers.Cassandra/Usings.cs create mode 100644 tests/Testcontainers.Cassandra.Tests/CassandraContainerTest.cs create mode 100644 tests/Testcontainers.Cassandra.Tests/Testcontainers.Cassandra.Tests.csproj create mode 100644 tests/Testcontainers.Cassandra.Tests/Usings.cs diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index 642ce1a33..ad937c5df 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -42,6 +42,7 @@ jobs: { name: "Testcontainers.Azurite", runs-on: "ubuntu-22.04" }, { name: "Testcontainers.BigQuery", runs-on: "ubuntu-22.04" }, { name: "Testcontainers.Bigtable", runs-on: "ubuntu-22.04" }, + { name: "Testcontainers.Cassandra", runs-on: "ubuntu-22.04" }, { name: "Testcontainers.ClickHouse", runs-on: "ubuntu-22.04" }, { name: "Testcontainers.CockroachDb", runs-on: "ubuntu-22.04" }, { name: "Testcontainers.Consul", runs-on: "ubuntu-22.04" }, diff --git a/Directory.Packages.props b/Directory.Packages.props index 8c825fa6c..0c065ceb4 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -12,6 +12,7 @@ + @@ -70,4 +71,4 @@ - + \ No newline at end of file diff --git a/Testcontainers.sln b/Testcontainers.sln index 444bdb1c3..2c69556e3 100644 --- a/Testcontainers.sln +++ b/Testcontainers.sln @@ -209,6 +209,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.WebDriver.Te EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Xunit.Tests", "tests\Testcontainers.Xunit.Tests\Testcontainers.Xunit.Tests.csproj", "{E901DF14-6F05-4FC2-825A-3055FAD33561}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Cassandra", "src\Testcontainers.Cassandra\Testcontainers.Cassandra.csproj", "{8495D757-5FD7-491C-B941-9D43B3DCF3C0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Cassandra.Tests", "tests\Testcontainers.Cassandra.Tests\Testcontainers.Cassandra.Tests.csproj", "{C6A2B99E-BFD5-4510-83D7-A8844142F27D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -610,6 +614,14 @@ Global {E901DF14-6F05-4FC2-825A-3055FAD33561}.Debug|Any CPU.Build.0 = Debug|Any CPU {E901DF14-6F05-4FC2-825A-3055FAD33561}.Release|Any CPU.ActiveCfg = Release|Any CPU {E901DF14-6F05-4FC2-825A-3055FAD33561}.Release|Any CPU.Build.0 = Release|Any CPU + {8495D757-5FD7-491C-B941-9D43B3DCF3C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8495D757-5FD7-491C-B941-9D43B3DCF3C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8495D757-5FD7-491C-B941-9D43B3DCF3C0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8495D757-5FD7-491C-B941-9D43B3DCF3C0}.Release|Any CPU.Build.0 = Release|Any CPU + {C6A2B99E-BFD5-4510-83D7-A8844142F27D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6A2B99E-BFD5-4510-83D7-A8844142F27D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6A2B99E-BFD5-4510-83D7-A8844142F27D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6A2B99E-BFD5-4510-83D7-A8844142F27D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {5365F780-0E6C-41F0-B1B9-7DC34368F80C} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} @@ -710,5 +722,7 @@ Global {DDB41BC8-5826-4D97-9C5F-001151E3FFD6} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {E901DF14-6F05-4FC2-825A-3055FAD33561} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} + {8495D757-5FD7-491C-B941-9D43B3DCF3C0} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} + {C6A2B99E-BFD5-4510-83D7-A8844142F27D} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} EndGlobalSection EndGlobal diff --git a/docs/modules/index.md b/docs/modules/index.md index 48a75587b..2d83a2b83 100644 --- a/docs/modules/index.md +++ b/docs/modules/index.md @@ -28,6 +28,7 @@ await moduleNameContainer.StartAsync(); | Azurite | `mcr.microsoft.com/azure-storage/azurite:3.24.0` | [NuGet](https://www.nuget.org/packages/Testcontainers.Azurite) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Azurite) | | BigQuery | `ghcr.io/goccy/bigquery-emulator:0.4` | [NuGet](https://www.nuget.org/packages/Testcontainers.BigQuery) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.BigQuery) | | Bigtable | `gcr.io/google.com/cloudsdktool/google-cloud-cli:446.0.1-emulators` | [NuGet](https://www.nuget.org/packages/Testcontainers.Bigtable) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Bigtable) | +| Cassandra | `library/cassandra:5.0.3` | [NuGet](https://www.nuget.org/packages/Testcontainers.Cassandra) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Cassandra) | | ClickHouse | `clickhouse/clickhouse-server:23.6-alpine` | [NuGet](https://www.nuget.org/packages/Testcontainers.ClickHouse) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.ClickHouse) | | CockroachDB | `cockroachdb:23.1.13` | [NuGet](https://www.nuget.org/packages/Testcontainers.CockroachDb) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.CockroachDb) | | Consul | `consul:1.15` | [NuGet](https://www.nuget.org/packages/Testcontainers.Consul) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Consul) | diff --git a/src/Testcontainers.Cassandra/.editorconfig b/src/Testcontainers.Cassandra/.editorconfig new file mode 100644 index 000000000..6f066619d --- /dev/null +++ b/src/Testcontainers.Cassandra/.editorconfig @@ -0,0 +1 @@ +root = true \ No newline at end of file diff --git a/src/Testcontainers.Cassandra/CassandraBuilder.cs b/src/Testcontainers.Cassandra/CassandraBuilder.cs new file mode 100644 index 000000000..90a5336bd --- /dev/null +++ b/src/Testcontainers.Cassandra/CassandraBuilder.cs @@ -0,0 +1,77 @@ +namespace Testcontainers.Cassandra +{ + /// + [PublicAPI] + public sealed class CassandraBuilder : ContainerBuilder + { + public const string CassandraImage = "library/cassandra:5.0.3"; + + public const ushort CqlPort = 9042; + + public const string DefaultLocalDataCentre = "datacentre1"; + + /// + /// Initializes a new instance of the class. + /// + public CassandraBuilder() + : this(new CassandraConfiguration()) + { + DockerResourceConfiguration = Init().DockerResourceConfiguration; + } + + /// + /// Initializes a new instance of the class. + /// + /// The Docker resource configuration. + private CassandraBuilder(CassandraConfiguration resourceConfiguration) + : base(resourceConfiguration) + { + DockerResourceConfiguration = resourceConfiguration; + } + + /// + protected override CassandraConfiguration DockerResourceConfiguration { get; } + + /// + public override CassandraContainer Build() + { + return new CassandraContainer(DockerResourceConfiguration); + } + + /// + protected override CassandraBuilder Init() + { + return base.Init() + .WithImage(CassandraImage) + .WithPortBinding(CqlPort, true) + .WithEnvironment("CASSANDRA_SNITCH", "GossipingPropertyFileSnitch") + .WithEnvironment("JVM_OPTS", "-Dcassandra.skip_wait_for_gossip_to_settle=0 -Dcassandra.initial_token=0") + .WithEnvironment("HEAP_NEWSIZE", "128M") + .WithEnvironment("MAX_HEAP_SIZE", "1024M") + .WithEnvironment("CASSANDRA_ENDPOINT_SNITCH", "GossipingPropertyFileSnitch") + .WithEnvironment("CASSANDRA_DC", DefaultLocalDataCentre) + .WithWaitStrategy( + Wait.ForUnixContainer() + .UntilPortIsAvailable(CqlPort) + .UntilMessageIsLogged("Startup complete")); + } + + /// + protected override CassandraBuilder Clone(IResourceConfiguration resourceConfiguration) + { + return Merge(DockerResourceConfiguration, new CassandraConfiguration(resourceConfiguration)); + } + + /// + protected override CassandraBuilder Clone(IContainerConfiguration resourceConfiguration) + { + return Merge(DockerResourceConfiguration, new CassandraConfiguration(resourceConfiguration)); + } + + /// + protected override CassandraBuilder Merge(CassandraConfiguration oldValue, CassandraConfiguration newValue) + { + return new CassandraBuilder(new CassandraConfiguration(oldValue, newValue)); + } + } +} diff --git a/src/Testcontainers.Cassandra/CassandraConfiguration.cs b/src/Testcontainers.Cassandra/CassandraConfiguration.cs new file mode 100644 index 000000000..88b569519 --- /dev/null +++ b/src/Testcontainers.Cassandra/CassandraConfiguration.cs @@ -0,0 +1,54 @@ +namespace Testcontainers.Cassandra +{ + /// + [PublicAPI] + public sealed class CassandraConfiguration : ContainerConfiguration + { + /// + /// Initializes a new instance of the class. + /// + public CassandraConfiguration() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The Docker resource configuration. + public CassandraConfiguration(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 CassandraConfiguration(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 CassandraConfiguration(CassandraConfiguration resourceConfiguration) + : this(new CassandraConfiguration(), 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 CassandraConfiguration(CassandraConfiguration oldValue, CassandraConfiguration newValue) + : base(oldValue, newValue) + { + } + } +} \ No newline at end of file diff --git a/src/Testcontainers.Cassandra/CassandraContainer.cs b/src/Testcontainers.Cassandra/CassandraContainer.cs new file mode 100644 index 000000000..141424147 --- /dev/null +++ b/src/Testcontainers.Cassandra/CassandraContainer.cs @@ -0,0 +1,43 @@ +namespace Testcontainers.Cassandra +{ + /// + [PublicAPI] + public class CassandraContainer : DockerContainer, IDatabaseContainer + { + private readonly CassandraConfiguration _configuration; + + /// + public CassandraContainer(CassandraConfiguration configuration) : base(configuration) + { + _configuration = configuration; + } + + public IPEndPoint GetEndPoint() + { + return new IPEndPoint(IPAddress.Loopback, GetMappedPublicPort(CassandraBuilder.CqlPort)); + } + + public string GetConnectionString() + { + throw new NotImplementedException(); + } + + /// + /// Executes the SQL script in the Cassandra container. + /// + /// The content of the CQL script to execute. + /// Cancellation token. + /// Task that completes when the CQL script has been executed. + public async Task ExecScriptAsync(string scriptContent, CancellationToken ct = default) + { + var scriptFilePath = string.Join("/", string.Empty, "tmp", Guid.NewGuid().ToString("D"), Path.GetRandomFileName()); + + await CopyAsync(Encoding.Default.GetBytes(scriptContent), scriptFilePath, Unix.FileMode644, ct) + .ConfigureAwait(false); + + return await ExecAsync(new[] { "cqlsh", "-f", scriptFilePath }, ct) + .ConfigureAwait(false); + } + + } +} diff --git a/src/Testcontainers.Cassandra/Testcontainers.Cassandra.csproj b/src/Testcontainers.Cassandra/Testcontainers.Cassandra.csproj new file mode 100644 index 000000000..906f34018 --- /dev/null +++ b/src/Testcontainers.Cassandra/Testcontainers.Cassandra.csproj @@ -0,0 +1,12 @@ + + + net8.0;net9.0;netstandard2.0;netstandard2.1 + latest + + + + + + + + \ No newline at end of file diff --git a/src/Testcontainers.Cassandra/Usings.cs b/src/Testcontainers.Cassandra/Usings.cs new file mode 100644 index 000000000..3b1dcb627 --- /dev/null +++ b/src/Testcontainers.Cassandra/Usings.cs @@ -0,0 +1,11 @@ +global using System; +global using System.IO; +global using System.Net; +global using System.Text; +global using System.Threading; +global using System.Threading.Tasks; +global using Docker.DotNet.Models; +global using DotNet.Testcontainers.Builders; +global using DotNet.Testcontainers.Configurations; +global using DotNet.Testcontainers.Containers; +global using JetBrains.Annotations; diff --git a/tests/Testcontainers.Cassandra.Tests/CassandraContainerTest.cs b/tests/Testcontainers.Cassandra.Tests/CassandraContainerTest.cs new file mode 100644 index 000000000..b53f9ef1e --- /dev/null +++ b/tests/Testcontainers.Cassandra.Tests/CassandraContainerTest.cs @@ -0,0 +1,73 @@ +namespace Testcontainers.Cassandra.Tests +{ + public sealed class CassandraContainerTest : IAsyncLifetime + { + private readonly CassandraContainer _cassandraContainer = new CassandraBuilder().Build(); + + public Task InitializeAsync() + { + return _cassandraContainer.StartAsync(); + } + + public Task DisposeAsync() + { + return _cassandraContainer.DisposeAsync().AsTask(); + } + + [Fact] + [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))] + public void ConnectionStateReturnsOpen() + { + // Given + var cluster = Cluster.Builder() + .AddContactPoint(_cassandraContainer.GetEndPoint()) + .Build(); + + // When + var session = cluster.Connect(); + + // Then + Assert.True(session.GetState().GetConnectedHosts().First().IsUp); + } + + [Fact] + [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))] + public async Task DriverExecutesCqlStatementAndReturnResult() + { + // Given + const string selectFromSystemLocalStatement = "SELECT * FROM system.local WHERE key = ?;"; + var cluster = Cluster.Builder() + .AddContactPoint(_cassandraContainer.GetEndPoint()) + .Build(); + + // When + var session = await cluster.ConnectAsync(); + var preparedStatement = await session.PrepareAsync(selectFromSystemLocalStatement); + var boundStatement = preparedStatement.Bind("local"); + var result = await session.ExecuteAsync(boundStatement); + + // Then + Assert.True(result.IsFullyFetched); + var resultRows = result.GetRows().ToList(); + Assert.Single(resultRows); + Assert.Equal("COMPLETED", resultRows.First()["bootstrapped"]); + } + + [Fact] + [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))] + public async Task ExecScriptAsyncReturnsSuccess() + { + // Given + const string selectFromSystemLocalStatement = "SELECT * FROM system.local;"; + + // When + var execResult = await _cassandraContainer.ExecScriptAsync(selectFromSystemLocalStatement) + .ConfigureAwait(true); + + // Then + Assert.True(0L.Equals(execResult.ExitCode), execResult.Stderr); + Assert.NotEmpty(execResult.Stdout); + Assert.Empty(execResult.Stderr); + } + } +} diff --git a/tests/Testcontainers.Cassandra.Tests/Testcontainers.Cassandra.Tests.csproj b/tests/Testcontainers.Cassandra.Tests/Testcontainers.Cassandra.Tests.csproj new file mode 100644 index 000000000..268dc4deb --- /dev/null +++ b/tests/Testcontainers.Cassandra.Tests/Testcontainers.Cassandra.Tests.csproj @@ -0,0 +1,18 @@ + + + net9.0 + false + false + + + + + + + + + + + + + diff --git a/tests/Testcontainers.Cassandra.Tests/Usings.cs b/tests/Testcontainers.Cassandra.Tests/Usings.cs new file mode 100644 index 000000000..25e8a9661 --- /dev/null +++ b/tests/Testcontainers.Cassandra.Tests/Usings.cs @@ -0,0 +1,5 @@ +global using System.Linq; +global using System.Threading.Tasks; +global using Cassandra; +global using DotNet.Testcontainers.Commons; +global using Xunit; From 57c537a1505602bc54a98482fb73a2462e3661f1 Mon Sep 17 00:00:00 2001 From: Gavin de Kock Date: Fri, 14 Feb 2025 13:58:55 +0000 Subject: [PATCH 2/6] Changed DataCentre to DC --- src/Testcontainers.Cassandra/CassandraBuilder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Testcontainers.Cassandra/CassandraBuilder.cs b/src/Testcontainers.Cassandra/CassandraBuilder.cs index 90a5336bd..bdec75a1c 100644 --- a/src/Testcontainers.Cassandra/CassandraBuilder.cs +++ b/src/Testcontainers.Cassandra/CassandraBuilder.cs @@ -8,7 +8,7 @@ public sealed class CassandraBuilder : ContainerBuilder /// Initializes a new instance of the class. @@ -49,7 +49,7 @@ protected override CassandraBuilder Init() .WithEnvironment("HEAP_NEWSIZE", "128M") .WithEnvironment("MAX_HEAP_SIZE", "1024M") .WithEnvironment("CASSANDRA_ENDPOINT_SNITCH", "GossipingPropertyFileSnitch") - .WithEnvironment("CASSANDRA_DC", DefaultLocalDataCentre) + .WithEnvironment("CASSANDRA_DC", DefaultLocalDc) .WithWaitStrategy( Wait.ForUnixContainer() .UntilPortIsAvailable(CqlPort) From f17f244e1f1fed7ab15537a6fe3f29413d4e7163 Mon Sep 17 00:00:00 2001 From: Gavin de Kock Date: Sat, 15 Feb 2025 21:19:37 +0000 Subject: [PATCH 3/6] Upgrade CassandraCSharpDriver to 3.22.0 --- Directory.Packages.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 32369b2f9..2e9483636 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -12,7 +12,7 @@ - + @@ -74,4 +74,4 @@ - \ No newline at end of file + From 309c52d8b0facb6d6601f18aff2b485966a186fb Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Sun, 16 Feb 2025 11:19:08 +0100 Subject: [PATCH 4/6] chore: Align repo standards --- Directory.Packages.props | 2 +- Testcontainers.sln | 28 ++-- docs/modules/index.md | 2 +- .../CassandraBuilder.cs | 127 +++++++++--------- .../CassandraConfiguration.cs | 91 +++++++------ .../CassandraContainer.cs | 45 ++++--- src/Testcontainers.Cassandra/Usings.cs | 2 +- .../.editorconfig | 1 + .../CassandraContainerTest.cs | 76 +++++------ .../Testcontainers.Cassandra.Tests.csproj | 8 +- .../Testcontainers.Cassandra.Tests/Usings.cs | 3 +- 11 files changed, 193 insertions(+), 192 deletions(-) create mode 100644 tests/Testcontainers.Cassandra.Tests/.editorconfig diff --git a/Directory.Packages.props b/Directory.Packages.props index 2e9483636..1cbb98f3f 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -12,7 +12,6 @@ - @@ -36,6 +35,7 @@ + diff --git a/Testcontainers.sln b/Testcontainers.sln index f6d3accf2..6d03c63dc 100644 --- a/Testcontainers.sln +++ b/Testcontainers.sln @@ -23,6 +23,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.BigQuery", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Bigtable", "src\Testcontainers.Bigtable\Testcontainers.Bigtable.csproj", "{302EC1E0-AE75-4E99-A6BF-524F35338BC8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Cassandra", "src\Testcontainers.Cassandra\Testcontainers.Cassandra.csproj", "{8495D757-5FD7-491C-B941-9D43B3DCF3C0}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.ClickHouse", "src\Testcontainers.ClickHouse\Testcontainers.ClickHouse.csproj", "{B061A78E-536E-4CA1-8401-234D5FBFBAB7}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.CockroachDb", "src\Testcontainers.CockroachDb\Testcontainers.CockroachDb.csproj", "{8D9871C6-5A39-4F0B-A15A-E87D34F3EA73}" @@ -121,6 +123,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.BigQuery.Tes EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Bigtable.Tests", "tests\Testcontainers.Bigtable.Tests\Testcontainers.Bigtable.Tests.csproj", "{2E7B92E3-8526-4706-90F3-00F0F5C47C37}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Cassandra.Tests", "tests\Testcontainers.Cassandra.Tests\Testcontainers.Cassandra.Tests.csproj", "{C6A2B99E-BFD5-4510-83D7-A8844142F27D}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.ClickHouse.Tests", "tests\Testcontainers.ClickHouse.Tests\Testcontainers.ClickHouse.Tests.csproj", "{9D0A0B32-4921-400C-99CB-8650677E3E44}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.CockroachDb.Tests", "tests\Testcontainers.CockroachDb.Tests\Testcontainers.CockroachDb.Tests.csproj", "{685E6D9A-B05E-41D9-A08E-5F3CA7733F7D}" @@ -217,10 +221,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.WebDriver.Te EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Xunit.Tests", "tests\Testcontainers.Xunit.Tests\Testcontainers.Xunit.Tests.csproj", "{E901DF14-6F05-4FC2-825A-3055FAD33561}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Cassandra", "src\Testcontainers.Cassandra\Testcontainers.Cassandra.csproj", "{8495D757-5FD7-491C-B941-9D43B3DCF3C0}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Cassandra.Tests", "tests\Testcontainers.Cassandra.Tests\Testcontainers.Cassandra.Tests.csproj", "{C6A2B99E-BFD5-4510-83D7-A8844142F27D}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -250,6 +250,10 @@ Global {302EC1E0-AE75-4E99-A6BF-524F35338BC8}.Debug|Any CPU.Build.0 = Debug|Any CPU {302EC1E0-AE75-4E99-A6BF-524F35338BC8}.Release|Any CPU.ActiveCfg = Release|Any CPU {302EC1E0-AE75-4E99-A6BF-524F35338BC8}.Release|Any CPU.Build.0 = Release|Any CPU + {8495D757-5FD7-491C-B941-9D43B3DCF3C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8495D757-5FD7-491C-B941-9D43B3DCF3C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8495D757-5FD7-491C-B941-9D43B3DCF3C0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8495D757-5FD7-491C-B941-9D43B3DCF3C0}.Release|Any CPU.Build.0 = Release|Any CPU {B061A78E-536E-4CA1-8401-234D5FBFBAB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B061A78E-536E-4CA1-8401-234D5FBFBAB7}.Debug|Any CPU.Build.0 = Debug|Any CPU {B061A78E-536E-4CA1-8401-234D5FBFBAB7}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -446,6 +450,10 @@ Global {2E7B92E3-8526-4706-90F3-00F0F5C47C37}.Debug|Any CPU.Build.0 = Debug|Any CPU {2E7B92E3-8526-4706-90F3-00F0F5C47C37}.Release|Any CPU.ActiveCfg = Release|Any CPU {2E7B92E3-8526-4706-90F3-00F0F5C47C37}.Release|Any CPU.Build.0 = Release|Any CPU + {C6A2B99E-BFD5-4510-83D7-A8844142F27D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6A2B99E-BFD5-4510-83D7-A8844142F27D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6A2B99E-BFD5-4510-83D7-A8844142F27D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6A2B99E-BFD5-4510-83D7-A8844142F27D}.Release|Any CPU.Build.0 = Release|Any CPU {9D0A0B32-4921-400C-99CB-8650677E3E44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9D0A0B32-4921-400C-99CB-8650677E3E44}.Debug|Any CPU.Build.0 = Debug|Any CPU {9D0A0B32-4921-400C-99CB-8650677E3E44}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -638,14 +646,6 @@ Global {E901DF14-6F05-4FC2-825A-3055FAD33561}.Debug|Any CPU.Build.0 = Debug|Any CPU {E901DF14-6F05-4FC2-825A-3055FAD33561}.Release|Any CPU.ActiveCfg = Release|Any CPU {E901DF14-6F05-4FC2-825A-3055FAD33561}.Release|Any CPU.Build.0 = Release|Any CPU - {8495D757-5FD7-491C-B941-9D43B3DCF3C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8495D757-5FD7-491C-B941-9D43B3DCF3C0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8495D757-5FD7-491C-B941-9D43B3DCF3C0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8495D757-5FD7-491C-B941-9D43B3DCF3C0}.Release|Any CPU.Build.0 = Release|Any CPU - {C6A2B99E-BFD5-4510-83D7-A8844142F27D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C6A2B99E-BFD5-4510-83D7-A8844142F27D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C6A2B99E-BFD5-4510-83D7-A8844142F27D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C6A2B99E-BFD5-4510-83D7-A8844142F27D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {5365F780-0E6C-41F0-B1B9-7DC34368F80C} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} @@ -653,6 +653,7 @@ Global {3F2E254F-C203-43FD-A078-DC3E2CBC0F9F} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} {A9FF9C7F-BBA0-4B44-90B7-48A60F9E00F3} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} {302EC1E0-AE75-4E99-A6BF-524F35338BC8} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} + {8495D757-5FD7-491C-B941-9D43B3DCF3C0} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} {B061A78E-536E-4CA1-8401-234D5FBFBAB7} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} {8D9871C6-5A39-4F0B-A15A-E87D34F3EA73} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} {51ED33B9-B688-401E-85F2-329D3C935BD1} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} @@ -702,6 +703,7 @@ Global {B272FDDE-5E01-425D-B9E1-10FF883DDAAA} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {03E60673-078A-4508-99AD-8537CE6F78F1} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {2E7B92E3-8526-4706-90F3-00F0F5C47C37} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} + {C6A2B99E-BFD5-4510-83D7-A8844142F27D} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {9D0A0B32-4921-400C-99CB-8650677E3E44} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {685E6D9A-B05E-41D9-A08E-5F3CA7733F7D} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {2478673C-B063-469D-ABD1-0C3E0A25541B} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} @@ -750,7 +752,5 @@ Global {DDB41BC8-5826-4D97-9C5F-001151E3FFD6} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {E901DF14-6F05-4FC2-825A-3055FAD33561} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} - {8495D757-5FD7-491C-B941-9D43B3DCF3C0} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} - {C6A2B99E-BFD5-4510-83D7-A8844142F27D} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} EndGlobalSection EndGlobal diff --git a/docs/modules/index.md b/docs/modules/index.md index 2d83a2b83..95df197cc 100644 --- a/docs/modules/index.md +++ b/docs/modules/index.md @@ -28,7 +28,7 @@ await moduleNameContainer.StartAsync(); | Azurite | `mcr.microsoft.com/azure-storage/azurite:3.24.0` | [NuGet](https://www.nuget.org/packages/Testcontainers.Azurite) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Azurite) | | BigQuery | `ghcr.io/goccy/bigquery-emulator:0.4` | [NuGet](https://www.nuget.org/packages/Testcontainers.BigQuery) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.BigQuery) | | Bigtable | `gcr.io/google.com/cloudsdktool/google-cloud-cli:446.0.1-emulators` | [NuGet](https://www.nuget.org/packages/Testcontainers.Bigtable) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Bigtable) | -| Cassandra | `library/cassandra:5.0.3` | [NuGet](https://www.nuget.org/packages/Testcontainers.Cassandra) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Cassandra) | +| Cassandra | `library/cassandra:5.0` | [NuGet](https://www.nuget.org/packages/Testcontainers.Cassandra) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Cassandra) | | ClickHouse | `clickhouse/clickhouse-server:23.6-alpine` | [NuGet](https://www.nuget.org/packages/Testcontainers.ClickHouse) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.ClickHouse) | | CockroachDB | `cockroachdb:23.1.13` | [NuGet](https://www.nuget.org/packages/Testcontainers.CockroachDb) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.CockroachDb) | | Consul | `consul:1.15` | [NuGet](https://www.nuget.org/packages/Testcontainers.Consul) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Consul) | diff --git a/src/Testcontainers.Cassandra/CassandraBuilder.cs b/src/Testcontainers.Cassandra/CassandraBuilder.cs index bdec75a1c..61a6f82b4 100644 --- a/src/Testcontainers.Cassandra/CassandraBuilder.cs +++ b/src/Testcontainers.Cassandra/CassandraBuilder.cs @@ -1,77 +1,74 @@ -namespace Testcontainers.Cassandra +namespace Testcontainers.Cassandra; + +/// +[PublicAPI] +public sealed class CassandraBuilder : ContainerBuilder { - /// - [PublicAPI] - public sealed class CassandraBuilder : ContainerBuilder - { - public const string CassandraImage = "library/cassandra:5.0.3"; + public const string CassandraImage = "cassandra:5.0"; - public const ushort CqlPort = 9042; + public const ushort CqlPort = 9042; - public const string DefaultLocalDc = "dc1"; + public const string DefaultDatacenterName = "dc1"; - /// - /// Initializes a new instance of the class. - /// - public CassandraBuilder() - : this(new CassandraConfiguration()) - { - DockerResourceConfiguration = Init().DockerResourceConfiguration; - } + /// + /// Initializes a new instance of the class. + /// + public CassandraBuilder() + : this(new CassandraConfiguration()) + { + DockerResourceConfiguration = Init().DockerResourceConfiguration; + } - /// - /// Initializes a new instance of the class. - /// - /// The Docker resource configuration. - private CassandraBuilder(CassandraConfiguration resourceConfiguration) - : base(resourceConfiguration) - { - DockerResourceConfiguration = resourceConfiguration; - } + /// + /// Initializes a new instance of the class. + /// + /// The Docker resource configuration. + private CassandraBuilder(CassandraConfiguration resourceConfiguration) + : base(resourceConfiguration) + { + DockerResourceConfiguration = resourceConfiguration; + } - /// - protected override CassandraConfiguration DockerResourceConfiguration { get; } + /// + protected override CassandraConfiguration DockerResourceConfiguration { get; } - /// - public override CassandraContainer Build() - { - return new CassandraContainer(DockerResourceConfiguration); - } + /// + public override CassandraContainer Build() + { + Validate(); + return new CassandraContainer(DockerResourceConfiguration); + } - /// - protected override CassandraBuilder Init() - { - return base.Init() - .WithImage(CassandraImage) - .WithPortBinding(CqlPort, true) - .WithEnvironment("CASSANDRA_SNITCH", "GossipingPropertyFileSnitch") - .WithEnvironment("JVM_OPTS", "-Dcassandra.skip_wait_for_gossip_to_settle=0 -Dcassandra.initial_token=0") - .WithEnvironment("HEAP_NEWSIZE", "128M") - .WithEnvironment("MAX_HEAP_SIZE", "1024M") - .WithEnvironment("CASSANDRA_ENDPOINT_SNITCH", "GossipingPropertyFileSnitch") - .WithEnvironment("CASSANDRA_DC", DefaultLocalDc) - .WithWaitStrategy( - Wait.ForUnixContainer() - .UntilPortIsAvailable(CqlPort) - .UntilMessageIsLogged("Startup complete")); - } + /// + protected override CassandraBuilder Init() + { + return base.Init() + .WithImage(CassandraImage) + .WithPortBinding(CqlPort, true) + .WithEnvironment("JVM_OPTS", "-Dcassandra.skip_wait_for_gossip_to_settle=0 -Dcassandra.initial_token=0") + .WithEnvironment("HEAP_NEWSIZE", "128M") + .WithEnvironment("MAX_HEAP_SIZE", "1024M") + .WithEnvironment("CASSANDRA_SNITCH", "GossipingPropertyFileSnitch") + .WithEnvironment("CASSANDRA_ENDPOINT_SNITCH", "GossipingPropertyFileSnitch") + .WithEnvironment("CASSANDRA_DC", DefaultDatacenterName) + .WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged("Startup complete")); + } - /// - protected override CassandraBuilder Clone(IResourceConfiguration resourceConfiguration) - { - return Merge(DockerResourceConfiguration, new CassandraConfiguration(resourceConfiguration)); - } + /// + protected override CassandraBuilder Clone(IResourceConfiguration resourceConfiguration) + { + return Merge(DockerResourceConfiguration, new CassandraConfiguration(resourceConfiguration)); + } - /// - protected override CassandraBuilder Clone(IContainerConfiguration resourceConfiguration) - { - return Merge(DockerResourceConfiguration, new CassandraConfiguration(resourceConfiguration)); - } + /// + protected override CassandraBuilder Clone(IContainerConfiguration resourceConfiguration) + { + return Merge(DockerResourceConfiguration, new CassandraConfiguration(resourceConfiguration)); + } - /// - protected override CassandraBuilder Merge(CassandraConfiguration oldValue, CassandraConfiguration newValue) - { - return new CassandraBuilder(new CassandraConfiguration(oldValue, newValue)); - } + /// + protected override CassandraBuilder Merge(CassandraConfiguration oldValue, CassandraConfiguration newValue) + { + return new CassandraBuilder(new CassandraConfiguration(oldValue, newValue)); } -} +} \ No newline at end of file diff --git a/src/Testcontainers.Cassandra/CassandraConfiguration.cs b/src/Testcontainers.Cassandra/CassandraConfiguration.cs index 88b569519..a1a02c62b 100644 --- a/src/Testcontainers.Cassandra/CassandraConfiguration.cs +++ b/src/Testcontainers.Cassandra/CassandraConfiguration.cs @@ -1,54 +1,53 @@ -namespace Testcontainers.Cassandra +namespace Testcontainers.Cassandra; + +/// +[PublicAPI] +public sealed class CassandraConfiguration : ContainerConfiguration { - /// - [PublicAPI] - public sealed class CassandraConfiguration : ContainerConfiguration + /// + /// Initializes a new instance of the class. + /// + public CassandraConfiguration() { - /// - /// Initializes a new instance of the class. - /// - public CassandraConfiguration() - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// The Docker resource configuration. - public CassandraConfiguration(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 CassandraConfiguration(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 CassandraConfiguration(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 CassandraConfiguration(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 CassandraConfiguration(CassandraConfiguration resourceConfiguration) - : this(new CassandraConfiguration(), 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 CassandraConfiguration(CassandraConfiguration resourceConfiguration) + : this(new CassandraConfiguration(), 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 CassandraConfiguration(CassandraConfiguration oldValue, CassandraConfiguration newValue) - : base(oldValue, newValue) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The old Docker resource configuration. + /// The new Docker resource configuration. + public CassandraConfiguration(CassandraConfiguration oldValue, CassandraConfiguration newValue) + : base(oldValue, newValue) + { } } \ No newline at end of file diff --git a/src/Testcontainers.Cassandra/CassandraContainer.cs b/src/Testcontainers.Cassandra/CassandraContainer.cs index 141424147..52ab289fc 100644 --- a/src/Testcontainers.Cassandra/CassandraContainer.cs +++ b/src/Testcontainers.Cassandra/CassandraContainer.cs @@ -1,43 +1,50 @@ -namespace Testcontainers.Cassandra +namespace Testcontainers.Cassandra; + +/// +[PublicAPI] +public sealed class CassandraContainer : DockerContainer, IDatabaseContainer { - /// - [PublicAPI] - public class CassandraContainer : DockerContainer, IDatabaseContainer - { private readonly CassandraConfiguration _configuration; /// - public CassandraContainer(CassandraConfiguration configuration) : base(configuration) + public CassandraContainer(CassandraConfiguration configuration) + : base(configuration) { - _configuration = configuration; + _configuration = configuration; } - public IPEndPoint GetEndPoint() + /// + /// Gets the Cassandra contact point. + /// + /// The Cassandra contact point. + public IPEndPoint GetContactPoint() { - return new IPEndPoint(IPAddress.Loopback, GetMappedPublicPort(CassandraBuilder.CqlPort)); + return new IPEndPoint(Dns.GetHostAddresses(Hostname)[0], GetMappedPublicPort(CassandraBuilder.CqlPort)); } + /// + /// Gets the Cassandra connection string. + /// + /// The Cassandra connection string. public string GetConnectionString() { - throw new NotImplementedException(); + throw new NotImplementedException(); } /// - /// Executes the SQL script in the Cassandra container. + /// Executes the CQL script in the Cassandra container. /// /// The content of the CQL script to execute. /// Cancellation token. /// Task that completes when the CQL script has been executed. public async Task ExecScriptAsync(string scriptContent, CancellationToken ct = default) { - var scriptFilePath = string.Join("/", string.Empty, "tmp", Guid.NewGuid().ToString("D"), Path.GetRandomFileName()); + var scriptFilePath = string.Join("/", string.Empty, "tmp", Guid.NewGuid().ToString("D"), Path.GetRandomFileName()); - await CopyAsync(Encoding.Default.GetBytes(scriptContent), scriptFilePath, Unix.FileMode644, ct) - .ConfigureAwait(false); + await CopyAsync(Encoding.Default.GetBytes(scriptContent), scriptFilePath, Unix.FileMode644, ct) + .ConfigureAwait(false); - return await ExecAsync(new[] { "cqlsh", "-f", scriptFilePath }, ct) - .ConfigureAwait(false); + return await ExecAsync(new[] { "cqlsh", "--file", scriptFilePath }, ct) + .ConfigureAwait(false); } - - } -} +} \ No newline at end of file diff --git a/src/Testcontainers.Cassandra/Usings.cs b/src/Testcontainers.Cassandra/Usings.cs index 3b1dcb627..98a608e61 100644 --- a/src/Testcontainers.Cassandra/Usings.cs +++ b/src/Testcontainers.Cassandra/Usings.cs @@ -8,4 +8,4 @@ global using DotNet.Testcontainers.Builders; global using DotNet.Testcontainers.Configurations; global using DotNet.Testcontainers.Containers; -global using JetBrains.Annotations; +global using JetBrains.Annotations; \ No newline at end of file diff --git a/tests/Testcontainers.Cassandra.Tests/.editorconfig b/tests/Testcontainers.Cassandra.Tests/.editorconfig new file mode 100644 index 000000000..6f066619d --- /dev/null +++ b/tests/Testcontainers.Cassandra.Tests/.editorconfig @@ -0,0 +1 @@ +root = true \ No newline at end of file diff --git a/tests/Testcontainers.Cassandra.Tests/CassandraContainerTest.cs b/tests/Testcontainers.Cassandra.Tests/CassandraContainerTest.cs index b53f9ef1e..a295ac29d 100644 --- a/tests/Testcontainers.Cassandra.Tests/CassandraContainerTest.cs +++ b/tests/Testcontainers.Cassandra.Tests/CassandraContainerTest.cs @@ -1,73 +1,69 @@ -namespace Testcontainers.Cassandra.Tests +namespace Testcontainers.Cassandra; + +public sealed class CassandraContainerTest : IAsyncLifetime { - public sealed class CassandraContainerTest : IAsyncLifetime - { private readonly CassandraContainer _cassandraContainer = new CassandraBuilder().Build(); public Task InitializeAsync() { - return _cassandraContainer.StartAsync(); + return _cassandraContainer.StartAsync(); } public Task DisposeAsync() { - return _cassandraContainer.DisposeAsync().AsTask(); + return _cassandraContainer.DisposeAsync().AsTask(); } [Fact] [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))] public void ConnectionStateReturnsOpen() { - // Given - var cluster = Cluster.Builder() - .AddContactPoint(_cassandraContainer.GetEndPoint()) - .Build(); + // Given + using var cluster = Cluster.Builder().AddContactPoint(_cassandraContainer.GetContactPoint()).Build(); - // When - var session = cluster.Connect(); + // When + using var session = cluster.Connect(); - // Then - Assert.True(session.GetState().GetConnectedHosts().First().IsUp); + // Then + Assert.True(session.GetState().GetConnectedHosts().Single().IsUp); } [Fact] [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))] - public async Task DriverExecutesCqlStatementAndReturnResult() + public void DriverExecutesCqlStatementAndReturnResult() { - // Given - const string selectFromSystemLocalStatement = "SELECT * FROM system.local WHERE key = ?;"; - var cluster = Cluster.Builder() - .AddContactPoint(_cassandraContainer.GetEndPoint()) - .Build(); + // Given + const string selectFromSystemLocalStatement = "SELECT * FROM system.local WHERE key = ?;"; + + using var cluster = Cluster.Builder().AddContactPoint(_cassandraContainer.GetContactPoint()).Build(); + + // When + using var session = cluster.Connect(); - // When - var session = await cluster.ConnectAsync(); - var preparedStatement = await session.PrepareAsync(selectFromSystemLocalStatement); - var boundStatement = preparedStatement.Bind("local"); - var result = await session.ExecuteAsync(boundStatement); + var preparedStatement = session.Prepare(selectFromSystemLocalStatement); + var boundStatement = preparedStatement.Bind("local"); + using var rowSet = session.Execute(boundStatement); + var rows = rowSet.GetRows().ToImmutableList(); - // Then - Assert.True(result.IsFullyFetched); - var resultRows = result.GetRows().ToList(); - Assert.Single(resultRows); - Assert.Equal("COMPLETED", resultRows.First()["bootstrapped"]); + // Then + Assert.True(rowSet.IsFullyFetched); + Assert.Single(rows); + Assert.Equal("COMPLETED", rows[0]["bootstrapped"]); } [Fact] [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))] public async Task ExecScriptAsyncReturnsSuccess() { - // Given - const string selectFromSystemLocalStatement = "SELECT * FROM system.local;"; + // Given + const string selectFromSystemLocalStatement = "SELECT * FROM system.local;"; - // When - var execResult = await _cassandraContainer.ExecScriptAsync(selectFromSystemLocalStatement) - .ConfigureAwait(true); + // When + var execResult = await _cassandraContainer.ExecScriptAsync(selectFromSystemLocalStatement) + .ConfigureAwait(true); - // Then - Assert.True(0L.Equals(execResult.ExitCode), execResult.Stderr); - Assert.NotEmpty(execResult.Stdout); - Assert.Empty(execResult.Stderr); + // Then + Assert.True(0L.Equals(execResult.ExitCode), execResult.Stderr); + Assert.Empty(execResult.Stderr); } - } -} +} \ No newline at end of file diff --git a/tests/Testcontainers.Cassandra.Tests/Testcontainers.Cassandra.Tests.csproj b/tests/Testcontainers.Cassandra.Tests/Testcontainers.Cassandra.Tests.csproj index 268dc4deb..467cd3d93 100644 --- a/tests/Testcontainers.Cassandra.Tests/Testcontainers.Cassandra.Tests.csproj +++ b/tests/Testcontainers.Cassandra.Tests/Testcontainers.Cassandra.Tests.csproj @@ -9,10 +9,10 @@ - + - - + + - + \ No newline at end of file diff --git a/tests/Testcontainers.Cassandra.Tests/Usings.cs b/tests/Testcontainers.Cassandra.Tests/Usings.cs index 25e8a9661..2d0caa4a3 100644 --- a/tests/Testcontainers.Cassandra.Tests/Usings.cs +++ b/tests/Testcontainers.Cassandra.Tests/Usings.cs @@ -1,5 +1,6 @@ global using System.Linq; +global using System.Collections.Immutable; global using System.Threading.Tasks; global using Cassandra; global using DotNet.Testcontainers.Commons; -global using Xunit; +global using Xunit; \ No newline at end of file From b430da817e0030bb235f732595a5fd3141f22a52 Mon Sep 17 00:00:00 2001 From: Gavin de Kock Date: Sun, 16 Feb 2025 14:29:11 +0000 Subject: [PATCH 5/6] Implemented the GetConnectionString --- .../CassandraContainer.cs | 18 +++++++----------- src/Testcontainers.Cassandra/Usings.cs | 4 +++- .../CassandraContainerTest.cs | 6 +++--- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/Testcontainers.Cassandra/CassandraContainer.cs b/src/Testcontainers.Cassandra/CassandraContainer.cs index 52ab289fc..f662e7596 100644 --- a/src/Testcontainers.Cassandra/CassandraContainer.cs +++ b/src/Testcontainers.Cassandra/CassandraContainer.cs @@ -13,22 +13,18 @@ public CassandraContainer(CassandraConfiguration configuration) _configuration = configuration; } - /// - /// Gets the Cassandra contact point. - /// - /// The Cassandra contact point. - public IPEndPoint GetContactPoint() - { - return new IPEndPoint(Dns.GetHostAddresses(Hostname)[0], GetMappedPublicPort(CassandraBuilder.CqlPort)); - } - /// /// Gets the Cassandra connection string. /// /// The Cassandra connection string. public string GetConnectionString() { - throw new NotImplementedException(); + var properties = new Dictionary + { + { "Contact Points", Hostname }, + { "Port", GetMappedPublicPort(CassandraBuilder.CqlPort).ToString() }, + }; + return string.Join(";", properties.Select(property => string.Join("=", property.Key, property.Value))); } /// @@ -47,4 +43,4 @@ await CopyAsync(Encoding.Default.GetBytes(scriptContent), scriptFilePath, Unix.F return await ExecAsync(new[] { "cqlsh", "--file", scriptFilePath }, ct) .ConfigureAwait(false); } -} \ No newline at end of file +} diff --git a/src/Testcontainers.Cassandra/Usings.cs b/src/Testcontainers.Cassandra/Usings.cs index 98a608e61..d26a2b28f 100644 --- a/src/Testcontainers.Cassandra/Usings.cs +++ b/src/Testcontainers.Cassandra/Usings.cs @@ -2,10 +2,12 @@ global using System.IO; global using System.Net; global using System.Text; +global using System.Linq; global using System.Threading; global using System.Threading.Tasks; +global using System.Collections.Generic; 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 +global using JetBrains.Annotations; diff --git a/tests/Testcontainers.Cassandra.Tests/CassandraContainerTest.cs b/tests/Testcontainers.Cassandra.Tests/CassandraContainerTest.cs index a295ac29d..063db3a91 100644 --- a/tests/Testcontainers.Cassandra.Tests/CassandraContainerTest.cs +++ b/tests/Testcontainers.Cassandra.Tests/CassandraContainerTest.cs @@ -19,7 +19,7 @@ public Task DisposeAsync() public void ConnectionStateReturnsOpen() { // Given - using var cluster = Cluster.Builder().AddContactPoint(_cassandraContainer.GetContactPoint()).Build(); + using var cluster = Cluster.Builder().WithConnectionString(_cassandraContainer.GetConnectionString()).Build(); // When using var session = cluster.Connect(); @@ -35,7 +35,7 @@ public void DriverExecutesCqlStatementAndReturnResult() // Given const string selectFromSystemLocalStatement = "SELECT * FROM system.local WHERE key = ?;"; - using var cluster = Cluster.Builder().AddContactPoint(_cassandraContainer.GetContactPoint()).Build(); + using var cluster = Cluster.Builder().WithConnectionString(_cassandraContainer.GetConnectionString()).Build(); // When using var session = cluster.Connect(); @@ -66,4 +66,4 @@ public async Task ExecScriptAsyncReturnsSuccess() Assert.True(0L.Equals(execResult.ExitCode), execResult.Stderr); Assert.Empty(execResult.Stderr); } -} \ No newline at end of file +} From 7aa69f9d26512a84e0932180ae168dbd8deb4ade Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Mon, 17 Feb 2025 17:19:32 +0100 Subject: [PATCH 6/6] chore: Test ADO.NET connection --- src/Testcontainers.Cassandra/CassandraContainer.cs | 13 ++++--------- src/Testcontainers.Cassandra/Usings.cs | 3 +-- .../CassandraContainerTest.cs | 10 +++++----- tests/Testcontainers.Cassandra.Tests/Usings.cs | 6 ++++-- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/Testcontainers.Cassandra/CassandraContainer.cs b/src/Testcontainers.Cassandra/CassandraContainer.cs index f662e7596..d9fcd7557 100644 --- a/src/Testcontainers.Cassandra/CassandraContainer.cs +++ b/src/Testcontainers.Cassandra/CassandraContainer.cs @@ -4,13 +4,10 @@ [PublicAPI] public sealed class CassandraContainer : DockerContainer, IDatabaseContainer { - private readonly CassandraConfiguration _configuration; - /// public CassandraContainer(CassandraConfiguration configuration) : base(configuration) { - _configuration = configuration; } /// @@ -19,11 +16,9 @@ public CassandraContainer(CassandraConfiguration configuration) /// The Cassandra connection string. public string GetConnectionString() { - var properties = new Dictionary - { - { "Contact Points", Hostname }, - { "Port", GetMappedPublicPort(CassandraBuilder.CqlPort).ToString() }, - }; + var properties = new Dictionary(); + properties.Add("Contact Points", Hostname); + properties.Add("Port", GetMappedPublicPort(CassandraBuilder.CqlPort).ToString()); return string.Join(";", properties.Select(property => string.Join("=", property.Key, property.Value))); } @@ -43,4 +38,4 @@ await CopyAsync(Encoding.Default.GetBytes(scriptContent), scriptFilePath, Unix.F return await ExecAsync(new[] { "cqlsh", "--file", scriptFilePath }, ct) .ConfigureAwait(false); } -} +} \ No newline at end of file diff --git a/src/Testcontainers.Cassandra/Usings.cs b/src/Testcontainers.Cassandra/Usings.cs index d26a2b28f..191eb3bce 100644 --- a/src/Testcontainers.Cassandra/Usings.cs +++ b/src/Testcontainers.Cassandra/Usings.cs @@ -1,6 +1,5 @@ global using System; global using System.IO; -global using System.Net; global using System.Text; global using System.Linq; global using System.Threading; @@ -10,4 +9,4 @@ global using DotNet.Testcontainers.Builders; global using DotNet.Testcontainers.Configurations; global using DotNet.Testcontainers.Containers; -global using JetBrains.Annotations; +global using JetBrains.Annotations; \ No newline at end of file diff --git a/tests/Testcontainers.Cassandra.Tests/CassandraContainerTest.cs b/tests/Testcontainers.Cassandra.Tests/CassandraContainerTest.cs index 063db3a91..0af198beb 100644 --- a/tests/Testcontainers.Cassandra.Tests/CassandraContainerTest.cs +++ b/tests/Testcontainers.Cassandra.Tests/CassandraContainerTest.cs @@ -19,18 +19,18 @@ public Task DisposeAsync() public void ConnectionStateReturnsOpen() { // Given - using var cluster = Cluster.Builder().WithConnectionString(_cassandraContainer.GetConnectionString()).Build(); + using DbConnection connection = new CqlConnection(_cassandraContainer.GetConnectionString()); // When - using var session = cluster.Connect(); + connection.Open(); // Then - Assert.True(session.GetState().GetConnectedHosts().Single().IsUp); + Assert.Equal(ConnectionState.Open, connection.State); } [Fact] [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))] - public void DriverExecutesCqlStatementAndReturnResult() + public void ExecuteCqlStatementReturnsExpectedResult() { // Given const string selectFromSystemLocalStatement = "SELECT * FROM system.local WHERE key = ?;"; @@ -66,4 +66,4 @@ public async Task ExecScriptAsyncReturnsSuccess() Assert.True(0L.Equals(execResult.ExitCode), execResult.Stderr); Assert.Empty(execResult.Stderr); } -} +} \ No newline at end of file diff --git a/tests/Testcontainers.Cassandra.Tests/Usings.cs b/tests/Testcontainers.Cassandra.Tests/Usings.cs index 2d0caa4a3..cb1d4b9d6 100644 --- a/tests/Testcontainers.Cassandra.Tests/Usings.cs +++ b/tests/Testcontainers.Cassandra.Tests/Usings.cs @@ -1,6 +1,8 @@ -global using System.Linq; -global using System.Collections.Immutable; +global using System.Collections.Immutable; +global using System.Data; +global using System.Data.Common; global using System.Threading.Tasks; global using Cassandra; +global using Cassandra.Data; global using DotNet.Testcontainers.Commons; global using Xunit; \ No newline at end of file