Files
AutopilotMonitor/src/Backend/AutopilotMonitor.Functions.Tests/IngestStatusPrefetchTests.cs
T
Oliver Kieselbach f4d51ea499 perf(backend): cut App Insights cost + ingest hot-path reads (review follow-through)
Telemetry cost (L4): worker-side adaptive sampling now excludes Request;Event
so the enriched RequestTelemetryMiddleware copy is never thinned; host.json
Host.Results=Error drops the duplicate unenriched host request item. One
complete request row per call instead of two (one unsampled+unenriched, one
sampled+enriched).

Ingest hot path (H2/H3): BlockedDeviceService caches negative answers (30s
revalidation, symmetric with positive entries) so healthy devices no longer
pay a BlockedDevices point-read per request; SessionDeletionGuard returns its
already-loaded row and IncrementSessionEventCountAsync returns the post-merge
snapshot, collapsing ~4 Sessions reads/batch to ~2.

Queue-worker correctness (O1/O2): new GetSessionEventsStrictAsync propagates
storage failures on the analyze + vulnerability-correlate paths so a transient
read fault retries/poisons instead of silently deleting the message after
"analyzing" an empty stream. Fail-soft variant kept for UI/metrics surfaces.

Review fixes: parse prefetched Status as string (the actual wire format, was
int -> optimization never fired); session-aware block over a cached negative
entry keeps its session scope instead of widening to whole-device.

2274/2274 backend tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 22:43:39 +02:00

54 lines
1.9 KiB
C#

using AutopilotMonitor.Functions.Functions.Ingest;
using AutopilotMonitor.Shared.Models;
using Azure.Data.Tables;
using Xunit;
namespace AutopilotMonitor.Functions.Tests;
/// <summary>
/// Pins the wire-format contract of the ingest status prefetch (Codex finding): Sessions
/// stores <c>Status</c> as a STRING (<c>status.ToString()</c>), so the prefetch must parse
/// strings — an int-only pattern match never fired and silently disabled the point-read
/// saving for the stall-heal probe.
/// </summary>
public class IngestStatusPrefetchTests
{
private static TableEntity Row(object? status = null)
{
var row = new TableEntity("11111111-1111-1111-1111-111111111111", "22222222-2222-2222-2222-222222222222");
if (status != null) row["Status"] = status;
return row;
}
[Theory]
[InlineData("InProgress", SessionStatus.InProgress)]
[InlineData("Stalled", SessionStatus.Stalled)]
[InlineData("succeeded", SessionStatus.Succeeded)] // mapper parses case-insensitively — mirror it
public void StringStatus_TheActualWireFormat_IsParsed(string stored, SessionStatus expected)
{
Assert.Equal(expected, IngestTelemetryFunction.TryReadSessionStatus(Row(stored)));
}
[Fact]
public void IntStatus_LegacyDefensiveFallback_IsCast()
{
var defined = (int)SessionStatus.Stalled;
Assert.Equal(SessionStatus.Stalled, IngestTelemetryFunction.TryReadSessionStatus(Row(defined)));
}
[Theory]
[InlineData("NotARealStatus")]
[InlineData("")]
public void UnparseableStatus_ReturnsNull_SoCallerFallsBackToOwnRead(string stored)
{
Assert.Null(IngestTelemetryFunction.TryReadSessionStatus(Row(stored)));
}
[Fact]
public void MissingStatusOrRow_ReturnsNull()
{
Assert.Null(IngestTelemetryFunction.TryReadSessionStatus(Row(status: null)));
Assert.Null(IngestTelemetryFunction.TryReadSessionStatus(null));
}
}