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

Testcontainer for CosmosDB Emulator #549

Closed
Closed
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
fcf80d6
Add CosmosDBTestcontainerConfiguration
Yeseh Jul 25, 2022
75bfbf3
Implement CosmosDbTestContainer
Yeseh Jul 25, 2022
301c551
Implement CosmosDbFixture
Yeseh Jul 25, 2022
32803e2
Write first test (not working)
Yeseh Jul 25, 2022
6d0ae41
Working initial setup, database creation
Yeseh Aug 2, 2022
c3809a4
Merge branch 'develop' of https://github.com/testcontainers/testconta…
Yeseh Aug 28, 2022
dad2dc9
Restructure to model Azurite testcontainer
Yeseh Aug 28, 2022
0f429ba
fix tests + cleanup
ktjn Sep 6, 2022
3fc1c18
Merge branch 'develop' into feature/cosmosdb-testcontainer
ktjn Sep 6, 2022
b1dff3f
(temp hack) wait for max 5 min
ktjn Sep 8, 2022
d38123a
Merge branch 'feature/cosmosdb-testcontainer' of https://github.com/Y…
ktjn Sep 8, 2022
4c45cd0
add debug logging
ktjn Sep 8, 2022
5a66c99
cleanup debug code
ktjn Sep 8, 2022
a21b5e4
set timeout on build
ktjn Sep 8, 2022
56dbe8f
first cleanup sweep
ktjn Sep 8, 2022
8cdb84e
more cleanup and tests
ktjn Sep 9, 2022
4ecdf9d
bail directly if cosmos is shut down
ktjn Sep 9, 2022
4f07e0e
try ubuntu 22
ktjn Sep 9, 2022
140a865
revert ubuntu 22, add restart hack
ktjn Sep 9, 2022
da7625d
clean up
ktjn Sep 9, 2022
246b4d9
try setting ip for cosmos
ktjn Sep 9, 2022
737708b
minor cleanups
ktjn Sep 9, 2022
88cf029
cleanup
ktjn Sep 10, 2022
bb7d473
Merge branch 'develop' into feature/cosmosdb-testcontainer
ktjn Sep 12, 2022
f349512
skip cosmos tests when running docker on a linux host
ktjn Sep 12, 2022
1a2c072
dummy change to trigger build
ktjn Sep 12, 2022
bf70b6c
Revert "skip cosmos tests when running docker on a linux host"
ktjn Sep 13, 2022
2f29611
cleanup
ktjn Sep 14, 2022
bf79586
add wait timeout
ktjn Sep 15, 2022
9043765
Merge branch 'develop' into feature/cosmosdb-testcontainer
ktjn Sep 15, 2022
0d77571
debug values removed
ktjn Sep 15, 2022
f5a4559
Merge branch 'feature/cosmosdb-testcontainer' of https://github.com/Y…
ktjn Sep 15, 2022
498e37b
cleanup
ktjn Sep 15, 2022
90dec5f
Revert "cleanup"
ktjn Sep 16, 2022
3b90301
Revert "debug values removed"
ktjn Sep 16, 2022
f0837d4
Revert "add wait timeout"
ktjn Sep 16, 2022
d3c1067
skip tests
ktjn Sep 16, 2022
9dcac2a
more cleanup
ktjn Sep 16, 2022
c6d2f81
Merge branch 'develop' into feature/cosmosdb-testcontainer
ktjn Sep 24, 2022
6e7fe69
fix environment init
ktjn Sep 25, 2022
0730fda
Merge branch 'feature/cosmosdb-testcontainer' of https://github.com/Y…
ktjn Sep 25, 2022
50fbb80
Merge branch 'develop' into feature/cosmosdb-testcontainer
ktjn Sep 26, 2022
ad4c507
expose HttpMessageHandler
ktjn Sep 26, 2022
db53567
Merge branch 'feature/cosmosdb-testcontainer' of https://github.com/Y…
ktjn Sep 26, 2022
93e8666
Merge branch 'develop' into feature/cosmosdb-testcontainer
ktjn Oct 1, 2022
297df85
review fixes
ktjn Oct 2, 2022
b5444ee
create waitstrategy in constructor
ktjn Oct 3, 2022
44687bf
ref cosmosdb emulator bug
ktjn Oct 3, 2022
a9d0151
cleanup
ktjn Oct 3, 2022
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 Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<PackageReference Update="Azure.Data.Tables" Version="12.6.1" />
<PackageReference Update="Azure.Storage.Blobs" Version="12.13.0" />
<PackageReference Update="Azure.Storage.Queues" Version="12.11.0" />
<PackageReference Update="Microsoft.Azure.Cosmos" Version="3.30.0" />
<PackageReference Update="Confluent.Kafka" Version="1.8.2" />
<PackageReference Update="CouchbaseNetClient" Version="3.2.9" />
<PackageReference Update="Elastic.Clients.Elasticsearch" Version="8.0.0-beta.3" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace DotNet.Testcontainers.Builders
{
using System.Linq;
using DotNet.Testcontainers.Configurations;
using DotNet.Testcontainers.Containers;
using JetBrains.Annotations;

[PublicAPI]
public static class TestcontainersBuilderCosmosDbExtension
HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved
{
public static ITestcontainersBuilder<CosmosDbTestcontainer> WithCosmosDb(
this ITestcontainersBuilder<CosmosDbTestcontainer> builder, CosmosDbTestcontainerConfiguration configuration)
{
builder = configuration.Environments.Aggregate(builder, (current, environment)
=> current.WithEnvironment(environment.Key, environment.Value));

return builder.WithImage(configuration.Image)
.WithPortBinding(configuration.DefaultPort, true)
HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved
.WithExposedPort(configuration.DefaultPort)
.WithWaitStrategy(configuration.WaitStrategy)
.WithOutputConsumer(configuration.OutputConsumer)
.ConfigureContainer(testcontainer =>
{
testcontainer.ContainerPort = configuration.DefaultPort;
testcontainer.Password = configuration.Password;
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
namespace DotNet.Testcontainers.Configurations
{
using System;
using System.Globalization;
using System.IO;
using DotNet.Testcontainers.Builders;
using JetBrains.Annotations;

[PublicAPI]
public class CosmosDbTestcontainerConfiguration : TestcontainerDatabaseConfiguration
{
public const string DefaultCosmosDbApiImage =
"mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator";
HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved

private const int DefaultCosmosPort = 8081;

public CosmosDbTestcontainerConfiguration()
: this(DefaultCosmosDbApiImage)
{
this.OutputConsumer = Consume.RedirectStdoutAndStderrToStream(new MemoryStream(), new MemoryStream());
HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved
}

public CosmosDbTestcontainerConfiguration(string image)
: base(image, DefaultCosmosPort)
{
this.PartitionCount = 1;
this.IpAddressOverride = "127.0.0.1";
}

public override IOutputConsumer OutputConsumer { get; }

public override IWaitForContainerOS WaitStrategy => Wait.ForUnixContainer().UntilMessageIsLogged(this.OutputConsumer.Stdout, "Started|Shutting");

public override string Password
{
// Default key for the emulator
// See: https://docs.microsoft.com/en-us/azure/cosmos-db/local-emulator?tabs=ssl-netstd21#authenticate-requests
get => "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
set => throw new NotImplementedException();
}

public override string Database
{
get => this.Environments["AZURE_COSMOS_EMULATOR_DATABASE"];
set => this.Environments["AZURE_COSMOS_EMULATOR_DATABASE"] = value;
}

public int PartitionCount
{
get => int.Parse(this.Environments["AZURE_COSMOS_EMULATOR_PARTITION_COUNT"], CultureInfo.InvariantCulture);
HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved
set => this.Environments["AZURE_COSMOS_EMULATOR_PARTITION_COUNT"] = value.ToString(CultureInfo.InvariantCulture);
}

public bool EnableDataPersistence
{
get => this.Environments["AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE"] == "true";
HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved
set => this.Environments["AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE"] = value.ToString().ToLower(CultureInfo.InvariantCulture);
HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved
}

public string IpAddressOverride
{
get => this.Environments["AZURE_COSMOS_EMULATOR_IP_ADDRESS_OVERRIDE"];
set => this.Environments["AZURE_COSMOS_EMULATOR_IP_ADDRESS_OVERRIDE"] = value;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
namespace DotNet.Testcontainers.Containers
{
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using DotNet.Testcontainers.Configurations;
using Microsoft.Extensions.Logging;

public sealed class CosmosDbTestcontainer : TestcontainerDatabase
HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved
{
internal CosmosDbTestcontainer(ITestcontainersConfiguration configuration, ILogger logger)
: base(configuration, logger)
{
}

public HttpMessageHandler HttpMessageHandler => new UrlRewriter(this.Hostname, this.Port, new HttpClientHandler { ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true, });
HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved

public HttpClient HttpClient
{
get
{
return new HttpClient(this.HttpMessageHandler);
HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved
}
}

public override string ConnectionString =>
$"AccountEndpoint=https://{this.Hostname}:{this.Port};AccountKey={this.Password}";

private class UrlRewriter : DelegatingHandler
HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved
{
private readonly string host;
private readonly int portNumber;

internal UrlRewriter(string host, int portNumber, HttpMessageHandler innerHandler)
: base(innerHandler)
{
this.host = host;
this.portNumber = portNumber;
}

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.RequestUri = new Uri($"https://{this.host}:{this.portNumber}{request.RequestUri?.PathAndQuery}");
var response = await base.SendAsync(request, cancellationToken);
return response;
}
}
HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
namespace DotNet.Testcontainers.Tests.Fixtures
{
using System;
using System.Data.Common;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Configurations;
using DotNet.Testcontainers.Containers;

public class CosmosDbFixture : DatabaseFixture<CosmosDbTestcontainer, DbConnection>
{
public CosmosDbFixture()
: this(new CosmosDbTestcontainerConfiguration())
{
}

private CosmosDbFixture(CosmosDbTestcontainerConfiguration configuration)
{
this.Configuration = configuration;
this.Container = new TestcontainersBuilder<CosmosDbTestcontainer>()
.WithCosmosDb(configuration)
.Build();
}

public CosmosDbTestcontainerConfiguration Configuration { get; set; }

public override async Task InitializeAsync()
{
// workaround for broken cosmosdb emulator
var maxWait = TimeSpan.FromSeconds(5 * 1000);
HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved
var cancellationTokenSource = new CancellationTokenSource();
var containerTask = this.Container.StartAsync(cancellationTokenSource.Token);
var task = await Task.WhenAny(new[] { containerTask, Task.Delay(maxWait) });
if (task != containerTask)
{
cancellationTokenSource.Cancel();
}
}

public override async Task DisposeAsync()
{
if (this.Connection != null && this.Connection.State != System.Data.ConnectionState.Closed)
{
this.Connection.Dispose();
}

await this.Container.DisposeAsync()
.ConfigureAwait(false);
}

public override void Dispose()
{
this.Configuration.Dispose();
}
}
}
1 change: 1 addition & 0 deletions tests/Testcontainers.Tests/Testcontainers.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<PackageReference Include="Azure.Data.Tables" />
<PackageReference Include="Azure.Storage.Blobs" />
<PackageReference Include="Azure.Storage.Queues" />
<PackageReference Include="Microsoft.Azure.Cosmos" />
<PackageReference Include="Confluent.Kafka" />
<PackageReference Include="CouchbaseNetClient" />
<PackageReference Include="Elastic.Clients.Elasticsearch" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
namespace DotNet.Testcontainers.Tests.Unit
{
using System.Net;
using System.Threading.Tasks;
using DotNet.Testcontainers.Tests.Fixtures;
using Microsoft.Azure.Cosmos;
using Xunit;

public static class CosmosDbTestcontainerTest
{
[Collection(nameof(Testcontainers))]
public sealed class ConnectionTests : IClassFixture<CosmosDbFixture>
{
private readonly CosmosDbFixture fixture;

public ConnectionTests(CosmosDbFixture fixture)
{
this.fixture = fixture;
}

private CosmosClientOptions Options => new CosmosClientOptions { HttpClientFactory = () => this.fixture.Container.HttpClient, ConnectionMode = ConnectionMode.Gateway, };
HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved

[Fact(Skip = "Waiting for a working cosmosdb emulator")]
HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved
public async Task ShouldEstablishConnection()
{
var client = new CosmosClient(this.fixture.Container.ConnectionString, this.Options);

var accountProperties = await client.ReadAccountAsync();
Assert.Equal("localhost", accountProperties.Id);
}

[Fact(Skip = "Waiting for a working cosmosdb emulator")]
public async Task CreateDatabaseTest()
{
var client = new CosmosClient(this.fixture.Container.ConnectionString, this.Options);

var db = await client.CreateDatabaseIfNotExistsAsync("test-db");
Assert.Equal(HttpStatusCode.Created, db.StatusCode);
}
}
}
}