using System.Globalization; using System.Text.Json; using Npgsql; using Xunit.Abstractions; namespace MeterVault.Integration.Tests.Performance; /// /// Loads the synthetic raw dataset into a database an app has already migrated — the pre-rework app (c0f52db) or the /// current one — for the page-level before/after comparison (brief §9.10). Nothing derived is written: the next start /// of that app rebuilds consumption (and, in the new app, rollups and coverage) itself, because the load clears the /// stored normalization revision. Writes manifest-<label>.json with the meter and type ids the page /// timings address. /// /// /// METERVAULT_PERF=1 METERVAULT_PERF_LOAD_DB="Host=…;Port=…;Database=metervault;Username=metervault;Password=metervault" /// dotnet test tests/Integration.Tests --filter "FullyQualifiedName~Performance.SyntheticLoadTests". The dataset ends at /// METERVAULT_PERF_NOW, or at the current time, so the pages see recent live data. /// [Trait("Category", "Performance")] public sealed class SyntheticLoadTests(ITestOutputHelper output) { [PerfLoadFact] public async Task Load_the_synthetic_dataset_into_an_app_migrated_database() { var settings = PerfSettings.Current; using var log = new PerfLog(settings, "load", output); var target = settings.LoadDatabase!; await using (var connection = new NpgsqlConnection(target)) { await connection.OpenAsync(); var migrated = await PerfDatabase.ScalarAsync(connection, "SELECT to_regclass('meter') IS NOT NULL AND to_regclass('app_setting') IS NOT NULL"); Assert.True(migrated is true, "The target database is not migrated: start the app against it once first."); var schema = await PerfDatabase.ScalarAsync(connection, "SELECT to_regclass('consumption_rollup') IS NOT NULL") is true ? "analysis rework" : "pre-rework (c0f52db)"; log.Write($"Target schema: {schema}"); } // The current minute, so the hourly live meters end just before the pages are timed. var now = settings.Now ?? DateTimeOffset.UtcNow.AddSeconds(-DateTimeOffset.UtcNow.Second); var zone = TimeZoneInfo.FindSystemTimeZoneById("Europe/Berlin"); var manifest = await SyntheticDataset.LoadAsync(target, now, zone, settings.Scale, log.Write); Directory.CreateDirectory(settings.OutputDirectory); var path = Path.Combine(settings.OutputDirectory, $"manifest-{settings.Label}.json"); await File.WriteAllTextAsync(path, JsonSerializer.Serialize(manifest, DatasetManifest.Json)); log.Write(string.Create(CultureInfo.InvariantCulture, $"Loaded {manifest.MeterCount} meters and {manifest.Readings:N0} readings; manifest {path}")); } }