File: Shared\SqliteRepositoryTestHelpers.cs
Web Access
Project: src\tests\Aspire.Dashboard.Tests\Aspire.Dashboard.Tests.csproj (Aspire.Dashboard.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Aspire.Dashboard.Configuration;
using Aspire.Dashboard.Model;
using Aspire.Dashboard.Otlp.Storage;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
 
namespace Aspire.Dashboard.Tests.Shared;
 
internal static class SqliteRepositoryTestHelpers
{
    public static SqliteRepositoryTestContext<SqliteTelemetryRepository> CreateTemporaryTelemetryRepository(
        int? maxMetricsCount = null,
        int? maxAttributeCount = null,
        int? maxAttributeLength = null,
        int? maxSpanEventCount = null,
        int? maxTraceCount = null,
        int? maxLogCount = null,
        int? maxResourceCount = null,
        TimeSpan? subscriptionMinExecuteInterval = null,
        ILoggerFactory? loggerFactory = null,
        PauseManager? pauseManager = null,
        TimeProvider? timeProvider = null,
        IOutgoingPeerResolver[]? outgoingPeerResolvers = null)
    {
        var telemetryLimits = new TelemetryLimitOptions();
        telemetryLimits.MaxMetricsCount = maxMetricsCount ?? telemetryLimits.MaxMetricsCount;
        telemetryLimits.MaxAttributeCount = maxAttributeCount ?? telemetryLimits.MaxAttributeCount;
        telemetryLimits.MaxAttributeLength = maxAttributeLength ?? telemetryLimits.MaxAttributeLength;
        telemetryLimits.MaxSpanEventCount = maxSpanEventCount ?? telemetryLimits.MaxSpanEventCount;
        telemetryLimits.MaxTraceCount = maxTraceCount ?? telemetryLimits.MaxTraceCount;
        telemetryLimits.MaxLogCount = maxLogCount ?? telemetryLimits.MaxLogCount;
        telemetryLimits.MaxResourceCount = maxResourceCount ?? telemetryLimits.MaxResourceCount;
 
        var temporaryDirectory = Directory.CreateTempSubdirectory("aspire-tests-dashboard-telemetry-");
        try
        {
            var context = CreateTelemetryRepository(
                Path.Combine(temporaryDirectory.FullName, "dashboard.db"),
                pooling: true,
                loggerFactory: loggerFactory,
                dashboardOptions: Options.Create(new DashboardOptions { TelemetryLimits = telemetryLimits }),
                pauseManager: pauseManager,
                timeProvider: timeProvider,
                outgoingPeerResolvers: outgoingPeerResolvers);
            context.TemporaryDirectory = temporaryDirectory;
 
            if (subscriptionMinExecuteInterval is not null)
            {
                context.Repository.SubscriptionMinExecuteInterval = subscriptionMinExecuteInterval.Value;
            }
 
            return context;
        }
        catch
        {
            temporaryDirectory.Delete(recursive: true);
            throw;
        }
    }
 
    public static SqliteRepositoryTestContext<SqliteTelemetryRepository> CreateTelemetryRepository(
        string databasePath,
        bool readOnly = false,
        bool pooling = false,
        ILoggerFactory? loggerFactory = null,
        IOptions<DashboardOptions>? dashboardOptions = null,
        PauseManager? pauseManager = null,
        TimeProvider? timeProvider = null,
        IEnumerable<IOutgoingPeerResolver>? outgoingPeerResolvers = null)
    {
        var database = new DashboardSqliteDatabase(databasePath, readOnly, pooling);
        try
        {
            if (!readOnly)
            {
                database.InitializeSchemaAsync(cancellationToken: CancellationToken.None).GetAwaiter().GetResult();
            }
 
            return CreateTelemetryRepository(
                database,
                loggerFactory,
                dashboardOptions,
                pauseManager,
                timeProvider,
                outgoingPeerResolvers);
        }
        catch
        {
            database.ClearPool();
            database.Dispose();
            throw;
        }
    }
 
    public static async Task<SqliteRepositoryTestContext<SqliteTelemetryRepository>> CreateTelemetryRepositoryAsync(
        string databasePath,
        bool readOnly = false,
        bool pooling = false,
        ILoggerFactory? loggerFactory = null,
        IOptions<DashboardOptions>? dashboardOptions = null,
        PauseManager? pauseManager = null,
        TimeProvider? timeProvider = null,
        IEnumerable<IOutgoingPeerResolver>? outgoingPeerResolvers = null)
    {
        var database = new DashboardSqliteDatabase(databasePath, readOnly, pooling);
        try
        {
            if (!readOnly)
            {
                await database.InitializeSchemaAsync(cancellationToken: CancellationToken.None);
            }
 
            return CreateTelemetryRepository(
                database,
                loggerFactory,
                dashboardOptions,
                pauseManager,
                timeProvider,
                outgoingPeerResolvers);
        }
        catch
        {
            database.ClearPool();
            database.Dispose();
            throw;
        }
    }
 
    private static SqliteRepositoryTestContext<SqliteTelemetryRepository> CreateTelemetryRepository(
        DashboardSqliteDatabase database,
        ILoggerFactory? loggerFactory,
        IOptions<DashboardOptions>? dashboardOptions,
        PauseManager? pauseManager,
        TimeProvider? timeProvider,
        IEnumerable<IOutgoingPeerResolver>? outgoingPeerResolvers)
    {
        var repository = new SqliteTelemetryRepository(
            database,
            loggerFactory ?? NullLoggerFactory.Instance,
            dashboardOptions ?? Options.Create(new DashboardOptions()),
            pauseManager ?? new PauseManager(),
            timeProvider ?? TimeProvider.System,
            outgoingPeerResolvers ?? []);
        return new SqliteRepositoryTestContext<SqliteTelemetryRepository>(database, repository);
    }
 
    public static SqliteRepositoryTestContext<SqliteResourceRepository> CreateResourceRepository(
        string databasePath,
        IKnownPropertyLookup knownPropertyLookup,
        bool readOnly = false,
        bool pooling = false,
        ILoggerFactory? loggerFactory = null)
    {
        var database = new DashboardSqliteDatabase(databasePath, readOnly, pooling);
        try
        {
            if (!readOnly)
            {
                database.InitializeSchemaAsync(cancellationToken: CancellationToken.None).GetAwaiter().GetResult();
            }
 
            var repository = new SqliteResourceRepository(
                database,
                knownPropertyLookup,
                loggerFactory ?? NullLoggerFactory.Instance);
            return new SqliteRepositoryTestContext<SqliteResourceRepository>(database, repository);
        }
        catch
        {
            database.ClearPool();
            database.Dispose();
            throw;
        }
    }
}
 
internal sealed class SqliteRepositoryTestContext<TRepository>(
    DashboardSqliteDatabase database,
    TRepository repository) : IDisposable
    where TRepository : IDisposable
{
    internal DirectoryInfo? TemporaryDirectory { get; set; }
 
    public DashboardSqliteDatabase Database { get; } = database;
 
    public TRepository Repository { get; } = repository;
 
    public void Dispose()
    {
        try
        {
            Repository.Dispose();
        }
        finally
        {
            Database.ClearPool();
            Database.Dispose();
            TemporaryDirectory?.Delete(recursive: true);
        }
    }
}