From 2bb71be5cf8f26574d2f257268211768a7f612ef Mon Sep 17 00:00:00 2001 From: Mads Magnus Due Date: Fri, 13 Dec 2024 13:14:11 +0100 Subject: [PATCH] test: forward metered data load test (#1421) --- ...ataForMeasurementPointMessageProcessDto.cs | 3 +- ...zeMeteredDataForMeasurementPointHandler.cs | 1 + .../Drivers/EdiDatabaseDriver.cs | 37 +++++++++++ .../LoadTest/ForwardMeteredData.cs | 65 +++++++++++++++++++ .../LoadTest/LoadTestFixture.cs | 3 +- 5 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 source/SubsystemTests/LoadTest/ForwardMeteredData.cs diff --git a/source/OutgoingMessages.Interfaces/Models/MeteredDataForMeasurementPoint/MeteredDataForMeasurementPointMessageProcessDto.cs b/source/OutgoingMessages.Interfaces/Models/MeteredDataForMeasurementPoint/MeteredDataForMeasurementPointMessageProcessDto.cs index 97827a51ce..8197576c72 100644 --- a/source/OutgoingMessages.Interfaces/Models/MeteredDataForMeasurementPoint/MeteredDataForMeasurementPointMessageProcessDto.cs +++ b/source/OutgoingMessages.Interfaces/Models/MeteredDataForMeasurementPoint/MeteredDataForMeasurementPointMessageProcessDto.cs @@ -20,6 +20,7 @@ public sealed class MeteredDataForMeasurementPointMessageProcessDto( EventId eventId, Actor receiver, BusinessReason businessReason, + MessageId relatedToMessageId, MeteredDataForMeasurementPointMessageSeriesDto series) : OutgoingMessageDto( DocumentType.NotifyValidatedMeasureData, @@ -29,7 +30,7 @@ public sealed class MeteredDataForMeasurementPointMessageProcessDto( businessReason.Name, receiver.ActorRole, new ExternalId(Guid.NewGuid()), - null) + relatedToMessageId) { public MeteredDataForMeasurementPointMessageSeriesDto Series { get; } = series; } diff --git a/source/Process.Application/ProcessInitializationHandlers/InitializeMeteredDataForMeasurementPointHandler.cs b/source/Process.Application/ProcessInitializationHandlers/InitializeMeteredDataForMeasurementPointHandler.cs index 1b4b14e1e3..ca92d02645 100644 --- a/source/Process.Application/ProcessInitializationHandlers/InitializeMeteredDataForMeasurementPointHandler.cs +++ b/source/Process.Application/ProcessInitializationHandlers/InitializeMeteredDataForMeasurementPointHandler.cs @@ -61,6 +61,7 @@ await _outgoingMessagesClient.EnqueueAndCommitAsync( EventId.From(Guid.NewGuid()), new Actor(ActorNumber.Create("8100000000115"), ActorRole.EnergySupplier), BusinessReason.FromCode(marketMessage.BusinessReason), + MessageId.Create(marketMessage.MessageId), new MeteredDataForMeasurementPointMessageSeriesDto( TransactionId.From(string.Join(string.Empty, series.TransactionId.Reverse())), series.MeteringPointLocationId!, diff --git a/source/SubsystemTests/Drivers/EdiDatabaseDriver.cs b/source/SubsystemTests/Drivers/EdiDatabaseDriver.cs index 89c62b73ac..ff1f107d1f 100644 --- a/source/SubsystemTests/Drivers/EdiDatabaseDriver.cs +++ b/source/SubsystemTests/Drivers/EdiDatabaseDriver.cs @@ -216,6 +216,29 @@ internal async Task DeleteOutgoingMessagesForCalculationAsync(Guid calculationId } } + /// + /// Delete outgoing messages for previuse performance test. + /// + internal async Task DeleteOutgoingMessagesForFromLoadTestAsync() + { + await using var connection = new SqlConnection(_connectionString); + + await connection.OpenAsync().ConfigureAwait(false); + await using (var deleteOutgoingMessagesCommand = new SqlCommand()) + { + deleteOutgoingMessagesCommand.CommandText = @" + DELETE FROM [MarketDocuments] WHERE BundleId IN (SELECT Id FROM [Bundles] WHERE RelatedToMessageId like 'perf_test_%'); + DELETE FROM [OutgoingMessages] WHERE [AssignedBundleId] = (SELECT Id FROM [Bundles] WHERE RelatedToMessageId like 'perf_test_%'); + DELETE FROM [Bundles] WHERE RelatedToMessageId like 'perf_test_%'; + "; + + deleteOutgoingMessagesCommand.Connection = connection; + deleteOutgoingMessagesCommand.CommandTimeout = (int)TimeSpan.FromMinutes(2).TotalSeconds; + + await deleteOutgoingMessagesCommand.ExecuteNonQueryAsync().ConfigureAwait(false); + } + } + internal async Task<(bool Success, string? Payload)> GetOutboxMessageAsync( Instant createdAfter, @@ -289,6 +312,20 @@ internal async Task CountEnqueuedMessagesForCalculationAsync(Guid calculati return enqueuedMessagesCount; } + internal async Task CountEnqueuedNotifyValidatedMeasureDataMessagesFromLoadTestAsync() + { + await using var connection = new SqlConnection(_connectionString); + + await connection.OpenAsync(); + + var enqueuedMessagesCount = await connection.ExecuteScalarAsync( + sql: @"SELECT COUNT(B.[Id]) FROM [Bundles] + WHERE [DocumentTypeInBundle] = 'NotifyValidatedMeasureData' + AND RelatedToMessageId like 'perf_test_%'"); + + return enqueuedMessagesCount; + } + private async Task GetProcessIdAsync(SqlCommand command, CancellationToken cancellationToken) { await using var connection = new SqlConnection(_connectionString); diff --git a/source/SubsystemTests/LoadTest/ForwardMeteredData.cs b/source/SubsystemTests/LoadTest/ForwardMeteredData.cs new file mode 100644 index 0000000000..f7899ebf91 --- /dev/null +++ b/source/SubsystemTests/LoadTest/ForwardMeteredData.cs @@ -0,0 +1,65 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System.Diagnostics.CodeAnalysis; +using Energinet.DataHub.EDI.SubsystemTests.Drivers; +using FluentAssertions; +using FluentAssertions.Execution; +using Xunit.Abstractions; + +namespace Energinet.DataHub.EDI.SubsystemTests.LoadTest; + +/// +/// Test class used in the CI to trigger a calculation completed event, used for load testing on t001. +/// GitHub action should be as following: +/// 1. Run Before_load_test() test +/// 2. Start Azure Load Test +/// 3. Wait for the Azure Load Test to finish +/// 4. Run After_load_test() test +/// +[SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "Test class")] +public sealed class ForwardMeteredData : IClassFixture +{ + private const string ForwardMeteredEnqueuedAmountMetric = "ForwardMeteredEnqueuedAmount"; + private readonly LoadTestFixture _fixture; + private readonly ITestOutputHelper _logger; + private readonly EdiDatabaseDriver _ediDatabaseDriver; + + public ForwardMeteredData(LoadTestFixture fixture, ITestOutputHelper logger) + { + _fixture = fixture; + _logger = logger; + _ediDatabaseDriver = new EdiDatabaseDriver(_fixture.DatabaseConnectionString); + } + + [Fact] + public async Task Before_load_test() + { + await _ediDatabaseDriver.DeleteOutgoingMessagesForFromLoadTestAsync(); + } + + [Fact] + public async Task After_load_test() + { + var enqueuedMessagesCount = await _ediDatabaseDriver.CountEnqueuedNotifyValidatedMeasureDataMessagesFromLoadTestAsync(); + _logger.WriteLine($"Enqueued messages count: {enqueuedMessagesCount} (CalculationId={_fixture.LoadTestCalculationId})"); + + _fixture.TelemetryClient.GetMetric(ForwardMeteredEnqueuedAmountMetric).TrackValue(enqueuedMessagesCount); + + using var scope = new AssertionScope(); + enqueuedMessagesCount.Should().BeGreaterThanOrEqualTo( + _fixture.MinimumEnqueuedMessagesCount, + $"because the system should be performant enough to enqueue at least {_fixture.MinimumEnqueuedMessagesCount} messages during the load test"); + } +} diff --git a/source/SubsystemTests/LoadTest/LoadTestFixture.cs b/source/SubsystemTests/LoadTest/LoadTestFixture.cs index 9514c0803c..6f2673ce7c 100644 --- a/source/SubsystemTests/LoadTest/LoadTestFixture.cs +++ b/source/SubsystemTests/LoadTest/LoadTestFixture.cs @@ -61,7 +61,8 @@ public LoadTestFixture() LoadTestCalculationId = GetConfigurationValue( configuration, - "LOAD_TEST_CALCULATION_ID"); + "LOAD_TEST_CALCULATION_ID", + defaultValue: Guid.Empty); MinimumEnqueuedMessagesCount = GetConfigurationValue( configuration,