diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml
index e12f947b2..129fe97c4 100644
--- a/.github/workflows/cicd.yml
+++ b/.github/workflows/cicd.yml
@@ -50,6 +50,7 @@ jobs:
{ name: "Testcontainers.Couchbase", runs-on: "ubuntu-22.04" },
{ name: "Testcontainers.CouchDb", runs-on: "ubuntu-22.04" },
{ name: "Testcontainers.Db2", runs-on: "ubuntu-22.04" },
+ { name: "Testcontainers.DragonflyDb", runs-on: "ubuntu-22.04" },
{ name: "Testcontainers.DynamoDb", runs-on: "ubuntu-22.04" },
{ name: "Testcontainers.Elasticsearch", runs-on: "ubuntu-22.04" },
{ name: "Testcontainers.EventHubs", runs-on: "ubuntu-22.04" },
diff --git a/Testcontainers.sln b/Testcontainers.sln
index e09e2b093..404dd09ba 100644
--- a/Testcontainers.sln
+++ b/Testcontainers.sln
@@ -257,6 +257,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Xunit.Tests"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.XunitV3.Tests", "tests\Testcontainers.XunitV3.Tests\Testcontainers.XunitV3.Tests.csproj", "{B2E8B7FB-7D1E-4DD3-A25E-34DE4386B1EB}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.DragonflyDb", "src\Testcontainers.DragonflyDb\Testcontainers.DragonflyDb.csproj", "{0686A718-3933-D826-BDC5-2F683AB593CD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.DragonflyDb.Tests", "tests\Testcontainers.DragonflyDb.Tests\Testcontainers.DragonflyDb.Tests.csproj", "{546824C2-F360-5F78-1FC6-3D1E191C3FAF}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -751,6 +755,14 @@ Global
{B2E8B7FB-7D1E-4DD3-A25E-34DE4386B1EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2E8B7FB-7D1E-4DD3-A25E-34DE4386B1EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B2E8B7FB-7D1E-4DD3-A25E-34DE4386B1EB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0686A718-3933-D826-BDC5-2F683AB593CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0686A718-3933-D826-BDC5-2F683AB593CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0686A718-3933-D826-BDC5-2F683AB593CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0686A718-3933-D826-BDC5-2F683AB593CD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {546824C2-F360-5F78-1FC6-3D1E191C3FAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {546824C2-F360-5F78-1FC6-3D1E191C3FAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {546824C2-F360-5F78-1FC6-3D1E191C3FAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {546824C2-F360-5F78-1FC6-3D1E191C3FAF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -878,5 +890,10 @@ Global
{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
{E901DF14-6F05-4FC2-825A-3055FAD33561} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
{B2E8B7FB-7D1E-4DD3-A25E-34DE4386B1EB} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
+ {0686A718-3933-D826-BDC5-2F683AB593CD} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
+ {546824C2-F360-5F78-1FC6-3D1E191C3FAF} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {3BA67751-0C2A-4D17-A84E-C0AC59B94254}
EndGlobalSection
EndGlobal
diff --git a/src/Testcontainers.DragonflyDb/.editorconfig b/src/Testcontainers.DragonflyDb/.editorconfig
new file mode 100644
index 000000000..6f066619d
--- /dev/null
+++ b/src/Testcontainers.DragonflyDb/.editorconfig
@@ -0,0 +1 @@
+root = true
\ No newline at end of file
diff --git a/src/Testcontainers.DragonflyDb/DragonflyDbBuilder.cs b/src/Testcontainers.DragonflyDb/DragonflyDbBuilder.cs
new file mode 100644
index 000000000..6da4a80ff
--- /dev/null
+++ b/src/Testcontainers.DragonflyDb/DragonflyDbBuilder.cs
@@ -0,0 +1,66 @@
+namespace Testcontainers.DragonflyDb;
+
+///
+[PublicAPI]
+public sealed class DragonflyDbBuilder : ContainerBuilder
+{
+ public const string DragonflyDbImage = "docker.dragonflydb.io/dragonflydb/dragonfly";
+
+ public const ushort DragonflyDbPort = 6379;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public DragonflyDbBuilder()
+ : this(new DragonflyDbConfiguration())
+ {
+ DockerResourceConfiguration = Init().DockerResourceConfiguration;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The Docker resource configuration.
+ private DragonflyDbBuilder(DragonflyDbConfiguration resourceConfiguration)
+ : base(resourceConfiguration)
+ {
+ DockerResourceConfiguration = resourceConfiguration;
+ }
+
+ ///
+ protected override DragonflyDbConfiguration DockerResourceConfiguration { get; }
+
+ ///
+ public override DragonflyDbContainer Build()
+ {
+ Validate();
+ return new DragonflyDbContainer(DockerResourceConfiguration);
+ }
+
+ ///
+ protected override DragonflyDbBuilder Init()
+ {
+ return base.Init()
+ .WithImage(DragonflyDbImage)
+ .WithPortBinding(DragonflyDbPort, true)
+ .WithWaitStrategy(Wait.ForUnixContainer().UntilCommandIsCompleted("/usr/local/bin/healthcheck.sh"));
+ }
+
+ ///
+ protected override DragonflyDbBuilder Clone(IResourceConfiguration resourceConfiguration)
+ {
+ return Merge(DockerResourceConfiguration, new DragonflyDbConfiguration(resourceConfiguration));
+ }
+
+ ///
+ protected override DragonflyDbBuilder Clone(IContainerConfiguration resourceConfiguration)
+ {
+ return Merge(DockerResourceConfiguration, new DragonflyDbConfiguration(resourceConfiguration));
+ }
+
+ ///
+ protected override DragonflyDbBuilder Merge(DragonflyDbConfiguration oldValue, DragonflyDbConfiguration newValue)
+ {
+ return new DragonflyDbBuilder(new DragonflyDbConfiguration(oldValue, newValue));
+ }
+}
\ No newline at end of file
diff --git a/src/Testcontainers.DragonflyDb/DragonflyDbConfiguration.cs b/src/Testcontainers.DragonflyDb/DragonflyDbConfiguration.cs
new file mode 100644
index 000000000..2b8918876
--- /dev/null
+++ b/src/Testcontainers.DragonflyDb/DragonflyDbConfiguration.cs
@@ -0,0 +1,53 @@
+namespace Testcontainers.DragonflyDb;
+
+///
+[PublicAPI]
+public sealed class DragonflyDbConfiguration : ContainerConfiguration
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public DragonflyDbConfiguration()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The Docker resource configuration.
+ public DragonflyDbConfiguration(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 DragonflyDbConfiguration(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 DragonflyDbConfiguration(DragonflyDbConfiguration resourceConfiguration)
+ : this(new DragonflyDbConfiguration(), 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 DragonflyDbConfiguration(DragonflyDbConfiguration oldValue, DragonflyDbConfiguration newValue)
+ : base(oldValue, newValue)
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/Testcontainers.DragonflyDb/DragonflyDbContainer.cs b/src/Testcontainers.DragonflyDb/DragonflyDbContainer.cs
new file mode 100644
index 000000000..0ff6bd343
--- /dev/null
+++ b/src/Testcontainers.DragonflyDb/DragonflyDbContainer.cs
@@ -0,0 +1,42 @@
+namespace Testcontainers.DragonflyDb;
+
+///
+[PublicAPI]
+public sealed class DragonflyDbContainer : DockerContainer
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The container configuration.
+ public DragonflyDbContainer(DragonflyDbConfiguration configuration)
+ : base(configuration)
+ {
+ }
+
+ ///
+ /// Gets the DragonflyDb connection string.
+ ///
+ /// The DragonflyDb connection string.
+ public string GetConnectionString()
+ {
+ return new UriBuilder("DragonflyDb", Hostname, GetMappedPublicPort(DragonflyDbBuilder.DragonflyDbPort)).Uri.Authority;
+ }
+
+ ///
+ /// Executes the Lua script in the DragonflyDb 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, fileMode: Unix.FileMode644, ct: ct)
+ .ConfigureAwait(false);
+
+ //DragonflyDb uses the same cli as redis
+ return await ExecAsync(new[] { "redis-cli", "--eval", scriptFilePath, "0" }, ct)
+ .ConfigureAwait(false);
+ }
+}
\ No newline at end of file
diff --git a/src/Testcontainers.DragonflyDb/Testcontainers.DragonflyDb.csproj b/src/Testcontainers.DragonflyDb/Testcontainers.DragonflyDb.csproj
new file mode 100644
index 000000000..9a25b9c4d
--- /dev/null
+++ b/src/Testcontainers.DragonflyDb/Testcontainers.DragonflyDb.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.DragonflyDb/Usings.cs b/src/Testcontainers.DragonflyDb/Usings.cs
new file mode 100644
index 000000000..3c22a4545
--- /dev/null
+++ b/src/Testcontainers.DragonflyDb/Usings.cs
@@ -0,0 +1,10 @@
+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.Builders;
+global using DotNet.Testcontainers.Configurations;
+global using DotNet.Testcontainers.Containers;
+global using JetBrains.Annotations;
\ No newline at end of file
diff --git a/tests/Testcontainers.DragonflyDb.Tests/.editorconfig b/tests/Testcontainers.DragonflyDb.Tests/.editorconfig
new file mode 100644
index 000000000..6f066619d
--- /dev/null
+++ b/tests/Testcontainers.DragonflyDb.Tests/.editorconfig
@@ -0,0 +1 @@
+root = true
\ No newline at end of file
diff --git a/tests/Testcontainers.DragonflyDb.Tests/DragonflyDbContainerTest.cs b/tests/Testcontainers.DragonflyDb.Tests/DragonflyDbContainerTest.cs
new file mode 100644
index 000000000..22a8928af
--- /dev/null
+++ b/tests/Testcontainers.DragonflyDb.Tests/DragonflyDbContainerTest.cs
@@ -0,0 +1,60 @@
+namespace Testcontainers.DragonflyDb;
+
+public sealed class DragonflyDbContainerTest : IAsyncLifetime
+{
+ private readonly DragonflyDbContainer _dragonflyDbContainer = new DragonflyDbBuilder().Build();
+
+ public async ValueTask InitializeAsync()
+ {
+ await _dragonflyDbContainer.StartAsync()
+ .ConfigureAwait(false);
+ }
+
+ public ValueTask DisposeAsync()
+ {
+ return _dragonflyDbContainer.DisposeAsync();
+ }
+
+ [Fact]
+ [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
+ public void ConnectionStateReturnsOpen()
+ {
+ using var connection = ConnectionMultiplexer.Connect(_dragonflyDbContainer.GetConnectionString());
+ Assert.True(connection.IsConnected);
+ }
+
+ [Fact]
+ [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
+ public async Task ExecScriptReturnsSuccessful()
+ {
+ // Given
+ const string scriptContent = "return 'Hello, scripting!'";
+
+ // When
+ var execResult = await _dragonflyDbContainer.ExecScriptAsync(scriptContent, TestContext.Current.CancellationToken)
+ .ConfigureAwait(true);
+
+ // Then
+ Assert.Equal(0L, execResult.ExitCode);
+ Assert.Equal("Hello, scripting!\n", execResult.Stdout);
+ Assert.Empty(execResult.Stderr);
+ }
+
+ [Fact]
+ [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
+ public async Task SetAndGetValueReturnsExpected()
+ {
+ // Given
+ using var connection = ConnectionMultiplexer.Connect(_dragonflyDbContainer.GetConnectionString());
+ var database = connection.GetDatabase();
+ const string key = "test-key";
+ const string value = "test-value";
+
+ // When
+ await database.StringSetAsync(key, value);
+ var result = await database.StringGetAsync(key);
+
+ // Then
+ Assert.Equal(value, result);
+ }
+}
\ No newline at end of file
diff --git a/tests/Testcontainers.DragonflyDb.Tests/Testcontainers.DragonflyDb.Tests.csproj b/tests/Testcontainers.DragonflyDb.Tests/Testcontainers.DragonflyDb.Tests.csproj
new file mode 100644
index 000000000..f6412ac5e
--- /dev/null
+++ b/tests/Testcontainers.DragonflyDb.Tests/Testcontainers.DragonflyDb.Tests.csproj
@@ -0,0 +1,19 @@
+
+
+ net9.0
+ false
+ false
+ Exe
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/Testcontainers.DragonflyDb.Tests/Usings.cs b/tests/Testcontainers.DragonflyDb.Tests/Usings.cs
new file mode 100644
index 000000000..4e7182108
--- /dev/null
+++ b/tests/Testcontainers.DragonflyDb.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