Add unit tests and implementations for MongoDB index models and OpenAPI metadata

- Implemented `MongoIndexModelTests` to verify index models for various stores.
- Created `OpenApiMetadataFactory` with methods to generate OpenAPI metadata.
- Added tests for `OpenApiMetadataFactory` to ensure expected defaults and URL overrides.
- Introduced `ObserverSurfaceSecrets` and `WebhookSurfaceSecrets` for managing secrets.
- Developed `RuntimeSurfaceFsClient` and `WebhookSurfaceFsClient` for manifest retrieval.
- Added dependency injection tests for `SurfaceEnvironmentRegistration` in both Observer and Webhook contexts.
- Implemented tests for secret resolution in `ObserverSurfaceSecretsTests` and `WebhookSurfaceSecretsTests`.
- Created `EnsureLinkNotMergeCollectionsMigrationTests` to validate MongoDB migration logic.
- Added project files for MongoDB tests and NuGet package mirroring.
This commit is contained in:
master
2025-11-17 21:21:56 +02:00
parent d3128aec24
commit 9075bad2d9
146 changed files with 152183 additions and 82 deletions

View File

@@ -0,0 +1,37 @@
using System.Text.Json;
using LedgerReplayHarness;
using FluentAssertions;
using Xunit;
namespace StellaOps.Findings.Ledger.Tests;
public class HarnessRunnerTests
{
[Fact]
public async Task HarnessRunner_WritesReportAndValidatesHashes()
{
var fixturePath = Path.Combine(AppContext.BaseDirectory, "fixtures", "sample.ndjson");
var tempReport = Path.GetTempFileName();
try
{
var exitCode = await HarnessRunner.RunAsync(new[] { fixturePath }, "tenant-test", tempReport);
exitCode.Should().Be(0);
var json = await File.ReadAllTextAsync(tempReport);
using var doc = JsonDocument.Parse(json);
doc.RootElement.GetProperty("eventsWritten").GetInt64().Should().BeGreaterThan(0);
doc.RootElement.GetProperty("status").GetString().Should().Be("pass");
doc.RootElement.GetProperty("tenant").GetString().Should().Be("tenant-test");
doc.RootElement.GetProperty("hashSummary").GetProperty("uniqueEventHashes").GetInt32().Should().Be(1);
doc.RootElement.GetProperty("hashSummary").GetProperty("uniqueMerkleLeaves").GetInt32().Should().Be(1);
}
finally
{
if (File.Exists(tempReport))
{
File.Delete(tempReport);
}
}
}
}

View File

@@ -0,0 +1,223 @@
using System.Diagnostics.Metrics;
using System.Linq;
using FluentAssertions;
using StellaOps.Findings.Ledger.Observability;
using Xunit;
namespace StellaOps.Findings.Ledger.Tests;
public class LedgerMetricsTests
{
[Fact]
public void ProjectionLagGauge_RecordsLatestPerTenant()
{
using var listener = CreateListener();
var measurements = new List<Measurement<double>>();
listener.SetMeasurementEventCallback<double>((instrument, measurement, tags, state) =>
{
if (instrument.Name == "ledger_projection_lag_seconds")
{
measurements.Add(measurement);
}
});
LedgerMetrics.RecordProjectionLag(TimeSpan.FromSeconds(42), "tenant-a");
listener.RecordObservableInstruments();
var measurement = measurements.Should().ContainSingle().Subject;
measurement.Value.Should().BeApproximately(42, precision: 0.001);
measurement.Tags.ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
.Should().Contain(new KeyValuePair<string, object?>("tenant", "tenant-a"));
}
[Fact]
public void MerkleAnchorDuration_EmitsHistogramMeasurement()
{
using var listener = CreateListener();
var measurements = new List<Measurement<double>>();
listener.SetMeasurementEventCallback<double>((instrument, measurement, tags, state) =>
{
if (instrument.Name == "ledger_merkle_anchor_duration_seconds")
{
measurements.Add(measurement);
}
});
LedgerMetrics.RecordMerkleAnchorDuration(TimeSpan.FromSeconds(1.5), "tenant-b");
var measurement = measurements.Should().ContainSingle().Subject;
measurement.Value.Should().BeApproximately(1.5, precision: 0.001);
measurement.Tags.ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
.Should().Contain(new KeyValuePair<string, object?>("tenant", "tenant-b"));
}
[Fact]
public void MerkleAnchorFailure_IncrementsCounter()
{
using var listener = CreateListener();
var measurements = new List<Measurement<long>>();
listener.SetMeasurementEventCallback<long>((instrument, measurement, tags, state) =>
{
if (instrument.Name == "ledger_merkle_anchor_failures_total")
{
measurements.Add(measurement);
}
});
LedgerMetrics.RecordMerkleAnchorFailure("tenant-c", "persist_failure");
var measurement = measurements.Should().ContainSingle().Subject;
measurement.Value.Should().Be(1);
var tags = measurement.Tags.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
tags.Should().Contain(new KeyValuePair<string, object?>("tenant", "tenant-c"));
tags.Should().Contain(new KeyValuePair<string, object?>("reason", "persist_failure"));
}
[Fact]
public void AttachmentFailure_IncrementsCounter()
{
using var listener = CreateListener();
var measurements = new List<Measurement<long>>();
listener.SetMeasurementEventCallback<long>((instrument, measurement, tags, state) =>
{
if (instrument.Name == "ledger_attachments_encryption_failures_total")
{
measurements.Add(measurement);
}
});
LedgerMetrics.RecordAttachmentFailure("tenant-d", "encrypt");
var measurement = measurements.Should().ContainSingle().Subject;
measurement.Value.Should().Be(1);
var tags = measurement.Tags.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
tags.Should().Contain(new KeyValuePair<string, object?>("tenant", "tenant-d"));
tags.Should().Contain(new KeyValuePair<string, object?>("stage", "encrypt"));
}
[Fact]
public void BacklogGauge_ReflectsOutstandingQueue()
{
using var listener = CreateListener();
var measurements = new List<Measurement<long>>();
// Reset
LedgerMetrics.DecrementBacklog("tenant-q");
LedgerMetrics.IncrementBacklog("tenant-q");
LedgerMetrics.IncrementBacklog("tenant-q");
LedgerMetrics.DecrementBacklog("tenant-q");
listener.SetMeasurementEventCallback<long>((instrument, measurement, tags, state) =>
{
if (instrument.Name == "ledger_ingest_backlog_events")
{
measurements.Add(measurement);
}
});
listener.RecordObservableInstruments();
var measurement = measurements.Should().ContainSingle().Subject;
measurement.Value.Should().Be(1);
measurement.Tags.ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
.Should().Contain(new KeyValuePair<string, object?>("tenant", "tenant-q"));
}
[Fact]
public void ProjectionRebuildHistogram_RecordsScenarioTags()
{
using var listener = CreateListener();
var measurements = new List<Measurement<double>>();
listener.SetMeasurementEventCallback<double>((instrument, measurement, tags, state) =>
{
if (instrument.Name == "ledger_projection_rebuild_seconds")
{
measurements.Add(measurement);
}
});
LedgerMetrics.RecordProjectionRebuild(TimeSpan.FromSeconds(3.2), "tenant-r", "replay");
var measurement = measurements.Should().ContainSingle().Subject;
measurement.Value.Should().BeApproximately(3.2, 0.001);
var tags = measurement.Tags.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
tags.Should().Contain(new KeyValuePair<string, object?>("tenant", "tenant-r"));
tags.Should().Contain(new KeyValuePair<string, object?>("scenario", "replay"));
}
[Fact]
public void DbConnectionsGauge_TracksRoleCounts()
{
using var listener = CreateListener();
var measurements = new List<Measurement<long>>();
// Reset
LedgerMetrics.DecrementDbConnection("writer");
LedgerMetrics.IncrementDbConnection("writer");
listener.SetMeasurementEventCallback<long>((instrument, measurement, tags, state) =>
{
if (instrument.Name == "ledger_db_connections_active")
{
measurements.Add(measurement);
}
});
listener.RecordObservableInstruments();
var measurement = measurements.Should().ContainSingle().Subject;
measurement.Value.Should().Be(1);
measurement.Tags.ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
.Should().Contain(new KeyValuePair<string, object?>("role", "writer"));
LedgerMetrics.DecrementDbConnection("writer");
}
[Fact]
public void VersionInfoGauge_EmitsConstantOne()
{
using var listener = CreateListener();
var measurements = new List<Measurement<long>>();
listener.SetMeasurementEventCallback<long>((instrument, measurement, tags, state) =>
{
if (instrument.Name == "ledger_app_version_info")
{
measurements.Add(measurement);
}
});
listener.RecordObservableInstruments();
var measurement = measurements.Should().ContainSingle().Subject;
measurement.Value.Should().Be(1);
var tags = measurement.Tags.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
tags.Should().ContainKey("version");
tags.Should().ContainKey("git_sha");
}
private static MeterListener CreateListener()
{
var listener = new MeterListener
{
InstrumentPublished = (instrument, l) =>
{
if (instrument.Meter.Name == "StellaOps.Findings.Ledger")
{
l.EnableMeasurementEvents(instrument);
}
}
};
listener.Start();
return listener;
}
}