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

@@ -8,7 +8,8 @@ namespace StellaOps.Telemetry.Analyzers.Tests;
public sealed class MetricLabelAnalyzerTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ValidLabelKey_NoDiagnostic()
{
var test = """
@@ -37,7 +38,8 @@ public sealed class MetricLabelAnalyzerTests
await Verifier.VerifyAnalyzerAsync(test);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task InvalidLabelKey_UpperCase_ReportsDiagnostic()
{
var test = """
@@ -70,7 +72,8 @@ public sealed class MetricLabelAnalyzerTests
await Verifier.VerifyAnalyzerAsync(test, expected);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task HighCardinalityLabelKey_UserId_ReportsDiagnostic()
{
var test = """
@@ -103,7 +106,8 @@ public sealed class MetricLabelAnalyzerTests
await Verifier.VerifyAnalyzerAsync(test, expected);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task HighCardinalityLabelKey_RequestId_ReportsDiagnostic()
{
var test = """
@@ -136,7 +140,8 @@ public sealed class MetricLabelAnalyzerTests
await Verifier.VerifyAnalyzerAsync(test, expected);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task HighCardinalityLabelKey_Email_ReportsDiagnostic()
{
var test = """
@@ -169,7 +174,8 @@ public sealed class MetricLabelAnalyzerTests
await Verifier.VerifyAnalyzerAsync(test, expected);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DynamicLabelValue_Variable_ReportsDiagnostic()
{
var test = """
@@ -201,7 +207,8 @@ public sealed class MetricLabelAnalyzerTests
await Verifier.VerifyAnalyzerAsync(test, expected);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DynamicLabelValue_InterpolatedString_ReportsDiagnostic()
{
var test = """
@@ -233,7 +240,8 @@ public sealed class MetricLabelAnalyzerTests
await Verifier.VerifyAnalyzerAsync(test, expected);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StaticLabelValue_Constant_NoDiagnostic()
{
var test = """
@@ -264,7 +272,8 @@ public sealed class MetricLabelAnalyzerTests
await Verifier.VerifyAnalyzerAsync(test);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task EnumLabelValue_NoDiagnostic()
{
var test = """
@@ -295,7 +304,8 @@ public sealed class MetricLabelAnalyzerTests
await Verifier.VerifyAnalyzerAsync(test);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task EnumToStringLabelValue_NoDiagnostic()
{
var test = """
@@ -326,7 +336,8 @@ public sealed class MetricLabelAnalyzerTests
await Verifier.VerifyAnalyzerAsync(test);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task TupleSyntax_ValidLabel_NoDiagnostic()
{
var test = """
@@ -348,7 +359,8 @@ public sealed class MetricLabelAnalyzerTests
await Verifier.VerifyAnalyzerAsync(test);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task KeyValuePairCreation_HighCardinalityKey_ReportsDiagnostic()
{
var test = """
@@ -375,7 +387,8 @@ public sealed class MetricLabelAnalyzerTests
await Verifier.VerifyAnalyzerAsync(test, expected);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task NonMetricMethod_NoDiagnostic()
{
var test = """
@@ -404,7 +417,8 @@ public sealed class MetricLabelAnalyzerTests
await Verifier.VerifyAnalyzerAsync(test);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MultipleIssues_ReportsAllDiagnostics()
{
var test = """
@@ -442,13 +456,15 @@ public sealed class MetricLabelAnalyzerTests
await Verifier.VerifyAnalyzerAsync(test, expected1, expected2);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StaticReadonlyField_LabelValue_NoDiagnostic()
{
var test = """
using System;
using System.Collections.Generic;
using StellaOps.TestKit;
namespace TestNamespace
{
public class GoldenSignalMetrics

View File

@@ -13,7 +13,8 @@ namespace StellaOps.Telemetry.Core.Tests;
/// </summary>
public sealed class AsyncResumeTestHarness
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task JobScope_CaptureAndResume_PreservesContext()
{
var accessor = new TelemetryContextAccessor();
@@ -50,7 +51,8 @@ public sealed class AsyncResumeTestHarness
Assert.Null(accessor.Context);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task JobScope_Resume_WithNullPayload_DoesNotThrow()
{
var accessor = new TelemetryContextAccessor();
@@ -61,7 +63,8 @@ public sealed class AsyncResumeTestHarness
}
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task JobScope_Resume_WithInvalidPayload_DoesNotThrow()
{
var accessor = new TelemetryContextAccessor();
@@ -72,7 +75,8 @@ public sealed class AsyncResumeTestHarness
}
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task JobScope_CreateQueueHeaders_IncludesAllContextFields()
{
var accessor = new TelemetryContextAccessor();
@@ -92,7 +96,8 @@ public sealed class AsyncResumeTestHarness
Assert.Equal("rule-789", headers["X-Imposed-Rule"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Context_Propagates_AcrossSimulatedJobQueue()
{
var accessor = new TelemetryContextAccessor();
@@ -133,7 +138,8 @@ public sealed class AsyncResumeTestHarness
Assert.Equal("tenant-B", results["job-2"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Context_IsolatedBetween_ConcurrentJobWorkers()
{
var workerResults = new ConcurrentDictionary<int, (string? TenantId, string? CorrelationId)>();
@@ -173,7 +179,8 @@ public sealed class AsyncResumeTestHarness
Assert.Equal(("tenant-3", "corr-3"), workerResults[3]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Context_FlowsThrough_NestedAsyncOperations()
{
var accessor = new TelemetryContextAccessor();
@@ -200,7 +207,8 @@ public sealed class AsyncResumeTestHarness
Assert.Equal(4, capturedTenants.Count);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Context_Preserved_AcrossConfigureAwait()
{
var accessor = new TelemetryContextAccessor();
@@ -210,6 +218,7 @@ public sealed class AsyncResumeTestHarness
using (accessor.CreateScope(new TelemetryContext { TenantId = "await-test" }))
{
capturedBefore = accessor.Context?.TenantId;
using StellaOps.TestKit;
await Task.Delay(10).ConfigureAwait(false);
capturedAfter = accessor.Context?.TenantId;
}
@@ -218,7 +227,8 @@ public sealed class AsyncResumeTestHarness
Assert.Equal("await-test", capturedAfter);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ContextInjector_Inject_AddsAllHeaders()
{
var context = new TelemetryContext
@@ -238,7 +248,8 @@ public sealed class AsyncResumeTestHarness
Assert.Equal("rule-789", headers["X-Imposed-Rule"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ContextInjector_Extract_ReconstructsContext()
{
var headers = new Dictionary<string, string>
@@ -257,7 +268,8 @@ public sealed class AsyncResumeTestHarness
Assert.Equal("rule-789", context.ImposedRule);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ContextInjector_RoundTrip_PreservesAllFields()
{
var original = new TelemetryContext

View File

@@ -6,7 +6,8 @@ namespace StellaOps.Telemetry.Core.Tests;
public sealed class CliTelemetryContextTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ParseTelemetryArgs_ExtractsTenantId_EqualsSyntax()
{
var args = new[] { "--tenant-id=my-tenant", "--other-arg", "value" };
@@ -16,7 +17,8 @@ public sealed class CliTelemetryContextTests
Assert.Equal("my-tenant", result["tenant-id"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ParseTelemetryArgs_ExtractsTenantId_SpaceSyntax()
{
var args = new[] { "--tenant-id", "my-tenant", "--other-arg", "value" };
@@ -26,7 +28,8 @@ public sealed class CliTelemetryContextTests
Assert.Equal("my-tenant", result["tenant-id"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ParseTelemetryArgs_ExtractsActor()
{
var args = new[] { "--actor=user@example.com" };
@@ -36,7 +39,8 @@ public sealed class CliTelemetryContextTests
Assert.Equal("user@example.com", result["actor"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ParseTelemetryArgs_ExtractsCorrelationId()
{
var args = new[] { "--correlation-id", "corr-123" };
@@ -46,7 +50,8 @@ public sealed class CliTelemetryContextTests
Assert.Equal("corr-123", result["correlation-id"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ParseTelemetryArgs_ExtractsImposedRule()
{
var args = new[] { "--imposed-rule=policy-abc" };
@@ -56,7 +61,8 @@ public sealed class CliTelemetryContextTests
Assert.Equal("policy-abc", result["imposed-rule"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ParseTelemetryArgs_ExtractsMultipleArgs()
{
var args = new[]
@@ -76,7 +82,8 @@ public sealed class CliTelemetryContextTests
Assert.Equal("rule-789", result["imposed-rule"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ParseTelemetryArgs_IgnoresUnknownArgs()
{
var args = new[] { "--unknown-arg", "value", "--another", "thing" };
@@ -86,7 +93,8 @@ public sealed class CliTelemetryContextTests
Assert.Empty(result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ParseTelemetryArgs_CaseInsensitive()
{
var args = new[] { "--TENANT-ID=upper", "--Actor=mixed" };
@@ -97,7 +105,8 @@ public sealed class CliTelemetryContextTests
Assert.Equal("mixed", result["actor"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Initialize_SetsContextFromExplicitValues()
{
var accessor = new TelemetryContextAccessor();
@@ -120,7 +129,8 @@ public sealed class CliTelemetryContextTests
Assert.Null(accessor.Context);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Initialize_GeneratesCorrelationId_WhenNotProvided()
{
var accessor = new TelemetryContextAccessor();
@@ -134,7 +144,8 @@ public sealed class CliTelemetryContextTests
}
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void InitializeFromArgs_UsesParseOutput()
{
var accessor = new TelemetryContextAccessor();
@@ -153,7 +164,8 @@ public sealed class CliTelemetryContextTests
}
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Initialize_ClearsContext_OnScopeDisposal()
{
var accessor = new TelemetryContextAccessor();
@@ -165,7 +177,8 @@ public sealed class CliTelemetryContextTests
Assert.Null(accessor.Context);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void InitializeFromEnvironment_ReadsEnvVars()
{
var accessor = new TelemetryContextAccessor();
@@ -195,7 +208,8 @@ public sealed class CliTelemetryContextTests
}
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Initialize_ExplicitValues_OverrideEnvironment()
{
var accessor = new TelemetryContextAccessor();
@@ -209,6 +223,7 @@ public sealed class CliTelemetryContextTests
using (CliTelemetryContext.Initialize(accessor, tenantId: "explicit-tenant"))
{
var context = accessor.Context;
using StellaOps.TestKit;
Assert.NotNull(context);
Assert.Equal("explicit-tenant", context.TenantId);
}

View File

@@ -3,11 +3,13 @@ using System.Collections.Generic;
using System.Linq;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Telemetry.Core.Tests;
public sealed class DeterministicLogFormatterTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void NormalizeTimestamp_ConvertsToUtc()
{
var localTime = new DateTimeOffset(2025, 6, 15, 14, 30, 45, 123, TimeSpan.FromHours(5));
@@ -17,7 +19,8 @@ public sealed class DeterministicLogFormatterTests
Assert.Equal("2025-06-15T09:30:45.123Z", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void NormalizeTimestamp_TruncatesSubmilliseconds()
{
var timestamp1 = new DateTimeOffset(2025, 6, 15, 14, 30, 45, 123, TimeSpan.Zero).AddTicks(1234);
@@ -30,7 +33,8 @@ public sealed class DeterministicLogFormatterTests
Assert.Equal("2025-06-15T14:30:45.123Z", result1);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void NormalizeTimestamp_DateTime_HandledCorrectly()
{
var dateTime = new DateTime(2025, 6, 15, 14, 30, 45, 123, DateTimeKind.Utc);
@@ -40,7 +44,8 @@ public sealed class DeterministicLogFormatterTests
Assert.Equal("2025-06-15T14:30:45.123Z", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void OrderFields_ReservedFieldsFirst()
{
var fields = new List<KeyValuePair<string, object?>>
@@ -59,7 +64,8 @@ public sealed class DeterministicLogFormatterTests
Assert.Equal("custom_field", result[3].Key);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void OrderFields_RemainingFieldsSortedAlphabetically()
{
var fields = new List<KeyValuePair<string, object?>>
@@ -80,7 +86,8 @@ public sealed class DeterministicLogFormatterTests
Assert.Equal("zebra", result[3].Key);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void OrderFields_CaseInsensitiveSorting()
{
var fields = new List<KeyValuePair<string, object?>>
@@ -99,7 +106,8 @@ public sealed class DeterministicLogFormatterTests
Assert.Equal("Zebra", result[3].Key);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void OrderFields_DeterministicWithSameInput()
{
var fields1 = new List<KeyValuePair<string, object?>>
@@ -124,7 +132,8 @@ public sealed class DeterministicLogFormatterTests
Assert.Equal(result1, result2);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void FormatAsNdJson_FieldsInDeterministicOrder()
{
var fields = new List<KeyValuePair<string, object?>>
@@ -145,7 +154,8 @@ public sealed class DeterministicLogFormatterTests
Assert.True(messageIndex < customIndex);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void FormatAsNdJson_WithTimestamp_NormalizesTimestamp()
{
var fields = new List<KeyValuePair<string, object?>>
@@ -159,7 +169,8 @@ public sealed class DeterministicLogFormatterTests
Assert.Contains("\"timestamp\":\"2025-06-15T09:30:45.123Z\"", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void FormatAsNdJson_ReplacesExistingTimestamp()
{
var fields = new List<KeyValuePair<string, object?>>
@@ -175,7 +186,8 @@ public sealed class DeterministicLogFormatterTests
Assert.Contains("2025-06-15T14:30:45.123Z", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void FormatAsNdJson_NullValues_Excluded()
{
var fields = new List<KeyValuePair<string, object?>>
@@ -189,7 +201,8 @@ public sealed class DeterministicLogFormatterTests
Assert.DoesNotContain("null_field", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void FormatAsKeyValue_FieldsInDeterministicOrder()
{
var fields = new List<KeyValuePair<string, object?>>
@@ -209,7 +222,8 @@ public sealed class DeterministicLogFormatterTests
Assert.True(messageIndex < customIndex);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void FormatAsKeyValue_QuotesStringsWithSpaces()
{
var fields = new List<KeyValuePair<string, object?>>
@@ -224,7 +238,8 @@ public sealed class DeterministicLogFormatterTests
Assert.Contains("simple=nospace", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void FormatAsKeyValue_EscapesQuotesInValues()
{
var fields = new List<KeyValuePair<string, object?>>
@@ -237,7 +252,8 @@ public sealed class DeterministicLogFormatterTests
Assert.Contains("\\\"quotes\\\"", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void FormatAsKeyValue_WithTimestamp_NormalizesTimestamp()
{
var fields = new List<KeyValuePair<string, object?>>
@@ -251,7 +267,8 @@ public sealed class DeterministicLogFormatterTests
Assert.Contains("timestamp=2025-06-15T09:30:45.123Z", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void FormatAsKeyValue_NullValues_ShownAsNull()
{
var fields = new List<KeyValuePair<string, object?>>
@@ -265,7 +282,8 @@ public sealed class DeterministicLogFormatterTests
Assert.Contains("null_field=null", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RepeatedFormatting_ProducesSameOutput()
{
var fields = new List<KeyValuePair<string, object?>>
@@ -285,7 +303,8 @@ public sealed class DeterministicLogFormatterTests
Assert.All(results, r => Assert.Equal(results[0], r));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RepeatedKeyValueFormatting_ProducesSameOutput()
{
var fields = new List<KeyValuePair<string, object?>>
@@ -304,7 +323,8 @@ public sealed class DeterministicLogFormatterTests
Assert.All(results, r => Assert.Equal(results[0], r));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void DateTimeOffsetValuesInFields_NormalizedToUtc()
{
var localTimestamp = new DateTimeOffset(2025, 6, 15, 14, 30, 45, 123, TimeSpan.FromHours(5));
@@ -318,7 +338,8 @@ public sealed class DeterministicLogFormatterTests
Assert.Contains("2025-06-15T09:30:45.123Z", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ReservedFieldOrder_MatchesSpecification()
{
var expectedOrder = new[]

View File

@@ -39,7 +39,8 @@ public sealed class GoldenSignalMetricsTests : IDisposable
_listener.Dispose();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RecordLatency_RecordsMeasurement()
{
using var metrics = new GoldenSignalMetrics();
@@ -49,7 +50,8 @@ public sealed class GoldenSignalMetricsTests : IDisposable
Assert.Contains(_recordedMeasurements, m => m.Name == "stellaops_latency_seconds" && (double)m.Value == 0.123);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RecordLatency_AcceptsStopwatch()
{
using var metrics = new GoldenSignalMetrics();
@@ -61,7 +63,8 @@ public sealed class GoldenSignalMetricsTests : IDisposable
Assert.Contains(_recordedMeasurements, m => m.Name == "stellaops_latency_seconds");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void MeasureLatency_RecordsDurationOnDispose()
{
using var metrics = new GoldenSignalMetrics();
@@ -75,7 +78,8 @@ public sealed class GoldenSignalMetricsTests : IDisposable
m.Name == "stellaops_latency_seconds" && (double)m.Value >= 0.01);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncrementErrors_IncreasesCounter()
{
using var metrics = new GoldenSignalMetrics();
@@ -87,7 +91,8 @@ public sealed class GoldenSignalMetricsTests : IDisposable
Assert.Contains(_recordedMeasurements, m => m.Name == "stellaops_errors_total" && (long)m.Value == 5);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncrementRequests_IncreasesCounter()
{
using var metrics = new GoldenSignalMetrics();
@@ -99,7 +104,8 @@ public sealed class GoldenSignalMetricsTests : IDisposable
Assert.Contains(_recordedMeasurements, m => m.Name == "stellaops_requests_total" && (long)m.Value == 10);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RecordLatency_WithTags_Works()
{
using var metrics = new GoldenSignalMetrics();
@@ -111,7 +117,8 @@ public sealed class GoldenSignalMetricsTests : IDisposable
Assert.Contains(_recordedMeasurements, m => m.Name == "stellaops_latency_seconds");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Options_PrefixIsApplied()
{
var options = new GoldenSignalMetricsOptions { Prefix = "custom_" };
@@ -122,7 +129,8 @@ public sealed class GoldenSignalMetricsTests : IDisposable
Assert.Contains(_recordedMeasurements, m => m.Name == "custom_latency_seconds");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SetSaturationProvider_IsInvoked()
{
var options = new GoldenSignalMetricsOptions { EnableSaturationGauge = true };
@@ -134,7 +142,8 @@ public sealed class GoldenSignalMetricsTests : IDisposable
Assert.NotNull(metrics);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CardinalityGuard_WarnsOnHighCardinality()
{
var logEntries = new List<string>();
@@ -157,7 +166,8 @@ public sealed class GoldenSignalMetricsTests : IDisposable
Assert.Contains(logEntries, e => e.Contains("High cardinality"));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CardinalityGuard_DropsMetrics_WhenConfigured()
{
var options = new GoldenSignalMetricsOptions
@@ -167,6 +177,7 @@ public sealed class GoldenSignalMetricsTests : IDisposable
};
using var metrics = new GoldenSignalMetrics(options);
using StellaOps.TestKit;
for (int i = 0; i < 10; i++)
{
metrics.IncrementRequests(1, GoldenSignalMetrics.Tag("unique_id", $"id-{i}"));
@@ -176,7 +187,8 @@ public sealed class GoldenSignalMetricsTests : IDisposable
Assert.True(requestCount <= 3);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Tag_CreatesKeyValuePair()
{
var tag = GoldenSignalMetrics.Tag("key", "value");

View File

@@ -39,7 +39,8 @@ public sealed class IncidentModeServiceTests : IDisposable
return new IncidentModeService(monitor, _contextAccessor.Object, _logger.Object, _timeProvider);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ActivateAsync_ValidActor_ReturnsSuccess()
{
using var service = CreateService();
@@ -52,7 +53,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.True(service.IsActive);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ActivateAsync_NullActor_ThrowsArgumentException()
{
using var service = CreateService();
@@ -61,7 +63,8 @@ public sealed class IncidentModeServiceTests : IDisposable
service.ActivateAsync(null!));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ActivateAsync_EmptyActor_ThrowsArgumentException()
{
using var service = CreateService();
@@ -70,7 +73,8 @@ public sealed class IncidentModeServiceTests : IDisposable
service.ActivateAsync(""));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ActivateAsync_WithTenantId_StoresTenantId()
{
using var service = CreateService();
@@ -82,7 +86,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal("tenant-123", result.State.TenantId);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ActivateAsync_WithReason_StoresReason()
{
using var service = CreateService();
@@ -94,7 +99,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal("Production incident INC-001", result.State.Reason);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ActivateAsync_DefaultTtl_UsesConfiguredDefault()
{
using var service = CreateService(opt => opt.DefaultTtl = TimeSpan.FromMinutes(45));
@@ -107,7 +113,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal(expectedExpiry, result.State.ExpiresAt);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ActivateAsync_CustomTtl_UsesTtlOverride()
{
using var service = CreateService();
@@ -120,7 +127,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal(expectedExpiry, result.State.ExpiresAt);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ActivateAsync_TtlBelowMin_ClampedToMin()
{
using var service = CreateService(opt =>
@@ -136,7 +144,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal(expectedExpiry, result.State.ExpiresAt);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ActivateAsync_TtlAboveMax_ClampedToMax()
{
using var service = CreateService(opt =>
@@ -152,7 +161,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal(expectedExpiry, result.State.ExpiresAt);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ActivateAsync_AlreadyActive_ExtendsTtlAndReturnsWasAlreadyActive()
{
using var service = CreateService();
@@ -167,7 +177,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal(firstActivationId, secondResult.State!.ActivationId); // Same activation
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ActivateAsync_RaisesActivatedEvent()
{
using var service = CreateService();
@@ -181,7 +192,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.False(eventArgs.WasReactivation);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ActivateAsync_WhenAlreadyActive_RaisesReactivationEvent()
{
using var service = CreateService();
@@ -196,7 +208,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.True(eventArgs.WasReactivation);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DeactivateAsync_WhenActive_ReturnsSuccessWithWasActive()
{
using var service = CreateService();
@@ -210,7 +223,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.False(service.IsActive);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DeactivateAsync_WhenNotActive_ReturnsSuccessWithWasNotActive()
{
using var service = CreateService();
@@ -221,7 +235,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.False(result.WasActive);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DeactivateAsync_RaisesDeactivatedEvent()
{
using var service = CreateService();
@@ -238,7 +253,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal("deactivator", eventArgs.DeactivatedBy);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ExtendTtlAsync_WhenActive_ExtendsExpiry()
{
using var service = CreateService(opt =>
@@ -255,7 +271,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal(originalExpiry + TimeSpan.FromMinutes(15), newExpiry);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ExtendTtlAsync_WhenNotActive_ReturnsNull()
{
using var service = CreateService();
@@ -265,7 +282,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Null(result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ExtendTtlAsync_WhenDisabled_ReturnsNull()
{
using var service = CreateService(opt =>
@@ -279,7 +297,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Null(result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ExtendTtlAsync_ExceedsMaxExtensions_ReturnsNull()
{
using var service = CreateService(opt =>
@@ -296,7 +315,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Null(thirdExtension);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ExtendTtlAsync_WouldExceedMaxTtl_ClampedToMax()
{
using var service = CreateService(opt =>
@@ -314,7 +334,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal(activatedAt + TimeSpan.FromHours(24), result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetIncidentTags_WhenActive_ReturnsTagDictionary()
{
using var service = CreateService(opt =>
@@ -332,7 +353,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.True(tags.ContainsKey("incident_activation_id"));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetIncidentTags_WhenNotActive_ReturnsEmptyDictionary()
{
using var service = CreateService();
@@ -342,7 +364,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Empty(tags);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetIncidentTags_WithAdditionalTags_IncludesThem()
{
using var service = CreateService(opt =>
@@ -358,7 +381,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal("us-east-1", tags["region"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CurrentState_WhenActive_ReturnsState()
{
using var service = CreateService();
@@ -372,7 +396,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal(IncidentModeSource.Api, state.Source);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CurrentState_WhenNotActive_ReturnsNull()
{
using var service = CreateService();
@@ -382,7 +407,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Null(state);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsActive_WhenNotActivated_ReturnsFalse()
{
using var service = CreateService();
@@ -390,7 +416,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.False(service.IsActive);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task IsActive_WhenActivated_ReturnsTrue()
{
using var service = CreateService();
@@ -399,7 +426,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.True(service.IsActive);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task IsActive_WhenExpired_ReturnsFalse()
{
using var service = CreateService(opt =>
@@ -414,7 +442,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.False(service.IsActive);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ActivateFromCliAsync_SetsSourceToCli()
{
using var service = CreateService();
@@ -426,7 +455,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal(IncidentModeSource.Cli, result.State.Source);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ActivateFromConfigAsync_WhenEnabled_Activates()
{
using var service = CreateService(opt =>
@@ -441,12 +471,14 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal(IncidentModeSource.Configuration, result.State.Source);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ActivateFromConfigAsync_WhenDisabled_FailsActivation()
{
using var service = CreateService(opt =>
{
opt.Enabled = false;
using StellaOps.TestKit;
});
var result = await service.ActivateFromConfigAsync();
@@ -455,7 +487,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.NotNull(result.Error);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncidentModeOptions_Validate_ValidOptions_ReturnsNoErrors()
{
var options = new IncidentModeOptions();
@@ -465,7 +498,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Empty(errors);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncidentModeOptions_Validate_DefaultTtlBelowMin_ReturnsError()
{
var options = new IncidentModeOptions
@@ -480,7 +514,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Contains("DefaultTtl", errors[0]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncidentModeOptions_Validate_DefaultTtlAboveMax_ReturnsError()
{
var options = new IncidentModeOptions
@@ -495,7 +530,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Contains("DefaultTtl", errors[0]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncidentModeOptions_Validate_InvalidSamplingRate_ReturnsError()
{
var options = new IncidentModeOptions
@@ -509,7 +545,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Contains("IncidentSamplingRate", errors[0]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncidentModeOptions_Validate_NegativeMaxExtensions_ReturnsError()
{
var options = new IncidentModeOptions
@@ -523,7 +560,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Contains("MaxExtensions", errors[0]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncidentModeOptions_ClampTtl_BelowMin_ReturnsMin()
{
var options = new IncidentModeOptions
@@ -537,7 +575,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal(TimeSpan.FromMinutes(10), result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncidentModeOptions_ClampTtl_AboveMax_ReturnsMax()
{
var options = new IncidentModeOptions
@@ -551,7 +590,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal(TimeSpan.FromHours(4), result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncidentModeOptions_ClampTtl_WithinRange_ReturnsSame()
{
var options = new IncidentModeOptions
@@ -565,7 +605,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal(TimeSpan.FromHours(2), result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncidentModeState_IsExpired_BeforeExpiry_ReturnsFalse()
{
var state = new IncidentModeState
@@ -581,7 +622,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.False(state.IsExpired);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncidentModeState_IsExpired_AfterExpiry_ReturnsTrue()
{
var state = new IncidentModeState
@@ -597,7 +639,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.True(state.IsExpired);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncidentModeState_RemainingTime_WhenNotExpired_ReturnsPositive()
{
var state = new IncidentModeState
@@ -613,7 +656,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.True(state.RemainingTime > TimeSpan.Zero);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncidentModeState_RemainingTime_WhenExpired_ReturnsZero()
{
var state = new IncidentModeState
@@ -629,7 +673,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal(TimeSpan.Zero, state.RemainingTime);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncidentModeActivationResult_Succeeded_CreatesSuccessResult()
{
var state = new IncidentModeState
@@ -650,7 +695,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Null(result.Error);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncidentModeActivationResult_Failed_CreatesFailureResult()
{
var result = IncidentModeActivationResult.Failed("Test error message");
@@ -660,7 +706,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Equal("Test error message", result.Error);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncidentModeDeactivationResult_Succeeded_CreatesSuccessResult()
{
var result = IncidentModeDeactivationResult.Succeeded(wasActive: true, IncidentModeDeactivationReason.Manual);
@@ -671,7 +718,8 @@ public sealed class IncidentModeServiceTests : IDisposable
Assert.Null(result.Error);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IncidentModeDeactivationResult_Failed_CreatesFailureResult()
{
var result = IncidentModeDeactivationResult.Failed("Test error");

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using Microsoft.Extensions.Options;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Telemetry.Core.Tests;
public sealed class LogRedactorTests
@@ -15,7 +16,8 @@ public sealed class LogRedactorTests
return new LogRedactor(monitor);
}
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData("password")]
[InlineData("Password")]
[InlineData("PASSWORD")]
@@ -34,7 +36,8 @@ public sealed class LogRedactorTests
Assert.True(result);
}
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData("TraceId")]
[InlineData("SpanId")]
[InlineData("RequestId")]
@@ -48,7 +51,8 @@ public sealed class LogRedactorTests
Assert.False(result);
}
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData("status")]
[InlineData("operation")]
[InlineData("duration")]
@@ -62,7 +66,8 @@ public sealed class LogRedactorTests
Assert.False(result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RedactString_JwtToken_Redacted()
{
var redactor = CreateRedactor();
@@ -75,7 +80,8 @@ public sealed class LogRedactorTests
Assert.Contains("[REDACTED]", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RedactString_BearerToken_Redacted()
{
var redactor = CreateRedactor();
@@ -87,7 +93,8 @@ public sealed class LogRedactorTests
Assert.Contains("[REDACTED]", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RedactString_EmailAddress_Redacted()
{
var redactor = CreateRedactor();
@@ -99,7 +106,8 @@ public sealed class LogRedactorTests
Assert.Contains("[REDACTED]", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RedactString_CreditCardNumber_Redacted()
{
var redactor = CreateRedactor();
@@ -111,7 +119,8 @@ public sealed class LogRedactorTests
Assert.Contains("[REDACTED]", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RedactString_SSN_Redacted()
{
var redactor = CreateRedactor();
@@ -123,7 +132,8 @@ public sealed class LogRedactorTests
Assert.Contains("[REDACTED]", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RedactString_IPAddress_Redacted()
{
var redactor = CreateRedactor();
@@ -135,7 +145,8 @@ public sealed class LogRedactorTests
Assert.Contains("[REDACTED]", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RedactString_ConnectionString_Redacted()
{
var redactor = CreateRedactor();
@@ -147,7 +158,8 @@ public sealed class LogRedactorTests
Assert.Contains("[REDACTED]", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RedactString_AWSAccessKey_Redacted()
{
var redactor = CreateRedactor();
@@ -159,7 +171,8 @@ public sealed class LogRedactorTests
Assert.Contains("[REDACTED]", result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RedactString_NullOrEmpty_ReturnsOriginal()
{
var redactor = CreateRedactor();
@@ -168,7 +181,8 @@ public sealed class LogRedactorTests
Assert.Equal("", redactor.RedactString(""));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RedactString_NoSensitiveData_ReturnsOriginal()
{
var redactor = CreateRedactor();
@@ -179,7 +193,8 @@ public sealed class LogRedactorTests
Assert.Equal(input, result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RedactString_DisabledRedaction_ReturnsOriginal()
{
var redactor = CreateRedactor(options => options.Enabled = false);
@@ -190,7 +205,8 @@ public sealed class LogRedactorTests
Assert.Equal(input, result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RedactAttributes_SensitiveFieldName_Redacted()
{
var redactor = CreateRedactor();
@@ -210,7 +226,8 @@ public sealed class LogRedactorTests
Assert.Contains("password", result.RedactedFieldNames);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RedactAttributes_PatternInValue_Redacted()
{
var redactor = CreateRedactor();
@@ -226,7 +243,8 @@ public sealed class LogRedactorTests
Assert.Equal("login", attributes["operation"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RedactAttributes_EmptyDictionary_ReturnsNone()
{
var redactor = CreateRedactor();
@@ -237,7 +255,8 @@ public sealed class LogRedactorTests
Assert.Equal(0, result.RedactedFieldCount);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RedactAttributes_ExcludedField_NotRedacted()
{
var redactor = CreateRedactor();
@@ -253,7 +272,8 @@ public sealed class LogRedactorTests
Assert.Equal("[REDACTED]", attributes["password"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void TenantOverride_AdditionalSensitiveFields_Applied()
{
var redactor = CreateRedactor(options =>
@@ -271,7 +291,8 @@ public sealed class LogRedactorTests
Assert.True(redactor.IsSensitiveField("customer_id", "tenant-a"));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void TenantOverride_ExcludedFields_Applied()
{
var redactor = CreateRedactor(options =>
@@ -290,7 +311,8 @@ public sealed class LogRedactorTests
Assert.False(redactor.IsSensitiveField("password", "tenant-a"));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void TenantOverride_DisableRedaction_Applied()
{
var redactor = CreateRedactor(options =>
@@ -306,7 +328,8 @@ public sealed class LogRedactorTests
Assert.False(redactor.IsRedactionEnabled("tenant-a"));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void TenantOverride_ExpiredOverride_NotApplied()
{
var redactor = CreateRedactor(options =>
@@ -321,7 +344,8 @@ public sealed class LogRedactorTests
Assert.True(redactor.IsRedactionEnabled("tenant-a"));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void TenantOverride_FutureExpiry_Applied()
{
var redactor = CreateRedactor(options =>
@@ -336,7 +360,8 @@ public sealed class LogRedactorTests
Assert.False(redactor.IsRedactionEnabled("tenant-a"));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RedactAttributes_TracksMatchedPatterns()
{
var redactor = CreateRedactor();
@@ -352,7 +377,8 @@ public sealed class LogRedactorTests
Assert.Contains("Email", result.MatchedPatterns);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CustomPlaceholder_Used()
{
var redactor = CreateRedactor(options =>

View File

@@ -4,7 +4,8 @@ using StellaOps.Telemetry.Core;
public class MetricLabelGuardTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Coerce_Enforces_Cardinality_Limit()
{
var options = Options.Create(new StellaOpsTelemetryOptions
@@ -27,7 +28,8 @@ public class MetricLabelGuardTests
Assert.Equal("other", third); // budget exceeded
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RecordRequestDuration_Truncates_Long_Labels()
{
var options = Options.Create(new StellaOpsTelemetryOptions
@@ -41,6 +43,7 @@ public class MetricLabelGuardTests
var guard = new MetricLabelGuard(options);
using var meter = new Meter("test");
using StellaOps.TestKit;
var histogram = meter.CreateHistogram<double>("request.duration");
histogram.RecordRequestDuration(guard, 42, "verylongroute", "GET", "200", "ok");

View File

@@ -4,7 +4,8 @@ namespace StellaOps.Telemetry.Core.Tests;
public sealed class ProofCoverageMetricsTests
{
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData(0, 0, 1.0)]
[InlineData(0, 10, 0.0)]
[InlineData(5, 10, 0.5)]
@@ -16,11 +17,13 @@ public sealed class ProofCoverageMetricsTests
Assert.Equal(expected, ratio, precision: 10);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RecordScanCoverage_StoresLatestValues()
{
using var metrics = new ProofCoverageMetrics();
using StellaOps.TestKit;
metrics.RecordScanCoverage(
tenantId: "tenant-1",
surfaceId: "surface-1",

View File

@@ -51,7 +51,8 @@ public sealed class SealedModeFileExporterTests : IDisposable
return new SealedModeFileExporter(monitor, _logger.Object, _timeProvider);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Initialize_CreatesFile()
{
using var exporter = CreateExporter();
@@ -63,7 +64,8 @@ public sealed class SealedModeFileExporterTests : IDisposable
Assert.True(File.Exists(exporter.CurrentFilePath));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Initialize_CreatesDirectory_WhenNotExists()
{
var newDir = Path.Combine(_testDirectory, "subdir", "nested");
@@ -77,7 +79,8 @@ public sealed class SealedModeFileExporterTests : IDisposable
Assert.True(Directory.Exists(newDir));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Initialize_CalledMultipleTimes_DoesNotThrow()
{
using var exporter = CreateExporter();
@@ -88,7 +91,8 @@ public sealed class SealedModeFileExporterTests : IDisposable
Assert.True(exporter.IsInitialized);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Write_WritesDataToFile()
{
using var exporter = CreateExporter();
@@ -103,7 +107,8 @@ public sealed class SealedModeFileExporterTests : IDisposable
Assert.Contains("[Traces]", fileContent);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Write_IncludesTimestamp()
{
using var exporter = CreateExporter();
@@ -117,7 +122,8 @@ public sealed class SealedModeFileExporterTests : IDisposable
Assert.Contains("2025-11-27", fileContent);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Write_AutoInitializesIfNotCalled()
{
using var exporter = CreateExporter();
@@ -131,7 +137,8 @@ public sealed class SealedModeFileExporterTests : IDisposable
Assert.Contains("auto-init test", fileContent);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void WriteRecord_WritesStringData()
{
using var exporter = CreateExporter();
@@ -145,7 +152,8 @@ public sealed class SealedModeFileExporterTests : IDisposable
Assert.Contains("[Logs]", fileContent);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Write_RotatesFile_WhenMaxBytesExceeded()
{
using var exporter = CreateExporter(opt =>
@@ -167,7 +175,8 @@ public sealed class SealedModeFileExporterTests : IDisposable
Assert.True(File.Exists($"{filePath}.1") || exporter.CurrentSize < 100);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CurrentSize_TracksWrittenBytes()
{
using var exporter = CreateExporter();
@@ -180,7 +189,8 @@ public sealed class SealedModeFileExporterTests : IDisposable
Assert.True(exporter.CurrentSize > initialSize);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Flush_DoesNotThrow()
{
using var exporter = CreateExporter();
@@ -192,7 +202,8 @@ public sealed class SealedModeFileExporterTests : IDisposable
// Should not throw
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Write_AfterDispose_ThrowsObjectDisposedException()
{
var exporter = CreateExporter();
@@ -203,7 +214,8 @@ public sealed class SealedModeFileExporterTests : IDisposable
exporter.Write(Encoding.UTF8.GetBytes("test"), TelemetrySignal.Traces));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Initialize_WithEmptyFilePath_Throws()
{
using var exporter = CreateExporter(opt =>
@@ -214,7 +226,8 @@ public sealed class SealedModeFileExporterTests : IDisposable
Assert.Throws<InvalidOperationException>(() => exporter.Initialize());
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Write_DifferentSignals_IncludesSignalType()
{
using var exporter = CreateExporter();
@@ -231,12 +244,14 @@ public sealed class SealedModeFileExporterTests : IDisposable
Assert.Contains("[Logs]", fileContent);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Rotation_DeletesOldestFile_WhenMaxRotatedFilesExceeded()
{
using var exporter = CreateExporter(opt =>
{
opt.MaxBytes = 50;
using StellaOps.TestKit;
opt.MaxRotatedFiles = 2;
});
exporter.Initialize();

View File

@@ -44,7 +44,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
_timeProvider);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsSealed_WhenOptionsEnabled_ReturnsTrue()
{
using var service = CreateService(opt => opt.Enabled = true);
@@ -52,7 +53,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.True(service.IsSealed);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsSealed_WhenOptionsDisabled_ReturnsFalse()
{
using var service = CreateService(opt => opt.Enabled = false);
@@ -60,7 +62,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.False(service.IsSealed);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsSealed_WhenEgressPolicySealed_ReturnsTrue()
{
_egressPolicy.Setup(p => p.IsSealed).Returns(true);
@@ -69,7 +72,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.True(service.IsSealed);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsSealed_WhenEgressPolicyNotSealed_ReturnsFalse()
{
_egressPolicy.Setup(p => p.IsSealed).Returns(false);
@@ -78,7 +82,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.False(service.IsSealed);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void EffectiveSamplingRate_WhenNotSealed_ReturnsFullSampling()
{
using var service = CreateService(opt => opt.Enabled = false);
@@ -86,7 +91,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Equal(1.0, service.EffectiveSamplingRate);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void EffectiveSamplingRate_WhenSealed_ReturnsMaxPercent()
{
using var service = CreateService(opt =>
@@ -98,7 +104,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Equal(0.1, service.EffectiveSamplingRate);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void EffectiveSamplingRate_WhenSealedWithIncidentMode_ReturnsFullSampling()
{
_incidentModeService.Setup(s => s.IsActive).Returns(true);
@@ -112,7 +119,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Equal(1.0, service.EffectiveSamplingRate);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void EffectiveSamplingRate_WhenSealedWithDisabledIncidentOverride_ReturnsCapped()
{
_incidentModeService.Setup(s => s.IsActive).Returns(true);
@@ -126,7 +134,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Equal(0.1, service.EffectiveSamplingRate);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsIncidentModeOverrideActive_WhenConditionsMet_ReturnsTrue()
{
_incidentModeService.Setup(s => s.IsActive).Returns(true);
@@ -139,7 +148,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.True(service.IsIncidentModeOverrideActive);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsIncidentModeOverrideActive_WhenNotSealed_ReturnsFalse()
{
_incidentModeService.Setup(s => s.IsActive).Returns(true);
@@ -152,7 +162,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.False(service.IsIncidentModeOverrideActive);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsIncidentModeOverrideActive_WhenIncidentNotActive_ReturnsFalse()
{
_incidentModeService.Setup(s => s.IsActive).Returns(false);
@@ -165,7 +176,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.False(service.IsIncidentModeOverrideActive);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void GetSealedModeTags_WhenNotSealed_ReturnsEmpty()
{
using var service = CreateService(opt => opt.Enabled = false);
@@ -175,7 +187,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Empty(tags);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void GetSealedModeTags_WhenSealed_ReturnsSealedTag()
{
using var service = CreateService(opt =>
@@ -189,7 +202,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Equal("true", tags["sealed"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void GetSealedModeTags_WhenSealedWithForceScrub_ReturnsScrubbedTag()
{
using var service = CreateService(opt =>
@@ -204,7 +218,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Equal("true", tags["scrubbed"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void GetSealedModeTags_WhenSealedWithIncidentOverride_ReturnsOverrideTag()
{
_incidentModeService.Setup(s => s.IsActive).Returns(true);
@@ -219,7 +234,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Equal("true", tags["incident_override"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void GetSealedModeTags_WithAdditionalTags_IncludesThem()
{
using var service = CreateService(opt =>
@@ -235,7 +251,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Equal("us-east-1", tags["region"]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsExternalExportAllowed_WhenNotSealed_ReturnsTrue()
{
using var service = CreateService(opt => opt.Enabled = false);
@@ -246,7 +263,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.True(allowed);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsExternalExportAllowed_WhenSealed_ReturnsFalse()
{
using var service = CreateService(opt => opt.Enabled = true);
@@ -257,7 +275,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.False(allowed);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void GetLocalExporterConfig_WhenNotSealed_ReturnsNull()
{
using var service = CreateService(opt => opt.Enabled = false);
@@ -267,7 +286,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Null(config);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void GetLocalExporterConfig_WhenSealed_ReturnsConfig()
{
using var service = CreateService(opt =>
@@ -288,7 +308,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Equal(5, config.MaxRotatedFiles);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RecordSealEvent_RaisesStateChangedEvent()
{
using var service = CreateService(opt => opt.Enabled = true);
@@ -303,7 +324,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Equal("test-actor", eventArgs.Actor);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RecordUnsealEvent_RaisesStateChangedEvent()
{
using var service = CreateService(opt => opt.Enabled = false);
@@ -318,17 +340,20 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Equal("admin", eventArgs.Actor);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RecordDriftEvent_DoesNotThrow()
{
using var service = CreateService(opt => opt.Enabled = true);
using StellaOps.TestKit;
var endpoint = new Uri("https://collector.example.com");
// Should not throw
service.RecordDriftEvent(endpoint, TelemetrySignal.Traces);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SealedModeTelemetryOptions_Validate_ValidOptions_ReturnsNoErrors()
{
var options = new SealedModeTelemetryOptions();
@@ -338,7 +363,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Empty(errors);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SealedModeTelemetryOptions_Validate_InvalidSamplingPercent_ReturnsError()
{
var options = new SealedModeTelemetryOptions
@@ -352,7 +378,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Contains("MaxSamplingPercent", errors[0]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SealedModeTelemetryOptions_Validate_NegativeSamplingPercent_ReturnsError()
{
var options = new SealedModeTelemetryOptions
@@ -366,7 +393,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Contains("MaxSamplingPercent", errors[0]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SealedModeTelemetryOptions_Validate_InvalidMaxBytes_ReturnsError()
{
var options = new SealedModeTelemetryOptions
@@ -380,7 +408,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Contains("MaxBytes", errors[0]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SealedModeTelemetryOptions_Validate_MissingFilePath_ReturnsError()
{
var options = new SealedModeTelemetryOptions
@@ -395,7 +424,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Contains("FilePath", errors[0]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SealedModeTelemetryOptions_GetEffectiveSamplingRate_WithoutIncident_ReturnsCapped()
{
var options = new SealedModeTelemetryOptions
@@ -408,7 +438,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Equal(0.25, rate);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SealedModeTelemetryOptions_GetEffectiveSamplingRate_WithIncidentOverride_ReturnsRequested()
{
var options = new SealedModeTelemetryOptions
@@ -422,7 +453,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Equal(0.5, rate);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SealedModeTelemetryOptions_GetEffectiveSamplingRate_WithIncidentOverride_CapsAtOne()
{
var options = new SealedModeTelemetryOptions
@@ -436,7 +468,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Equal(1.0, rate);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SealedModeExporterConfig_PropertiesAreSet()
{
var config = new SealedModeExporterConfig
@@ -453,7 +486,8 @@ public sealed class SealedModeTelemetryServiceTests : IDisposable
Assert.Equal(3, config.MaxRotatedFiles);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SealedModeStateChangedEventArgs_PropertiesAreSet()
{
var timestamp = DateTimeOffset.UtcNow;

View File

@@ -5,14 +5,16 @@ namespace StellaOps.Telemetry.Core.Tests;
public sealed class TelemetryContextAccessorTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Context_StartsNull()
{
var accessor = new TelemetryContextAccessor();
Assert.Null(accessor.Context);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Context_CanBeSetAndRead()
{
var accessor = new TelemetryContextAccessor();
@@ -23,7 +25,8 @@ public sealed class TelemetryContextAccessorTests
Assert.Same(context, accessor.Context);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Context_CanBeCleared()
{
var accessor = new TelemetryContextAccessor();
@@ -34,7 +37,8 @@ public sealed class TelemetryContextAccessorTests
Assert.Null(accessor.Context);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CreateScope_SetsContextForDuration()
{
var accessor = new TelemetryContextAccessor();
@@ -46,7 +50,8 @@ public sealed class TelemetryContextAccessorTests
}
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CreateScope_RestoresPreviousContextOnDispose()
{
var accessor = new TelemetryContextAccessor();
@@ -63,7 +68,8 @@ public sealed class TelemetryContextAccessorTests
Assert.Same(originalContext, accessor.Context);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CreateScope_RestoresNull_WhenNoPreviousContext()
{
var accessor = new TelemetryContextAccessor();
@@ -72,12 +78,14 @@ public sealed class TelemetryContextAccessorTests
using (accessor.CreateScope(scopeContext))
{
Assert.Same(scopeContext, accessor.Context);
using StellaOps.TestKit;
}
Assert.Null(accessor.Context);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Context_FlowsAcrossAsyncBoundaries()
{
var accessor = new TelemetryContextAccessor();
@@ -89,7 +97,8 @@ public sealed class TelemetryContextAccessorTests
Assert.Same(context, accessor.Context);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Context_IsIsolatedBetweenAsyncContexts()
{
var accessor = new TelemetryContextAccessor();

View File

@@ -5,7 +5,8 @@ namespace StellaOps.Telemetry.Core.Tests;
public sealed class TelemetryContextTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Context_Clone_CopiesAllFields()
{
var context = new TelemetryContext
@@ -24,7 +25,8 @@ public sealed class TelemetryContextTests
Assert.Equal(context.CorrelationId, clone.CorrelationId);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Context_Clone_IsIndependent()
{
var context = new TelemetryContext
@@ -39,38 +41,44 @@ public sealed class TelemetryContextTests
Assert.Equal("different-tenant", clone.TenantId);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsInitialized_ReturnsTrueWhenTenantIdSet()
{
var context = new TelemetryContext { TenantId = "tenant-123" };
Assert.True(context.IsInitialized);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsInitialized_ReturnsTrueWhenActorSet()
{
var context = new TelemetryContext { Actor = "user@example.com" };
Assert.True(context.IsInitialized);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsInitialized_ReturnsTrueWhenCorrelationIdSet()
{
var context = new TelemetryContext { CorrelationId = "corr-789" };
Assert.True(context.IsInitialized);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsInitialized_ReturnsFalseWhenEmpty()
{
var context = new TelemetryContext();
Assert.False(context.IsInitialized);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void TraceId_ReturnsActivityTraceId_WhenActivityExists()
{
using var activity = new Activity("test-operation");
using StellaOps.TestKit;
activity.Start();
var context = new TelemetryContext();
@@ -78,7 +86,8 @@ public sealed class TelemetryContextTests
Assert.Equal(activity.TraceId.ToString(), context.TraceId);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void TraceId_ReturnsEmpty_WhenNoActivity()
{
Activity.Current = null;

View File

@@ -9,7 +9,8 @@ namespace StellaOps.Telemetry.Core.Tests;
public sealed class TelemetryExporterGuardTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void AllowsExporterWhenPolicyMissing()
{
var loggerFactory = CreateLoggerFactory();
@@ -32,7 +33,8 @@ public sealed class TelemetryExporterGuardTests
Assert.Null(decision);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void BlocksRemoteEndpointWhenSealed()
{
var policyOptions = new EgressPolicyOptions
@@ -45,6 +47,7 @@ public sealed class TelemetryExporterGuardTests
var provider = new CollectingLoggerProvider();
using var loggerFactory = LoggerFactory.Create(builder => builder.AddProvider(provider));
using StellaOps.TestKit;
var guard = new TelemetryExporterGuard(loggerFactory.CreateLogger<TelemetryExporterGuard>(), policy);
var descriptor = new TelemetryServiceDescriptor("PolicyEngine", "1.2.3");
var collectorOptions = new StellaOpsTelemetryOptions.CollectorOptions

View File

@@ -8,7 +8,8 @@ using StellaOps.Telemetry.Core;
public class TelemetryPropagationHandlerTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Handler_Forwards_Context_Headers()
{
var options = Options.Create(new StellaOpsTelemetryOptions());
@@ -36,7 +37,8 @@ public class TelemetryPropagationHandlerTests
Assert.Equal("rule-b", terminal.SeenHeaders[options.Value.Propagation.ImposedRuleHeader]);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Handler_Propagates_Trace_When_Context_Missing()
{
var options = Options.Create(new StellaOpsTelemetryOptions());
@@ -44,6 +46,7 @@ public class TelemetryPropagationHandlerTests
using var activity = new Activity("test-trace").Start();
using StellaOps.TestKit;
var terminal = new RecordingHandler();
var handler = new TelemetryPropagationHandler(accessor, options)
{

View File

@@ -6,7 +6,8 @@ using StellaOps.Telemetry.Core;
public class TelemetryPropagationMiddlewareTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Middleware_Populates_Accessor_And_Activity_Tags()
{
var options = Options.Create(new StellaOpsTelemetryOptions());
@@ -17,6 +18,7 @@ public class TelemetryPropagationMiddlewareTests
// Assert using HttpContext.Items (source of truth for propagation in tests)
var ctx = context.Items[typeof(TelemetryContext)] as TelemetryContext
?? context.Items["TelemetryContext"] as TelemetryContext;
using StellaOps.TestKit;
Assert.NotNull(ctx);
Assert.Equal("tenant-a", ctx!.TenantId);
Assert.Equal("service-x", ctx.Actor);

View File

@@ -32,7 +32,8 @@ public sealed class TimeToFirstSignalMetricsTests : IDisposable
public void Dispose() => _listener.Dispose();
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RecordSignalRendered_WithValidData_RecordsHistogram()
{
using var metrics = new TimeToFirstSignalMetrics();
@@ -52,7 +53,8 @@ public sealed class TimeToFirstSignalMetricsTests : IDisposable
Assert.Contains(_measurements, m => m.Name == "ttfs_cache_hit_total" && m.Value is long v && v == 1);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RecordSignalRendered_ExceedsSlo_IncrementsBreachCounter()
{
var options = new TimeToFirstSignalOptions
@@ -73,7 +75,8 @@ public sealed class TimeToFirstSignalMetricsTests : IDisposable
Assert.Contains(_measurements, m => m.Name == "ttfs_slo_breach_total" && m.Value is long v && v == 1);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RecordCacheHit_IncrementsCounter()
{
using var metrics = new TimeToFirstSignalMetrics();
@@ -90,7 +93,8 @@ public sealed class TimeToFirstSignalMetricsTests : IDisposable
Assert.Contains(_measurements, m => m.Name == "ttfs_cache_hit_total" && m.Value is long v && v == 1);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void RecordCacheMiss_IncrementsCounter()
{
using var metrics = new TimeToFirstSignalMetrics();
@@ -107,7 +111,8 @@ public sealed class TimeToFirstSignalMetricsTests : IDisposable
Assert.Contains(_measurements, m => m.Name == "ttfs_cache_miss_total" && m.Value is long v && v == 1);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void MeasureSignal_Scope_RecordsLatencyOnDispose()
{
using var metrics = new TimeToFirstSignalMetrics();
@@ -125,7 +130,8 @@ public sealed class TimeToFirstSignalMetricsTests : IDisposable
Assert.Contains(_measurements, m => m.Name == "ttfs_latency_seconds" && m.Value is double v && v >= 0);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void MeasureSignal_Scope_RecordsFailureOnException()
{
using var metrics = new TimeToFirstSignalMetrics();
@@ -140,13 +146,15 @@ public sealed class TimeToFirstSignalMetricsTests : IDisposable
phase: TtfsPhase.Unknown))
{
throw new InvalidOperationException("boom");
using StellaOps.TestKit;
}
}));
Assert.Contains(_measurements, m => m.Name == "ttfs_error_total" && m.Value is long v && v == 1 && m.HasTag("error_type", "exception"));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Options_DefaultValues_MatchAdvisory()
{
var options = new TimeToFirstSignalOptions();

View File

@@ -39,7 +39,8 @@ public sealed class TtfsIngestionServiceTests : IDisposable
public void Dispose() => _listener.Dispose();
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void EvidenceBitset_From_ComputesScoreAndFlags()
{
var bitset = EvidenceBitset.From(reachability: true, callstack: false, provenance: true, vex: true);
@@ -51,7 +52,8 @@ public sealed class TtfsIngestionServiceTests : IDisposable
Assert.Equal(3, bitset.CompletenessScore);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IngestEvent_Skeleton_RecordsDurationAndBudgetViolation()
{
using var loggerFactory = LoggerFactory.Create(_ => { });
@@ -73,7 +75,8 @@ public sealed class TtfsIngestionServiceTests : IDisposable
m.HasTag("phase", "skeleton"));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IngestEvent_FirstEvidence_RecordsDurationAndEvidenceType()
{
using var loggerFactory = LoggerFactory.Create(_ => { });
@@ -99,7 +102,8 @@ public sealed class TtfsIngestionServiceTests : IDisposable
m.HasTag("phase", "first_evidence"));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IngestEvent_FullEvidence_RecordsCompletenessAndEvidenceByType()
{
using var loggerFactory = LoggerFactory.Create(_ => { });
@@ -129,10 +133,12 @@ public sealed class TtfsIngestionServiceTests : IDisposable
Assert.Contains("vex", evidenceByType);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IngestEvent_DecisionRecorded_RecordsDecisionMetricsAndClickBudgetViolation()
{
using var loggerFactory = LoggerFactory.Create(_ => { });
using StellaOps.TestKit;
var service = new TtfsIngestionService(loggerFactory.CreateLogger<TtfsIngestionService>());
service.IngestEvent(new TtfsEvent