feat(admin): add safe processing monitor and operation correlation

This commit is contained in:
cesnimda
2026-10-28 19:31:32 +01:00
parent 1f87301ee9
commit d52403dba8
19 changed files with 1064 additions and 6 deletions
@@ -1,12 +1,42 @@
using JobTrackerApi.Models;
using JobTrackerApi.Controllers;
using JobTrackerApi.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Xunit;
namespace JobTrackerApi.MariaDb.Tests;
public sealed class UserOperationHistoryPersistenceTests
{
[Fact]
public async Task Administrator_metadata_grouping_paging_associations_and_string_cursors_use_real_MariaDB_SQL()
{
await using var database = await MariaDbDatabase.CreateAsync();
await using var db = database.Context();
db.Users.Add(new() { Id = "rd21-owner", UserName = "synthetic-history", Email = "history@example.test" });
var artifact = new CvUploadArtifact { OwnerUserId = "rd21-owner", OriginalFileName = "synthetic.pdf", MimeType = "application/pdf", ByteSize = 400 };
db.CvUploadArtifacts.Add(artifact);
await db.SaveChangesAsync();
var run = new CvExtractionRun { OwnerUserId = "rd21-owner", ArtifactId = artifact.Id, Trigger = "document_import", ParserVersion = "docling-v1", DocumentJson = "{\"PageCount\":2,\"Text\":\"SECRET_SOURCE\"}" };
db.CvExtractionRuns.Add(run);
await db.SaveChangesAsync();
var operation = (await new UserOperationStore(db, TimeProvider.System).CreateAsync(Request("admin-query") with { SubjectType = CvProcessingQueue.SubjectType, SubjectId = run.Id.ToString() }, default)).Operation;
var controller = new AdminProcessingController(db, new ConfigurationBuilder().Build(), TimeProvider.System);
var listing = Assert.IsType<AdminProcessingController.PageDto>(Assert.IsType<OkObjectResult>((await controller.List(owner: "rd21-owner", pageSize: 1)).Result).Value);
Assert.Equal(1, listing.Total);
Assert.Equal(1, listing.Counts[OperationStatuses.Queued]);
Assert.Equal("synthetic.pdf", Assert.Single(listing.Items).Document!.Name);
var detail = Assert.IsType<AdminProcessingController.ItemDto>(Assert.IsType<OkObjectResult>((await controller.Detail(operation.Id, default)).Result).Value);
Assert.Equal(2, detail.Document!.Pages);
Assert.DoesNotContain("SECRET", System.Text.Json.JsonSerializer.Serialize(detail));
var events = Assert.IsType<AdminProcessingController.EventPageDto>(Assert.IsType<OkObjectResult>((await controller.Events(operation.Id)).Result).Value);
var item = Assert.Single(events.Items);
Assert.True(long.TryParse(item.Id, out _));
Assert.Equal(DateTimeKind.Utc, item.AtUtc.Kind);
}
private static CreateUserOperation Request(string key) => new("cv.process", key, "authorized", "local_only");
[Fact]