Skip to content

Commit 6306178

Browse files
feat: Add Typesense module (#1446)
Co-authored-by: Andre Hofmeister <[email protected]>
1 parent addca5b commit 6306178

File tree

13 files changed

+293
-0
lines changed

13 files changed

+293
-0
lines changed

.github/workflows/cicd.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ jobs:
9090
{ name: "Testcontainers.Redpanda", runs-on: "ubuntu-22.04" },
9191
{ name: "Testcontainers.ServiceBus", runs-on: "ubuntu-22.04" },
9292
{ name: "Testcontainers.Sftp", runs-on: "ubuntu-22.04" },
93+
{ name: "Testcontainers.Typesense", runs-on: "ubuntu-22.04" },
9394
{ name: "Testcontainers.Weaviate", runs-on: "ubuntu-22.04" },
9495
{ name: "Testcontainers.WebDriver", runs-on: "ubuntu-22.04" },
9596
{ name: "Testcontainers.Xunit", runs-on: "ubuntu-22.04" },

Testcontainers.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.ServiceBus",
113113
EndProject
114114
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Sftp", "src\Testcontainers.Sftp\Testcontainers.Sftp.csproj", "{7D5C6816-0DD2-4E13-A585-033B5D3C80D5}"
115115
EndProject
116+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Typesense", "src\Testcontainers.Typesense\Testcontainers.Typesense.csproj", "{E044A94A-3081-4EE4-8DC6-81601F96DA14}"
117+
EndProject
116118
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Weaviate", "src\Testcontainers.Weaviate\Testcontainers.Weaviate.csproj", "{68F8600D-24E9-4E03-9E25-5F6EB338EAC1}"
117119
EndProject
118120
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.WebDriver", "src\Testcontainers.WebDriver\Testcontainers.WebDriver.csproj", "{64A87DE5-29B0-4A54-9E74-560484D8C7C0}"
@@ -241,6 +243,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Sftp.Tests",
241243
EndProject
242244
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Tests", "tests\Testcontainers.Tests\Testcontainers.Tests.csproj", "{27CDB869-A150-4593-958F-6F26E5391E7C}"
243245
EndProject
246+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Typesense.Tests", "tests\Testcontainers.Typesense.Tests\Testcontainers.Typesense.Tests.csproj", "{73CC8E45-5608-1398-4029-0802428B5565}"
247+
EndProject
244248
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Weaviate.Tests", "tests\Testcontainers.Weaviate.Tests\Testcontainers.Weaviate.Tests.csproj", "{DDB41BC8-5826-4D97-9C5F-001151E3FFD6}"
245249
EndProject
246250
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.WebDriver.Tests", "tests\Testcontainers.WebDriver.Tests\Testcontainers.WebDriver.Tests.csproj", "{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}"
@@ -455,6 +459,10 @@ Global
455459
{7D5C6816-0DD2-4E13-A585-033B5D3C80D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
456460
{7D5C6816-0DD2-4E13-A585-033B5D3C80D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
457461
{7D5C6816-0DD2-4E13-A585-033B5D3C80D5}.Release|Any CPU.Build.0 = Release|Any CPU
462+
{E044A94A-3081-4EE4-8DC6-81601F96DA14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
463+
{E044A94A-3081-4EE4-8DC6-81601F96DA14}.Debug|Any CPU.Build.0 = Debug|Any CPU
464+
{E044A94A-3081-4EE4-8DC6-81601F96DA14}.Release|Any CPU.ActiveCfg = Release|Any CPU
465+
{E044A94A-3081-4EE4-8DC6-81601F96DA14}.Release|Any CPU.Build.0 = Release|Any CPU
458466
{68F8600D-24E9-4E03-9E25-5F6EB338EAC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
459467
{68F8600D-24E9-4E03-9E25-5F6EB338EAC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
460468
{68F8600D-24E9-4E03-9E25-5F6EB338EAC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -711,6 +719,10 @@ Global
711719
{27CDB869-A150-4593-958F-6F26E5391E7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
712720
{27CDB869-A150-4593-958F-6F26E5391E7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
713721
{27CDB869-A150-4593-958F-6F26E5391E7C}.Release|Any CPU.Build.0 = Release|Any CPU
722+
{73CC8E45-5608-1398-4029-0802428B5565}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
723+
{73CC8E45-5608-1398-4029-0802428B5565}.Debug|Any CPU.Build.0 = Debug|Any CPU
724+
{73CC8E45-5608-1398-4029-0802428B5565}.Release|Any CPU.ActiveCfg = Release|Any CPU
725+
{73CC8E45-5608-1398-4029-0802428B5565}.Release|Any CPU.Build.0 = Release|Any CPU
714726
{DDB41BC8-5826-4D97-9C5F-001151E3FFD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
715727
{DDB41BC8-5826-4D97-9C5F-001151E3FFD6}.Debug|Any CPU.Build.0 = Debug|Any CPU
716728
{DDB41BC8-5826-4D97-9C5F-001151E3FFD6}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -782,6 +794,7 @@ Global
782794
{45D6F69C-4D87-4130-AA90-0DB2F7460DAE} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
783795
{2E39E532-B81E-4B48-A004-FAE18EDF9E79} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
784796
{7D5C6816-0DD2-4E13-A585-033B5D3C80D5} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
797+
{E044A94A-3081-4EE4-8DC6-81601F96DA14} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
785798
{68F8600D-24E9-4E03-9E25-5F6EB338EAC1} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
786799
{64A87DE5-29B0-4A54-9E74-560484D8C7C0} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
787800
{380BB29B-F556-404D-B13B-CA250599C565} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
@@ -846,6 +859,7 @@ Global
846859
{232DD918-46ED-4BA8-B383-1A9146D83064} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
847860
{B73C3CC0-9F16-4B34-92BE-6EC0853912C5} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
848861
{27CDB869-A150-4593-958F-6F26E5391E7C} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
862+
{73CC8E45-5608-1398-4029-0802428B5565} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
849863
{DDB41BC8-5826-4D97-9C5F-001151E3FFD6} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
850864
{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
851865
{E901DF14-6F05-4FC2-825A-3055FAD33561} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}

docs/modules/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ await moduleNameContainer.StartAsync();
6969
| Redpanda | `docker.redpanda.com/redpandadata/redpanda:v22.2.1` | [NuGet](https://www.nuget.org/packages/Testcontainers.Redpanda) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Redpanda) |
7070
| Sftp | `atmoz/sftp:alpine` | [NuGet](https://www.nuget.org/packages/Testcontainers.Sftp) | [Source](https://github.com/testcontainers/testcontainers-dotnet/tree/develop/src/Testcontainers.Sftp) |
7171
| 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) |
72+
| 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) |
7273
| 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) |
7374
| 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) |
7475

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
root = true
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFrameworks>net8.0;net9.0;netstandard2.0;netstandard2.1</TargetFrameworks>
4+
<LangVersion>latest</LangVersion>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<PackageReference Include="JetBrains.Annotations" VersionOverride="2023.3.0" PrivateAssets="All"/>
8+
</ItemGroup>
9+
<ItemGroup>
10+
<ProjectReference Include="../Testcontainers/Testcontainers.csproj"/>
11+
</ItemGroup>
12+
</Project>
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
namespace Testcontainers.Typesense;
2+
3+
/// <inheritdoc cref="ContainerBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}" />
4+
[PublicAPI]
5+
public sealed class TypesenseBuilder : ContainerBuilder<TypesenseBuilder, TypesenseContainer, TypesenseConfiguration>
6+
{
7+
public const string TypesenseImage = "typesense/typesense:28.0";
8+
9+
public const ushort TypesensePort = 8108;
10+
11+
public const string DefaultDataDirectory = "/tmp";
12+
13+
public const string DefaultApiKey = "testcontainers";
14+
15+
/// <summary>
16+
/// Initializes a new instance of the <see cref="TypesenseBuilder" /> class.
17+
/// </summary>
18+
public TypesenseBuilder()
19+
: this(new TypesenseConfiguration())
20+
{
21+
DockerResourceConfiguration = Init().DockerResourceConfiguration;
22+
}
23+
24+
/// <summary>
25+
/// Initializes a new instance of the <see cref="TypesenseBuilder" /> class.
26+
/// </summary>
27+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
28+
private TypesenseBuilder(TypesenseConfiguration resourceConfiguration)
29+
: base(resourceConfiguration)
30+
{
31+
DockerResourceConfiguration = resourceConfiguration;
32+
}
33+
34+
/// <inheritdoc />
35+
protected override TypesenseConfiguration DockerResourceConfiguration { get; }
36+
37+
/// <summary>
38+
/// Sets the data directory.
39+
/// </summary>
40+
/// <param name="dataDirectoryPath">The data directory path.</param>
41+
/// <returns>A configured instance of <see cref="TypesenseBuilder" />.</returns>
42+
public TypesenseBuilder WithDataDirectory(string dataDirectoryPath)
43+
{
44+
return WithEnvironment("TYPESENSE_DATA_DIR", dataDirectoryPath);
45+
}
46+
47+
/// <summary>
48+
/// Sets the API key.
49+
/// </summary>
50+
/// <param name="apiKey">The API key.</param>
51+
/// <returns>A configured instance of <see cref="TypesenseBuilder" />.</returns>
52+
public TypesenseBuilder WithApiKey(string apiKey)
53+
{
54+
return WithEnvironment("TYPESENSE_API_KEY", apiKey);
55+
}
56+
57+
/// <inheritdoc />
58+
public override TypesenseContainer Build()
59+
{
60+
Validate();
61+
return new TypesenseContainer(DockerResourceConfiguration);
62+
}
63+
64+
/// <inheritdoc />
65+
protected override TypesenseBuilder Init()
66+
{
67+
return base.Init()
68+
.WithImage(TypesenseImage)
69+
.WithPortBinding(TypesensePort, true)
70+
.WithDataDirectory(DefaultDataDirectory)
71+
.WithApiKey(DefaultApiKey)
72+
.WithWaitStrategy(Wait.ForUnixContainer().UntilHttpRequestIsSucceeded(request =>
73+
request.ForPort(TypesensePort).ForPath("/health").ForResponseMessageMatching(IsNodeReadyAsync)));
74+
}
75+
76+
/// <inheritdoc />
77+
protected override void Validate()
78+
{
79+
base.Validate();
80+
81+
_ = Guard.Argument(DockerResourceConfiguration.Environments["TYPESENSE_DATA_DIR"], "DataDirectory")
82+
.NotNull()
83+
.NotEmpty();
84+
85+
_ = Guard.Argument(DockerResourceConfiguration.Environments["TYPESENSE_API_KEY"], "ApiKey")
86+
.NotNull()
87+
.NotEmpty();
88+
}
89+
90+
/// <inheritdoc />
91+
protected override TypesenseBuilder Clone(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
92+
{
93+
return Merge(DockerResourceConfiguration, new TypesenseConfiguration(resourceConfiguration));
94+
}
95+
96+
/// <inheritdoc />
97+
protected override TypesenseBuilder Clone(IContainerConfiguration resourceConfiguration)
98+
{
99+
return Merge(DockerResourceConfiguration, new TypesenseConfiguration(resourceConfiguration));
100+
}
101+
102+
/// <inheritdoc />
103+
protected override TypesenseBuilder Merge(TypesenseConfiguration oldValue, TypesenseConfiguration newValue)
104+
{
105+
return new TypesenseBuilder(new TypesenseConfiguration(oldValue, newValue));
106+
}
107+
108+
private static async Task<bool> IsNodeReadyAsync(HttpResponseMessage response)
109+
{
110+
var content = await response.Content.ReadAsStringAsync()
111+
.ConfigureAwait(false);
112+
113+
return "{\"ok\":true}".Equals(content, StringComparison.OrdinalIgnoreCase);
114+
}
115+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
namespace Testcontainers.Typesense;
2+
3+
/// <inheritdoc cref="ContainerConfiguration" />
4+
[PublicAPI]
5+
public sealed class TypesenseConfiguration : ContainerConfiguration
6+
{
7+
/// <summary>
8+
/// Initializes a new instance of the <see cref="TypesenseConfiguration" /> class.
9+
/// </summary>
10+
public TypesenseConfiguration()
11+
{
12+
}
13+
14+
/// <summary>
15+
/// Initializes a new instance of the <see cref="TypesenseConfiguration" /> class.
16+
/// </summary>
17+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
18+
public TypesenseConfiguration(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
19+
: base(resourceConfiguration)
20+
{
21+
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
22+
}
23+
24+
/// <summary>
25+
/// Initializes a new instance of the <see cref="TypesenseConfiguration" /> class.
26+
/// </summary>
27+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
28+
public TypesenseConfiguration(IContainerConfiguration resourceConfiguration)
29+
: base(resourceConfiguration)
30+
{
31+
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
32+
}
33+
34+
/// <summary>
35+
/// Initializes a new instance of the <see cref="TypesenseConfiguration" /> class.
36+
/// </summary>
37+
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
38+
public TypesenseConfiguration(TypesenseConfiguration resourceConfiguration)
39+
: this(new TypesenseConfiguration(), resourceConfiguration)
40+
{
41+
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
42+
}
43+
44+
/// <summary>
45+
/// Initializes a new instance of the <see cref="TypesenseConfiguration" /> class.
46+
/// </summary>
47+
/// <param name="oldValue">The old Docker resource configuration.</param>
48+
/// <param name="newValue">The new Docker resource configuration.</param>
49+
public TypesenseConfiguration(TypesenseConfiguration oldValue, TypesenseConfiguration newValue)
50+
: base(oldValue, newValue)
51+
{
52+
}
53+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
namespace Testcontainers.Typesense;
2+
3+
/// <inheritdoc cref="DockerContainer" />
4+
[PublicAPI]
5+
public sealed class TypesenseContainer : DockerContainer
6+
{
7+
/// <summary>
8+
/// Initializes a new instance of the <see cref="TypesenseContainer" /> class.
9+
/// </summary>
10+
/// <param name="configuration">The container configuration.</param>
11+
public TypesenseContainer(TypesenseConfiguration configuration)
12+
: base(configuration)
13+
{
14+
}
15+
16+
/// <summary>
17+
/// Gets the Typesense base address.
18+
/// </summary>
19+
/// <returns>The Typesense base address.</returns>
20+
public string GetBaseAddress()
21+
{
22+
return new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(TypesenseBuilder.TypesensePort)).ToString();
23+
}
24+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
global using System;
2+
global using System.Net.Http;
3+
global using System.Threading.Tasks;
4+
global using Docker.DotNet.Models;
5+
global using DotNet.Testcontainers;
6+
global using DotNet.Testcontainers.Builders;
7+
global using DotNet.Testcontainers.Configurations;
8+
global using DotNet.Testcontainers.Containers;
9+
global using JetBrains.Annotations;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
root = true

0 commit comments

Comments
 (0)