Skip to content

Commit

Permalink
Merge branch 'main' into madu/improve-perf-for-checking-duplicated-tr…
Browse files Browse the repository at this point in the history
…ansactionid
  • Loading branch information
MadsDue authored Dec 13, 2024
2 parents ee48811 + 41f9628 commit fb74cf4
Show file tree
Hide file tree
Showing 17 changed files with 847 additions and 143 deletions.
4 changes: 3 additions & 1 deletion source/B2BApi/IncomingMessages/IncomingMessageReceiver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ public async Task<HttpResponseData> RunAsync(
var stopwatch = Stopwatch.StartNew();
var cancellationToken = request.GetCancellationToken(hostCancellationToken);

if (!await _featureFlagManager.ReceiveMeteredDataForMeasurementPointsAsync().ConfigureAwait(false))
if (incomingDocumentTypeName != null &&
incomingDocumentTypeName.Equals(IncomingDocumentType.NotifyValidatedMeasureData.Name, StringComparison.OrdinalIgnoreCase)
&& !await _featureFlagManager.ReceiveMeteredDataForMeasurementPointsAsync().ConfigureAwait(false))
{
/*
* The HTTP 403 Forbidden client error response status code indicates that the server understood the request
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.

using System.Diagnostics.CodeAnalysis;
using System.Text;
using Energinet.DataHub.EDI.BuildingBlocks.Domain.Models;
using Energinet.DataHub.EDI.IntegrationTests.Fixtures;
using Energinet.DataHub.EDI.OutgoingMessages.IntegrationTests.DocumentAsserters;
using Energinet.DataHub.EDI.OutgoingMessages.Interfaces.Models.Peek;
using Energinet.DataHub.EDI.Tests.Infrastructure.OutgoingMessages.RSM012;
using FluentAssertions;
using FluentAssertions.Execution;
using NodaTime;
Expand All @@ -26,6 +28,10 @@

namespace Energinet.DataHub.EDI.IntegrationTests.Behaviours.IncomingRequests;

[SuppressMessage(
"StyleCop.CSharp.ReadabilityRules",
"SA1118:Parameter should not span multiple lines",
Justification = "Readability")]
public sealed class GivenMeteredDataForMeasurementPointTests(
IntegrationTestFixture integrationTestFixture,
ITestOutputHelper testOutputHelper)
Expand All @@ -50,15 +56,18 @@ public async Task When_ActorPeeksAllMessages_Then_ReceivesOneDocumentWithCorrect

var transactionIdPrefix = Guid.NewGuid().ToString("N");

var transactionId1 = $"{transactionIdPrefix}-1";
var transactionId2 = $"{transactionIdPrefix}-2";

await GivenReceivedMeteredDataForMeasurementPoint(
documentFormat: DocumentFormat.Xml,
senderActorNumber: currentActor.ActorNumber,
[
($"{transactionIdPrefix}-1",
(transactionId1,
InstantPattern.General.Parse("2024-11-28T13:51:42Z").Value,
InstantPattern.General.Parse("2024-11-29T09:15:28Z").Value,
Resolution.Hourly),
($"{transactionIdPrefix}-2",
(transactionId2,
InstantPattern.General.Parse("2024-11-24T18:51:58Z").Value,
InstantPattern.General.Parse("2024-11-25T03:39:45Z").Value,
Resolution.QuarterHourly),
Expand All @@ -75,12 +84,111 @@ await GivenReceivedMeteredDataForMeasurementPoint(
peekFormat);

// Assert
peekResults.Should().HaveCount(2);

foreach (var peekResultDto in peekResults)
{
// This is not pretty, but it works for now
var foo = new StreamReader(peekResultDto.Bundle);
var content = await foo.ReadToEndAsync();
var isTransOne = content.Contains(transactionId1);
peekResultDto.Bundle.Position = 0;

await ThenNotifyValidatedMeasureDataDocumentIsCorrect(
peekResultDto.Bundle,
peekFormat,
new NotifyValidatedMeasureDataDocumentAssertionInput());
new NotifyValidatedMeasureDataDocumentAssertionInput(
new RequiredHeaderDocumentFields(
"E23",
"8100000000115",
"A10",
"5790001330552",
"A10",
"DGL",
"DDQ",
"2024-07-01T14:57:09Z"),
new OptionalHeaderDocumentFields(
"23",
[
isTransOne
? new AssertSeriesDocumentFieldsInput(
1,
new RequiredSeriesFields(
TransactionId.From(string.Join(string.Empty, transactionId1.Reverse())),
"579999993331812345",
"A10",
"E17",
"KWH",
new RequiredPeriodDocumentFields(
"PT1H",
"2024-11-28T13:51Z",
"2024-11-29T09:15Z",
Enumerable.Range(1, 24)
.Select(
i => new AssertPointDocumentFieldsInput(
new RequiredPointDocumentFields(i),
new OptionalPointDocumentFields("A03", 1000 + i)))
.ToList())),
new OptionalSeriesFields(
transactionId1,
"2022-12-17T09:30:47Z",
null,
null,
"8716867000030"))
: new AssertSeriesDocumentFieldsInput(
1,
new RequiredSeriesFields(
TransactionId.From(string.Join(string.Empty, transactionId2.Reverse())),
"579999993331812345",
"A10",
"E17",
"KWH",
new RequiredPeriodDocumentFields(
"PT15M",
"2024-11-24T18:51Z",
"2024-11-25T03:39Z",
Enumerable.Range(1, 96)
.Select(
i => new AssertPointDocumentFieldsInput(
new RequiredPointDocumentFields(i),
new OptionalPointDocumentFields("A03", 1000 + i)))
.ToList())),
new OptionalSeriesFields(
transactionId2,
"2022-12-17T09:30:47Z",
null,
null,
"8716867000030")),
])));
}
}

[Theory]
[MemberData(nameof(PeekFormats))]
public async Task AndGiven_MessageIsEmpty_When_ActorPeeksAllMessages_Then_ReceivesNoMessages(
DocumentFormat peekFormat)
{
// Arrange
var senderSpy = CreateServiceBusSenderSpy();
var currentActor = (ActorNumber: ActorNumber.Create("1111111111111"), ActorRole: ActorRole.GridAccessProvider);

GivenNowIs(Instant.FromUtc(2024, 7, 1, 14, 57, 09));
GivenAuthenticatedActorIs(currentActor.ActorNumber, currentActor.ActorRole);

await GivenReceivedMeteredDataForMeasurementPoint(
documentFormat: DocumentFormat.Xml,
senderActorNumber: currentActor.ActorNumber,
[]);

await WhenMeteredDataForMeasurementPointProcessIsInitialized(senderSpy.LatestMessage!);

// Act
var peekResults = await WhenActorPeeksAllMessages(
ActorNumber.Create("8100000000115"),
ActorRole.EnergySupplier,
peekFormat);

// Assert
peekResults.Should().BeEmpty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,18 @@ private Document ParseFrom(OutgoingMessageHeader header, IReadOnlyCollection<str
{
ArgumentNullException.ThrowIfNull(transactions);

var meteredDataForMeasurementPoints = new Collection<MeteredDataForMeasurementPoint>();
var meteredDataForMeasurementSeries = new Collection<MeteredDataForMeasurementSeries>();
foreach (var activityRecord in transactions.Select(t => _parser.From<MeteredDateForMeasurementPointMarketActivityRecord>(t)))
{
meteredDataForMeasurementPoints.Add(
new MeteredDataForMeasurementPoint(
meteredDataForMeasurementSeries.Add(
new MeteredDataForMeasurementSeries(
activityRecord.TransactionId.Value,
activityRecord.MarketEvaluationPointNumber,
activityRecord.MarketEvaluationPointType,
activityRecord.OriginalTransactionIdReferenceId?.Value,
activityRecord.Product,
activityRecord.QuantityMeasureUnit.Code,
activityRecord.RegistrationDateTime.ToString(),
activityRecord.RegistrationDateTime?.ToString(),
new Period(
activityRecord.Resolution.Code,
new TimeInterval(
Expand All @@ -100,7 +100,7 @@ private Document ParseFrom(OutgoingMessageHeader header, IReadOnlyCollection<str
header.SenderId,
header.SenderRole,
TypeCode,
meteredDataForMeasurementPoints));
meteredDataForMeasurementSeries));
}
}

Expand All @@ -120,7 +120,7 @@ internal class MeteredDateForMeasurementPoint(
string senderId,
string senderRole,
string typeCode,
IReadOnlyCollection<MeteredDataForMeasurementPoint> meteredDataForMeasurementPoints)
IReadOnlyCollection<MeteredDataForMeasurementSeries> meteredDataForMeasurementSeries)
{
[JsonPropertyName("mRID")]
public string MessageId { get; init; } = messageId;
Expand Down Expand Up @@ -150,17 +150,18 @@ internal class MeteredDateForMeasurementPoint(
public ValueObject<string> Type { get; init; } = ValueObject<string>.Create(typeCode);

[JsonPropertyName("Series")]
public IReadOnlyCollection<MeteredDataForMeasurementPoint> MeteredDataForMeasurementPoints { get; init; } = meteredDataForMeasurementPoints;
public IReadOnlyCollection<MeteredDataForMeasurementSeries> MeteredDataForMeasurementSeries { get; init; } =
meteredDataForMeasurementSeries;
}

internal class MeteredDataForMeasurementPoint(
internal class MeteredDataForMeasurementSeries(
string transactionId,
string marketEvaluationPointNumber,
string marketEvaluationPointType,
string? originalTransactionIdReferenceId,
string product,
string? product,
string quantityMeasureUnit,
string registrationDateTime,
string? registrationDateTime,
Period period)
{
[JsonPropertyName("mRID")]
Expand All @@ -177,13 +178,15 @@ internal class MeteredDataForMeasurementPoint(
public string? OriginalTransactionIdReferenceId { get; init; } = originalTransactionIdReferenceId; //TODO: what does this field represent?

[JsonPropertyName("product")]
public string Product { get; init; } = product;
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Product { get; init; } = product;

[JsonPropertyName("quantity_Measure_Unit.name")]
public ValueObject<string> QuantityMeasureUnit { get; init; } = ValueObject<string>.Create(quantityMeasureUnit);

[JsonPropertyName("registration_DateAndOrTime.dateTime")]
public string RegistrationDateTime { get; init; } = registrationDateTime;
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? RegistrationDateTime { get; init; } = registrationDateTime;

[JsonPropertyName("Period")]
public Period Period { get; init; } = period;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,43 @@ protected override async Task WriteMarketActivityRecordsAsync(
XNamespace @namespace = "urn:ediel.org:measure:notifyvalidatedmeasuredata:0:1";
foreach (var activityRecord in ParseFrom<MeteredDateForMeasurementPointMarketActivityRecord>(marketActivityPayloads))
{
var seriesElement = new XElement(
@namespace + "Series",
new XElement(@namespace + "mRID", activityRecord.TransactionId.Value),
new XElement(
var seriesElement = new XElement(@namespace + "Series");
seriesElement.Add(new XElement(@namespace + "mRID", activityRecord.TransactionId.Value));

if (activityRecord.OriginalTransactionIdReferenceId is not null)
{
seriesElement.Add(
new XElement(
@namespace + "originalTransactionIDReference_Series.mRID",
activityRecord.OriginalTransactionIdReferenceId?.Value),
activityRecord.OriginalTransactionIdReferenceId?.Value));
}

seriesElement.Add(
new XElement(
@namespace + "marketEvaluationPoint.mRID",
new XAttribute("codingScheme", "A10"),
activityRecord.MarketEvaluationPointNumber),
new XElement(@namespace + "marketEvaluationPoint.type", activityRecord.MarketEvaluationPointType),
new XElement(@namespace + "registration_DateAndOrTime.dateTime", activityRecord.RegistrationDateTime),
new XElement(@namespace + "product", activityRecord.Product),
new XElement(@namespace + "quantity_Measure_Unit.name", activityRecord.QuantityMeasureUnit.Code),
activityRecord.MarketEvaluationPointNumber));

seriesElement.Add(
new XElement(@namespace + "marketEvaluationPoint.type", activityRecord.MarketEvaluationPointType));

if (activityRecord.RegistrationDateTime is not null)
{
seriesElement.Add(
new XElement(
@namespace + "registration_DateAndOrTime.dateTime",
activityRecord.RegistrationDateTime));
}

if (activityRecord.Product is not null)
{
seriesElement.Add(new XElement(@namespace + "product", activityRecord.Product));
}

seriesElement.Add(
new XElement(@namespace + "quantity_Measure_Unit.name", activityRecord.QuantityMeasureUnit.Code));

seriesElement.Add(
new XElement(
@namespace + "Period",
new XElement(@namespace + "resolution", activityRecord.Resolution.Code),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ public sealed record MeteredDateForMeasurementPointMarketActivityRecord(
string MarketEvaluationPointNumber,
string MarketEvaluationPointType,
TransactionId? OriginalTransactionIdReferenceId,
string Product,
string? Product,
MeasurementUnit QuantityMeasureUnit,
Instant RegistrationDateTime,
Instant? RegistrationDateTime,
Resolution Resolution,
Instant StartedDateTime,
Instant EndedDateTime,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,55 @@ public static async Task AssertCorrectDocumentAsync(
_ => throw new ArgumentOutOfRangeException(nameof(documentFormat), documentFormat, null),
};

var requiredHeaderDocumentFields = assertionInput.RequiredHeaderDocumentFields;

// Required fields
asserter
.MessageIdExists()
.HasBusinessReason(requiredHeaderDocumentFields.BusinessReasonCode)
.HasSenderId(
requiredHeaderDocumentFields.SenderId,
requiredHeaderDocumentFields.SenderScheme)
.HasSenderRole(requiredHeaderDocumentFields.SenderRole)
.HasReceiverId(
requiredHeaderDocumentFields.ReceiverId,
requiredHeaderDocumentFields.ReceiverScheme)
.HasReceiverRole(requiredHeaderDocumentFields.ReceiverRole)
.HasTimestamp(requiredHeaderDocumentFields.Timestamp);

var optionalHeaderDocumentFields = assertionInput.OptionalHeaderDocumentFields;

// Optional fields
asserter.HasBusinessSectorType(optionalHeaderDocumentFields.BusinessSectorType);

foreach (var assertSeriesDocumentFieldsInput in optionalHeaderDocumentFields.AssertSeriesDocumentFieldsInput)
{
var (seriesIndex, requiredSeriesFields, optionalSeriesFields) = assertSeriesDocumentFieldsInput;

// Required series fields
asserter
.HasTransactionId(seriesIndex, requiredSeriesFields.TransactionId)
.HasMeteringPointNumber(
seriesIndex,
requiredSeriesFields.MeteringPointNumber,
requiredSeriesFields.MeteringPointScheme)
.HasMeteringPointType(seriesIndex, requiredSeriesFields.MeteringPointType)
.HasQuantityMeasureUnit(seriesIndex, requiredSeriesFields.QuantityMeasureUnit)
// Required period fields
.HasResolution(seriesIndex, requiredSeriesFields.RequiredPeriodDocumentFields.Resolution)
.HasStartedDateTime(seriesIndex, requiredSeriesFields.RequiredPeriodDocumentFields.StartedDateTime)
.HasEndedDateTime(seriesIndex, requiredSeriesFields.RequiredPeriodDocumentFields.EndedDateTime)
.HasPoints(seriesIndex, requiredSeriesFields.RequiredPeriodDocumentFields.Points.ToList().AsReadOnly());

// Optional series fields
asserter
.HasOriginalTransactionIdReferenceId(seriesIndex, optionalSeriesFields.OriginalTransactionIdReferenceId)
.HasRegistrationDateTime(seriesIndex, optionalSeriesFields.RegistrationDateTime)
.HasProduct(seriesIndex, optionalSeriesFields.Product)
.HasInDomain(seriesIndex, optionalSeriesFields.InDomain)
.HasOutDomain(seriesIndex, optionalSeriesFields.OutDomain);
}

await asserter
.DocumentIsValidAsync();
}
Expand Down
Loading

0 comments on commit fb74cf4

Please sign in to comment.