128 lines
5.2 KiB
C#
128 lines
5.2 KiB
C#
using Microsoft.Extensions.Logging;
|
|
using Omika.Core.Observability;
|
|
using Omika.Core.Observability.External;
|
|
using Omika.Core.Observability.Outbox;
|
|
|
|
namespace Omika.Tests.Observability.External;
|
|
|
|
/// <summary>Liste blanche et filtrage sécurité du mapping externe (§31/§79/§71).</summary>
|
|
public class OmikaEventExternalMapperTests
|
|
{
|
|
[Fact]
|
|
public void MapsWhitelistFields_AndExcludesIdentity()
|
|
{
|
|
var e = new TelemetryEvent
|
|
{
|
|
EventCode = TelemetryEventCodes.MobileAppStarted,
|
|
Level = TelemetryLevel.Warning,
|
|
Priority = TelemetryPriority.P2,
|
|
Component = "SyncEngine",
|
|
TraceId = Guid.NewGuid(),
|
|
SessionId = Guid.NewGuid(),
|
|
OperationId = Guid.NewGuid(),
|
|
AppVersion = "1.2.3",
|
|
Platform = "Android",
|
|
ErrorCode = "ERR-1",
|
|
DurationMs = 123,
|
|
Success = true,
|
|
DeviceId = "device-abc",
|
|
ClientId = "client-1",
|
|
UserId = "user-1",
|
|
CollaborateurId = "col-1",
|
|
EntityId = "entity-1"
|
|
};
|
|
|
|
ExternalLogRecord? record = OmikaEventExternalMapper.ToLogRecord(e);
|
|
|
|
Assert.NotNull(record);
|
|
Assert.Equal(LogLevel.Warning, record.Level);
|
|
Assert.Equal(TelemetryEventCodes.MobileAppStarted.Value, record.EventCode);
|
|
Assert.Equal(e.TraceId, record.TraceId);
|
|
Assert.Contains(record.Attributes, kv => kv.Key == "omika.trace_id");
|
|
Assert.Contains(record.Attributes, kv => kv.Key == "omika.session_id");
|
|
Assert.Contains(record.Attributes, kv => kv.Key == "omika.operation_id");
|
|
Assert.Contains(record.Attributes, kv => kv.Key == "component" && (string?)kv.Value == "SyncEngine");
|
|
|
|
// Identité métier : JAMAIS exportée (liste blanche externe).
|
|
Assert.DoesNotContain(record.Attributes, kv => kv.Key == "omika.device_id");
|
|
Assert.DoesNotContain(record.Attributes, kv => kv.Key == "userid");
|
|
Assert.DoesNotContain(record.Attributes, kv => kv.Key == "clientid");
|
|
Assert.DoesNotContain(record.Attributes, kv => kv.Key == "collaborateurid");
|
|
Assert.DoesNotContain(record.Attributes, kv => kv.Key == "entityid");
|
|
}
|
|
|
|
[Fact]
|
|
public void DropsForbiddenMetadataKeysAndValues()
|
|
{
|
|
var e = new TelemetryEvent
|
|
{
|
|
EventCode = TelemetryEventCodes.MobileAppStarted,
|
|
Metadata = TelemetryMetadata.Create(
|
|
("ok_key", "safe-value"),
|
|
("password", "hunter2"),
|
|
("Authorization", "Bearer secret"),
|
|
("connectionString", "Server=..." ),
|
|
("note", "contains token here"))
|
|
};
|
|
|
|
ExternalLogRecord? record = OmikaEventExternalMapper.ToLogRecord(e);
|
|
|
|
Assert.NotNull(record);
|
|
Assert.Contains(record.Attributes, kv => kv.Key == "ok_key");
|
|
Assert.DoesNotContain(record.Attributes, kv => kv.Key == "password");
|
|
Assert.DoesNotContain(record.Attributes, kv => kv.Key == "Authorization");
|
|
Assert.DoesNotContain(record.Attributes, kv => kv.Key == "connectionString");
|
|
Assert.DoesNotContain(record.Attributes, kv => kv.Key == "note");
|
|
}
|
|
|
|
[Fact]
|
|
public void ReturnsNullForInvalidEvent()
|
|
{
|
|
Assert.Null(OmikaEventExternalMapper.ToLogRecord((OmikaEvent?)null));
|
|
|
|
// EventCode invalide (défaut) → événement non mappable.
|
|
var e = new TelemetryEvent();
|
|
Assert.Null(OmikaEventExternalMapper.ToLogRecord(e));
|
|
}
|
|
|
|
[Fact]
|
|
public void LogLevelMapping_IsDeterministic()
|
|
{
|
|
Assert.Equal(LogLevel.Trace, OmikaEventExternalMapper.ToLogLevel(TelemetryLevel.Trace));
|
|
Assert.Equal(LogLevel.Debug, OmikaEventExternalMapper.ToLogLevel(TelemetryLevel.Debug));
|
|
Assert.Equal(LogLevel.Information, OmikaEventExternalMapper.ToLogLevel(TelemetryLevel.Info));
|
|
Assert.Equal(LogLevel.Warning, OmikaEventExternalMapper.ToLogLevel(TelemetryLevel.Warning));
|
|
Assert.Equal(LogLevel.Error, OmikaEventExternalMapper.ToLogLevel(TelemetryLevel.Error));
|
|
Assert.Equal(LogLevel.Critical, OmikaEventExternalMapper.ToLogLevel(TelemetryLevel.Critical));
|
|
}
|
|
|
|
[Fact]
|
|
public void MapsDto_WithWhitelist()
|
|
{
|
|
var dto = new DiagnosticEventDto
|
|
{
|
|
EventId = Guid.NewGuid(),
|
|
EventCode = "OMK-MOB-SYNC-001",
|
|
TimestampUtc = DateTimeOffset.UtcNow,
|
|
Level = "Error",
|
|
Priority = "P1",
|
|
Component = "MobileSync",
|
|
TraceId = Guid.NewGuid(),
|
|
SessionId = Guid.NewGuid(),
|
|
DeviceId = "device-abc",
|
|
ClientId = "client-1",
|
|
ErrorCode = "ERR-X",
|
|
Metadata = new Dictionary<string, object?> { ["k"] = "v", ["password"] = "secret" }
|
|
};
|
|
|
|
ExternalLogRecord? record = OmikaEventExternalMapper.ToLogRecord(dto);
|
|
|
|
Assert.NotNull(record);
|
|
Assert.Equal(LogLevel.Error, record.Level);
|
|
Assert.Contains(record.Attributes, kv => kv.Key == "omika.trace_id");
|
|
Assert.DoesNotContain(record.Attributes, kv => kv.Key == "deviceid");
|
|
Assert.DoesNotContain(record.Attributes, kv => kv.Key == "password");
|
|
Assert.Contains(record.Attributes, kv => kv.Key == "k");
|
|
}
|
|
}
|