I have a microservices application and I wan't to start the whole stack to run integration tests. The idea is to be able to run the tests from Test Explorer within Visual Studio. So I don't want to create a shell script to be able to accomplish this.
The idea is to start all external microservice dependencies in containers and then run a TestServer of the system under test to receive the test requests so that the system can call other microservices.
I found this library and liked the idea of start containers programmatically to achieve the afore mentioned.
What I don't know, is if this would work running on an Azure Pipeline. What would be the correct docker engine address on Azure to initialize Docker.DotNet?
// Default Docker Engine on Windows
using Docker.DotNet;
DockerClient client = new DockerClientConfiguration(
new Uri("npipe://./pipe/docker_engine"))
.CreateClient();
// Default Docker Engine on Linux
using Docker.DotNet;
DockerClient client = new DockerClientConfiguration(
new Uri("unix:///var/run/docker.sock"))
.CreateClient();
I did a little research and found that both Windows and Linux images for Ms-hosted agents have Docker and Docker-Compose pre-installed, so it is possible to start containers using these agents.
My problem was that I didn't realize that the Ops team configured a Linux agent. I was trying to execute using a Windows named pipe and not a Unix socket.
I changed the Docker Engine API address accordingly and it worked.
Here is my code in case someone is interested in creating Integration Tests that start containers for microservices dependencies:
using Docker.DotNet;
using System;
using System.Runtime.InteropServices;
namespace Relationship.Promotion.Applier.IntegrationTest.Helpers
{
public class DockerClientFactory
{
private static readonly Uri defaultWindowsDockerEngineUri = new Uri("npipe://./pipe/docker_engine");
private static readonly Uri defaultLinuxDockerEngineUri = new Uri("unix:///var/run/docker.sock");
public static DockerClient CreateInstance()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return new DockerClientConfiguration(defaultWindowsDockerEngineUri).CreateClient();
else
return new DockerClientConfiguration(defaultLinuxDockerEngineUri).CreateClient();
}
}
}
namespace Relationship.Promotion.Applier.IntegrationTest
{
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
private readonly DockerClient dockerClient;
private readonly PromotionContainer promotionContainer;
private readonly StoreContainer storeContainer;
private readonly ConversionContainer conversionContainer;
public CustomWebApplicationFactory()
{
try
{
// Alternative to Docker.DotNet
// https://github.com/Deffiss/testenvironment-docker
dockerClient = DockerClientFactory.CreateInstance();
DockerContainerBase.CleanupOrphanedContainers(dockerClient).Wait(300.Seconds());
if (!dockerClient.Networks.ListNetworksAsync().Result.Select(n => n.Name).Contains("boti-network"))
{
var result = dockerClient.Networks.CreateNetworkAsync(new Docker.DotNet.Models.NetworksCreateParameters()
{
Name = "boti-network",
Driver = "bridge"
}).Result;
}
promotionContainer = new PromotionContainer(imageName: "promotion-engine-promotion-api");
promotionContainer.Start(dockerClient).Wait(300.Seconds());
conversionContainer = new ConversionContainer(imageName: "promotion-engine-conversion-api");
conversionContainer.Start(dockerClient).Wait(300.Seconds());
storeContainer = new StoreContainer("promotion-engine-store-api");
storeContainer.Start(dockerClient).Wait(300.Seconds());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
protected override IWebHostBuilder CreateWebHostBuilder()
{
return base.CreateWebHostBuilder().UseEnvironment("Docker");
}
protected override void Dispose(bool itIsSafeToAlsoFreeManagedObjects)
{
if (!itIsSafeToAlsoFreeManagedObjects) return;
promotionContainer.Remove(dockerClient).Wait(300.Seconds());
conversionContainer.Remove(dockerClient).Wait(300.Seconds());
storeContainer.Remove(dockerClient).Wait(300.Seconds());
dockerClient.Dispose();
base.Dispose(itIsSafeToAlsoFreeManagedObjects);
}
}
}