Refactor code structure and optimize performance across multiple modules

This commit is contained in:
StellaOps Bot
2025-12-26 20:03:22 +02:00
parent c786faae84
commit f10d83c444
1385 changed files with 69732 additions and 10280 deletions

View File

@@ -6,13 +6,15 @@ using StellaOps.Notify.Engine;
using StellaOps.Notify.Models;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Notify.Connectors.Email.Tests;
public sealed class EmailChannelHealthProviderTests
{
private static readonly EmailChannelHealthProvider Provider = new();
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CheckAsync_ReturnsHealthy()
{
var channel = CreateChannel(enabled: true, target: "ops@example.com");
@@ -32,7 +34,8 @@ public sealed class EmailChannelHealthProviderTests
Assert.Equal("ops@example.com", result.Metadata["email.target"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CheckAsync_ReturnsDegradedWhenDisabled()
{
var channel = CreateChannel(enabled: false, target: "ops@example.com");
@@ -50,7 +53,8 @@ public sealed class EmailChannelHealthProviderTests
Assert.Equal("false", result.Metadata["email.channel.enabled"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CheckAsync_ReturnsUnhealthyWhenTargetMissing()
{
var channel = NotifyChannel.Create(

View File

@@ -6,13 +6,15 @@ using StellaOps.Notify.Engine;
using StellaOps.Notify.Models;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Notify.Connectors.Slack.Tests;
public sealed class SlackChannelHealthProviderTests
{
private static readonly SlackChannelHealthProvider Provider = new();
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CheckAsync_ReturnsHealthy()
{
var channel = CreateChannel(enabled: true, target: "#sec-ops");
@@ -33,7 +35,8 @@ public sealed class SlackChannelHealthProviderTests
Assert.Equal(ComputeSecretHash(channel.Config.SecretRef), result.Metadata["slack.secretRef.hash"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CheckAsync_ReturnsDegradedWhenDisabled()
{
var channel = CreateChannel(enabled: false, target: "#sec-ops");
@@ -51,7 +54,8 @@ public sealed class SlackChannelHealthProviderTests
Assert.Equal("false", result.Metadata["slack.channel.enabled"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CheckAsync_ReturnsUnhealthyWhenTargetMissing()
{
var channel = CreateChannel(enabled: true, target: null);

View File

@@ -22,7 +22,8 @@ public sealed class SlackChannelTestProviderTests
Metadata: new Dictionary<string, string>(),
Attachments: new List<string>());
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task BuildPreviewAsync_ProducesDeterministicMetadata()
{
var provider = new SlackChannelTestProvider();
@@ -64,7 +65,8 @@ public sealed class SlackChannelTestProviderTests
Assert.Equal(ComputeSecretHash(channel.Config.SecretRef), result.Metadata["slack.secretRef.hash"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task BuildPreviewAsync_RedactsSensitiveProperties()
{
var provider = new SlackChannelTestProvider();
@@ -106,6 +108,7 @@ public sealed class SlackChannelTestProviderTests
private static string ComputeSecretHash(string secretRef)
{
using var sha = System.Security.Cryptography.SHA256.Create();
using StellaOps.TestKit;
var bytes = System.Text.Encoding.UTF8.GetBytes(secretRef.Trim());
var hash = sha.ComputeHash(bytes);
return System.Convert.ToHexString(hash, 0, 8).ToLowerInvariant();

View File

@@ -6,13 +6,15 @@ using StellaOps.Notify.Engine;
using StellaOps.Notify.Models;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Notify.Connectors.Teams.Tests;
public sealed class TeamsChannelHealthProviderTests
{
private static readonly TeamsChannelHealthProvider Provider = new();
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CheckAsync_ReturnsHealthyWithMetadata()
{
var channel = CreateChannel(enabled: true, endpoint: "https://contoso.webhook.office.com/webhook");
@@ -34,7 +36,8 @@ public sealed class TeamsChannelHealthProviderTests
Assert.Equal(ComputeSecretHash(channel.Config.SecretRef), result.Metadata["teams.secretRef.hash"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CheckAsync_ReturnsDegradedWhenDisabled()
{
var channel = CreateChannel(enabled: false, endpoint: "https://contoso.webhook.office.com/webhook");
@@ -52,7 +55,8 @@ public sealed class TeamsChannelHealthProviderTests
Assert.Equal("false", result.Metadata["teams.channel.enabled"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CheckAsync_ReturnsUnhealthyWhenTargetMissing()
{
var channel = CreateChannel(enabled: true, endpoint: null);

View File

@@ -11,7 +11,8 @@ namespace StellaOps.Notify.Connectors.Teams.Tests;
public sealed class TeamsChannelTestProviderTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task BuildPreviewAsync_EmitsFallbackMetadata()
{
var provider = new TeamsChannelTestProvider();
@@ -63,6 +64,7 @@ public sealed class TeamsChannelTestProviderTests
Assert.Equal(channel.Config.Endpoint, result.Metadata["teams.config.endpoint"]);
using var payload = JsonDocument.Parse(result.Preview.Body);
using StellaOps.TestKit;
Assert.Equal("message", payload.RootElement.GetProperty("type").GetString());
Assert.Equal(result.Preview.TextBody, payload.RootElement.GetProperty("text").GetString());
Assert.Equal(result.Preview.Summary, payload.RootElement.GetProperty("summary").GetString());
@@ -74,7 +76,8 @@ public sealed class TeamsChannelTestProviderTests
attachments[0].GetProperty("content").GetProperty("type").GetString());
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task BuildPreviewAsync_TruncatesLongFallback()
{
var provider = new TeamsChannelTestProvider();

View File

@@ -2,11 +2,13 @@ using System.Text.Json;
using System.Text.Json.Nodes;
using Xunit.Sdk;
using StellaOps.TestKit;
namespace StellaOps.Notify.Models.Tests;
public sealed class DocSampleTests
{
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData("notify-rule@1.sample.json")]
[InlineData("notify-channel@1.sample.json")]
[InlineData("notify-template@1.sample.json")]

View File

@@ -2,11 +2,13 @@ using System;
using System.Collections.Generic;
using System.Text.Json.Nodes;
using StellaOps.TestKit;
namespace StellaOps.Notify.Models.Tests;
public sealed class NotifyCanonicalJsonSerializerTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SerializeRuleIsDeterministic()
{
var ruleA = NotifyRule.Create(
@@ -52,7 +54,8 @@ public sealed class NotifyCanonicalJsonSerializerTests
Assert.Contains("\"schemaVersion\":\"notify.rule@1\"", jsonA, StringComparison.Ordinal);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SerializeEventOrdersPayloadKeys()
{
var payload = JsonNode.Parse("{\"b\":2,\"a\":1}");

View File

@@ -1,11 +1,13 @@
using System;
using System.Linq;
using StellaOps.TestKit;
namespace StellaOps.Notify.Models.Tests;
public sealed class NotifyDeliveryTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void AttemptsAreSortedChronologically()
{
var attempts = new[]
@@ -30,7 +32,8 @@ public sealed class NotifyDeliveryTests
attempt => Assert.Equal(NotifyDeliveryAttemptStatus.Succeeded, attempt.Status));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RenderedNormalizesAttachments()
{
var rendered = NotifyDeliveryRendered.Create(

View File

@@ -2,11 +2,13 @@ using System;
using System.Collections.Generic;
using System.Linq;
using StellaOps.TestKit;
namespace StellaOps.Notify.Models.Tests;
public sealed class NotifyRuleTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ConstructorThrowsWhenActionsMissing()
{
var match = NotifyRuleMatch.Create(eventKinds: new[] { NotifyEventKinds.ScannerReportReady });
@@ -22,7 +24,8 @@ public sealed class NotifyRuleTests
Assert.Contains("At least one action is required", exception.Message, StringComparison.Ordinal);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ConstructorNormalizesCollections()
{
var rule = NotifyRule.Create(

View File

@@ -1,11 +1,13 @@
using System;
using System.Text.Json.Nodes;
using StellaOps.TestKit;
namespace StellaOps.Notify.Models.Tests;
public sealed class NotifySchemaMigrationTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void UpgradeRuleAddsSchemaVersionWhenMissing()
{
var json = JsonNode.Parse(
@@ -28,7 +30,8 @@ public sealed class NotifySchemaMigrationTests
Assert.Equal("rule-legacy", rule.RuleId);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void UpgradeRuleThrowsOnUnknownSchema()
{
var json = JsonNode.Parse(
@@ -50,7 +53,8 @@ public sealed class NotifySchemaMigrationTests
Assert.Contains("notify rule schema version", exception.Message, StringComparison.Ordinal);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void UpgradeChannelDefaultsMissingVersion()
{
var json = JsonNode.Parse(
@@ -73,7 +77,8 @@ public sealed class NotifySchemaMigrationTests
Assert.Equal("channel-email", channel.ChannelId);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void UpgradeTemplateDefaultsMissingVersion()
{
var json = JsonNode.Parse(

View File

@@ -5,13 +5,15 @@ using System.Text.Json.Nodes;
using StellaOps.Notify.Models;
using Xunit.Sdk;
using StellaOps.TestKit;
namespace StellaOps.Notify.Models.Tests;
public sealed class PlatformEventSamplesTests
{
private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web);
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData("scanner.report.ready@1.sample.json", NotifyEventKinds.ScannerReportReady)]
[InlineData("scanner.scan.completed@1.sample.json", NotifyEventKinds.ScannerScanCompleted)]
[InlineData("scheduler.rescan.delta@1.sample.json", NotifyEventKinds.SchedulerRescanDelta)]

View File

@@ -6,6 +6,7 @@ using NJsonSchema;
using Xunit;
using System.Threading.Tasks;
using StellaOps.TestKit;
namespace StellaOps.Notify.Models.Tests;
public sealed class PlatformEventSchemaValidationTests
@@ -18,7 +19,8 @@ public sealed class PlatformEventSchemaValidationTests
new object[] { "attestor.logged@1.sample.json", "attestor.logged@1.json" }
};
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[MemberData(nameof(SampleFiles))]
public async Task EventSamplesConformToPublishedSchemas(string sampleFile, string schemaFile)
{

View File

@@ -57,7 +57,8 @@ public sealed class NatsNotifyDeliveryQueueTests : IAsyncLifetime
await _nats.DisposeAsync().ConfigureAwait(false);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Publish_ShouldDeduplicate_ByDeliveryId()
{
if (SkipIfUnavailable())
@@ -82,7 +83,8 @@ public sealed class NatsNotifyDeliveryQueueTests : IAsyncLifetime
second.MessageId.Should().Be(first.MessageId);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Release_Retry_ShouldReschedule()
{
if (SkipIfUnavailable())
@@ -108,7 +110,8 @@ public sealed class NatsNotifyDeliveryQueueTests : IAsyncLifetime
await retried.AcknowledgeAsync();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Release_RetryBeyondMax_ShouldDeadLetter()
{
if (SkipIfUnavailable())
@@ -139,6 +142,7 @@ public sealed class NatsNotifyDeliveryQueueTests : IAsyncLifetime
await Task.Delay(200);
await using var connection = new NatsConnection(new NatsOpts { Url = options.Nats.Url! });
using StellaOps.TestKit;
await connection.ConnectAsync();
var js = new NatsJSContext(connection);

View File

@@ -54,7 +54,8 @@ public sealed class NatsNotifyEventQueueTests : IAsyncLifetime
await _nats.DisposeAsync().ConfigureAwait(false);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Publish_ShouldDeduplicate_ByIdempotencyKey()
{
if (SkipIfUnavailable())
@@ -79,7 +80,8 @@ public sealed class NatsNotifyEventQueueTests : IAsyncLifetime
second.MessageId.Should().Be(first.MessageId);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Lease_Acknowledge_ShouldRemoveMessage()
{
if (SkipIfUnavailable())
@@ -114,7 +116,8 @@ public sealed class NatsNotifyEventQueueTests : IAsyncLifetime
afterAck.Should().BeEmpty();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Lease_ShouldPreserveOrdering()
{
if (SkipIfUnavailable())
@@ -139,7 +142,8 @@ public sealed class NatsNotifyEventQueueTests : IAsyncLifetime
.ContainInOrder(first.EventId, second.EventId);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ClaimExpired_ShouldReassignLease()
{
if (SkipIfUnavailable())
@@ -150,6 +154,7 @@ public sealed class NatsNotifyEventQueueTests : IAsyncLifetime
var options = CreateOptions();
await using var queue = CreateQueue(options);
using StellaOps.TestKit;
var notifyEvent = TestData.CreateEvent();
await queue.PublishAsync(new NotifyQueueEventMessage(notifyEvent, options.Nats.Subject));

View File

@@ -51,7 +51,8 @@ public sealed class RedisNotifyDeliveryQueueTests : IAsyncLifetime
await _redis.DisposeAsync().AsTask();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Publish_ShouldDeduplicate_ByDeliveryId()
{
if (SkipIfUnavailable())
@@ -76,7 +77,8 @@ public sealed class RedisNotifyDeliveryQueueTests : IAsyncLifetime
second.MessageId.Should().Be(first.MessageId);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Release_Retry_ShouldRescheduleDelivery()
{
if (SkipIfUnavailable())
@@ -103,7 +105,8 @@ public sealed class RedisNotifyDeliveryQueueTests : IAsyncLifetime
await retried.AcknowledgeAsync();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Release_RetryBeyondMax_ShouldDeadLetter()
{
if (SkipIfUnavailable())
@@ -119,6 +122,7 @@ public sealed class RedisNotifyDeliveryQueueTests : IAsyncLifetime
await using var queue = CreateQueue(options);
using StellaOps.TestKit;
await queue.PublishAsync(new NotifyDeliveryQueueMessage(
TestData.CreateDelivery(),
channelId: "channel-dead",

View File

@@ -52,7 +52,8 @@ public sealed class RedisNotifyEventQueueTests : IAsyncLifetime
await _redis.DisposeAsync().AsTask();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Publish_ShouldDeduplicate_ByIdempotencyKey()
{
if (SkipIfUnavailable())
@@ -74,7 +75,8 @@ public sealed class RedisNotifyEventQueueTests : IAsyncLifetime
second.MessageId.Should().Be(first.MessageId);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Lease_Acknowledge_ShouldRemoveMessage()
{
if (SkipIfUnavailable())
@@ -109,7 +111,8 @@ public sealed class RedisNotifyEventQueueTests : IAsyncLifetime
afterAck.Should().BeEmpty();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Lease_ShouldPreserveOrdering()
{
if (SkipIfUnavailable())
@@ -135,7 +138,8 @@ public sealed class RedisNotifyEventQueueTests : IAsyncLifetime
.ContainInOrder(new[] { firstEvent.EventId, secondEvent.EventId });
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ClaimExpired_ShouldReassignLease()
{
if (SkipIfUnavailable())
@@ -146,6 +150,7 @@ public sealed class RedisNotifyEventQueueTests : IAsyncLifetime
var options = CreateOptions();
await using var queue = CreateQueue(options);
using StellaOps.TestKit;
var notifyEvent = TestData.CreateEvent();
await queue.PublishAsync(new NotifyQueueEventMessage(notifyEvent, options.Redis.Streams[0].Stream));

View File

@@ -5,6 +5,7 @@ using StellaOps.Notify.Storage.Postgres.Models;
using StellaOps.Notify.Storage.Postgres.Repositories;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Notify.Storage.Postgres.Tests;
[Collection(NotifyPostgresCollection.Name)]
@@ -27,7 +28,8 @@ public sealed class ChannelRepositoryTests : IAsyncLifetime
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public Task DisposeAsync() => Task.CompletedTask;
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CreateAndGetById_RoundTripsChannel()
{
// Arrange
@@ -52,7 +54,8 @@ public sealed class ChannelRepositoryTests : IAsyncLifetime
fetched.ChannelType.Should().Be(ChannelType.Email);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetByName_ReturnsCorrectChannel()
{
// Arrange
@@ -67,7 +70,8 @@ public sealed class ChannelRepositoryTests : IAsyncLifetime
fetched!.Id.Should().Be(channel.Id);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetAll_ReturnsAllChannelsForTenant()
{
// Arrange
@@ -84,7 +88,8 @@ public sealed class ChannelRepositoryTests : IAsyncLifetime
channels.Select(c => c.Name).Should().Contain(["channel1", "channel2"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetAll_FiltersByEnabled()
{
// Arrange
@@ -108,7 +113,8 @@ public sealed class ChannelRepositoryTests : IAsyncLifetime
enabledChannels[0].Name.Should().Be("enabled");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetAll_FiltersByChannelType()
{
// Arrange
@@ -125,7 +131,8 @@ public sealed class ChannelRepositoryTests : IAsyncLifetime
slackChannels[0].Name.Should().Be("slack");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Update_ModifiesChannel()
{
// Arrange
@@ -151,7 +158,8 @@ public sealed class ChannelRepositoryTests : IAsyncLifetime
fetched.Config.Should().Contain("updated");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Delete_RemovesChannel()
{
// Arrange
@@ -167,7 +175,8 @@ public sealed class ChannelRepositoryTests : IAsyncLifetime
fetched.Should().BeNull();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetEnabledByType_ReturnsOnlyEnabledChannelsOfType()
{
// Arrange

View File

@@ -5,6 +5,7 @@ using StellaOps.Notify.Storage.Postgres.Models;
using StellaOps.Notify.Storage.Postgres.Repositories;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Notify.Storage.Postgres.Tests;
[Collection(NotifyPostgresCollection.Name)]
@@ -46,7 +47,8 @@ public sealed class DeliveryRepositoryTests : IAsyncLifetime
await _channelRepository.CreateAsync(channel);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CreateAndGetById_RoundTripsDelivery()
{
// Arrange
@@ -64,7 +66,8 @@ public sealed class DeliveryRepositoryTests : IAsyncLifetime
fetched.Status.Should().Be(DeliveryStatus.Pending);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetPending_ReturnsPendingDeliveries()
{
// Arrange
@@ -80,7 +83,8 @@ public sealed class DeliveryRepositoryTests : IAsyncLifetime
pendingDeliveries[0].Id.Should().Be(pending.Id);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetByStatus_ReturnsDeliveriesWithStatus()
{
// Arrange
@@ -96,7 +100,8 @@ public sealed class DeliveryRepositoryTests : IAsyncLifetime
deliveries[0].Status.Should().Be(DeliveryStatus.Pending);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetByCorrelationId_ReturnsCorrelatedDeliveries()
{
// Arrange
@@ -121,7 +126,8 @@ public sealed class DeliveryRepositoryTests : IAsyncLifetime
deliveries[0].CorrelationId.Should().Be(correlationId);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MarkQueued_UpdatesStatus()
{
// Arrange
@@ -139,7 +145,8 @@ public sealed class DeliveryRepositoryTests : IAsyncLifetime
fetched.QueuedAt.Should().NotBeNull();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MarkSent_UpdatesStatusAndExternalId()
{
// Arrange
@@ -159,7 +166,8 @@ public sealed class DeliveryRepositoryTests : IAsyncLifetime
fetched.SentAt.Should().NotBeNull();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MarkDelivered_UpdatesStatus()
{
// Arrange
@@ -179,7 +187,8 @@ public sealed class DeliveryRepositoryTests : IAsyncLifetime
fetched.DeliveredAt.Should().NotBeNull();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MarkFailed_UpdatesStatusAndError()
{
// Arrange
@@ -203,7 +212,8 @@ public sealed class DeliveryRepositoryTests : IAsyncLifetime
}
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetStats_ReturnsCorrectCounts()
{
// Arrange

View File

@@ -5,6 +5,7 @@ using StellaOps.Notify.Storage.Postgres.Models;
using StellaOps.Notify.Storage.Postgres.Repositories;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Notify.Storage.Postgres.Tests;
/// <summary>
@@ -38,7 +39,8 @@ public sealed class DigestAggregationTests : IAsyncLifetime
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public Task DisposeAsync() => Task.CompletedTask;
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Digest_CompleteLifecycle_CollectingToSent()
{
// Arrange - Create channel
@@ -90,7 +92,8 @@ public sealed class DigestAggregationTests : IAsyncLifetime
sent.SentAt.Should().NotBeNull();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Digest_GetReadyToSend_ReturnsExpiredCollectingDigests()
{
// Arrange
@@ -141,7 +144,8 @@ public sealed class DigestAggregationTests : IAsyncLifetime
ready.Should().NotContain(d => d.Id == notReadyDigest.Id);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Digest_GetByKey_ReturnsExistingDigest()
{
// Arrange
@@ -179,7 +183,8 @@ public sealed class DigestAggregationTests : IAsyncLifetime
fetched.DigestKey.Should().Be(digestKey);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Digest_Upsert_UpdatesExistingDigest()
{
// Arrange
@@ -227,7 +232,8 @@ public sealed class DigestAggregationTests : IAsyncLifetime
fetched!.CollectUntil.Should().BeCloseTo(DateTimeOffset.UtcNow.AddHours(2), TimeSpan.FromMinutes(1));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Digest_DeleteOld_RemovesSentDigests()
{
// Arrange
@@ -281,7 +287,8 @@ public sealed class DigestAggregationTests : IAsyncLifetime
recentFetch.Should().NotBeNull();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Digest_MultipleRecipients_SeparateDigests()
{
// Arrange
@@ -329,7 +336,8 @@ public sealed class DigestAggregationTests : IAsyncLifetime
fetched1!.Id.Should().NotBe(fetched2!.Id);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Digest_EventAccumulation_AppendsToArray()
{
// Arrange
@@ -374,7 +382,8 @@ public sealed class DigestAggregationTests : IAsyncLifetime
}
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Digest_QuietHoursIntegration_RespectsSilencePeriod()
{
// Arrange - Create quiet hours config
@@ -402,7 +411,8 @@ public sealed class DigestAggregationTests : IAsyncLifetime
fetched[0].Enabled.Should().BeTrue();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Digest_MaintenanceWindowIntegration_RespectsWindow()
{
// Arrange - Create maintenance window
@@ -430,7 +440,8 @@ public sealed class DigestAggregationTests : IAsyncLifetime
all.Should().ContainSingle(w => w.Id == window.Id);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Digest_DeterministicOrdering_ConsistentResults()
{
// Arrange
@@ -474,7 +485,8 @@ public sealed class DigestAggregationTests : IAsyncLifetime
ids2.Should().Equal(ids3);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Digest_MultiTenantIsolation_NoLeakage()
{
// Arrange

View File

@@ -5,6 +5,7 @@ using StellaOps.Notify.Storage.Postgres.Models;
using StellaOps.Notify.Storage.Postgres.Repositories;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Notify.Storage.Postgres.Tests;
[Collection(NotifyPostgresCollection.Name)]
@@ -46,7 +47,8 @@ public sealed class DigestRepositoryTests : IAsyncLifetime
await _channelRepository.CreateAsync(channel);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task UpsertAndGetById_RoundTripsDigest()
{
// Arrange
@@ -74,7 +76,8 @@ public sealed class DigestRepositoryTests : IAsyncLifetime
fetched.Status.Should().Be(DigestStatus.Collecting);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetByKey_ReturnsCorrectDigest()
{
// Arrange
@@ -98,7 +101,8 @@ public sealed class DigestRepositoryTests : IAsyncLifetime
fetched!.Id.Should().Be(digest.Id);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task AddEvent_IncrementsEventCount()
{
// Arrange
@@ -115,7 +119,8 @@ public sealed class DigestRepositoryTests : IAsyncLifetime
fetched!.EventCount.Should().Be(2);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetReadyToSend_ReturnsDigestsReadyToSend()
{
// Arrange - One ready digest (past CollectUntil), one not ready
@@ -151,7 +156,8 @@ public sealed class DigestRepositoryTests : IAsyncLifetime
readyDigests[0].DigestKey.Should().Be("ready");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MarkSending_UpdatesStatus()
{
// Arrange
@@ -168,7 +174,8 @@ public sealed class DigestRepositoryTests : IAsyncLifetime
fetched!.Status.Should().Be(DigestStatus.Sending);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MarkSent_UpdatesStatusAndSentAt()
{
// Arrange
@@ -187,7 +194,8 @@ public sealed class DigestRepositoryTests : IAsyncLifetime
fetched.SentAt.Should().NotBeNull();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DeleteOld_RemovesOldDigests()
{
// Arrange

View File

@@ -5,6 +5,7 @@ using StellaOps.Notify.Storage.Postgres.Models;
using StellaOps.Notify.Storage.Postgres.Repositories;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Notify.Storage.Postgres.Tests;
/// <summary>
@@ -38,7 +39,8 @@ public sealed class EscalationHandlingTests : IAsyncLifetime
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public Task DisposeAsync() => Task.CompletedTask;
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Escalation_CompleteLifecycle_ActiveToResolved()
{
// Arrange - Create escalation policy with multiple steps
@@ -121,7 +123,8 @@ public sealed class EscalationHandlingTests : IAsyncLifetime
finalActive.Should().NotContain(s => s.Id == escalationState.Id);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Escalation_MultiStepProgression_TracksCorrectly()
{
// Arrange
@@ -167,7 +170,8 @@ public sealed class EscalationHandlingTests : IAsyncLifetime
final.Status.Should().Be(EscalationStatus.Active);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Escalation_GetByCorrelation_RetrievesCorrectState()
{
// Arrange
@@ -202,7 +206,8 @@ public sealed class EscalationHandlingTests : IAsyncLifetime
fetched.CorrelationId.Should().Be(correlationId);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Escalation_OnCallScheduleIntegration_FindsCorrectResponder()
{
// Arrange - Create on-call schedules
@@ -238,7 +243,8 @@ public sealed class EscalationHandlingTests : IAsyncLifetime
secondary!.Participants.Should().Contain("charlie@example.com");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Escalation_MultipleActiveStates_AllTracked()
{
// Arrange
@@ -279,7 +285,8 @@ public sealed class EscalationHandlingTests : IAsyncLifetime
}
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Escalation_PolicyDisabled_NotUsed()
{
// Arrange
@@ -309,7 +316,8 @@ public sealed class EscalationHandlingTests : IAsyncLifetime
enabledOnly.Should().ContainSingle(p => p.Id == enabledPolicy.Id);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Escalation_IncidentLinking_TracksAssociation()
{
// Arrange
@@ -354,7 +362,8 @@ public sealed class EscalationHandlingTests : IAsyncLifetime
fetched!.IncidentId.Should().Be(incident.Id);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Escalation_RepeatIteration_TracksRepeats()
{
// Arrange
@@ -387,7 +396,8 @@ public sealed class EscalationHandlingTests : IAsyncLifetime
fetched!.RepeatIteration.Should().Be(2);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Escalation_DeterministicOrdering_ConsistentResults()
{
// Arrange
@@ -429,7 +439,8 @@ public sealed class EscalationHandlingTests : IAsyncLifetime
ids2.Should().Equal(ids3);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Escalation_Metadata_PreservedThroughLifecycle()
{
// Arrange

View File

@@ -5,6 +5,7 @@ using StellaOps.Notify.Storage.Postgres.Models;
using StellaOps.Notify.Storage.Postgres.Repositories;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Notify.Storage.Postgres.Tests;
[Collection(NotifyPostgresCollection.Name)]
@@ -27,7 +28,8 @@ public sealed class InboxRepositoryTests : IAsyncLifetime
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public Task DisposeAsync() => Task.CompletedTask;
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CreateAndGetById_RoundTripsInboxItem()
{
// Arrange
@@ -54,7 +56,8 @@ public sealed class InboxRepositoryTests : IAsyncLifetime
fetched.Read.Should().BeFalse();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetForUser_ReturnsUserInboxItems()
{
// Arrange
@@ -74,7 +77,8 @@ public sealed class InboxRepositoryTests : IAsyncLifetime
items.Select(i => i.Title).Should().Contain(["Item 1", "Item 2"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetForUser_FiltersUnreadOnly()
{
// Arrange
@@ -93,7 +97,8 @@ public sealed class InboxRepositoryTests : IAsyncLifetime
unreadItems[0].Title.Should().Be("Unread");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetUnreadCount_ReturnsCorrectCount()
{
// Arrange
@@ -111,7 +116,8 @@ public sealed class InboxRepositoryTests : IAsyncLifetime
count.Should().Be(2);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MarkRead_UpdatesReadStatus()
{
// Arrange
@@ -129,7 +135,8 @@ public sealed class InboxRepositoryTests : IAsyncLifetime
fetched.ReadAt.Should().NotBeNull();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MarkAllRead_MarksAllUserItemsAsRead()
{
// Arrange
@@ -147,7 +154,8 @@ public sealed class InboxRepositoryTests : IAsyncLifetime
unreadCount.Should().Be(0);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Archive_ArchivesItem()
{
// Arrange
@@ -165,7 +173,8 @@ public sealed class InboxRepositoryTests : IAsyncLifetime
fetched.ArchivedAt.Should().NotBeNull();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Delete_RemovesItem()
{
// Arrange
@@ -182,7 +191,8 @@ public sealed class InboxRepositoryTests : IAsyncLifetime
fetched.Should().BeNull();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DeleteOld_RemovesOldItems()
{
// Arrange - We can't easily set CreatedAt in the test, so this tests the API works

View File

@@ -5,6 +5,7 @@ using StellaOps.Notify.Storage.Postgres.Models;
using StellaOps.Notify.Storage.Postgres.Repositories;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Notify.Storage.Postgres.Tests;
/// <summary>
@@ -40,7 +41,8 @@ public sealed class NotificationDeliveryFlowTests : IAsyncLifetime
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public Task DisposeAsync() => Task.CompletedTask;
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DeliveryFlow_CompleteLifecycle_PendingToDelivered()
{
// Arrange - Create channel
@@ -129,7 +131,8 @@ public sealed class NotificationDeliveryFlowTests : IAsyncLifetime
finalPending.Should().NotContain(d => d.Id == delivery.Id);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DeliveryFlow_FailureAndRetry_TracksErrorState()
{
// Arrange
@@ -167,7 +170,8 @@ public sealed class NotificationDeliveryFlowTests : IAsyncLifetime
failed.Attempt.Should().BeGreaterThanOrEqualTo(1);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DeliveryFlow_MultipleChannels_IndependentDeliveries()
{
// Arrange - Create two channels
@@ -232,7 +236,8 @@ public sealed class NotificationDeliveryFlowTests : IAsyncLifetime
slack.Status.Should().Be(DeliveryStatus.Failed);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DeliveryFlow_StatsAccumulation_CorrectAggregates()
{
// Arrange
@@ -290,7 +295,8 @@ public sealed class NotificationDeliveryFlowTests : IAsyncLifetime
stats.Failed.Should().Be(2);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DeliveryFlow_DeterministicOrdering_ConsistentResults()
{
// Arrange
@@ -332,7 +338,8 @@ public sealed class NotificationDeliveryFlowTests : IAsyncLifetime
ids2.Should().Equal(ids3);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DeliveryFlow_AuditTrail_RecordsActions()
{
// Arrange
@@ -372,7 +379,8 @@ public sealed class NotificationDeliveryFlowTests : IAsyncLifetime
audits[0].Action.Should().Be("channel.created");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DeliveryFlow_DisabledChannel_NotQueried()
{
// Arrange

View File

@@ -5,6 +5,7 @@ using StellaOps.Notify.Storage.Postgres.Models;
using StellaOps.Notify.Storage.Postgres.Repositories;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Notify.Storage.Postgres.Tests;
[Collection(NotifyPostgresCollection.Name)]
@@ -29,7 +30,8 @@ public sealed class NotifyAuditRepositoryTests : IAsyncLifetime
private Task ResetAsync() => _fixture.ExecuteSqlAsync("TRUNCATE TABLE notify.audit, notify.deliveries, notify.digests, notify.channels RESTART IDENTITY CASCADE;");
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Create_ReturnsGeneratedId()
{
// Arrange
@@ -50,7 +52,8 @@ public sealed class NotifyAuditRepositoryTests : IAsyncLifetime
id.Should().BeGreaterThan(0);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task List_ReturnsAuditEntriesOrderedByCreatedAtDesc()
{
// Arrange
@@ -69,7 +72,8 @@ public sealed class NotifyAuditRepositoryTests : IAsyncLifetime
audits[0].Action.Should().Be("action2"); // Most recent first
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetByResource_ReturnsResourceAudits()
{
// Arrange
@@ -92,7 +96,8 @@ public sealed class NotifyAuditRepositoryTests : IAsyncLifetime
audits[0].ResourceId.Should().Be(resourceId);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetByResource_WithoutResourceId_ReturnsAllOfType()
{
// Arrange
@@ -119,7 +124,8 @@ public sealed class NotifyAuditRepositoryTests : IAsyncLifetime
audits.Should().HaveCount(2);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetByCorrelationId_ReturnsCorrelatedAudits()
{
// Arrange
@@ -150,7 +156,8 @@ public sealed class NotifyAuditRepositoryTests : IAsyncLifetime
audits.Should().AllSatisfy(a => a.CorrelationId.Should().Be(correlationId));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DeleteOld_RemovesOldAudits()
{
// Arrange

View File

@@ -5,6 +5,7 @@ using StellaOps.Notify.Storage.Postgres.Models;
using StellaOps.Notify.Storage.Postgres.Repositories;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Notify.Storage.Postgres.Tests;
[Collection(NotifyPostgresCollection.Name)]
@@ -27,7 +28,8 @@ public sealed class RuleRepositoryTests : IAsyncLifetime
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public Task DisposeAsync() => Task.CompletedTask;
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CreateAndGetById_RoundTripsRule()
{
// Arrange
@@ -55,7 +57,8 @@ public sealed class RuleRepositoryTests : IAsyncLifetime
fetched.EventTypes.Should().Contain(["scan.completed", "vulnerability.found"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetByName_ReturnsCorrectRule()
{
// Arrange
@@ -70,7 +73,8 @@ public sealed class RuleRepositoryTests : IAsyncLifetime
fetched!.Id.Should().Be(rule.Id);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task List_ReturnsAllRulesForTenant()
{
// Arrange
@@ -87,7 +91,8 @@ public sealed class RuleRepositoryTests : IAsyncLifetime
rules.Select(r => r.Name).Should().Contain(["rule1", "rule2"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task List_FiltersByEnabled()
{
// Arrange
@@ -111,7 +116,8 @@ public sealed class RuleRepositoryTests : IAsyncLifetime
enabledRules[0].Name.Should().Be("enabled");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetMatchingRules_ReturnsRulesForEventType()
{
// Arrange
@@ -142,7 +148,8 @@ public sealed class RuleRepositoryTests : IAsyncLifetime
matchingRules[0].Name.Should().Be("scan-rule");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Update_ModifiesRule()
{
// Arrange
@@ -170,7 +177,8 @@ public sealed class RuleRepositoryTests : IAsyncLifetime
fetched.Enabled.Should().BeFalse();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Delete_RemovesRule()
{
// Arrange

View File

@@ -5,6 +5,7 @@ using StellaOps.Notify.Storage.Postgres.Models;
using StellaOps.Notify.Storage.Postgres.Repositories;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Notify.Storage.Postgres.Tests;
[Collection(NotifyPostgresCollection.Name)]
@@ -27,7 +28,8 @@ public sealed class TemplateRepositoryTests : IAsyncLifetime
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public Task DisposeAsync() => Task.CompletedTask;
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CreateAndGetById_RoundTripsTemplate()
{
// Arrange
@@ -54,7 +56,8 @@ public sealed class TemplateRepositoryTests : IAsyncLifetime
fetched.SubjectTemplate.Should().Contain("{{imageName}}");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetByName_ReturnsCorrectTemplate()
{
// Arrange
@@ -69,7 +72,8 @@ public sealed class TemplateRepositoryTests : IAsyncLifetime
fetched!.Id.Should().Be(template.Id);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetByName_FiltersCorrectlyByLocale()
{
// Arrange
@@ -102,7 +106,8 @@ public sealed class TemplateRepositoryTests : IAsyncLifetime
frFetched!.BodyTemplate.Should().Contain("français");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task List_ReturnsAllTemplatesForTenant()
{
// Arrange
@@ -119,7 +124,8 @@ public sealed class TemplateRepositoryTests : IAsyncLifetime
templates.Select(t => t.Name).Should().Contain(["template1", "template2"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task List_FiltersByChannelType()
{
// Arrange
@@ -136,7 +142,8 @@ public sealed class TemplateRepositoryTests : IAsyncLifetime
emailTemplates[0].Name.Should().Be("email");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Update_ModifiesTemplate()
{
// Arrange
@@ -162,7 +169,8 @@ public sealed class TemplateRepositoryTests : IAsyncLifetime
fetched.BodyTemplate.Should().Be("Updated body content");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Delete_RemovesTemplate()
{
// Arrange

View File

@@ -78,7 +78,8 @@ public sealed class CrudEndpointsTests : IClassFixture<WebApplicationFactory<Pro
public Task DisposeAsync() => Task.CompletedTask;
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task RuleCrudLifecycle()
{
var client = _factory.CreateClient();
@@ -100,7 +101,8 @@ public sealed class CrudEndpointsTests : IClassFixture<WebApplicationFactory<Pro
Assert.Equal(HttpStatusCode.NotFound, afterDelete.StatusCode);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ChannelTemplateDeliveryAndAuditFlows()
{
var client = _factory.CreateClient();
@@ -170,7 +172,8 @@ public sealed class CrudEndpointsTests : IClassFixture<WebApplicationFactory<Pro
Assert.Equal(HttpStatusCode.NotFound, digestAfterDelete.StatusCode);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task LockEndpointsAllowAcquireAndRelease()
{
var client = _factory.CreateClient();
@@ -198,7 +201,8 @@ public sealed class CrudEndpointsTests : IClassFixture<WebApplicationFactory<Pro
Assert.True(secondContent? ["acquired"]?.GetValue<bool>());
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ChannelTestSendReturnsPreview()
{
var client = _factory.CreateClient();
@@ -243,7 +247,8 @@ public sealed class CrudEndpointsTests : IClassFixture<WebApplicationFactory<Pro
Assert.Equal(json["traceId"]?.GetValue<string>(), metadata?["traceId"]?.GetValue<string>());
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ChannelTestSendHonoursRateLimit()
{
using var limitedFactory = _factory.WithWebHostBuilder(builder =>
@@ -280,7 +285,8 @@ public sealed class CrudEndpointsTests : IClassFixture<WebApplicationFactory<Pro
Assert.NotNull(second.Headers.RetryAfter);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ChannelTestSendUsesRegisteredProvider()
{
var providerName = typeof(FakeSlackTestProvider).FullName!;
@@ -290,6 +296,7 @@ public sealed class CrudEndpointsTests : IClassFixture<WebApplicationFactory<Pro
builder.ConfigureServices(services =>
{
services.AddSingleton<INotifyChannelTestProvider, FakeSlackTestProvider>();
using StellaOps.TestKit;
});
});

View File

@@ -2,6 +2,7 @@ using System.Net.Http.Json;
using System.Text.Json.Nodes;
using Microsoft.AspNetCore.Mvc.Testing;
using StellaOps.TestKit;
namespace StellaOps.Notify.WebService.Tests;
public sealed class NormalizeEndpointsTests : IClassFixture<WebApplicationFactory<Program>>, IAsyncLifetime
@@ -25,7 +26,8 @@ public sealed class NormalizeEndpointsTests : IClassFixture<WebApplicationFactor
public Task DisposeAsync() => Task.CompletedTask;
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task RuleNormalizeAddsSchemaVersion()
{
var client = _factory.CreateClient();
@@ -41,7 +43,8 @@ public sealed class NormalizeEndpointsTests : IClassFixture<WebApplicationFactor
Assert.Equal("notify.rule@1", normalized?["schemaVersion"]?.GetValue<string>());
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ChannelNormalizeAddsSchemaVersion()
{
var client = _factory.CreateClient();
@@ -57,7 +60,8 @@ public sealed class NormalizeEndpointsTests : IClassFixture<WebApplicationFactor
Assert.Equal("notify.channel@1", normalized?["schemaVersion"]?.GetValue<string>());
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task TemplateNormalizeAddsSchemaVersion()
{
var client = _factory.CreateClient();

View File

@@ -12,11 +12,13 @@ using StellaOps.Notify.Worker.Handlers;
using StellaOps.Notify.Worker.Processing;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Notify.Worker.Tests;
public sealed class NotifyEventLeaseProcessorTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ProcessOnce_ShouldAcknowledgeSuccessfulLease()
{
var lease = new FakeLease();
@@ -32,7 +34,8 @@ public sealed class NotifyEventLeaseProcessorTests
lease.ReleaseCount.Should().Be(0);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ProcessOnce_ShouldRetryOnHandlerFailure()
{
var lease = new FakeLease();