Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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" },
Expand Down
14 changes: 14 additions & 0 deletions Testcontainers.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
Expand Down Expand Up @@ -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}"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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}
Expand Down
1 change: 1 addition & 0 deletions docs/modules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) |

Expand Down
52 changes: 52 additions & 0 deletions docs/modules/valkey.md
Original file line number Diff line number Diff line change
@@ -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);
```
12 changes: 12 additions & 0 deletions src/Testcontainers.Valkey/Testcontainers.Valkey.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0;net9.0;netstandard2.0;netstandard2.1</TargetFrameworks>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" VersionOverride="2023.3.0" PrivateAssets="All"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../Testcontainers/Testcontainers.csproj"/>
</ItemGroup>
</Project>
11 changes: 11 additions & 0 deletions src/Testcontainers.Valkey/Usings.cs
Original file line number Diff line number Diff line change
@@ -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;
66 changes: 66 additions & 0 deletions src/Testcontainers.Valkey/ValkeyBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
namespace Testcontainers.Valkey;

/// <inheritdoc cref="ContainerBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}" />
[PublicAPI]
public sealed class ValkeyBuilder : ContainerBuilder<ValkeyBuilder, ValkeyContainer, ValkeyConfiguration>
{
public const string ValkeyImage = "valkey/valkey:8.1";

public const ushort ValkeyPort = 6379;

/// <summary>
/// Initializes a new instance of the <see cref="ValkeyBuilder" /> class.
/// </summary>
public ValkeyBuilder()
: this(new ValkeyConfiguration())
{
DockerResourceConfiguration = Init().DockerResourceConfiguration;
}

/// <summary>
/// Initializes a new instance of the <see cref="ValkeyBuilder" /> class.
/// </summary>
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
private ValkeyBuilder(ValkeyConfiguration resourceConfiguration)
: base(resourceConfiguration)
{
DockerResourceConfiguration = resourceConfiguration;
}

/// <inheritdoc />
protected override ValkeyConfiguration DockerResourceConfiguration { get; }

/// <inheritdoc />
public override ValkeyContainer Build()
{
Validate();
return new ValkeyContainer(DockerResourceConfiguration);
}

/// <inheritdoc />
protected override ValkeyBuilder Init()
{
return base.Init()
.WithImage(ValkeyImage)
.WithPortBinding(ValkeyPort, true)
.WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged("Ready to accept connections"));
}

/// <inheritdoc />
protected override ValkeyBuilder Clone(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
{
return Merge(DockerResourceConfiguration, new ValkeyConfiguration(resourceConfiguration));
}

/// <inheritdoc />
protected override ValkeyBuilder Clone(IContainerConfiguration resourceConfiguration)
{
return Merge(DockerResourceConfiguration, new ValkeyConfiguration(resourceConfiguration));
}

/// <inheritdoc />
protected override ValkeyBuilder Merge(ValkeyConfiguration oldValue, ValkeyConfiguration newValue)
{
return new ValkeyBuilder(new ValkeyConfiguration(oldValue, newValue));
}
}
53 changes: 53 additions & 0 deletions src/Testcontainers.Valkey/ValkeyConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
namespace Testcontainers.Valkey;

/// <inheritdoc cref="ContainerConfiguration" />
[PublicAPI]
public sealed class ValkeyConfiguration : ContainerConfiguration
{
/// <summary>
/// Initializes a new instance of the <see cref="ValkeyConfiguration" /> class.
/// </summary>
public ValkeyConfiguration()
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ValkeyConfiguration" /> class.
/// </summary>
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
public ValkeyConfiguration(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
: base(resourceConfiguration)
{
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
}

/// <summary>
/// Initializes a new instance of the <see cref="ValkeyConfiguration" /> class.
/// </summary>
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
public ValkeyConfiguration(IContainerConfiguration resourceConfiguration)
: base(resourceConfiguration)
{
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
}

/// <summary>
/// Initializes a new instance of the <see cref="ValkeyConfiguration" /> class.
/// </summary>
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
public ValkeyConfiguration(ValkeyConfiguration resourceConfiguration)
: this(new ValkeyConfiguration(), resourceConfiguration)
{
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
}

/// <summary>
/// Initializes a new instance of the <see cref="ValkeyConfiguration" /> class.
/// </summary>
/// <param name="oldValue">The old Docker resource configuration.</param>
/// <param name="newValue">The new Docker resource configuration.</param>
public ValkeyConfiguration(ValkeyConfiguration oldValue, ValkeyConfiguration newValue)
: base(oldValue, newValue)
{
}
}
41 changes: 41 additions & 0 deletions src/Testcontainers.Valkey/ValkeyContainer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
namespace Testcontainers.Valkey;

/// <inheritdoc cref="DockerContainer" />
[PublicAPI]
public sealed class ValkeyContainer : DockerContainer
{
/// <summary>
/// Initializes a new instance of the <see cref="ValkeyContainer" /> class.
/// </summary>
/// <param name="configuration">The container configuration.</param>
public ValkeyContainer(ValkeyConfiguration configuration)
: base(configuration)
{
}

/// <summary>
/// Gets the Valkey connection string.
/// </summary>
/// <returns>The Valkey connection string.</returns>
public string GetConnectionString()
{
return new UriBuilder("valkey", Hostname, GetMappedPublicPort(ValkeyBuilder.ValkeyPort)).Uri.Authority;
}

/// <summary>
/// Executes the Lua script in the Valkey container.
/// </summary>
/// <param name="scriptContent">The content of the Lua script to execute.</param>
/// <param name="ct">Cancellation token.</param>
/// <returns>Task that completes when the Lua script has been executed.</returns>
public async Task<ExecResult> 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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net9.0</TargetFrameworks>
<IsPackable>false</IsPackable>
<IsPublishable>false</IsPublishable>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk"/>
<PackageReference Include="coverlet.collector"/>
<PackageReference Include="xunit.runner.visualstudio"/>
<PackageReference Include="xunit.v3"/>
<PackageReference Include="StackExchange.Redis"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../../src/Testcontainers.Valkey/Testcontainers.Valkey.csproj"/>
<ProjectReference Include="../Testcontainers.Commons/Testcontainers.Commons.csproj"/>
</ItemGroup>
</Project>
4 changes: 4 additions & 0 deletions tests/Testcontainers.Valkey.Tests/Usings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
global using System.Threading.Tasks;
global using DotNet.Testcontainers.Commons;
global using StackExchange.Redis;
global using Xunit;
Loading