Skip to content

Commit

Permalink
feat: add closure error data (#225)
Browse files Browse the repository at this point in the history
* feat: add closure error data

* feat: add closure error data to view

* chore: add error cause
  • Loading branch information
pietro-tota authored Dec 17, 2024
1 parent 8755970 commit 1339bcb
Show file tree
Hide file tree
Showing 9 changed files with 282 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
@AllArgsConstructor
@NoArgsConstructor
@Generated
public sealed class BaseTransactionRetriedData permits TransactionRefundRetriedData,TransactionRetriedData {
public sealed class BaseTransactionRetriedData permits TransactionClosureRetriedData,TransactionRefundRetriedData,TransactionRetriedData {
/**
* Retry event count
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package it.pagopa.ecommerce.commons.documents.v2;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Generated;
import lombok.NoArgsConstructor;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.http.HttpStatus;

import javax.annotation.Nullable;
import javax.validation.constraints.NotNull;

/**
* Data related to closure error event
*/
@Data
@Document
@AllArgsConstructor
@NoArgsConstructor
@Generated
public class ClosureErrorData {

/**
* Enumeration of errors that can happen
*/
public enum ErrorType {
/**
* KO response received from Node
*/
KO_RESPONSE_RECEIVED,
/**
* Error happen during communication, no response have been received
*/
COMMUNICATION_ERROR,
}

/**
* Http error code received by Node in close payment response: This field is
* null when HTTP response error code cannot be detected (f.e. timeout)
*/
@Nullable
private HttpStatus httpErrorCode;

/**
* Node error description taken from error response body, if any
*/
@Nullable
private String errorDescription;

@NotNull
private ErrorType errorType;

}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ public class Transaction extends BaseTransactionView {
@Nullable
private String userId;

@Nullable
private ClosureErrorData closureErrorData;

/**
* Enumeration of transaction client initiators
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,18 @@
@Generated
@NoArgsConstructor
@ToString(callSuper = true)
public final class TransactionClosureErrorEvent extends TransactionEvent<Void> {
public final class TransactionClosureErrorEvent extends TransactionEvent<ClosureErrorData> {

/**
* Convenience constructor which sets the creation date to now
*
* @param transactionId transaction unique id
* @param transactionId transaction unique id
* @param closureErrorData the closure error related data
*/
public TransactionClosureErrorEvent(
String transactionId
String transactionId,
ClosureErrorData closureErrorData
) {
super(transactionId, TransactionEventCode.TRANSACTION_CLOSURE_ERROR_EVENT, null);
super(transactionId, TransactionEventCode.TRANSACTION_CLOSURE_ERROR_EVENT, closureErrorData);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package it.pagopa.ecommerce.commons.documents.v2;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Generated;
import lombok.NoArgsConstructor;
import org.springframework.data.mongodb.core.mapping.Document;

import javax.annotation.Nullable;

/**
* Data related to retry event for a transaction closure operation
*
* @see BaseTransactionRetriedData
*/

@Data
@EqualsAndHashCode(callSuper = true)
@Document
@NoArgsConstructor
@Generated
public final class TransactionClosureRetriedData extends BaseTransactionRetriedData {

@Nullable
private ClosureErrorData closureErrorData;

/**
* Constructor
*
* @param closureErrorData node closure error data
* @param retryCount the retry event counter
*/
public TransactionClosureRetriedData(
@Nullable ClosureErrorData closureErrorData,
Integer retryCount
) {
super(retryCount);
this.closureErrorData = closureErrorData;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@
@Generated
@NoArgsConstructor
@ToString(callSuper = true)
public final class TransactionClosureRetriedEvent extends TransactionEvent<TransactionRetriedData> {
public final class TransactionClosureRetriedEvent extends TransactionEvent<TransactionClosureRetriedData> {

/**
* Convenience constructor which sets the creation date to now
*
* @param transactionId transaction unique id
* @param transactionRetriedData retry count data
* @param transactionId transaction unique id
* @param closureRetriedData closure retry data
*/
public TransactionClosureRetriedEvent(
String transactionId,
TransactionRetriedData transactionRetriedData
TransactionClosureRetriedData closureRetriedData
) {
super(transactionId, TransactionEventCode.TRANSACTION_CLOSURE_RETRIED_EVENT, transactionRetriedData);
super(transactionId, TransactionEventCode.TRANSACTION_CLOSURE_RETRIED_EVENT, closureRetriedData);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpStatus;
import org.testcontainers.shaded.org.apache.commons.io.FileUtils;
import reactor.core.publisher.Hooks;
import reactor.core.publisher.Mono;
Expand Down Expand Up @@ -1483,7 +1484,12 @@ void canRoundTripQueueClosureRetriedEvent() {
"transactionId": "bdb92a6577fb4aab9bba2ebb80cd8310",
"creationDate": "2023-09-25T14:44:31.177776+02:00[Europe/Rome]",
"data": {
"retryCount": 0
"retryCount": 0,
"closureErrorData": {
"httpErrorCode":"BAD_REQUEST",
"errorDescription":"ERROR",
"errorType": "KO_RESPONSE_RECEIVED"
}
},
"eventCode": "TRANSACTION_CLOSURE_RETRIED_EVENT"
},
Expand All @@ -1497,7 +1503,12 @@ void canRoundTripQueueClosureRetriedEvent() {
.replace("\n", "").replace(" ", "");
QueueEvent<TransactionClosureRetriedEvent> originalEvent = new QueueEvent<>(
TransactionTestUtils.transactionClosureRetriedEvent(
0
0,
new ClosureErrorData(
HttpStatus.BAD_REQUEST,
"ERROR",
ClosureErrorData.ErrorType.KO_RESPONSE_RECEIVED
)
),
MOCK_TRACING_INFO
);
Expand Down Expand Up @@ -1815,4 +1826,149 @@ void shouldDeserializeAuthorizationRequestedEventWithNullIdBundle() {
.expectNext(expectedEvent)
.verifyComplete();
}

@Test
void canDeserializeClosureRetriedEventWithoutClosureErrorData() {
String serializedEvent = """
{
"event": {
"_class": "it.pagopa.ecommerce.commons.documents.v2.TransactionClosureRetriedEvent",
"id": "0660cd04-db3e-4b7e-858b-e8f75a29ac30",
"transactionId": "bdb92a6577fb4aab9bba2ebb80cd8310",
"creationDate": "2023-09-25T14:44:31.177776+02:00[Europe/Rome]",
"data": {
"retryCount": 0
},
"eventCode": "TRANSACTION_CLOSURE_RETRIED_EVENT"
},
"tracingInfo": {
"traceparent": "mock_traceparent",
"tracestate": "mock_tracestate",
"baggage": "mock_baggage"
}
}
"""
.replace("\n", "").replace(" ", "");
QueueEvent<TransactionClosureRetriedEvent> originalEvent = new QueueEvent<>(
TransactionTestUtils.transactionClosureRetriedEvent(
0
),
MOCK_TRACING_INFO
);
originalEvent.event().setTransactionId("bdb92a6577fb4aab9bba2ebb80cd8310");
originalEvent.event().setId("0660cd04-db3e-4b7e-858b-e8f75a29ac30");
originalEvent.event().setCreationDate("2023-09-25T14:44:31.177776+02:00[Europe/Rome]");
originalEvent.event().getData().setClosureErrorData(null);
Hooks.onOperatorDebug();
StepVerifier.create(
jsonSerializer
.deserializeFromBytesAsync(
serializedEvent.getBytes(StandardCharsets.UTF_8),
new TypeReference<QueueEvent<TransactionClosureRetriedEvent>>() {
}
)
)
.expectNext(originalEvent)
.verifyComplete();
}

@Test
void canRoundTripQueueClosureErrorEventWithClosureErrorData() {
String expectedSerializedEvent = """
{
"event": {
"_class": "it.pagopa.ecommerce.commons.documents.v2.TransactionClosureErrorEvent",
"id": "0660cd04-db3e-4b7e-858b-e8f75a29ac30",
"transactionId": "bdb92a6577fb4aab9bba2ebb80cd8310",
"creationDate": "2023-09-25T14:44:31.177776+02:00[Europe/Rome]",
"data": {
"httpErrorCode":"BAD_REQUEST",
"errorDescription":"ERROR",
"errorType": "KO_RESPONSE_RECEIVED"
},
"eventCode": "TRANSACTION_CLOSURE_ERROR_EVENT"
},
"tracingInfo": {
"traceparent": "mock_traceparent",
"tracestate": "mock_tracestate",
"baggage": "mock_baggage"
}
}
"""
.replace("\n", "").replace(" ", "");
QueueEvent<TransactionClosureErrorEvent> originalEvent = new QueueEvent<>(
TransactionTestUtils.transactionClosureErrorEvent(
new ClosureErrorData(
HttpStatus.BAD_REQUEST,
"ERROR",
ClosureErrorData.ErrorType.KO_RESPONSE_RECEIVED
)
),
MOCK_TRACING_INFO
);
originalEvent.event().setTransactionId("bdb92a6577fb4aab9bba2ebb80cd8310");
originalEvent.event().setId("0660cd04-db3e-4b7e-858b-e8f75a29ac30");
originalEvent.event().setCreationDate("2023-09-25T14:44:31.177776+02:00[Europe/Rome]");
byte[] serialized = jsonSerializer.serializeToBytes(originalEvent);
String serializedString = new String(serialized);
System.out.println("Serialized object: " + serializedString);

assertTrue(
serializedString
.contains(
"\"_class\":\"it.pagopa.ecommerce.commons.documents.v2.TransactionClosureErrorEvent\""
)
);
assertEquals(expectedSerializedEvent, serializedString);
Hooks.onOperatorDebug();
StepVerifier.create(
jsonSerializer
.deserializeFromBytesAsync(
serialized,
new TypeReference<QueueEvent<TransactionClosureErrorEvent>>() {
}
)
)
.expectNext(originalEvent)
.verifyComplete();
}

@Test
void canDeserializeClosureErrorEventWithoutClosureErrorData() {
String serializedEvent = """
{
"event": {
"_class": "it.pagopa.ecommerce.commons.documents.v2.TransactionClosureErrorEvent",
"id": "0660cd04-db3e-4b7e-858b-e8f75a29ac30",
"transactionId": "bdb92a6577fb4aab9bba2ebb80cd8310",
"creationDate": "2023-09-25T14:44:31.177776+02:00[Europe/Rome]",
"eventCode": "TRANSACTION_CLOSURE_ERROR_EVENT"
},
"tracingInfo": {
"traceparent": "mock_traceparent",
"tracestate": "mock_tracestate",
"baggage": "mock_baggage"
}
}
"""
.replace("\n", "").replace(" ", "");
QueueEvent<TransactionClosureErrorEvent> originalEvent = new QueueEvent<>(
TransactionTestUtils.transactionClosureErrorEvent(),
MOCK_TRACING_INFO
);
originalEvent.event().setTransactionId("bdb92a6577fb4aab9bba2ebb80cd8310");
originalEvent.event().setId("0660cd04-db3e-4b7e-858b-e8f75a29ac30");
originalEvent.event().setCreationDate("2023-09-25T14:44:31.177776+02:00[Europe/Rome]");
Hooks.onOperatorDebug();
StepVerifier.create(
jsonSerializer
.deserializeFromBytesAsync(
serializedEvent.getBytes(StandardCharsets.UTF_8),
new TypeReference<QueueEvent<TransactionClosureErrorEvent>>() {
}
)
)
.expectNext(originalEvent)
.verifyComplete();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import it.pagopa.ecommerce.commons.documents.v2.authorization.*;
import it.pagopa.ecommerce.commons.domain.v2.pojos.*;
import it.pagopa.ecommerce.commons.generated.npg.v1.dto.OperationResultDto;
import it.pagopa.ecommerce.commons.generated.server.model.AuthorizationResultDto;
import it.pagopa.ecommerce.commons.generated.server.model.TransactionStatusDto;
import it.pagopa.ecommerce.commons.v2.TransactionTestUtils;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -637,10 +636,8 @@ void shouldConstructTransactionFromClosureErrorEventStream() {
.transactionWithClosureRequested(transactionAuthorizationCompleted);
it.pagopa.ecommerce.commons.domain.v2.TransactionWithClosureError expected = TransactionTestUtils
.transactionWithClosureError(transactionClosureErrorEvent, transactionWithClosureRequested);

Mono<it.pagopa.ecommerce.commons.domain.v2.Transaction> actual = events
.reduce(transaction, it.pagopa.ecommerce.commons.domain.v2.Transaction::applyEvent);

StepVerifier.create(actual).expectNextMatches(e -> e.equals(expected)).verifyComplete();
}

Expand Down
Loading

0 comments on commit 1339bcb

Please sign in to comment.