Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add Azure Data Explorer Kusto emulator module #963

Merged
merged 21 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
1c6701a
Implemented Azure Data Explorer Kusto emulator module
JonasBenz Jul 31, 2023
7c612b8
re-arrange solution file, so that Kusto project follow the order
JonasBenz Aug 2, 2023
44573b1
Added Unit Test for Kusto container
JonasBenz Aug 2, 2023
f8cedde
Fixed mistake in solution file.
JonasBenz Aug 2, 2023
889d32a
Umcommented documentation of KustoBuilder.DockerResourceConfiguration
JonasBenz Aug 2, 2023
b87c836
Merge branch 'develop' into kustainer
JonasBenz Aug 2, 2023
0a2dba4
Used UriBuilder to build connection string
JonasBenz Aug 3, 2023
4ff5f5c
Moved all usings to global Usings.cs
JonasBenz Aug 3, 2023
23f3c75
Extended HttpWaitStrategy with possibilty to provide the content (bod…
JonasBenz Aug 3, 2023
ad9635f
Replaced custom WaitStrategy with HttpWaitStrategy
JonasBenz Aug 3, 2023
6f7f28a
chore: Minor cleanup (apply project wide formatting styles)
HofmeisterAn Aug 3, 2023
2da80f5
fix: Suggest different wait strategy (parse console output)
HofmeisterAn Aug 3, 2023
ca78500
chore: Order usings
HofmeisterAn Aug 3, 2023
d004366
chore: Align namespace
HofmeisterAn Aug 6, 2023
09b0b06
HttpWaitStrategy.WithContent: Made sure to handle disposal of HttpCon…
JonasBenz Aug 7, 2023
1e18fde
KustoBuilder: Switched to HttpWaitStrategy again (with new contentFac…
JonasBenz Aug 7, 2023
55018dc
HttpWaitStrategy: Prevent null reference ex, when _contentFactory is …
JonasBenz Aug 7, 2023
244a873
HttpWaitStrategy: Initialized _contentFactory in constructor
JonasBenz Aug 7, 2023
bc84c72
Merge branch 'kustainer' of github.com:JonasBenz/testcontainers-dotne…
HofmeisterAn Aug 7, 2023
4e5ed89
chore: Remove unnecessary using: use default encoding
HofmeisterAn Aug 7, 2023
b665b1f
chore: Rename _contentFactory to _httpContentCallback
HofmeisterAn Aug 7, 2023
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
16 changes: 15 additions & 1 deletion Testcontainers.sln
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Expand Down Expand Up @@ -35,6 +35,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Kafka", "src
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Keycloak", "src\Testcontainers.Keycloak\Testcontainers.Keycloak.csproj", "{AA8834A3-82A7-4E83-8E4C-88D37F74056A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Kusto", "src\Testcontainers.Kusto\Testcontainers.Kusto.csproj", "{FCF59758-2403-4EC9-9EAE-4EC69A3F27AF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.LocalStack", "src\Testcontainers.LocalStack\Testcontainers.LocalStack.csproj", "{3792268A-EF08-4569-8118-991E08FD61C4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.MariaDb", "src\Testcontainers.MariaDb\Testcontainers.MariaDb.csproj", "{4B204EB3-C478-422E-9B6F-62DF3871291A}"
Expand Down Expand Up @@ -91,6 +93,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Kafka.Tests"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Keycloak.Tests", "tests\Testcontainers.Keycloak.Tests\Testcontainers.Keycloak.Tests.csproj", "{4827D606-89D5-4E00-8341-47A6E95817BA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Kusto.Tests", "tests\Testcontainers.Kusto.Tests\Testcontainers.Kusto.Tests.csproj", "{FA59D75A-8D3A-412C-92E6-4A56033162DD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.LocalStack.Tests", "tests\Testcontainers.LocalStack.Tests\Testcontainers.LocalStack.Tests.csproj", "{728CBE16-1D52-4F84-AF01-7229E6013512}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.MariaDb.Tests", "tests\Testcontainers.MariaDb.Tests\Testcontainers.MariaDb.Tests.csproj", "{7F0AE083-9DB8-4BD4-91F7-C199DCC7301D}"
Expand Down Expand Up @@ -182,6 +186,10 @@ Global
{AA8834A3-82A7-4E83-8E4C-88D37F74056A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AA8834A3-82A7-4E83-8E4C-88D37F74056A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AA8834A3-82A7-4E83-8E4C-88D37F74056A}.Release|Any CPU.Build.0 = Release|Any CPU
{FCF59758-2403-4EC9-9EAE-4EC69A3F27AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FCF59758-2403-4EC9-9EAE-4EC69A3F27AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FCF59758-2403-4EC9-9EAE-4EC69A3F27AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FCF59758-2403-4EC9-9EAE-4EC69A3F27AF}.Release|Any CPU.Build.0 = Release|Any CPU
{3792268A-EF08-4569-8118-991E08FD61C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3792268A-EF08-4569-8118-991E08FD61C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3792268A-EF08-4569-8118-991E08FD61C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -294,6 +302,10 @@ Global
{4827D606-89D5-4E00-8341-47A6E95817BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4827D606-89D5-4E00-8341-47A6E95817BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4827D606-89D5-4E00-8341-47A6E95817BA}.Release|Any CPU.Build.0 = Release|Any CPU
{FA59D75A-8D3A-412C-92E6-4A56033162DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA59D75A-8D3A-412C-92E6-4A56033162DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA59D75A-8D3A-412C-92E6-4A56033162DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA59D75A-8D3A-412C-92E6-4A56033162DD}.Release|Any CPU.Build.0 = Release|Any CPU
{728CBE16-1D52-4F84-AF01-7229E6013512}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{728CBE16-1D52-4F84-AF01-7229E6013512}.Debug|Any CPU.Build.0 = Debug|Any CPU
{728CBE16-1D52-4F84-AF01-7229E6013512}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -383,6 +395,7 @@ Global
{111B840F-9DB0-4166-83E6-0580FD418F07} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
{E93E40CE-59AA-4561-9B4C-E7B0A686326E} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
{AA8834A3-82A7-4E83-8E4C-88D37F74056A} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
{FCF59758-2403-4EC9-9EAE-4EC69A3F27AF} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
{3792268A-EF08-4569-8118-991E08FD61C4} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
{4B204EB3-C478-422E-9B6F-62DF3871291A} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
{1266E1E6-5CEF-4161-8B45-83282455746E} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
Expand Down Expand Up @@ -411,6 +424,7 @@ Global
{F0F40AE2-70FF-4191-ADDA-26A19E0D1A0F} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
{6F2AEE03-629A-4B49-BD5B-25CA3C61FFB7} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
{4827D606-89D5-4E00-8341-47A6E95817BA} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
{FA59D75A-8D3A-412C-92E6-4A56033162DD} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
{728CBE16-1D52-4F84-AF01-7229E6013512} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
{7F0AE083-9DB8-4BD4-91F7-C199DCC7301D} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
{5DB1F35F-B714-4B62-84BE-16A33084D3E1} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
Expand Down
1 change: 1 addition & 0 deletions src/Testcontainers.Kusto/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
root = true
100 changes: 100 additions & 0 deletions src/Testcontainers.Kusto/KustoBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
namespace Testcontainers.Kusto;

using System.Threading.Tasks;
HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved

/// <inheritdoc cref="ContainerBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}" />
/// <remarks>
/// Builds a container running the "Azure Data Explorer Kusto emulator":
/// https://learn.microsoft.com/en-us/azure/data-explorer/kusto-emulator-overview
/// </remarks>
[PublicAPI]
public sealed class KustoBuilder : ContainerBuilder<KustoBuilder, KustoContainer, KustoConfiguration>
{
public const string KustoImage = "mcr.microsoft.com/azuredataexplorer/kustainer-linux:latest";

public const ushort KustoPort = 8080;

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

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

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

/// <inheritdoc />
public override KustoContainer Build()
{
Validate();
return new KustoContainer(DockerResourceConfiguration, TestcontainersSettings.Logger);
}

/// <inheritdoc />
protected override KustoBuilder Init()
{
return base.Init()
.WithImage(KustoImage)
.WithPortBinding(KustoPort, true)
.WithEnvironment("ACCEPT_EULA", "Y")
.WithWaitStrategy(Wait.ForUnixContainer().AddCustomWaitStrategy(new WaitUntil()));
HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved
}

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

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

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

/// <inheritdoc cref="IWaitUntil" />
private sealed class WaitUntil : IWaitUntil
{
private readonly string[] _command =
{
"curl",
"-X",
"POST",
"-i",
"-H",
"Content-Type: application/json",
"-d",
"{\"csl\":\".show cluster\"}",
"http://localhost:8080/v1/rest/mgmt"
};

/// <inheritdoc />
public async Task<bool> UntilAsync(IContainer container)
{
var execResult = await container.ExecAsync(_command)
.ConfigureAwait(false);

return execResult.ExitCode == 0 &&
execResult.Stdout.Contains("200 OK");
}
}
}
53 changes: 53 additions & 0 deletions src/Testcontainers.Kusto/KustoConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
namespace Testcontainers.Kusto;

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

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

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

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

/// <summary>
/// Gets the Kusto connection string.
/// </summary>
/// <returns>The Kusto connection string.</returns>
public string GetConnectionString()
{
return $"http://{Hostname}:{GetMappedPublicPort(KustoBuilder.KustoPort)}";
JonasBenz marked this conversation as resolved.
Show resolved Hide resolved
}
}
13 changes: 13 additions & 0 deletions src/Testcontainers.Kusto/Testcontainers.Kusto.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All"/>
<PackageReference Include="JetBrains.Annotations" Version="2022.3.1" PrivateAssets="All"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(SolutionDir)src/Testcontainers/Testcontainers.csproj"/>
</ItemGroup>
</Project>
6 changes: 6 additions & 0 deletions src/Testcontainers.Kusto/Usings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
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 Microsoft.Extensions.Logging;
32 changes: 32 additions & 0 deletions tests/Testcontainers.Kusto.Tests/KustoContainerTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
namespace Testcontainers.Kusto.Tests;

public class KustoContainerTest : IAsyncLifetime
{
private readonly KustoContainer _kustainer = new KustoBuilder().Build();

public Task InitializeAsync()
{
return _kustainer.StartAsync();
}

public Task DisposeAsync()
{
return _kustainer.DisposeAsync().AsTask();
}

[Fact]
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
public async Task ShowDatabaseReturnsDefaultDbInformation()
{
// Given
using var client = KustoClientFactory.CreateCslAdminProvider(new KustoConnectionStringBuilder(_kustainer.GetConnectionString()));

// When
var dataReader = await client.ExecuteControlCommandAsync("NetDefaultDB", CslCommandGenerator.GenerateDatabaseShowCommand());
dataReader.Read();

// Then
Assert.Equal("DatabaseName", dataReader.GetName(0));
Assert.Equal("NetDefaultDB", dataReader.GetString(0));
}
}
18 changes: 18 additions & 0 deletions tests/Testcontainers.Kusto.Tests/Testcontainers.Kusto.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks>
<IsPackable>false</IsPackable>
<IsPublishable>false</IsPublishable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.Kusto.Data" Version="11.3.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" />
<PackageReference Include="xunit" Version="2.4.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(SolutionDir)src/Testcontainers.Kusto/Testcontainers.Kusto.csproj" />
<ProjectReference Include="$(SolutionDir)tests/Testcontainers.Commons/Testcontainers.Commons.csproj" />
</ItemGroup>
</Project>
6 changes: 6 additions & 0 deletions tests/Testcontainers.Kusto.Tests/Usings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
global using System.Threading.Tasks;
global using DotNet.Testcontainers.Commons;
global using Xunit;
global using Kusto.Data;
global using Kusto.Data.Common;
global using Kusto.Data.Net.Client;