Refactor SurfaceCacheValidator to simplify oldest entry calculation
Add global using for Xunit in test project Enhance ImportValidatorTests with async validation and quarantine checks Implement FileSystemQuarantineServiceTests for quarantine functionality Add integration tests for ImportValidator to check monotonicity Create BundleVersionTests to validate version parsing and comparison logic Implement VersionMonotonicityCheckerTests for monotonicity checks and activation logic
This commit is contained in:
@@ -743,6 +743,91 @@ signalsGroup.MapGet("/unknowns/{subjectKey}", async Task<IResult> (
|
||||
return items.Count == 0 ? Results.NotFound() : Results.Ok(items);
|
||||
}).WithName("SignalsUnknownsGet");
|
||||
|
||||
signalsGroup.MapGet("/unknowns", async Task<IResult> (
|
||||
HttpContext context,
|
||||
SignalsOptions options,
|
||||
IUnknownsRepository repository,
|
||||
SignalsSealedModeMonitor sealedModeMonitor,
|
||||
[FromQuery] string? band,
|
||||
[FromQuery] int limit = 100,
|
||||
[FromQuery] int offset = 0,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
{
|
||||
if (!Program.TryAuthorize(context, SignalsPolicies.Read, options.Authority.AllowAnonymousFallback, out var authFailure))
|
||||
{
|
||||
return authFailure ?? Results.Unauthorized();
|
||||
}
|
||||
|
||||
if (!Program.TryEnsureSealedMode(sealedModeMonitor, out var sealedFailure))
|
||||
{
|
||||
return sealedFailure ?? Results.StatusCode(StatusCodes.Status503ServiceUnavailable);
|
||||
}
|
||||
|
||||
limit = Math.Clamp(limit, 1, 1000);
|
||||
offset = Math.Max(0, offset);
|
||||
|
||||
UnknownsBand? bandFilter = null;
|
||||
if (!string.IsNullOrWhiteSpace(band) && Enum.TryParse<UnknownsBand>(band, ignoreCase: true, out var parsedBand))
|
||||
{
|
||||
bandFilter = parsedBand;
|
||||
}
|
||||
|
||||
var items = await repository.QueryAsync(bandFilter, limit, offset, cancellationToken).ConfigureAwait(false);
|
||||
return Results.Ok(new
|
||||
{
|
||||
items,
|
||||
count = items.Count,
|
||||
limit,
|
||||
offset,
|
||||
band = bandFilter?.ToString().ToLowerInvariant()
|
||||
});
|
||||
}).WithName("SignalsUnknownsQuery");
|
||||
|
||||
signalsGroup.MapGet("/unknowns/{id}/explain", async Task<IResult> (
|
||||
HttpContext context,
|
||||
SignalsOptions options,
|
||||
string id,
|
||||
IUnknownsRepository repository,
|
||||
IUnknownsScoringService scoringService,
|
||||
SignalsSealedModeMonitor sealedModeMonitor,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
if (!Program.TryAuthorize(context, SignalsPolicies.Read, options.Authority.AllowAnonymousFallback, out var authFailure))
|
||||
{
|
||||
return authFailure ?? Results.Unauthorized();
|
||||
}
|
||||
|
||||
if (!Program.TryEnsureSealedMode(sealedModeMonitor, out var sealedFailure))
|
||||
{
|
||||
return sealedFailure ?? Results.StatusCode(StatusCodes.Status503ServiceUnavailable);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
return Results.BadRequest(new { error = "id is required." });
|
||||
}
|
||||
|
||||
var unknown = await repository.GetByIdAsync(id.Trim(), cancellationToken).ConfigureAwait(false);
|
||||
if (unknown is null)
|
||||
{
|
||||
return Results.NotFound(new { error = $"Unknown with id '{id}' not found." });
|
||||
}
|
||||
|
||||
return Results.Ok(new
|
||||
{
|
||||
id = unknown.Id,
|
||||
subjectKey = unknown.SubjectKey,
|
||||
band = unknown.Band.ToString().ToLowerInvariant(),
|
||||
score = unknown.Score,
|
||||
normalizationTrace = unknown.NormalizationTrace,
|
||||
flags = unknown.Flags,
|
||||
nextScheduledRescan = unknown.NextScheduledRescan,
|
||||
rescanAttempts = unknown.RescanAttempts,
|
||||
createdAt = unknown.CreatedAt,
|
||||
updatedAt = unknown.UpdatedAt
|
||||
});
|
||||
}).WithName("SignalsUnknownsExplain");
|
||||
|
||||
signalsGroup.MapPost("/reachability/recompute", async Task<IResult> (
|
||||
HttpContext context,
|
||||
SignalsOptions options,
|
||||
|
||||
Reference in New Issue
Block a user