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

feat: add closure error data #225

Merged
merged 4 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading