-
-
Notifications
You must be signed in to change notification settings - Fork 302
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Tika service container + basic tests
- Loading branch information
i-mattanasio
committed
Feb 27, 2025
1 parent
b53e4f2
commit 9a74b7b
Showing
9 changed files
with
307 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
namespace Testcontainers.Tika; | ||
|
||
/// <inheritdoc cref="ContainerBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}" /> | ||
[PublicAPI] | ||
public sealed class TikaBuilder : ContainerBuilder<TikaBuilder, TikaContainer, TikaConfiguration> | ||
{ | ||
public const string TikaImage = "apache/tika:3.0.0.0-full"; | ||
public const ushort TikaHttpPort = 9998; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="TikaBuilder" /> class. | ||
/// </summary> | ||
public TikaBuilder() | ||
: this(new TikaConfiguration()) | ||
{ | ||
DockerResourceConfiguration = Init().DockerResourceConfiguration; | ||
} | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="TikaBuilder" /> class. | ||
/// </summary> | ||
/// <param name="resourceConfiguration">The Docker resource configuration.</param> | ||
private TikaBuilder(TikaConfiguration resourceConfiguration) | ||
: base(resourceConfiguration) | ||
{ | ||
DockerResourceConfiguration = resourceConfiguration; | ||
} | ||
/// <inheritdoc /> | ||
|
||
protected override TikaConfiguration DockerResourceConfiguration { get; } | ||
|
||
/// <summary> | ||
/// Sets the Tika server timeout. | ||
/// </summary> | ||
/// <param name="timeout">The timeout for the server in milliseconds.</param> | ||
/// <returns>A configured instance of <see cref="TikaBuilder" />.</returns> | ||
public TikaBuilder WithTimeout(int timeout) | ||
{ | ||
return Merge(DockerResourceConfiguration, new TikaConfiguration(timeout: timeout)) | ||
.WithEnvironment("TIKA_TIMEOUT", timeout.ToString()); | ||
} | ||
|
||
public override TikaContainer Build() | ||
{ | ||
Validate(); | ||
return new TikaContainer(DockerResourceConfiguration); | ||
} | ||
|
||
protected override TikaBuilder Init() | ||
{ | ||
return base.Init() | ||
.WithImage(TikaImage) | ||
.WithPortBinding(TikaHttpPort, true) | ||
.WithWaitStrategy(Wait.ForUnixContainer().AddCustomWaitStrategy(new WaitUntil())); | ||
} | ||
|
||
protected override TikaBuilder Clone(IResourceConfiguration<CreateContainerParameters> resourceConfiguration) | ||
{ | ||
return Merge(DockerResourceConfiguration, new TikaConfiguration(resourceConfiguration)); | ||
} | ||
|
||
protected override TikaBuilder Clone(IContainerConfiguration resourceConfiguration) | ||
{ | ||
return Merge(DockerResourceConfiguration, new TikaConfiguration(resourceConfiguration)); | ||
} | ||
|
||
protected override TikaBuilder Merge(TikaConfiguration oldValue, TikaConfiguration newValue) | ||
{ | ||
return new TikaBuilder(new TikaConfiguration(oldValue, newValue)); | ||
} | ||
|
||
private sealed class WaitUntil : IWaitUntil | ||
{ | ||
private const string HealthCheckPath = "tika"; | ||
private const int MaxRetryAttempts = 10; | ||
private const int DelayInMilliseconds = 1000; | ||
|
||
/// <summary> | ||
/// Waits until the Tika server is available by checking the health check endpoint. | ||
/// </summary> | ||
/// <param name="container">The container instance to check.</param> | ||
/// <returns> | ||
/// A task that represents the asynchronous operation. The task result contains a boolean indicating whether the Tika server is available. | ||
/// </returns> | ||
/// <remarks> | ||
/// This method sends HTTP GET requests to the Tika server's health check endpoint and retries up to a maximum number of times if the server is not available. | ||
/// </remarks> | ||
public async Task<bool> UntilAsync(DotNet.Testcontainers.Containers.IContainer container) | ||
{ | ||
string endpoint = $"http://{container.Hostname}:{container.GetMappedPublicPort(TikaBuilder.TikaHttpPort)}/{HealthCheckPath}"; | ||
|
||
using var client = new HttpClient(); | ||
|
||
for (int i = 0; i < MaxRetryAttempts; i++) | ||
{ | ||
try | ||
{ | ||
var response = await client.GetAsync(endpoint); | ||
|
||
response.EnsureSuccessStatusCode(); | ||
string responseContent = await response.Content.ReadAsStringAsync(); // This is Tika Server (Apache Tika 3.0.0). Please PUT, volendo si può fare questo check | ||
return true; | ||
} | ||
catch | ||
{ | ||
// Ignore exceptions and retry | ||
} | ||
|
||
await Task.Delay(DelayInMilliseconds); | ||
} | ||
|
||
return false; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
namespace Testcontainers.Tika; | ||
|
||
/// <inheritdoc cref="ContainerConfiguration" /> | ||
[PublicAPI] | ||
public sealed class TikaConfiguration : ContainerConfiguration | ||
{ | ||
/// <summary> | ||
/// Initializes a new instance of the <see cref="TikaConfiguration" /> class. | ||
/// </summary> | ||
/// <param name="timeout">The timeout for the Tika server.</param> | ||
public TikaConfiguration(int timeout = 30000) | ||
{ | ||
Timeout = timeout; | ||
} | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="TikaConfiguration" /> class. | ||
/// </summary> | ||
/// <param name="resourceConfiguration">The Docker resource configuration.</param> | ||
public TikaConfiguration(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="TikaConfiguration" /> class. | ||
/// </summary> | ||
/// <param name="resourceConfiguration">The Docker resource configuration.</param> | ||
public TikaConfiguration(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="TikaConfiguration" /> class, | ||
/// combining properties from two existing configurations. | ||
/// </summary> | ||
/// <param name="oldValue">The previous configuration values.</param> | ||
/// <param name="newValue">The new configuration values to merge with the old ones.</param> | ||
public TikaConfiguration(TikaConfiguration oldValue, TikaConfiguration newValue) | ||
: base(oldValue, newValue) | ||
{ | ||
// Combine values manually | ||
Timeout = BuildConfiguration.Combine(oldValue.Timeout, newValue.Timeout); | ||
} | ||
|
||
|
||
/// <summary> | ||
/// Gets the Tika server timeout. | ||
/// </summary> | ||
public int Timeout { get; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
namespace Testcontainers.Tika; | ||
|
||
/// <inheritdoc cref="DockerContainer" /> | ||
[PublicAPI] | ||
public sealed class TikaContainer : DockerContainer | ||
{ | ||
private readonly TikaConfiguration _configuration; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="TikaContainer" /> class. | ||
/// </summary> | ||
/// <param name="configuration">The container configuration.</param> | ||
public TikaContainer(TikaConfiguration configuration) | ||
: base(configuration) | ||
{ | ||
_configuration = configuration; | ||
} | ||
|
||
/// <summary> | ||
/// Gets the Tika connection string. | ||
/// </summary> | ||
/// <returns>The Tika connection string.</returns> | ||
public string GetConnectionString() | ||
{ | ||
var endpoint = new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(TikaBuilder.TikaHttpPort)); | ||
return endpoint.ToString(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
global using System; | ||
global using Docker.DotNet.Models; | ||
global using DotNet.Testcontainers.Builders; | ||
global using DotNet.Testcontainers.Configurations; | ||
global using DotNet.Testcontainers.Containers; | ||
global using JetBrains.Annotations; | ||
global using System.Threading.Tasks; | ||
global using System.Net.Http; |
19 changes: 19 additions & 0 deletions
19
tests/Testcontainers.Tika.Tests/Testcontainers.Tika.Tests.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
<Configurations>Debug;Release</Configurations> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<PackageReference Include="Microsoft.NET.Test.Sdk" /> | ||
<PackageReference Include="coverlet.collector" /> | ||
<PackageReference Include="xunit.runner.visualstudio" /> | ||
<PackageReference Include="xunit" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<ProjectReference Include="../Testcontainers.Commons/Testcontainers.Commons.csproj" /> | ||
<ProjectReference Include="../../src/Testcontainers.Tika/Testcontainers.Tika.csproj" /> | ||
</ItemGroup> | ||
</Project> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
namespace Testcontainers.Tika.Tests; | ||
|
||
public sealed class TikaContainerTests : IAsyncLifetime | ||
{ | ||
private readonly TikaContainer _tikaContainer = new TikaBuilder().Build(); | ||
|
||
public Task InitializeAsync() | ||
{ | ||
return _tikaContainer.StartAsync(); | ||
} | ||
|
||
public Task DisposeAsync() | ||
{ | ||
return _tikaContainer.DisposeAsync().AsTask(); | ||
} | ||
|
||
[Fact] | ||
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))] | ||
public async Task GetConnectionStringReturnsValidUrl() | ||
{ | ||
// When | ||
var connectionString = await Task.Run(() => _tikaContainer.GetConnectionString()); | ||
|
||
// Then | ||
Assert.False(string.IsNullOrEmpty(connectionString)); | ||
Assert.StartsWith("http://", connectionString, StringComparison.OrdinalIgnoreCase); | ||
} | ||
|
||
[Fact] | ||
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))] | ||
public async Task TikaHealthCheckShouldBeSuccessful() | ||
{ | ||
{ | ||
// Given | ||
var httpClient = new HttpClient(); | ||
var connectionString = await Task.Run(() => _tikaContainer.GetConnectionString()); | ||
var requestUrl = $"{connectionString}tika"; | ||
|
||
// When | ||
var response = await httpClient.GetAsync(requestUrl); | ||
|
||
// Then | ||
response.EnsureSuccessStatusCode(); | ||
var content = await response.Content.ReadAsStringAsync(); | ||
Assert.False(string.IsNullOrEmpty(content)); | ||
Assert.StartsWith("This is Tika Server", content); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
global using DotNet.Testcontainers.Commons; | ||
global using System; | ||
global using System.Net.Http; | ||
global using System.Threading.Tasks; | ||
global using Xunit; |