From d30f277047c538d994cb0ed61be8fd055c81f104 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Fri, 8 Aug 2025 22:44:17 +0100 Subject: [PATCH 1/3] feat: Add Valkey module support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Testcontainers module for Valkey, a Redis-compatible in-memory data store. Includes ValkeyContainer implementation with connection string support and comprehensive tests. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- Testcontainers.sln | 14 ++++ .../Testcontainers.Valkey.csproj | 12 ++++ src/Testcontainers.Valkey/Usings.cs | 11 ++++ src/Testcontainers.Valkey/ValkeyBuilder.cs | 66 +++++++++++++++++++ .../ValkeyConfiguration.cs | 53 +++++++++++++++ src/Testcontainers.Valkey/ValkeyContainer.cs | 41 ++++++++++++ .../Testcontainers.Valkey.Tests.csproj | 19 ++++++ tests/Testcontainers.Valkey.Tests/Usings.cs | 4 ++ .../ValkeyContainerTest.cs | 61 +++++++++++++++++ 9 files changed, 281 insertions(+) create mode 100644 src/Testcontainers.Valkey/Testcontainers.Valkey.csproj create mode 100644 src/Testcontainers.Valkey/Usings.cs create mode 100644 src/Testcontainers.Valkey/ValkeyBuilder.cs create mode 100644 src/Testcontainers.Valkey/ValkeyConfiguration.cs create mode 100644 src/Testcontainers.Valkey/ValkeyContainer.cs create mode 100644 tests/Testcontainers.Valkey.Tests/Testcontainers.Valkey.Tests.csproj create mode 100644 tests/Testcontainers.Valkey.Tests/Usings.cs create mode 100644 tests/Testcontainers.Valkey.Tests/ValkeyContainerTest.cs diff --git a/Testcontainers.sln b/Testcontainers.sln index e09e2b093..7c12bf125 100644 --- a/Testcontainers.sln +++ b/Testcontainers.sln @@ -111,6 +111,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Redis", "src EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Redpanda", "src\Testcontainers.Redpanda\Testcontainers.Redpanda.csproj", "{45D6F69C-4D87-4130-AA90-0DB2F7460DAE}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Valkey", "src\Testcontainers.Valkey\Testcontainers.Valkey.csproj", "{E91FFC43-082A-42DA-AF40-97C49D4F8C3C}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.ServiceBus", "src\Testcontainers.ServiceBus\Testcontainers.ServiceBus.csproj", "{2E39E532-B81E-4B48-A004-FAE18EDF9E79}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Sftp", "src\Testcontainers.Sftp\Testcontainers.Sftp.csproj", "{7D5C6816-0DD2-4E13-A585-033B5D3C80D5}" @@ -239,6 +241,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Redis.Tests" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Redpanda.Tests", "tests\Testcontainers.Redpanda.Tests\Testcontainers.Redpanda.Tests.csproj", "{867BD04E-4670-4FBA-98D5-9F83220E6DFB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Valkey.Tests", "tests\Testcontainers.Valkey.Tests\Testcontainers.Valkey.Tests.csproj", "{7A1885A8-291B-49D4-81A6-5644281C5A6E}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.ResourceReaper.Tests", "tests\Testcontainers.ResourceReaper.Tests\Testcontainers.ResourceReaper.Tests.csproj", "{9E8E6AA5-65D1-498F-BEAB-BA34723A0050}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.ServiceBus.Tests", "tests\Testcontainers.ServiceBus.Tests\Testcontainers.ServiceBus.Tests.csproj", "{232DD918-46ED-4BA8-B383-1A9146D83064}" @@ -459,6 +463,10 @@ Global {45D6F69C-4D87-4130-AA90-0DB2F7460DAE}.Debug|Any CPU.Build.0 = Debug|Any CPU {45D6F69C-4D87-4130-AA90-0DB2F7460DAE}.Release|Any CPU.ActiveCfg = Release|Any CPU {45D6F69C-4D87-4130-AA90-0DB2F7460DAE}.Release|Any CPU.Build.0 = Release|Any CPU + {E91FFC43-082A-42DA-AF40-97C49D4F8C3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E91FFC43-082A-42DA-AF40-97C49D4F8C3C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E91FFC43-082A-42DA-AF40-97C49D4F8C3C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E91FFC43-082A-42DA-AF40-97C49D4F8C3C}.Release|Any CPU.Build.0 = Release|Any CPU {2E39E532-B81E-4B48-A004-FAE18EDF9E79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2E39E532-B81E-4B48-A004-FAE18EDF9E79}.Debug|Any CPU.Build.0 = Debug|Any CPU {2E39E532-B81E-4B48-A004-FAE18EDF9E79}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -715,6 +723,10 @@ Global {867BD04E-4670-4FBA-98D5-9F83220E6DFB}.Debug|Any CPU.Build.0 = Debug|Any CPU {867BD04E-4670-4FBA-98D5-9F83220E6DFB}.Release|Any CPU.ActiveCfg = Release|Any CPU {867BD04E-4670-4FBA-98D5-9F83220E6DFB}.Release|Any CPU.Build.0 = Release|Any CPU + {7A1885A8-291B-49D4-81A6-5644281C5A6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7A1885A8-291B-49D4-81A6-5644281C5A6E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7A1885A8-291B-49D4-81A6-5644281C5A6E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7A1885A8-291B-49D4-81A6-5644281C5A6E}.Release|Any CPU.Build.0 = Release|Any CPU {9E8E6AA5-65D1-498F-BEAB-BA34723A0050}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9E8E6AA5-65D1-498F-BEAB-BA34723A0050}.Debug|Any CPU.Build.0 = Debug|Any CPU {9E8E6AA5-65D1-498F-BEAB-BA34723A0050}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -805,6 +817,7 @@ Global {F6394475-D6F1-46E2-81BF-4BA78A40B878} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} {BFDA179A-40EB-4CEB-B8E9-0DF32C65E2C5} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} {45D6F69C-4D87-4130-AA90-0DB2F7460DAE} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} + {E91FFC43-082A-42DA-AF40-97C49D4F8C3C} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} {2E39E532-B81E-4B48-A004-FAE18EDF9E79} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} {7D5C6816-0DD2-4E13-A585-033B5D3C80D5} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} {E044A94A-3081-4EE4-8DC6-81601F96DA14} = {673F23AE-7694-4BB9-ABD4-136D6C13634E} @@ -869,6 +882,7 @@ Global {D53726B6-5447-47E6-B881-A44EFF6E5534} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {31EE94A0-E721-4073-B6F1-DD912D004DEF} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {867BD04E-4670-4FBA-98D5-9F83220E6DFB} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} + {7A1885A8-291B-49D4-81A6-5644281C5A6E} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {9E8E6AA5-65D1-498F-BEAB-BA34723A0050} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {232DD918-46ED-4BA8-B383-1A9146D83064} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} {B73C3CC0-9F16-4B34-92BE-6EC0853912C5} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF} diff --git a/src/Testcontainers.Valkey/Testcontainers.Valkey.csproj b/src/Testcontainers.Valkey/Testcontainers.Valkey.csproj new file mode 100644 index 000000000..9a25b9c4d --- /dev/null +++ b/src/Testcontainers.Valkey/Testcontainers.Valkey.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.Valkey/Usings.cs b/src/Testcontainers.Valkey/Usings.cs new file mode 100644 index 000000000..6fe3559a7 --- /dev/null +++ b/src/Testcontainers.Valkey/Usings.cs @@ -0,0 +1,11 @@ +global using System; +global using System.IO; +global using System.Text; +global using System.Threading; +global using System.Threading.Tasks; +global using Docker.DotNet.Models; +global using DotNet.Testcontainers; +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 diff --git a/src/Testcontainers.Valkey/ValkeyBuilder.cs b/src/Testcontainers.Valkey/ValkeyBuilder.cs new file mode 100644 index 000000000..a37d9ee96 --- /dev/null +++ b/src/Testcontainers.Valkey/ValkeyBuilder.cs @@ -0,0 +1,66 @@ +namespace Testcontainers.Valkey; + +/// +[PublicAPI] +public sealed class ValkeyBuilder : ContainerBuilder +{ + public const string ValkeyImage = "valkey/valkey:8.1"; + + public const ushort ValkeyPort = 6379; + + /// + /// Initializes a new instance of the class. + /// + public ValkeyBuilder() + : this(new ValkeyConfiguration()) + { + DockerResourceConfiguration = Init().DockerResourceConfiguration; + } + + /// + /// Initializes a new instance of the class. + /// + /// The Docker resource configuration. + private ValkeyBuilder(ValkeyConfiguration resourceConfiguration) + : base(resourceConfiguration) + { + DockerResourceConfiguration = resourceConfiguration; + } + + /// + protected override ValkeyConfiguration DockerResourceConfiguration { get; } + + /// + public override ValkeyContainer Build() + { + Validate(); + return new ValkeyContainer(DockerResourceConfiguration); + } + + /// + protected override ValkeyBuilder Init() + { + return base.Init() + .WithImage(ValkeyImage) + .WithPortBinding(ValkeyPort, true) + .WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged("Ready to accept connections")); + } + + /// + protected override ValkeyBuilder Clone(IResourceConfiguration resourceConfiguration) + { + return Merge(DockerResourceConfiguration, new ValkeyConfiguration(resourceConfiguration)); + } + + /// + protected override ValkeyBuilder Clone(IContainerConfiguration resourceConfiguration) + { + return Merge(DockerResourceConfiguration, new ValkeyConfiguration(resourceConfiguration)); + } + + /// + protected override ValkeyBuilder Merge(ValkeyConfiguration oldValue, ValkeyConfiguration newValue) + { + return new ValkeyBuilder(new ValkeyConfiguration(oldValue, newValue)); + } +} \ No newline at end of file diff --git a/src/Testcontainers.Valkey/ValkeyConfiguration.cs b/src/Testcontainers.Valkey/ValkeyConfiguration.cs new file mode 100644 index 000000000..8c0f8308b --- /dev/null +++ b/src/Testcontainers.Valkey/ValkeyConfiguration.cs @@ -0,0 +1,53 @@ +namespace Testcontainers.Valkey; + +/// +[PublicAPI] +public sealed class ValkeyConfiguration : ContainerConfiguration +{ + /// + /// Initializes a new instance of the class. + /// + public ValkeyConfiguration() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The Docker resource configuration. + public ValkeyConfiguration(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 ValkeyConfiguration(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 ValkeyConfiguration(ValkeyConfiguration resourceConfiguration) + : this(new ValkeyConfiguration(), 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 ValkeyConfiguration(ValkeyConfiguration oldValue, ValkeyConfiguration newValue) + : base(oldValue, newValue) + { + } +} \ No newline at end of file diff --git a/src/Testcontainers.Valkey/ValkeyContainer.cs b/src/Testcontainers.Valkey/ValkeyContainer.cs new file mode 100644 index 000000000..c7067b719 --- /dev/null +++ b/src/Testcontainers.Valkey/ValkeyContainer.cs @@ -0,0 +1,41 @@ +namespace Testcontainers.Valkey; + +/// +[PublicAPI] +public sealed class ValkeyContainer : DockerContainer +{ + /// + /// Initializes a new instance of the class. + /// + /// The container configuration. + public ValkeyContainer(ValkeyConfiguration configuration) + : base(configuration) + { + } + + /// + /// Gets the Valkey connection string. + /// + /// The Valkey connection string. + public string GetConnectionString() + { + return new UriBuilder("valkey", Hostname, GetMappedPublicPort(ValkeyBuilder.ValkeyPort)).Uri.Authority; + } + + /// + /// Executes the Lua script in the Valkey container. + /// + /// The content of the Lua script to execute. + /// Cancellation token. + /// Task that completes when the Lua 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[] { "valkey-cli", "--eval", scriptFilePath, "0" }, ct) + .ConfigureAwait(false); + } +} \ No newline at end of file diff --git a/tests/Testcontainers.Valkey.Tests/Testcontainers.Valkey.Tests.csproj b/tests/Testcontainers.Valkey.Tests/Testcontainers.Valkey.Tests.csproj new file mode 100644 index 000000000..9ad23adf1 --- /dev/null +++ b/tests/Testcontainers.Valkey.Tests/Testcontainers.Valkey.Tests.csproj @@ -0,0 +1,19 @@ + + + net9.0 + false + false + Exe + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Testcontainers.Valkey.Tests/Usings.cs b/tests/Testcontainers.Valkey.Tests/Usings.cs new file mode 100644 index 000000000..4e7182108 --- /dev/null +++ b/tests/Testcontainers.Valkey.Tests/Usings.cs @@ -0,0 +1,4 @@ +global using System.Threading.Tasks; +global using DotNet.Testcontainers.Commons; +global using StackExchange.Redis; +global using Xunit; \ No newline at end of file diff --git a/tests/Testcontainers.Valkey.Tests/ValkeyContainerTest.cs b/tests/Testcontainers.Valkey.Tests/ValkeyContainerTest.cs new file mode 100644 index 000000000..693e98e9a --- /dev/null +++ b/tests/Testcontainers.Valkey.Tests/ValkeyContainerTest.cs @@ -0,0 +1,61 @@ +namespace Testcontainers.Valkey; + +public sealed class ValkeyContainerTest : IAsyncLifetime +{ + private readonly ValkeyContainer _valkeyContainer = new ValkeyBuilder().Build(); + + public async ValueTask InitializeAsync() + { + await _valkeyContainer.StartAsync() + .ConfigureAwait(false); + } + + public ValueTask DisposeAsync() + { + return _valkeyContainer.DisposeAsync(); + } + + [Fact] + [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))] + public void ConnectionStateReturnsOpen() + { + using var connection = ConnectionMultiplexer.Connect(_valkeyContainer.GetConnectionString()); + Assert.True(connection.IsConnected); + } + + [Fact] + [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))] + public void Can_Set_And_Retrieve_Key() + { + using var connection = ConnectionMultiplexer.Connect(_valkeyContainer.GetConnectionString()); + + var db = connection.GetDatabase(); + const string key = "test-key"; + const string value = "test-value"; + + Assert.True(db.StringGet(key).IsNull); + + db.StringSet(key, value); + + var retrievedValue = db.StringGet(key); + + Assert.Equal(value, retrievedValue); + } + + [Fact] + [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))] + public async Task ExecScriptReturnsSuccessful() + { + // Given + const string scriptContent = "return 'Hello, Valkey!'"; + + // When + var execResult = await _valkeyContainer.ExecScriptAsync(scriptContent, TestContext.Current.CancellationToken) + .ConfigureAwait(true); + + // Then + Assert.True(0L.Equals(execResult.ExitCode), execResult.Stderr); + Assert.True("Hello, Valkey!\n".Equals(execResult.Stdout), execResult.Stdout); + Assert.Empty(execResult.Stderr); + } +} From 6060f50d9f6bd921cd2b7d317545f833b616fdc1 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Fri, 8 Aug 2025 22:58:53 +0100 Subject: [PATCH 2/3] feat: Update ValkeyContainer tests to use async methods --- .../ValkeyContainerTest.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tests/Testcontainers.Valkey.Tests/ValkeyContainerTest.cs b/tests/Testcontainers.Valkey.Tests/ValkeyContainerTest.cs index 693e98e9a..c5aa69817 100644 --- a/tests/Testcontainers.Valkey.Tests/ValkeyContainerTest.cs +++ b/tests/Testcontainers.Valkey.Tests/ValkeyContainerTest.cs @@ -17,29 +17,30 @@ public ValueTask DisposeAsync() [Fact] [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))] - public void ConnectionStateReturnsOpen() + public async Task ConnectionStateReturnsOpen() { - using var connection = ConnectionMultiplexer.Connect(_valkeyContainer.GetConnectionString()); + using var connection = await ConnectionMultiplexer.ConnectAsync(_valkeyContainer.GetConnectionString()); Assert.True(connection.IsConnected); } [Fact] [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))] - public void Can_Set_And_Retrieve_Key() + public async Task Can_Set_And_Retrieve_Key() { - using var connection = ConnectionMultiplexer.Connect(_valkeyContainer.GetConnectionString()); + using var connection = await ConnectionMultiplexer.ConnectAsync(_valkeyContainer.GetConnectionString()); var db = connection.GetDatabase(); const string key = "test-key"; const string value = "test-value"; - Assert.True(db.StringGet(key).IsNull); + var redisValue = await db.StringGetAsync(key); + Assert.True(redisValue.IsNull); - db.StringSet(key, value); + await db.StringSetAsync(key, value); - var retrievedValue = db.StringGet(key); + var updatedValue = await db.StringGetAsync(key); - Assert.Equal(value, retrievedValue); + Assert.Equal(value, updatedValue); } [Fact] From 76117148c28ee1ed39509f4329ab47528d337166 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Fri, 8 Aug 2025 23:29:40 +0100 Subject: [PATCH 3/3] docs: Add CI/CD pipeline and documentation for Valkey module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Testcontainers.Valkey to CI/CD test matrix in workflow - Create comprehensive documentation for Valkey module - Add Valkey to modules index with Docker image and links 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .github/workflows/cicd.yml | 1 + docs/modules/index.md | 1 + docs/modules/valkey.md | 52 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 docs/modules/valkey.md diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index e12f947b2..c87505494 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -92,6 +92,7 @@ jobs: { name: "Testcontainers.ServiceBus", runs-on: "ubuntu-22.04" }, { name: "Testcontainers.Sftp", runs-on: "ubuntu-22.04" }, { name: "Testcontainers.Typesense", runs-on: "ubuntu-22.04" }, + { name: "Testcontainers.Valkey", runs-on: "ubuntu-22.04" }, { name: "Testcontainers.Weaviate", runs-on: "ubuntu-22.04" }, { name: "Testcontainers.WebDriver", runs-on: "ubuntu-22.04" }, { name: "Testcontainers.Xunit", runs-on: "ubuntu-22.04" }, diff --git a/docs/modules/index.md b/docs/modules/index.md index 254a2d9fe..2043b2f24 100644 --- a/docs/modules/index.md +++ b/docs/modules/index.md @@ -71,6 +71,7 @@ await moduleNameContainer.StartAsync(); | Sftp | `atmoz/sftp:alpine` | [NuGet](https://www.nuget.org/packages/Testcontainers.Sftp) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Sftp) | | SQL Server | `mcr.microsoft.com/mssql/server:2022-CU14-ubuntu-22.04` | [NuGet](https://www.nuget.org/packages/Testcontainers.MsSql) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.MsSql) | | Typesense | `typesense/typesense:28.0` | [NuGet](https://www.nuget.org/packages/Testcontainers.Typesense) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Typesense) | +| Valkey | `valkey/valkey:8.0-alpine` | [NuGet](https://www.nuget.org/packages/Testcontainers.Valkey) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Valkey) | | Weaviate | `semitechnologies/weaviate:1.26.14` | [NuGet](https://www.nuget.org/packages/Testcontainers.Weaviate) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Weaviate) | | WebDriver | `selenium/standalone-chrome:110.0` | [NuGet](https://www.nuget.org/packages/Testcontainers.WebDriver) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.WebDriver) | diff --git a/docs/modules/valkey.md b/docs/modules/valkey.md new file mode 100644 index 000000000..ddd611a15 --- /dev/null +++ b/docs/modules/valkey.md @@ -0,0 +1,52 @@ +# Valkey + +[Valkey](https://valkey.io/) is an open-source, high-performance data structure server that serves as a drop-in replacement for Redis. It supports various data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes, and streams. + +Add the following dependency to your project file: + +```shell title="NuGet" +dotnet add package Testcontainers.Valkey +``` + +You can start a Valkey container instance from any .NET application. Here, we create different container instances and pass them to the base test class. This allows us to test different configurations. + +=== "Create Container Instance" + ```csharp + --8<-- "tests/Testcontainers.Valkey.Tests/ValkeyContainerTest.cs:CreateValkeyContainer" + ``` + +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. + +=== "Usage Example" + ```csharp + --8<-- "tests/Testcontainers.Valkey.Tests/ValkeyContainerTest.cs:UseValkeyContainer" + ``` + +The test example uses the following NuGet dependencies: + +=== "Package References" + ```xml + --8<-- "tests/Testcontainers.Valkey.Tests/Testcontainers.Valkey.Tests.csproj:PackageReferences" + ``` + +To execute the tests, use the command `dotnet test` from a terminal. + +--8<-- "docs/modules/_call_out_test_projects.txt" + +## Connection String + +The Valkey module provides a `GetConnectionString()` method that returns a connection string compatible with StackExchange.Redis and other Redis client libraries that support Valkey: + +```csharp +var connectionString = _valkeyContainer.GetConnectionString(); +using var connection = await ConnectionMultiplexer.ConnectAsync(connectionString); +``` + +## Executing Scripts + +You can execute Lua scripts against the Valkey container using the standard Redis client libraries: + +```csharp +const string scriptContent = "return 'Hello, Valkey!'"; +var execResult = await _valkeyContainer.ExecScriptAsync(scriptContent); +``` \ No newline at end of file