up
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Metrics;
|
||||
using System.Text.Json;
|
||||
using StellaOps.Concelier.Core.Diagnostics;
|
||||
using StellaOps.Concelier.Core.Linksets;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Concelier.WebService.Tests;
|
||||
|
||||
public sealed class VulnExplorerTelemetryTests : IDisposable
|
||||
{
|
||||
private readonly MeterListener _listener;
|
||||
private readonly List<(string Name, double Value, KeyValuePair<string, object?>[] Tags)> _histogramMeasurements = new();
|
||||
private readonly List<(string Name, long Value, KeyValuePair<string, object?>[] Tags)> _counterMeasurements = new();
|
||||
|
||||
public VulnExplorerTelemetryTests()
|
||||
{
|
||||
_listener = new MeterListener
|
||||
{
|
||||
InstrumentPublished = (instrument, listener) =>
|
||||
{
|
||||
if (instrument.Meter.Name == VulnExplorerTelemetry.MeterName)
|
||||
{
|
||||
listener.EnableMeasurementEvents(instrument);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_listener.SetMeasurementEventCallback<long>((instrument, measurement, tags, state) =>
|
||||
{
|
||||
if (instrument.Meter.Name == VulnExplorerTelemetry.MeterName)
|
||||
{
|
||||
_counterMeasurements.Add((instrument.Name, measurement, tags.ToArray()));
|
||||
}
|
||||
});
|
||||
|
||||
_listener.SetMeasurementEventCallback<double>((instrument, measurement, tags, state) =>
|
||||
{
|
||||
if (instrument.Meter.Name == VulnExplorerTelemetry.MeterName)
|
||||
{
|
||||
_histogramMeasurements.Add((instrument.Name, measurement, tags.ToArray()));
|
||||
}
|
||||
});
|
||||
|
||||
_listener.Start();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CountAliasCollisions_FiltersAliasConflicts()
|
||||
{
|
||||
var conflicts = new List<AdvisoryLinksetConflict>
|
||||
{
|
||||
new("aliases", "alias-inconsistency", Array.Empty<string>()),
|
||||
new("ranges", "range-divergence", Array.Empty<string>()),
|
||||
new("alias-field", "ALIAS-INCONSISTENCY", Array.Empty<string>())
|
||||
};
|
||||
|
||||
var count = VulnExplorerTelemetry.CountAliasCollisions(conflicts);
|
||||
|
||||
Assert.Equal(2, count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsWithdrawn_DetectsWithdrawnFlagsAndTimestamps()
|
||||
{
|
||||
using var json = JsonDocument.Parse("{\"withdrawn\":true,\"withdrawn_at\":\"2024-10-10T00:00:00Z\"}");
|
||||
Assert.True(VulnExplorerTelemetry.IsWithdrawn(json.RootElement));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecordChunkLatency_EmitsHistogramMeasurement()
|
||||
{
|
||||
VulnExplorerTelemetry.RecordChunkLatency("tenant-a", "vendor-a", TimeSpan.FromMilliseconds(42));
|
||||
|
||||
var measurement = Assert.Single(_histogramMeasurements);
|
||||
Assert.Equal("vuln.chunk_latency_ms", measurement.Name);
|
||||
Assert.Equal(42, measurement.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecordWithdrawnStatement_EmitsCounter()
|
||||
{
|
||||
VulnExplorerTelemetry.RecordWithdrawnStatement("tenant-b", "vendor-b");
|
||||
|
||||
var measurement = Assert.Single(_counterMeasurements);
|
||||
Assert.Equal("vuln.withdrawn_statements_total", measurement.Name);
|
||||
Assert.Equal(1, measurement.Value);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_listener.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -75,16 +75,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
|
||||
public Task InitializeAsync()
|
||||
{
|
||||
PrepareMongoEnvironment();
|
||||
if (TryStartExternalMongo(out var externalConnectionString) && !string.IsNullOrWhiteSpace(externalConnectionString))
|
||||
{
|
||||
_factory = new ConcelierApplicationFactory(externalConnectionString);
|
||||
}
|
||||
else
|
||||
{
|
||||
_runner = MongoDbRunner.Start(singleNodeReplSet: true);
|
||||
_factory = new ConcelierApplicationFactory(_runner.ConnectionString);
|
||||
}
|
||||
_factory = new ConcelierApplicationFactory(string.Empty);
|
||||
WarmupFactory(_factory);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@@ -92,30 +83,6 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
public Task DisposeAsync()
|
||||
{
|
||||
_factory.Dispose();
|
||||
if (_externalMongo is not null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_externalMongo.HasExited)
|
||||
{
|
||||
_externalMongo.Kill(true);
|
||||
_externalMongo.WaitForExit(2000);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore cleanup errors in tests
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(_externalMongoDataPath) && Directory.Exists(_externalMongoDataPath))
|
||||
{
|
||||
try { Directory.Delete(_externalMongoDataPath, recursive: true); } catch { /* ignore */ }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_runner.Dispose();
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -141,12 +108,12 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
var healthPayload = await healthResponse.Content.ReadFromJsonAsync<HealthPayload>();
|
||||
Assert.NotNull(healthPayload);
|
||||
Assert.Equal("healthy", healthPayload!.Status);
|
||||
Assert.Equal("mongo", healthPayload.Storage.Driver);
|
||||
Assert.Equal("postgres", healthPayload.Storage.Backend);
|
||||
|
||||
var readyPayload = await readyResponse.Content.ReadFromJsonAsync<ReadyPayload>();
|
||||
Assert.NotNull(readyPayload);
|
||||
Assert.Equal("ready", readyPayload!.Status);
|
||||
Assert.Equal("ready", readyPayload.Mongo.Status);
|
||||
Assert.True(readyPayload!.Status is "ready" or "degraded");
|
||||
Assert.Equal("postgres", readyPayload.Storage.Backend);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -2019,9 +1986,10 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
private sealed class ConcelierApplicationFactory : WebApplicationFactory<Program>
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
private readonly string? _previousDsn;
|
||||
private readonly string? _previousDriver;
|
||||
private readonly string? _previousTimeout;
|
||||
private readonly string? _previousPgDsn;
|
||||
private readonly string? _previousPgEnabled;
|
||||
private readonly string? _previousPgTimeout;
|
||||
private readonly string? _previousPgSchema;
|
||||
private readonly string? _previousTelemetryEnabled;
|
||||
private readonly string? _previousTelemetryLogging;
|
||||
private readonly string? _previousTelemetryTracing;
|
||||
@@ -2035,11 +2003,15 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
Action<ConcelierOptions.AuthorityOptions>? authorityConfigure = null,
|
||||
IDictionary<string, string?>? environmentOverrides = null)
|
||||
{
|
||||
_connectionString = connectionString;
|
||||
var defaultPostgresDsn = "Host=localhost;Port=5432;Database=concelier_test;Username=postgres;Password=postgres";
|
||||
_connectionString = string.IsNullOrWhiteSpace(connectionString) || connectionString.StartsWith("mongodb://", StringComparison.OrdinalIgnoreCase)
|
||||
? defaultPostgresDsn
|
||||
: connectionString;
|
||||
_authorityConfigure = authorityConfigure;
|
||||
_previousDsn = Environment.GetEnvironmentVariable("CONCELIER_STORAGE__DSN");
|
||||
_previousDriver = Environment.GetEnvironmentVariable("CONCELIER_STORAGE__DRIVER");
|
||||
_previousTimeout = Environment.GetEnvironmentVariable("CONCELIER_STORAGE__COMMANDTIMEOUTSECONDS");
|
||||
_previousPgDsn = Environment.GetEnvironmentVariable("CONCELIER_POSTGRESSTORAGE__CONNECTIONSTRING");
|
||||
_previousPgEnabled = Environment.GetEnvironmentVariable("CONCELIER_POSTGRESSTORAGE__ENABLED");
|
||||
_previousPgTimeout = Environment.GetEnvironmentVariable("CONCELIER_POSTGRESSTORAGE__COMMANDTIMEOUTSECONDS");
|
||||
_previousPgSchema = Environment.GetEnvironmentVariable("CONCELIER_POSTGRESSTORAGE__SCHEMANAME");
|
||||
_previousTelemetryEnabled = Environment.GetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLED");
|
||||
_previousTelemetryLogging = Environment.GetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLELOGGING");
|
||||
_previousTelemetryTracing = Environment.GetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLETRACING");
|
||||
@@ -2055,13 +2027,15 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", merged);
|
||||
}
|
||||
|
||||
Environment.SetEnvironmentVariable("CONCELIER_STORAGE__DSN", connectionString);
|
||||
Environment.SetEnvironmentVariable("CONCELIER_STORAGE__DRIVER", "mongo");
|
||||
Environment.SetEnvironmentVariable("CONCELIER_STORAGE__COMMANDTIMEOUTSECONDS", "30");
|
||||
Environment.SetEnvironmentVariable("CONCELIER_POSTGRESSTORAGE__CONNECTIONSTRING", _connectionString);
|
||||
Environment.SetEnvironmentVariable("CONCELIER_POSTGRESSTORAGE__ENABLED", "true");
|
||||
Environment.SetEnvironmentVariable("CONCELIER_POSTGRESSTORAGE__COMMANDTIMEOUTSECONDS", "30");
|
||||
Environment.SetEnvironmentVariable("CONCELIER_POSTGRESSTORAGE__SCHEMANAME", "vuln");
|
||||
Environment.SetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLED", "false");
|
||||
Environment.SetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLELOGGING", "false");
|
||||
Environment.SetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLETRACING", "false");
|
||||
Environment.SetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLEMETRICS", "false");
|
||||
Environment.SetEnvironmentVariable("CONCELIER_SKIP_OPTIONS_VALIDATION", "1");
|
||||
const string EvidenceRootKey = "CONCELIER_EVIDENCE__ROOT";
|
||||
var repoRoot = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..", "..", ".."));
|
||||
_additionalPreviousEnvironment[EvidenceRootKey] = Environment.GetEnvironmentVariable(EvidenceRootKey);
|
||||
@@ -2176,9 +2150,11 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
Environment.SetEnvironmentVariable("CONCELIER_STORAGE__DSN", _previousDsn);
|
||||
Environment.SetEnvironmentVariable("CONCELIER_STORAGE__DRIVER", _previousDriver);
|
||||
Environment.SetEnvironmentVariable("CONCELIER_STORAGE__COMMANDTIMEOUTSECONDS", _previousTimeout);
|
||||
Environment.SetEnvironmentVariable("CONCELIER_POSTGRESSTORAGE__CONNECTIONSTRING", _previousPgDsn);
|
||||
Environment.SetEnvironmentVariable("CONCELIER_POSTGRESSTORAGE__ENABLED", _previousPgEnabled);
|
||||
Environment.SetEnvironmentVariable("CONCELIER_POSTGRESSTORAGE__COMMANDTIMEOUTSECONDS", _previousPgTimeout);
|
||||
Environment.SetEnvironmentVariable("CONCELIER_POSTGRESSTORAGE__SCHEMANAME", _previousPgSchema);
|
||||
Environment.SetEnvironmentVariable("CONCELIER_SKIP_OPTIONS_VALIDATION", null);
|
||||
Environment.SetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLED", _previousTelemetryEnabled);
|
||||
Environment.SetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLELOGGING", _previousTelemetryLogging);
|
||||
Environment.SetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLETRACING", _previousTelemetryTracing);
|
||||
@@ -2470,13 +2446,11 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
|
||||
private sealed record HealthPayload(string Status, DateTimeOffset StartedAt, double UptimeSeconds, StoragePayload Storage, TelemetryPayload Telemetry);
|
||||
|
||||
private sealed record StoragePayload(string Driver, bool Completed, DateTimeOffset? CompletedAt, double? DurationMs);
|
||||
private sealed record StoragePayload(string Backend, bool Ready, DateTimeOffset? CheckedAt, double? LatencyMs, string? Error);
|
||||
|
||||
private sealed record TelemetryPayload(bool Enabled, bool Tracing, bool Metrics, bool Logging);
|
||||
|
||||
private sealed record ReadyPayload(string Status, DateTimeOffset StartedAt, double UptimeSeconds, ReadyMongoPayload Mongo);
|
||||
|
||||
private sealed record ReadyMongoPayload(string Status, double? LatencyMs, DateTimeOffset? CheckedAt, string? Error);
|
||||
private sealed record ReadyPayload(string Status, DateTimeOffset StartedAt, double UptimeSeconds, StoragePayload Storage);
|
||||
|
||||
private sealed record JobDefinitionPayload(string Kind, bool Enabled, string? CronExpression, TimeSpan Timeout, TimeSpan LeaseDuration, JobRunPayload? LastRun);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user