Files
Omika/tests/Omika.Tests/Observability/External/ExternalObservabilityOptionsTests.cs
T
2026-10-23 18:46:50 +02:00

139 lines
3.8 KiB
C#

using System.Reflection;
using Omika.Core.Observability.External;
namespace Omika.Tests.Observability.External;
/// <summary>Validation de la configuration du pont externe (§74/§75).</summary>
public class ExternalObservabilityOptionsTests
{
[Fact]
public void Default_IsDisabled_AndNotUsable()
{
var options = new ExternalObservabilityOptions();
Assert.False(options.Enabled);
Assert.False(options.IsUsable);
Assert.Empty(options.Validate());
}
[Fact]
public void Disabled_IsAlwaysValid()
{
var options = new ExternalObservabilityOptions
{
Enabled = false,
OtlpEndpoint = "",
ExportTimeoutSeconds = 0,
MaxQueueSize = 0
};
Assert.Empty(options.Validate());
}
[Fact]
public void Enabled_WithEmptyEndpoint_IsInvalid()
{
var options = new ExternalObservabilityOptions { Enabled = true, OtlpEndpoint = "" };
Assert.False(options.IsUsable);
Assert.NotEmpty(options.Validate());
}
[Fact]
public void Enabled_WithValidHttpEndpoint_IsUsable()
{
var options = new ExternalObservabilityOptions
{
Enabled = true,
OtlpEndpoint = "http://10.0.0.10:4318"
};
Assert.True(options.IsUsable);
Assert.Empty(options.Validate());
}
[Fact]
public void Enabled_WithNonHttpEndpoint_IsInvalid()
{
var options = new ExternalObservabilityOptions
{
Enabled = true,
OtlpEndpoint = "ftp://collector:4318"
};
Assert.False(options.IsUsable);
Assert.Contains(options.Validate(), e => e.Contains("http", StringComparison.OrdinalIgnoreCase));
}
[Theory]
[InlineData(0)]
[InlineData(61)]
public void ExportTimeoutSeconds_MustBeBetween1And60(int value)
{
var options = new ExternalObservabilityOptions
{
Enabled = true,
OtlpEndpoint = "http://localhost:4318",
ExportTimeoutSeconds = value
};
Assert.False(options.IsUsable);
}
[Theory]
[InlineData(0)]
[InlineData(-1)]
public void NonPositiveBounds_AreInvalid(int value)
{
var options = new ExternalObservabilityOptions
{
Enabled = true,
OtlpEndpoint = "http://localhost:4318",
MaxQueueSize = value
};
Assert.False(options.IsUsable);
}
[Fact]
public void TwoInstances_AreIndependent_NoSharedStaticState()
{
var a = new ExternalObservabilityOptions
{
Enabled = true,
OtlpEndpoint = "http://a:4318",
MaxQueueSize = 111
};
var b = new ExternalObservabilityOptions
{
Enabled = false,
OtlpEndpoint = "http://b:4318",
MaxQueueSize = 222
};
// Chaque instance conserve ses propres valeurs (aucune contamination croisée,
// aucun état statique mutable partagé).
Assert.True(a.Enabled);
Assert.Equal("http://a:4318", a.OtlpEndpoint);
Assert.Equal(111, a.MaxQueueSize);
Assert.False(b.Enabled);
Assert.Equal("http://b:4318", b.OtlpEndpoint);
Assert.Equal(222, b.MaxQueueSize);
}
[Fact]
public void Options_HasNoStaticMutableState()
{
// Garde-fou anti-régression (§13/§28) : la config du pont externe ne doit
// être pilotée par AUCUN champ static mutable (DI-friendly, isolable, testable).
string[] staticMutable = typeof(ExternalObservabilityOptions)
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
.Where(f => !f.IsInitOnly && !f.IsLiteral)
.Select(f => f.Name)
.ToArray();
Assert.Empty(staticMutable);
}
}