Restructure solution layout by module
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using StellaOps.Notify.Models;
|
||||
using StellaOps.Notify.Queue;
|
||||
using StellaOps.Scheduler.Models;
|
||||
using StellaOps.Scheduler.Queue;
|
||||
using StellaOps.Scheduler.Worker.Events;
|
||||
using StellaOps.Scheduler.Worker.Execution;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Scheduler.Worker.Tests;
|
||||
|
||||
public sealed class SchedulerEventPublisherTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task PublishReportReadyAsync_EnqueuesNotifyEvent()
|
||||
{
|
||||
var queue = new RecordingNotifyEventQueue();
|
||||
var options = new NotifyEventQueueOptions();
|
||||
var publisher = new SchedulerEventPublisher(queue, options, TimeProvider.System, NullLogger<SchedulerEventPublisher>.Instance);
|
||||
var run = CreateRun();
|
||||
var message = CreateMessage(run);
|
||||
var delta = new DeltaSummary(
|
||||
run.Id,
|
||||
newFindings: 2,
|
||||
newCriticals: 1,
|
||||
newHigh: 1,
|
||||
newMedium: 0,
|
||||
newLow: 0);
|
||||
var result = CreateRunnerImageResult(run.Id, delta);
|
||||
var impact = new ImpactImage(run.Id, "registry", "repository");
|
||||
|
||||
await publisher.PublishReportReadyAsync(run, message, result, impact, CancellationToken.None);
|
||||
|
||||
Assert.Single(queue.Messages);
|
||||
var notifyEvent = queue.Messages[0].Event;
|
||||
Assert.Equal(NotifyEventKinds.ScannerReportReady, notifyEvent.Kind);
|
||||
Assert.Equal(run.TenantId, notifyEvent.Tenant);
|
||||
Assert.NotNull(notifyEvent.Scope);
|
||||
Assert.Equal("repository", notifyEvent.Scope!.Repo);
|
||||
|
||||
var payload = Assert.IsType<JsonObject>(notifyEvent.Payload);
|
||||
Assert.Equal(result.Report.ReportId, payload["reportId"]!.GetValue<string>());
|
||||
Assert.Equal("warn", payload["verdict"]!.GetValue<string>());
|
||||
var deltaNode = Assert.IsType<JsonObject>(payload["delta"]);
|
||||
Assert.Equal(1, deltaNode["newCritical"]!.GetValue<int>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PublishRescanDeltaAsync_EnqueuesDeltaEvent()
|
||||
{
|
||||
var queue = new RecordingNotifyEventQueue();
|
||||
var options = new NotifyEventQueueOptions();
|
||||
var publisher = new SchedulerEventPublisher(queue, options, TimeProvider.System, NullLogger<SchedulerEventPublisher>.Instance);
|
||||
var run = CreateRun();
|
||||
var message = CreateMessage(run);
|
||||
var delta = new DeltaSummary(run.Id, 1, 1, 0, 0, 0);
|
||||
var impactLookup = new Dictionary<string, ImpactImage>
|
||||
{
|
||||
[run.Id] = new ImpactImage(run.Id, "registry", "repository")
|
||||
};
|
||||
|
||||
await publisher.PublishRescanDeltaAsync(run, message, new[] { delta }, impactLookup, CancellationToken.None);
|
||||
|
||||
Assert.Single(queue.Messages);
|
||||
var notifyEvent = queue.Messages[0].Event;
|
||||
Assert.Equal(NotifyEventKinds.SchedulerRescanDelta, notifyEvent.Kind);
|
||||
var payload = Assert.IsType<JsonObject>(notifyEvent.Payload);
|
||||
var digests = Assert.IsType<JsonArray>(payload["impactedDigests"]);
|
||||
Assert.Equal(run.Id, digests[0]!.GetValue<string>());
|
||||
}
|
||||
|
||||
private const string SampleDigest = "sha256:1111111111111111111111111111111111111111111111111111111111111111";
|
||||
|
||||
private static Run CreateRun()
|
||||
=> new(
|
||||
id: SampleDigest,
|
||||
tenantId: "tenant-1",
|
||||
trigger: RunTrigger.Cron,
|
||||
state: RunState.Running,
|
||||
stats: new RunStats(queued: 1, completed: 0),
|
||||
createdAt: DateTimeOffset.UtcNow,
|
||||
scheduleId: "schedule-1");
|
||||
|
||||
private static RunnerSegmentQueueMessage CreateMessage(Run run)
|
||||
=> new(
|
||||
segmentId: $"{run.Id}:0000",
|
||||
runId: run.Id,
|
||||
tenantId: run.TenantId,
|
||||
imageDigests: new[] { run.Id },
|
||||
scheduleId: run.ScheduleId,
|
||||
ratePerSecond: null,
|
||||
usageOnly: true,
|
||||
attributes: new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["scheduleMode"] = ScheduleMode.AnalysisOnly.ToString()
|
||||
});
|
||||
|
||||
private static RunnerImageResult CreateRunnerImageResult(string digest, DeltaSummary? delta)
|
||||
{
|
||||
var summary = new RunnerReportSummary(
|
||||
Total: delta?.NewFindings ?? 0,
|
||||
Blocked: delta?.NewCriticals ?? 0,
|
||||
Warned: delta?.NewHigh ?? 0,
|
||||
Ignored: delta?.NewLow ?? 0,
|
||||
Quieted: 0);
|
||||
|
||||
var snapshot = new RunnerReportSnapshot(
|
||||
ReportId: $"report-{digest[^4..]}",
|
||||
ImageDigest: digest,
|
||||
Verdict: "warn",
|
||||
GeneratedAt: DateTimeOffset.UtcNow,
|
||||
Summary: summary,
|
||||
PolicyRevisionId: null,
|
||||
PolicyDigest: null);
|
||||
|
||||
return new RunnerImageResult(digest, delta, ContentRefreshed: false, snapshot, Dsse: null);
|
||||
}
|
||||
|
||||
private sealed class RecordingNotifyEventQueue : INotifyEventQueue
|
||||
{
|
||||
public List<NotifyQueueEventMessage> Messages { get; } = new();
|
||||
|
||||
public ValueTask<NotifyQueueEnqueueResult> PublishAsync(NotifyQueueEventMessage message, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Messages.Add(message);
|
||||
return ValueTask.FromResult(new NotifyQueueEnqueueResult(Guid.NewGuid().ToString("N"), false));
|
||||
}
|
||||
|
||||
public ValueTask<IReadOnlyList<INotifyQueueLease<NotifyQueueEventMessage>>> LeaseAsync(NotifyQueueLeaseRequest request, CancellationToken cancellationToken = default)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
public ValueTask<IReadOnlyList<INotifyQueueLease<NotifyQueueEventMessage>>> ClaimExpiredAsync(NotifyQueueClaimOptions options, CancellationToken cancellationToken = default)
|
||||
=> throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user