Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4131 failed claim requests #506

Merged
merged 10 commits into from
Jan 29, 2025
10 changes: 7 additions & 3 deletions src/ProjectOrigin.Vault/Activities/AllocateActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ public record AllocateArguments
public required Guid ProductionSliceId { get; init; }
public Guid? ChroniclerRequestId { get; init; }
public required FederatedStreamId CertificateId { get; init; }
public required Guid RequestId { get; init; }
public required string Owner { get; init; }
public required RequestStatusArgs RequestStatusArgs { get; init; }
}

public class AllocateActivity : IExecuteActivity<AllocateArguments>
Expand All @@ -44,7 +43,7 @@ public async Task<ExecutionResult> Execute(ExecuteContext<AllocateArguments> con
{
try
{
_logger.LogInformation("Starting Activity: {Activity}, RequestId: {RequestId} ", nameof(SendRegistryTransactionActivity), context.Arguments.RequestId);
_logger.LogInformation("Starting Activity: {Activity}, RequestId: {RequestId} ", nameof(SendRegistryTransactionActivity), context.Arguments.RequestStatusArgs.RequestId);
var cons = await _unitOfWork.CertificateRepository.GetWalletSlice(context.Arguments.ConsumptionSliceId);
var prod = await _unitOfWork.CertificateRepository.GetWalletSlice(context.Arguments.ProductionSliceId);

Expand All @@ -70,6 +69,11 @@ public async Task<ExecutionResult> Execute(ExecuteContext<AllocateArguments> con
catch (Exception ex)
{
_logger.LogError(ex, "Error registering claim intent with Chronicler");
await _unitOfWork.RequestStatusRepository.SetRequestStatus(context.Arguments.RequestStatusArgs.RequestId,
context.Arguments.RequestStatusArgs.Owner,
RequestStatusState.Failed,
"Error registering claim intent with Chronicler");
_unitOfWork.Commit();
return context.Faulted(ex);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public async Task<ExecutionResult> Execute(ExecuteContext<UpdateClaimStateArgume
{
_logger.LogError(ex, "Error while updating claim state");
_unitOfWork.Rollback();
return context.Faulted(ex);
throw;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ public async Task Consume(ConsumeContext<ClaimCertificateCommand> context)
{
_unitOfWork.Rollback();
_logger.LogWarning(ex, "Claim is not allowed.");
await _unitOfWork.RequestStatusRepository.SetRequestStatus(context.Message.ClaimId, context.Message.Owner, RequestStatusState.Failed, failedReason: "Claim is not allowed.");
_unitOfWork.Commit();
}
catch (QuantityNotYetAvailableToReserveException ex)
{
Expand All @@ -72,6 +74,8 @@ public async Task Consume(ConsumeContext<ClaimCertificateCommand> context)
{
_unitOfWork.Rollback();
_logger.LogError(ex, "failed to handle claim");
await _unitOfWork.RequestStatusRepository.SetRequestStatus(context.Message.ClaimId, context.Message.Owner, RequestStatusState.Failed, failedReason: "failed to handle claim");
_unitOfWork.Commit();
}
}

Expand Down
14 changes: 10 additions & 4 deletions src/ProjectOrigin.Vault/RegistryProcessBuilder/Claim.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@ public async Task Claim(WalletSlice productionSlice, WalletSlice consumptionSlic
ProductionSliceId = productionSlice.Id,
ConsumptionSliceId = consumptionSlice.Id,
ChroniclerRequestId = await GetClaimIntentId(productionSlice),
Owner = _owner,
RequestId = _routingSlipId
RequestStatusArgs = new RequestStatusArgs
{
Owner = _owner,
RequestId = _routingSlipId
}
});

AddActivity<AllocateActivity, AllocateArguments>(new AllocateArguments
Expand All @@ -35,8 +38,11 @@ public async Task Claim(WalletSlice productionSlice, WalletSlice consumptionSlic
ProductionSliceId = productionSlice.Id,
ConsumptionSliceId = consumptionSlice.Id,
ChroniclerRequestId = await GetClaimIntentId(consumptionSlice),
Owner = _owner,
RequestId = _routingSlipId
RequestStatusArgs = new RequestStatusArgs
{
Owner = _owner,
RequestId = _routingSlipId
}
});

await _unitOfWork.ClaimRepository.InsertClaim(new Claim
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,11 @@ public async Task ChroniclerAndAllocate_ShouldRevise()
AllocationId = Guid.NewGuid(),
ChroniclerRequestId = chroniclerId,
CertificateId = certId,
Owner = "",
RequestId = Guid.NewGuid(),
RequestStatusArgs = new RequestStatusArgs
{
Owner = "",
RequestId = Guid.NewGuid()
},
ConsumptionSliceId = Guid.NewGuid(),
ProductionSliceId = Guid.NewGuid(),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,10 @@ public async Task Execute_WhenSetClaimThrowsException_ShouldThrowException()
_unitOfWork.ClaimRepository.When(x => x.SetClaimState(Arg.Any<Guid>(), Arg.Any<ClaimState>())).Do(x => throw exceptionToBeThrown);

// Act
await _activity.Execute(_context);
await Assert.ThrowsAsync<Exception>(async () => await _activity.Execute(_context));

// Assert
_context.Received(1).Faulted(Arg.Is(exceptionToBeThrown));
_unitOfWork.Received(1).Rollback();
_unitOfWork.DidNotReceive().Commit();
_context.DidNotReceive().Completed();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public static Task<CreateExternalEndpointResponse> CreateExternalEndpoint(this H
public static Task<ResultList<GranularCertificate, PageInfo>> GetCertificates(this HttpClient client) =>
client.GetAsync($"v1/certificates").ParseJson<ResultList<GranularCertificate, PageInfo>>();

public static Task<RequestStatusResponse> GetRequestStatus(this HttpClient client, Guid requestId) =>
client.GetAsync($"v1/request-status/{requestId}").ParseJson<RequestStatusResponse>();

public static Task<IEnumerable<GranularCertificate>> GetCertificatesWithTimeout(this HttpClient client, int count, TimeSpan timeout) =>
Timeout(async () =>
{
Expand Down
59 changes: 59 additions & 0 deletions test/ProjectOrigin.Vault.Tests/FlowTests/ClaimTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,63 @@ public async Task CannotAllocateAfterExpired()
allocateEventStatus.Status.Should().Be(TransactionState.Failed);
allocateEventStatus.Message.Should().Be("Certificate has expired");
}

[Fact]
public async Task WhenClaimingMoreThanPossible_ClaimRequestSetToFailed()
{
var position = 1;
var endDate = DateTimeOffset.UtcNow;
var startDate = endDate.AddHours(-1);

var client = WalletTestFixture.ServerFixture.CreateHttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", WalletTestFixture.JwtTokenIssuerFixture.GenerateRandomToken());

var wallet = await client.CreateWallet();
var endpoint = await client.CreateWalletEndpoint(wallet.WalletId);

var productionId = await IssueCertificateToEndpoint(endpoint.WalletReference, Electricity.V1.GranularCertificateType.Production, new SecretCommitmentInfo(200), position++, startDate, endDate);
var consumptionId = await IssueCertificateToEndpoint(endpoint.WalletReference, Electricity.V1.GranularCertificateType.Consumption, new SecretCommitmentInfo(300), position++, startDate, endDate);

await client.GetCertificatesWithTimeout(2, TimeSpan.FromMinutes(1));

var response = await client.CreateClaim(
consumptionId,
productionId,
400u);

await Task.Delay(TimeSpan.FromSeconds(5));

var requestStatus = await client.GetRequestStatus(response.ClaimRequestId);

Assert.Equal(RequestStatus.Failed, requestStatus.Status);
}

[Fact]
public async Task WhenTryingToClaimUnknownCertificate_ClaimRequestSetToFailed()
{
var position = 1;
var endDate = DateTimeOffset.UtcNow;
var startDate = endDate.AddHours(-1);

var client = WalletTestFixture.ServerFixture.CreateHttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", WalletTestFixture.JwtTokenIssuerFixture.GenerateRandomToken());

var wallet = await client.CreateWallet();
var endpoint = await client.CreateWalletEndpoint(wallet.WalletId);

var consumptionId = await IssueCertificateToEndpoint(endpoint.WalletReference, Electricity.V1.GranularCertificateType.Consumption, new SecretCommitmentInfo(300), position++, startDate, endDate);

await client.GetCertificatesWithTimeout(1, TimeSpan.FromMinutes(1));

var response = await client.CreateClaim(
consumptionId,
consumptionId with { StreamId = Guid.NewGuid() },
400u);

await Task.Delay(TimeSpan.FromSeconds(5));

var requestStatus = await client.GetRequestStatus(response.ClaimRequestId);

Assert.Equal(RequestStatus.Failed, requestStatus.Status);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ public async Task TestClaimEqualSize_WithoutChronicler()
x.ChroniclerRequestId == null &&
x.CertificateId.Registry == prodCert.RegistryName &&
x.CertificateId.StreamId.Value == prodCert.Id.ToString() &&
x.RequestId != Guid.Empty &&
x.Owner != string.Empty);
x.RequestStatusArgs.RequestId != Guid.Empty &&
x.RequestStatusArgs.Owner != string.Empty);

var allocationId = slip.Itinerary[0].ShouldBeActivity<AllocateActivity, AllocateArguments>().AllocationId.ToString();

Expand All @@ -95,8 +95,8 @@ public async Task TestClaimEqualSize_WithoutChronicler()
x.ChroniclerRequestId == null &&
x.CertificateId.Registry == consCert.RegistryName &&
x.CertificateId.StreamId.Value == consCert.Id.ToString() &&
x.RequestId != Guid.Empty &&
x.Owner != string.Empty);
x.RequestStatusArgs.RequestId != Guid.Empty &&
x.RequestStatusArgs.Owner != string.Empty);

var (t3, _) = slip.Itinerary[2].ShouldBeTransactionWithEvent<ClaimedEvent>(
transaction =>
Expand Down Expand Up @@ -201,8 +201,8 @@ public async Task TestClaimEqualSize_WithChronicler()
x.ChroniclerRequestId.Equals(chronId) &&
x.CertificateId.Registry == prodCert.RegistryName &&
x.CertificateId.StreamId.Value == prodCert.Id.ToString() &&
x.RequestId != Guid.Empty &&
x.Owner != string.Empty);
x.RequestStatusArgs.RequestId != Guid.Empty &&
x.RequestStatusArgs.Owner != string.Empty);

var allocationId = slip.Itinerary[1].ShouldBeActivity<AllocateActivity, AllocateArguments>().AllocationId.ToString();

Expand All @@ -224,8 +224,8 @@ public async Task TestClaimEqualSize_WithChronicler()
x.ChroniclerRequestId.Equals(chronId2) &&
x.CertificateId.Registry == consCert.RegistryName &&
x.CertificateId.StreamId.Value == consCert.Id.ToString() &&
x.RequestId != Guid.Empty &&
x.Owner != string.Empty);
x.RequestStatusArgs.RequestId != Guid.Empty &&
x.RequestStatusArgs.Owner != string.Empty);

var (t3, _) = slip.Itinerary[4].ShouldBeTransactionWithEvent<ClaimedEvent>(
transaction =>
Expand Down
Loading