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 Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
<PackageVersion Include="Azure.Storage.Blobs" Version="12.29.1"/>
<PackageVersion Include="Azure.Storage.Queues" Version="12.27.1"/>
<PackageVersion Include="CassandraCSharpDriver" Version="3.22.0"/>
<PackageVersion Include="ChromaDotNet.Client" Version="2.14.0"/>
<PackageVersion Include="ClickHouse.Client" Version="7.14.0"/>
<PackageVersion Include="Confluent.Kafka" Version="2.15.0"/>
<PackageVersion Include="Confluent.SchemaRegistry.Serdes.Json" Version="2.15.0"/>
Expand Down
1 change: 1 addition & 0 deletions Testcontainers.dic
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ azurecr
azurite
buildx
capi
chromadb
creds
dind
dockerignore
Expand Down
1 change: 1 addition & 0 deletions Testcontainers.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=azurite/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=buildx/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=capi/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=chromadb/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=creds/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=dind/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=dockerignore/@EntryIndexedValue">True</s:Boolean>
Expand Down
2 changes: 2 additions & 0 deletions Testcontainers.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<Project Path="src/Testcontainers.BigQuery/Testcontainers.BigQuery.csproj"/>
<Project Path="src/Testcontainers.Bigtable/Testcontainers.Bigtable.csproj"/>
<Project Path="src/Testcontainers.Cassandra/Testcontainers.Cassandra.csproj"/>
<Project Path="src/Testcontainers.Chroma/Testcontainers.Chroma.csproj"/>
<Project Path="src/Testcontainers.ClickHouse/Testcontainers.ClickHouse.csproj"/>
<Project Path="src/Testcontainers.CockroachDb/Testcontainers.CockroachDb.csproj"/>
<Project Path="src/Testcontainers.Consul/Testcontainers.Consul.csproj"/>
Expand Down Expand Up @@ -91,6 +92,7 @@
<Project Path="tests/Testcontainers.BigQuery.Tests/Testcontainers.BigQuery.Tests.csproj"/>
<Project Path="tests/Testcontainers.Bigtable.Tests/Testcontainers.Bigtable.Tests.csproj"/>
<Project Path="tests/Testcontainers.Cassandra.Tests/Testcontainers.Cassandra.Tests.csproj"/>
<Project Path="tests/Testcontainers.Chroma.Tests/Testcontainers.Chroma.Tests.csproj"/>
<Project Path="tests/Testcontainers.ClickHouse.Tests/Testcontainers.ClickHouse.Tests.csproj"/>
<Project Path="tests/Testcontainers.CockroachDb.Tests/Testcontainers.CockroachDb.Tests.csproj"/>
<Project Path="tests/Testcontainers.Commons/Testcontainers.Commons.csproj"/>
Expand Down
31 changes: 31 additions & 0 deletions docs/modules/chroma.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Chroma

[Chroma](https://www.trychroma.com/) is an open-source vector database for AI applications. It stores embeddings with their documents and metadata, and finds the nearest ones to a query, through a REST API.

Add the following dependency to your project file:

```shell title="NuGet"
dotnet add package Testcontainers.Chroma
```

You can start a Chroma container instance from any .NET application. This example uses xUnit.net's `IAsyncLifetime` interface to manage the lifecycle of the container. The container is started in the `InitializeAsync` method before the test method runs, ensuring that the environment is ready for testing. After the test completes, the container is removed in the `DisposeAsync` method.

=== "Usage Example"
```csharp
--8<-- "tests/Testcontainers.Chroma.Tests/ChromaDefaultContainerTest.cs:UseChromaContainer"
```

The test example uses the following NuGet dependencies:

=== "Package References"
```xml
--8<-- "tests/Testcontainers.Chroma.Tests/Testcontainers.Chroma.Tests.csproj:PackageReferences"
```

To execute the tests, use the command `dotnet test` from a terminal.

--8<-- "docs/modules/_call_out_test_projects.txt"

## Chroma versions

The container is ready when the heartbeat of the Chroma API answers. Chroma 0.5.16 and later answer the heartbeat of the v2 API, and the earlier releases have only the v1 API, so the module asks both: it works with any Chroma image, whatever its tag.
1 change: 1 addition & 0 deletions docs/modules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ await moduleNameContainer.StartAsync();
| 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` | [NuGet](https://www.nuget.org/packages/Testcontainers.Cassandra) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Cassandra) |
| Chroma | `chromadb/chroma:1.5.9` | [NuGet](https://www.nuget.org/packages/Testcontainers.Chroma) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Chroma) |
| 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) |
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ nav:
- modules/aspire-dashboard.md
- modules/eventhubs.md # Azure
- modules/servicebus.md # Azure
- modules/chroma.md
- modules/clickhouse.md
- modules/db2.md
- modules/elasticsearch.md
Expand Down
1 change: 1 addition & 0 deletions src/Testcontainers.Chroma/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
root = true
124 changes: 124 additions & 0 deletions src/Testcontainers.Chroma/ChromaBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
namespace Testcontainers.Chroma;

/// <inheritdoc cref="ContainerBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}" />
[PublicAPI]
public sealed class ChromaBuilder : ContainerBuilder<ChromaBuilder, ChromaContainer, ChromaConfiguration>
{
[Obsolete("This constant is obsolete and will be removed in the future. Use the constructor with the image parameter instead: https://github.com/testcontainers/testcontainers-dotnet/discussions/1470#discussioncomment-15185721.")]
public const string ChromaImage = "chromadb/chroma:1.5.9";

public const ushort ChromaHttpPort = 8000;

/// <summary>
/// Initializes a new instance of the <see cref="ChromaBuilder" /> class.
/// </summary>
[Obsolete("This parameterless constructor is obsolete and will be removed. Use the constructor with the image parameter instead: https://github.com/testcontainers/testcontainers-dotnet/discussions/1470#discussioncomment-15185721.")]
[ExcludeFromCodeCoverage]
public ChromaBuilder()
: this(ChromaImage)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ChromaBuilder" /> class.
/// </summary>
/// <param name="image">
/// The full Docker image name, including the image repository and tag
/// (e.g., <c>chromadb/chroma:1.5.9</c>).
/// </param>
/// <remarks>
/// Docker image tags available at <see href="https://hub.docker.com/r/chromadb/chroma/tags" />.
/// </remarks>
public ChromaBuilder(string image)
: this(new DockerImage(image))
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ChromaBuilder" /> class.
/// </summary>
/// <param name="image">
/// An <see cref="IImage" /> instance that specifies the Docker image to be used
/// for the container builder configuration.
/// </param>
/// <remarks>
/// Docker image tags available at <see href="https://hub.docker.com/r/chromadb/chroma/tags" />.
/// </remarks>
public ChromaBuilder(IImage image)
: this(new ChromaConfiguration())
{
DockerResourceConfiguration = Init().WithImage(image).DockerResourceConfiguration;
}

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

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

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

/// <inheritdoc />
protected override ChromaBuilder Init()
{
return base.Init()
.WithPortBinding(ChromaHttpPort, true)
.WithConnectionStringProvider(new ChromaConnectionStringProvider())
.WithWaitStrategy(Wait.ForUnixContainer().AddCustomWaitStrategy(new WaitUntil()));
}

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

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

/// <inheritdoc />
protected override ChromaBuilder Merge(ChromaConfiguration oldValue, ChromaConfiguration newValue)
{
return new ChromaBuilder(new ChromaConfiguration(oldValue, newValue));
}

/// <inheritdoc cref="IWaitUntil" />
/// <remarks>
/// Chroma is ready when its heartbeat answers. Chroma 0.5.16 and later answer the heartbeat of the v2 API,
/// the earlier releases have only the v1 API, and Chroma 1.x answers the v1 API with <c>410 Gone</c>.
/// Asking both works on every release, without reading the version from the image tag.
/// </remarks>
private sealed class WaitUntil : IWaitUntil
{
private static readonly IWaitUntil V2Heartbeat = new HttpWaitStrategy()
.ForPort(ChromaHttpPort)
.ForPath("/api/v2/heartbeat");

private static readonly IWaitUntil V1Heartbeat = new HttpWaitStrategy()
.ForPort(ChromaHttpPort)
.ForPath("/api/v1/heartbeat");

/// <inheritdoc />
public async Task<bool> UntilAsync(IContainer container)
{
return await V2Heartbeat.UntilAsync(container)
.ConfigureAwait(false) || await V1Heartbeat.UntilAsync(container)
.ConfigureAwait(false);
}
}
}
53 changes: 53 additions & 0 deletions src/Testcontainers.Chroma/ChromaConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
namespace Testcontainers.Chroma;

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

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

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

/// <summary>
/// Provides the Chroma connection string.
/// </summary>
internal sealed class ChromaConnectionStringProvider : ContainerConnectionStringProvider<ChromaContainer, ChromaConfiguration>
{
/// <inheritdoc />
protected override string GetHostConnectionString()
{
return Container.GetBaseAddress();
}
}
24 changes: 24 additions & 0 deletions src/Testcontainers.Chroma/ChromaContainer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace Testcontainers.Chroma;

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

/// <summary>
/// Gets the base address of the Chroma HTTP API.
/// </summary>
/// <returns>The base address of the Chroma HTTP API, like <c>http://localhost:32768/</c>.</returns>
public string GetBaseAddress()
{
return new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(ChromaBuilder.ChromaHttpPort)).ToString();
}
}
12 changes: 12 additions & 0 deletions src/Testcontainers.Chroma/Testcontainers.Chroma.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;net10.0;netstandard2.0;netstandard2.1</TargetFrameworks>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" VersionOverride="2026.2.0" PrivateAssets="All"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../Testcontainers/Testcontainers.csproj"/>
</ItemGroup>
</Project>
9 changes: 9 additions & 0 deletions src/Testcontainers.Chroma/Usings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
global using System;
global using System.Diagnostics.CodeAnalysis;
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 DotNet.Testcontainers.Images;
global using JetBrains.Annotations;
1 change: 1 addition & 0 deletions tests/Testcontainers.Chroma.Tests/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
root = true
1 change: 1 addition & 0 deletions tests/Testcontainers.Chroma.Tests/.runs-on
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ubuntu-24.04
Loading
Loading