notify doctors work, audit work, new product advisory sprints
This commit is contained in:
@@ -0,0 +1,240 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// GreyQueueEntryTests.cs
|
||||
// Description: Unit tests for Grey Queue entry model.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using System.Text.Json;
|
||||
using FluentAssertions;
|
||||
using StellaOps.Unknowns.Core.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Unknowns.Core.Tests.Models;
|
||||
|
||||
[Trait("Category", "Unit")]
|
||||
[Trait("Category", "GreyQueue")]
|
||||
public sealed class GreyQueueEntryTests
|
||||
{
|
||||
[Fact]
|
||||
public void IsPending_WhenStatusPending_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var entry = CreateEntry(GreyQueueStatus.Pending);
|
||||
|
||||
// Act & Assert
|
||||
entry.IsPending.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsPending_WhenStatusRetrying_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var entry = CreateEntry(GreyQueueStatus.Retrying);
|
||||
|
||||
// Act & Assert
|
||||
entry.IsPending.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(GreyQueueStatus.Processing)]
|
||||
[InlineData(GreyQueueStatus.Resolved)]
|
||||
[InlineData(GreyQueueStatus.Failed)]
|
||||
[InlineData(GreyQueueStatus.Expired)]
|
||||
[InlineData(GreyQueueStatus.Dismissed)]
|
||||
public void IsPending_WhenStatusNotPendingOrRetrying_ReturnsFalse(GreyQueueStatus status)
|
||||
{
|
||||
// Arrange
|
||||
var entry = CreateEntry(status);
|
||||
|
||||
// Act & Assert
|
||||
entry.IsPending.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsExhausted_WhenAttemptsEqualMax_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var entry = CreateEntry(GreyQueueStatus.Pending) with
|
||||
{
|
||||
ProcessingAttempts = 10,
|
||||
MaxAttempts = 10
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
entry.IsExhausted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsExhausted_WhenAttemptsExceedMax_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var entry = CreateEntry(GreyQueueStatus.Pending) with
|
||||
{
|
||||
ProcessingAttempts = 15,
|
||||
MaxAttempts = 10
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
entry.IsExhausted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsExhausted_WhenAttemptsBelowMax_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var entry = CreateEntry(GreyQueueStatus.Pending) with
|
||||
{
|
||||
ProcessingAttempts = 5,
|
||||
MaxAttempts = 10
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
entry.IsExhausted.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsReadyForProcessing_WhenPendingNotExhaustedAndPastTime_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var entry = CreateEntry(GreyQueueStatus.Pending) with
|
||||
{
|
||||
ProcessingAttempts = 3,
|
||||
MaxAttempts = 10,
|
||||
NextProcessingAt = DateTimeOffset.UtcNow.AddHours(-1)
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
entry.IsReadyForProcessing.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsReadyForProcessing_WhenPendingNotExhaustedAndNullTime_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var entry = CreateEntry(GreyQueueStatus.Pending) with
|
||||
{
|
||||
ProcessingAttempts = 3,
|
||||
MaxAttempts = 10,
|
||||
NextProcessingAt = null
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
entry.IsReadyForProcessing.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsReadyForProcessing_WhenFutureNextProcessingTime_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var entry = CreateEntry(GreyQueueStatus.Pending) with
|
||||
{
|
||||
ProcessingAttempts = 3,
|
||||
MaxAttempts = 10,
|
||||
NextProcessingAt = DateTimeOffset.UtcNow.AddHours(1)
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
entry.IsReadyForProcessing.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsReadyForProcessing_WhenExhausted_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var entry = CreateEntry(GreyQueueStatus.Pending) with
|
||||
{
|
||||
ProcessingAttempts = 10,
|
||||
MaxAttempts = 10,
|
||||
NextProcessingAt = DateTimeOffset.UtcNow.AddHours(-1)
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
entry.IsReadyForProcessing.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsReadyForProcessing_WhenNotPending_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var entry = CreateEntry(GreyQueueStatus.Resolved) with
|
||||
{
|
||||
ProcessingAttempts = 3,
|
||||
MaxAttempts = 10,
|
||||
NextProcessingAt = DateTimeOffset.UtcNow.AddHours(-1)
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
entry.IsReadyForProcessing.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanSerializeToJson_WithAllFields()
|
||||
{
|
||||
// Arrange
|
||||
var entry = CreateEntry(GreyQueueStatus.Pending) with
|
||||
{
|
||||
ReasonDetail = "Insufficient VEX coverage from vendors",
|
||||
TriggerOnCveUpdate = ["CVE-2025-12345", "CVE-2025-12346"],
|
||||
TriggerOnPurlMatch = ["pkg:npm/*"]
|
||||
};
|
||||
|
||||
// Act
|
||||
var json = JsonSerializer.Serialize(entry);
|
||||
var deserialized = JsonSerializer.Deserialize<GreyQueueEntry>(json);
|
||||
|
||||
// Assert
|
||||
deserialized.Should().NotBeNull();
|
||||
deserialized!.Id.Should().Be(entry.Id);
|
||||
deserialized.Reason.Should().Be(entry.Reason);
|
||||
deserialized.TriggerOnCveUpdate.Should().BeEquivalentTo(entry.TriggerOnCveUpdate);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(GreyQueueReason.InsufficientVex)]
|
||||
[InlineData(GreyQueueReason.ConflictingVex)]
|
||||
[InlineData(GreyQueueReason.MissingReachability)]
|
||||
[InlineData(GreyQueueReason.AmbiguousIdentity)]
|
||||
[InlineData(GreyQueueReason.FeedNotAvailable)]
|
||||
[InlineData(GreyQueueReason.ToolUnsupported)]
|
||||
[InlineData(GreyQueueReason.BinaryAnalysisInconclusive)]
|
||||
[InlineData(GreyQueueReason.BackportUncertain)]
|
||||
[InlineData(GreyQueueReason.MultipleInterpretations)]
|
||||
[InlineData(GreyQueueReason.AwaitingUpstreamAdvisory)]
|
||||
public void AllGreyQueueReasons_AreValid(GreyQueueReason reason)
|
||||
{
|
||||
// Arrange & Act
|
||||
var entry = CreateEntry(GreyQueueStatus.Pending) with { Reason = reason };
|
||||
|
||||
// Assert
|
||||
entry.Reason.Should().Be(reason);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(GreyQueueResolution.FeedUpdate)]
|
||||
[InlineData(GreyQueueResolution.ToolUpdate)]
|
||||
[InlineData(GreyQueueResolution.VexReceived)]
|
||||
[InlineData(GreyQueueResolution.ManualResolution)]
|
||||
[InlineData(GreyQueueResolution.Superseded)]
|
||||
[InlineData(GreyQueueResolution.NotApplicable)]
|
||||
[InlineData(GreyQueueResolution.Expired)]
|
||||
public void AllGreyQueueResolutions_AreValid(GreyQueueResolution resolution)
|
||||
{
|
||||
// Arrange & Act
|
||||
var entry = CreateEntry(GreyQueueStatus.Resolved) with { Resolution = resolution };
|
||||
|
||||
// Assert
|
||||
entry.Resolution.Should().Be(resolution);
|
||||
}
|
||||
|
||||
private static GreyQueueEntry CreateEntry(GreyQueueStatus status) => new()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = "test-tenant",
|
||||
UnknownId = Guid.NewGuid(),
|
||||
Fingerprint = "sha256:abc123",
|
||||
Status = status,
|
||||
Priority = 100,
|
||||
Reason = GreyQueueReason.InsufficientVex,
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
CreatedBy = "test-user"
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user