Observability
El ObservabilityContainer
es un componente de la librería CodeDesignPlus.Net.xUnit que proporciona un conjunto de contenedores Docker para ejecutar servicios de observabilidad, como Loki (para logs), Grafana (para dashboards), Prometheus (para métricas) y Tempo (para trazas). Este componente facilita la creación de pruebas unitarias que requieren herramientas de observabilidad, ofreciendo un entorno de pruebas aislado y reproducible.
¿Cómo Funciona?
El ObservabilityContainer
utiliza Docker Compose
para definir y gestionar los contenedores de observabilidad. Al inicializar una instancia de esta clase, se genera un archivo docker-compose.yml
temporal con la configuración necesaria para ejecutar los contenedores. Luego, los contenedores se inician y se detienen automáticamente al final de la ejecución de las pruebas.
El proceso general de funcionamiento es el siguiente:
- Configuración del Contenedor: El método
Build()
define la configuración específica de los contenedores de observabilidad, incluyendo la ruta al archivodocker-compose.yml
, opciones de reinicio forzado, eliminación de contenedores huérfanos, parada al finalizar y un nombre de servicio alternativo generado dinámicamente para evitar conflictos. - Creación del Contenedor: Se crea una instancia de
DockerComposeCompositeService
usando la configuración definida. - Inicio y Detención del Contenedor: Los contenedores se inician cuando se crea una instancia de la clase
ObservabilityContainer
y se detienen automáticamente cuando la instancia se elimina, asegurando la limpieza del entorno.
Container
El ObservabilityContainer
hereda de la clase DockerCompose
, la cual proporciona la lógica base para interactuar con Docker Compose. La clase utiliza la clase DockerComposeCompositeService
de la librería Testcontainers
para iniciar y detener contenedores docker. La configuración de los contenedores se define en el método Build()
que crea un archivo docker-compose.yml
con los parámetros necesarios para la ejecución de los contenedores de observabilidad. El archivo docker-compose.yml
se encuentra dentro del directorio Containers/ObservabilityContainer
.
namespace CodeDesignPlus.Net.xUnit.Containers.ObservabilityContainer;
/// <summary>/// Represents a Docker container for Observability services, managed using Docker Compose./// </summary>public class ObservabilityContainer : DockerCompose{ /// <summary> /// Builds the Docker Compose service configuration for the Observability container. /// </summary> /// <returns>An <see cref="ICompositeService"/> representing the Docker Compose service.</returns> protected override ICompositeService Build() { // Define the path to the Docker Compose file. var file = Path.Combine(Directory.GetCurrentDirectory(), "Containers", "ObservabilityContainer", "docker-compose.yml");
// Configure the Docker Compose settings. var dockerCompose = new DockerComposeConfig { ComposeFilePath = new[] { file }, ForceRecreate = true, RemoveOrphans = true, StopOnDispose = true, AlternativeServiceName = "observability_" + Guid.NewGuid().ToString("N"), };
// Create and return the Docker Compose service. var compose = new DockerComposeCompositeService(base.DockerHost, dockerCompose);
return compose; }}
La clase ObservabilityCollectionFixture
se utiliza como un fixture de xUnit, que proporciona una forma de compartir los contenedores entre las pruebas de una colección.
namespace CodeDesignPlus.Net.xUnit.Containers.ObservabilityContainer;
/// <summary>/// Provides a fixture for managing an Observability container during xUnit tests./// </summary>public sealed class ObservabilityCollectionFixture : IDisposable{ /// <summary> /// The name of the collection for the Observability tests. /// </summary> public const string Collection = "Observability Collection";
/// <summary> /// Gets the Observability container instance. /// </summary> public ObservabilityContainer Container { get; }
/// <summary> /// Initializes a new instance of the <see cref="ObservabilityCollectionFixture"/> class. /// </summary> public ObservabilityCollectionFixture() { this.Container = new ObservabilityContainer(); }
/// <summary> /// Disposes the Observability container instance. /// </summary> public void Dispose() { this.Container.StopInstance(); }}
Ejemplo de Uso
Este ejemplo demuestra cómo usar ObservabilityContainer
para realizar pruebas de integración con los servicios de observabilidad. La prueba verifica que los contenedores de observabilidad (Loki, Grafana, Prometheus, Tempo) se han iniciado correctamente utilizando la propiedad IsRunning
del contenedor. Este ejemplo muestra la configuración básica para asegurar que los servicios estén operativos para su uso en pruebas más complejas.
using CodeDesignPlus.Net.xUnit.Containers.ObservabilityContainer;
namespace CodeDesignPlus.Net.xUnit.Test;
[Collection(ObservabilityCollectionFixture.Collection)]public class ObservabilityContainerTest(ObservabilityCollectionFixture fixture){
[Fact] public void CheckRunning() { Assert.True(fixture.Container.IsRunning); }
}
using CodeDesignPlus.Net.xUnit.Containers.ObservabilityContainer;
namespace CodeDesignPlus.Net.xUnit.Test.Definitions;
[CollectionDefinition(ObservabilityCollectionFixture.Collection)]public class ObservabilityCollectionDefinition: ICollectionFixture<ObservabilityCollectionFixture>{
}
Conclusiones
- El
ObservabilityContainer
facilita la creación de pruebas unitarias que requieren servicios de observabilidad como Loki, Grafana, Prometheus y Tempo. - Utiliza Docker Compose para la gestión de los contenedores, proporcionando una forma sencilla de definir la configuración.
- La clase
ObservabilityCollectionFixture
permite compartir los contenedores entre todas las pruebas de una misma colección. - El uso del
ObservabilityContainer
mejora la reproducibilidad y el aislamiento de las pruebas unitarias. - Los contenedores de observabilidad se inician automaticamente al comienzo de cada prueba y se detienen una vez termina, esto permite un ambiente de pruebas limpio.