Skip to content

Instantly share code, notes, and snippets.

@thefringeninja
Created December 8, 2017 13:00
Show Gist options
  • Save thefringeninja/5b9613d626b439f1a51c0d2e68303a7c to your computer and use it in GitHub Desktop.
Save thefringeninja/5b9613d626b439f1a51c0d2e68303a7c to your computer and use it in GitHub Desktop.
Run Raven Tests in Ur Docker Container
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Docker.DotNet;
using Docker.DotNet.Models;
using Raven.Client.Documents;
using Raven.Client.Documents.Session;
using Raven.Client.Exceptions;
using Raven.Client.Exceptions.Database;
using Raven.Client.ServerWide;
using Raven.Client.ServerWide.Operations;
internal class RavenDatabaseManager : IDisposable
{
private static readonly Uri s_DockerUri = new Uri(Environment.OSVersion.IsWindows() ? WindowsPipe : UnixPipe);
private readonly int _httpPort;
private readonly int _tcpPort;
private readonly string _databaseName;
private readonly TaskCompletionSource<object> _databaseCreated;
private readonly IDocumentStore _documentStore;
private const string RavenDbImage = "ravendb/ravendb";
private const string ContainerName = "ravendb";
private const string UnixPipe = "unix:///var/run/docker.sock";
private const string WindowsPipe = "npipe://./pipe/docker_engine";
public RavenDatabaseManager(int httpPort = 8080, int tcpPort = 38888)
{
_httpPort = httpPort;
_tcpPort = tcpPort;
_databaseName = Guid.NewGuid().ToString("n");
_databaseCreated = new TaskCompletionSource<object>();
_documentStore = new DocumentStore
{
Urls = new[] {$"http://localhost:{_httpPort}/"}
}.Initialize();
Task.Run(CreateDatabase);
}
public Func<IAsyncDocumentSession> CreateSessionFactory()
{
_databaseCreated.Task.Wait(TimeSpan.FromSeconds(60));
return () => _documentStore.OpenAsyncSession(_databaseName);
}
private async Task CreateDatabase()
{
try
{
await TryStartContainer();
await TryCreateDatabase().WithTimeout(TimeSpan.FromSeconds(60));
_databaseCreated.SetResult(null);
}
catch(Exception ex)
{
_databaseCreated.SetException(ex);
}
}
private async Task TryCreateDatabase()
{
while(true)
{
try
{
await _documentStore.Admin.Server.SendAsync(new CreateDatabaseOperation(new DatabaseRecord(_databaseName)));
break;
}
catch(AllTopologyNodesDownException)
{ }
}
while(true)
{
try
{
await EnsureDatabaseExists();
return;
}
catch (DatabaseDoesNotExistException){}
}
}
private async Task EnsureDatabaseExists()
{
using(var session = _documentStore.OpenAsyncSession(_databaseName))
{
await session.StoreAsync(new DummyDocument());
await session.SaveChangesAsync();
}
using(var session = _documentStore.OpenAsyncSession(_databaseName))
{
var dummy = await session.LoadAsync<DummyDocument>(new DummyDocument().Id);
session.Delete(dummy);
await session.SaveChangesAsync();
}
}
private async Task TryStartContainer()
{
var config = new DockerClientConfiguration(s_DockerUri);
var client = config.CreateClient();
var images = await client.Images.ListImagesAsync(new ImagesListParameters {MatchName = RavenDbImage});
if(images.Count == 0)
{
// No image found. Pulling latest ..
await client.Images.CreateImageAsync(new ImagesCreateParameters {FromImage = RavenDbImage, Tag = "latest"}, null, IgnoreProgress.Forever);
}
var containers = await client.Containers.ListContainersAsync(new ContainersListParameters {All = true});
if(containers.Any(container => container.Image == RavenDbImage && container.Names.Any(name => name == $"/{ContainerName}")))
{
return;
}
await CreateContainer(client);
}
private async Task CreateContainer(IDockerClient client)
{
try
{
var container = await client.Containers.CreateContainerAsync(
new CreateContainerParameters
{
Image = RavenDbImage,
Name = ContainerName,
Tty = true,
Env = new[]
{
"UNSECURED_ACCESS_ALLOWED=PublicNetwork",
$"PUBLIC_SERVER_URL=http://localhost:{_httpPort}/",
$"PUBLIC_TCP_SERVER_URL=tcp://localhost:{_tcpPort}/"
},
HostConfig = new HostConfig
{
PortBindings = new Dictionary<string, IList<PortBinding>>
{
["8080/tcp"] = new List<PortBinding>
{
new PortBinding
{
HostPort = _httpPort.ToString()
}
},
["38888/tcp"] = new List<PortBinding>
{
new PortBinding
{
HostPort = _tcpPort.ToString()
}
}
}
}
});
// Starting the container ...
var started = await client.Containers.StartContainerAsync(ContainerName, new ContainerStartParameters { });
if(started)
{
for(;;)
{
var result = await client.Containers.ListContainersAsync(new ContainersListParameters
{
All = true,
Filters = new Dictionary<string, IDictionary<string, bool>>
{
["id"] = new Dictionary<string, bool>
{
[container.ID] = true
},
["health"] = new Dictionary<string, bool>
{
["healthy"] = true
}
}
});
if(result.Any())
{
return;
}
}
}
}
catch(DockerApiException ex)
when(ex.StatusCode == HttpStatusCode.BadRequest)
{
}
}
public void Dispose()
{
try
{
_documentStore.Admin.Server.Send(new DeleteDatabasesOperation(_databaseName, true));
}
catch(Exception)
{ }
_documentStore.Dispose();
}
class IgnoreProgress : IProgress<JSONMessage>
{
public static readonly IProgress<JSONMessage> Forever = new IgnoreProgress();
public void Report(JSONMessage value)
{ }
}
class DummyDocument
{
public string Id { get; } = "Dummy";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment