159 lines
5.9 KiB
C#
159 lines
5.9 KiB
C#
using Omika.Diagnostics.Referential;
|
|
|
|
namespace Omika.Diagnostics.Tests.Fakes;
|
|
|
|
/// <summary>
|
|
/// Fake en mémoire de <see cref="IDiagnosticReferenceRepository"/> pour les tests sans
|
|
/// PostgreSQL. Reproduit la sémantique du repository Npgsql : normalisation TRIM+UPPER,
|
|
/// unicité (type, code), code immuable, archivage (enabled=false) sans DELETE. Les codes
|
|
/// « observés » (pour <see cref="GetUnreferencedAsync"/>) sont injectés via
|
|
/// <see cref="SeedObserved"/> (miroir du DISTINCT diagnostic_event, sans base réelle).
|
|
/// </summary>
|
|
public sealed class FakeDiagnosticReferenceRepository : IDiagnosticReferenceRepository
|
|
{
|
|
private readonly List<DiagnosticReferenceRecord> _references = [];
|
|
private readonly List<(string Type, string Code, long Count, DateTimeOffset LastSeen)> _observed = [];
|
|
private long _nextId = 1;
|
|
|
|
public IReadOnlyList<DiagnosticReferenceRecord> Seed(params DiagnosticReferenceRecord[] records)
|
|
{
|
|
foreach (DiagnosticReferenceRecord r in records)
|
|
{
|
|
if (r.Id == 0)
|
|
{
|
|
r.Id = _nextId++;
|
|
}
|
|
else
|
|
{
|
|
_nextId = Math.Max(_nextId, r.Id + 1);
|
|
}
|
|
|
|
_references.Add(r);
|
|
}
|
|
|
|
return _references;
|
|
}
|
|
|
|
public void SeedObserved(string type, string code, long count, DateTimeOffset lastSeen) =>
|
|
_observed.Add((type, code, count, lastSeen));
|
|
|
|
public Task<IReadOnlyList<DiagnosticReferenceRecord>> ListAsync(
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
IReadOnlyList<DiagnosticReferenceRecord> ordered = _references
|
|
.OrderBy(r => r.ReferenceType, StringComparer.Ordinal)
|
|
.ThenBy(r => r.SortOrder)
|
|
.ThenBy(r => r.Code, StringComparer.Ordinal)
|
|
.ToList();
|
|
return Task.FromResult(ordered);
|
|
}
|
|
|
|
public Task<DiagnosticReferenceRecord?> GetByTypeAndCodeAsync(
|
|
string referenceType,
|
|
string code,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
string? normalized = DiagnosticReferenceNormalization.NormalizeCode(code);
|
|
DiagnosticReferenceRecord? found = _references.FirstOrDefault(r =>
|
|
r.ReferenceType == referenceType && r.Code == normalized);
|
|
return Task.FromResult(found);
|
|
}
|
|
|
|
public Task<DiagnosticReferenceRecord?> GetByIdAsync(
|
|
long id,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
return Task.FromResult(_references.FirstOrDefault(r => r.Id == id));
|
|
}
|
|
|
|
public Task<DiagnosticReferenceRecord?> CreateAsync(
|
|
string referenceType,
|
|
string code,
|
|
string label,
|
|
string? description,
|
|
bool enabled,
|
|
int sortOrder,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
string? normalizedCode = DiagnosticReferenceNormalization.NormalizeCode(code);
|
|
string? normalizedLabel = DiagnosticReferenceNormalization.NormalizeLabel(label);
|
|
if (!DiagnosticReferenceTypes.IsSupported(referenceType) || normalizedCode is null || normalizedLabel is null)
|
|
{
|
|
return Task.FromResult<DiagnosticReferenceRecord?>(null);
|
|
}
|
|
|
|
if (_references.Any(r => r.ReferenceType == referenceType && r.Code == normalizedCode))
|
|
{
|
|
return Task.FromResult<DiagnosticReferenceRecord?>(null); // doublon.
|
|
}
|
|
|
|
DateTimeOffset now = DateTimeOffset.UtcNow;
|
|
var record = new DiagnosticReferenceRecord
|
|
{
|
|
Id = _nextId++,
|
|
ReferenceType = referenceType,
|
|
Code = normalizedCode,
|
|
Label = normalizedLabel,
|
|
Description = DiagnosticReferenceNormalization.NormalizeLabel(description),
|
|
Enabled = enabled,
|
|
SortOrder = sortOrder,
|
|
CreatedAtUtc = now,
|
|
UpdatedAtUtc = now
|
|
};
|
|
_references.Add(record);
|
|
return Task.FromResult<DiagnosticReferenceRecord?>(record);
|
|
}
|
|
|
|
public Task<bool> UpdateAsync(
|
|
long id,
|
|
string label,
|
|
string? description,
|
|
bool enabled,
|
|
int sortOrder,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
string? normalizedLabel = DiagnosticReferenceNormalization.NormalizeLabel(label);
|
|
DiagnosticReferenceRecord? record = _references.FirstOrDefault(r => r.Id == id);
|
|
if (record is null || normalizedLabel is null)
|
|
{
|
|
return Task.FromResult(false);
|
|
}
|
|
|
|
record.Label = normalizedLabel;
|
|
record.Description = DiagnosticReferenceNormalization.NormalizeLabel(description);
|
|
record.Enabled = enabled;
|
|
record.SortOrder = sortOrder;
|
|
record.UpdatedAtUtc = DateTimeOffset.UtcNow;
|
|
return Task.FromResult(true);
|
|
}
|
|
|
|
public Task<IReadOnlyDictionary<string, string>> GetLabelsAsync(
|
|
string referenceType,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var labels = new Dictionary<string, string>(StringComparer.Ordinal);
|
|
foreach (DiagnosticReferenceRecord r in _references.Where(r => r.ReferenceType == referenceType))
|
|
{
|
|
labels[r.Code] = r.Label;
|
|
}
|
|
|
|
return Task.FromResult<IReadOnlyDictionary<string, string>>(labels);
|
|
}
|
|
|
|
public Task<IReadOnlyList<DiagnosticUnreferencedCode>> GetUnreferencedAsync(
|
|
int limit,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var result = _observed
|
|
.Where(o => !_references.Any(r => r.ReferenceType == o.Type && r.Code == o.Code))
|
|
.Select(o => new DiagnosticUnreferencedCode(o.Type, o.Code, o.Count, o.LastSeen))
|
|
.OrderByDescending(x => x.ObservedCount)
|
|
.ThenBy(x => x.ReferenceType, StringComparer.Ordinal)
|
|
.ThenBy(x => x.Code, StringComparer.Ordinal)
|
|
.Take(Math.Clamp(limit, 1, 200))
|
|
.ToList();
|
|
|
|
return Task.FromResult<IReadOnlyList<DiagnosticUnreferencedCode>>(result);
|
|
}
|
|
}
|