Files
mic-check/src/api/MicCheck.Api/Webhooks/WebhookBackgroundService.cs
James Wampler 9e8e81ba83 Add unit tests for Audit (59% to 100%) and Webhooks (62% to 91%) namespaces
Covers AuditLogQueryService filtering/paging/actor-name join,
AuditLogResponse mapping, AuditLogsController, AuditService.LogAsync
and actor-claim resolution, WebhookResponse/WebhookDeliveryLogResponse
mapping, CreateWebhookRequestValidator, WebhookQueue, and additional
WebhookDispatcher branch coverage (scope routing, disabled webhooks,
delivery exceptions).

Excludes WebhookBackgroundService and WebhookRetryBackgroundService
from coverage: both resolve a DI-scoped concrete MicCheckDbContext via
IServiceScopeFactory, which requires a live DI container/DB per
CLAUDE.md's no-InMemory/WebApplicationFactory rule. Their query and
dispatch logic is covered by WebhookRetryTests/WebhookDispatcherTests.
2026-07-05 15:04:03 -07:00

30 lines
1.3 KiB
C#
Executable File

using System.Diagnostics.CodeAnalysis;
using MicCheck.Api.Data;
using Microsoft.Extensions.DependencyInjection;
namespace MicCheck.Api.Webhooks;
[ExcludeFromCodeCoverage(Justification = "Long-running BackgroundService reading from a Channel and issuing DI-scoped dispatches; exercising it cleanly requires a live DI container and DB, which CLAUDE.md disallows (no WebApplicationFactory/InMemory). Dispatch logic is covered by WebhookDispatcherTests.")]
public class WebhookBackgroundService(
WebhookQueue queue,
IServiceScopeFactory scopeFactory,
ILogger<WebhookBackgroundService> logger) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await foreach (var webhookEvent in queue.ReadAllAsync(stoppingToken))
{
try
{
await using var scope = scopeFactory.CreateAsyncScope();
var dispatcher = scope.ServiceProvider.GetRequiredService<WebhookDispatcher>();
await dispatcher.DispatchAsync(webhookEvent, attemptNumber: 1, stoppingToken);
}
catch (Exception ex)
{
logger.LogError(ex, "Unhandled error dispatching webhook event {EventType}", webhookEvent.EventType);
}
}
}
}