From 9ab0849b09de35e79d0282aa29391272a8455e72 Mon Sep 17 00:00:00 2001 From: giomella Date: Tue, 5 Dec 2023 10:53:29 +0100 Subject: [PATCH 1/5] [PRDP-267] added timer trigger function for recovering failed receipt --- README.md | 1 + helm/values-dev.yaml | 1 + helm/values-prod.yaml | 1 + helm/values-uat.yaml | 1 + .../helpdesk/RecoverFailedReceiptMassive.java | 10 +- .../RecoverFailedReceiptScheduled.java | 112 ++++++++++++++++++ 6 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduled.java diff --git a/README.md b/README.md index 8c0ca3d..1d2a87c 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,7 @@ then replace env variables with correct values | `PDV_TOKENIZER_MAX_RETRIES` | PDV Tokenizer max request retry | 3 | | `TOKENIZER_APIM_HEADER_KEY` | Tokenizer APIM header key | x-api-key | | `MAX_DATE_DIFF_MILLIS` | Difference in millis between the current time and the date from witch the
receipts will be fetched in massive recover operation | 360000 | +| `RECOVER_FAILED_CRON` | CRON expression for timer trigger function that recover failed receipt | | > to doc details about AZ fn config > see [here](https://stackoverflow.com/questions/62669672/azure-functions-what-is-the-purpose-of-having-host-json-and-local-settings-jso) diff --git a/helm/values-dev.yaml b/helm/values-dev.yaml index 846370f..a890314 100644 --- a/helm/values-dev.yaml +++ b/helm/values-dev.yaml @@ -110,6 +110,7 @@ microservice-chart: MAX_DATE_DIFF_MILLIS: "360000" MAX_DATE_DIFF_NOTIFY_MILLIS: "360000" TRIGGER_NOTIFY_REC_SCHEDULE: "0 0 */6 * * *" + RECOVER_FAILED_CRON: "0 0 /12 * * *" AZURE_FUNCTIONS_MESH_JAVA_OPTS: "-javaagent:/home/site/wwwroot/jmx_prometheus_javaagent-0.19.0.jar=12345:/home/site/wwwroot/config.yaml -javaagent:/home/site/wwwroot/opentelemetry-javaagent.jar -Xmx768m -XX:+UseG1GC" envFieldRef: APP_NAME: "metadata.labels['app.kubernetes.io/instance']" diff --git a/helm/values-prod.yaml b/helm/values-prod.yaml index f426742..bc22ad6 100644 --- a/helm/values-prod.yaml +++ b/helm/values-prod.yaml @@ -110,6 +110,7 @@ microservice-chart: MAX_DATE_DIFF_MILLIS: "360000" MAX_DATE_DIFF_NOTIFY_MILLIS: "360000" TRIGGER_NOTIFY_REC_SCHEDULE: "0 0 */6 * * *" + RECOVER_FAILED_CRON: "0 0 /12 * * *" AZURE_FUNCTIONS_MESH_JAVA_OPTS: "-javaagent:/home/site/wwwroot/jmx_prometheus_javaagent-0.19.0.jar=12345:/home/site/wwwroot/config.yaml -javaagent:/home/site/wwwroot/opentelemetry-javaagent.jar -Xmx768m -XX:+UseG1GC" envFieldRef: APP_NAME: "metadata.labels['app.kubernetes.io/instance']" diff --git a/helm/values-uat.yaml b/helm/values-uat.yaml index 5715086..8a6be73 100644 --- a/helm/values-uat.yaml +++ b/helm/values-uat.yaml @@ -110,6 +110,7 @@ microservice-chart: MAX_DATE_DIFF_MILLIS: "360000" MAX_DATE_DIFF_NOTIFY_MILLIS: "360000" TRIGGER_NOTIFY_REC_SCHEDULE: "0 0 */6 * * *" + RECOVER_FAILED_CRON: "0 0 /12 * * *" AZURE_FUNCTIONS_MESH_JAVA_OPTS: "-javaagent:/home/site/wwwroot/jmx_prometheus_javaagent-0.19.0.jar=12345:/home/site/wwwroot/config.yaml -javaagent:/home/site/wwwroot/opentelemetry-javaagent.jar -Xmx768m -XX:+UseG1GC" envFieldRef: APP_NAME: "metadata.labels['app.kubernetes.io/instance']" diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptMassive.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptMassive.java index 7f5f2c9..379f3d9 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptMassive.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptMassive.java @@ -42,7 +42,7 @@ public class RecoverFailedReceiptMassive { private final BizEventCosmosClient bizEventCosmosClient; private final ReceiptCosmosService receiptCosmosService; - public RecoverFailedReceiptMassive(){ + public RecoverFailedReceiptMassive() { this.bizEventToReceiptService = new BizEventToReceiptServiceImpl(); this.receiptCosmosService = new ReceiptCosmosServiceImpl(); this.bizEventCosmosClient = BizEventCosmosClientImpl.getInstance(); @@ -50,7 +50,7 @@ public RecoverFailedReceiptMassive(){ RecoverFailedReceiptMassive(BizEventToReceiptService bizEventToReceiptService, BizEventCosmosClient bizEventCosmosClient, - ReceiptCosmosService receiptCosmosService){ + ReceiptCosmosService receiptCosmosService) { this.bizEventToReceiptService = bizEventToReceiptService; this.bizEventCosmosClient = bizEventCosmosClient; this.receiptCosmosService = receiptCosmosService; @@ -62,7 +62,7 @@ public RecoverFailedReceiptMassive(){ * @return response with HttpStatus.OK */ @FunctionName("RecoverFailedReceiptMassive") - public HttpResponseMessage run ( + public HttpResponseMessage run( @HttpTrigger(name = "RecoverFailedReceiptMassiveTrigger", methods = {HttpMethod.POST}, route = "receipts/recover-failed", @@ -127,7 +127,7 @@ public HttpResponseMessage run ( } } while (continuationToken != null); } catch (NoSuchElementException e) { - logger.error(e.getMessage(), e); + logger.error("[{}] Unexpected error during recover of failed receipt", context.getFunctionName(), e); return request .createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR) .body(ProblemJson.builder() @@ -137,7 +137,7 @@ public HttpResponseMessage run ( .build()) .build(); } - + documentdb.setValue(receiptList); if (errorCounter > 0) { String msg = String.format("Recovered %s receipts but %s encountered an error.", receiptList.size(), errorCounter); diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduled.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduled.java new file mode 100644 index 0000000..b710629 --- /dev/null +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduled.java @@ -0,0 +1,112 @@ +package it.gov.pagopa.receipt.pdf.helpdesk; + +import java.time.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.NoSuchElementException; + +import com.azure.cosmos.models.FeedResponse; +import com.microsoft.azure.functions.annotation.*; +import com.microsoft.azure.functions.*; +import it.gov.pagopa.receipt.pdf.helpdesk.client.BizEventCosmosClient; +import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.BizEventCosmosClientImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.Receipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.enumeration.ReceiptStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.service.BizEventToReceiptService; +import it.gov.pagopa.receipt.pdf.helpdesk.service.ReceiptCosmosService; +import it.gov.pagopa.receipt.pdf.helpdesk.service.impl.BizEventToReceiptServiceImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.service.impl.ReceiptCosmosServiceImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static it.gov.pagopa.receipt.pdf.helpdesk.utils.BizEventToReceiptUtils.getEvent; + +/** + * Azure Functions with Timer trigger. + */ +public class RecoverFailedReceiptScheduled { + + private final Logger logger = LoggerFactory.getLogger(RecoverFailedReceiptScheduled.class); + + private final BizEventToReceiptService bizEventToReceiptService; + private final BizEventCosmosClient bizEventCosmosClient; + private final ReceiptCosmosService receiptCosmosService; + + public RecoverFailedReceiptScheduled() { + this.bizEventToReceiptService = new BizEventToReceiptServiceImpl(); + this.receiptCosmosService = new ReceiptCosmosServiceImpl(); + this.bizEventCosmosClient = BizEventCosmosClientImpl.getInstance(); + } + + RecoverFailedReceiptScheduled(BizEventToReceiptService bizEventToReceiptService, + BizEventCosmosClient bizEventCosmosClient, + ReceiptCosmosService receiptCosmosService) { + this.bizEventToReceiptService = bizEventToReceiptService; + this.bizEventCosmosClient = bizEventCosmosClient; + this.receiptCosmosService = receiptCosmosService; + } + + /** + * This function will be invoked periodically according to the specified schedule. + */ + @FunctionName("RecoverFailedReceiptScheduled") + public void run( + @TimerTrigger(name = "timerInfo", schedule = "%RECOVER_FAILED_CRON%") String timerInfo, + @CosmosDBOutput( + name = "ReceiptDatastore", + databaseName = "db", + collectionName = "receipts", + connectionStringSetting = "COSMOS_RECEIPTS_CONN_STRING") + OutputBinding> documentdb, + final ExecutionContext context + ) { + logger.info("[{}] function called at {}", context.getFunctionName(), LocalDateTime.now()); + List receiptList = new ArrayList<>(); + + receiptList.addAll(recoverFailed(context, ReceiptStatusType.INSERTED)); + receiptList.addAll(recoverFailed(context, ReceiptStatusType.FAILED)); + receiptList.addAll(recoverFailed(context, ReceiptStatusType.NOT_QUEUE_SENT)); + + documentdb.setValue(receiptList); + } + + private List recoverFailed(ExecutionContext context, ReceiptStatusType statusType) { + try { + return recover(context, statusType); + } catch (NoSuchElementException e) { + logger.error("[{}] Unexpected error during recover of failed receipt for status {}", + context.getFunctionName(), statusType, e); + return Collections.emptyList(); + } + } + + private List recover(ExecutionContext context, ReceiptStatusType statusType) { + int errorCounter = 0; + List receiptList = new ArrayList<>(); + String continuationToken = null; + do { + Iterable> feedResponseIterator = + this.receiptCosmosService.getFailedReceiptByStatus(continuationToken, 100, statusType); + + for (FeedResponse page : feedResponseIterator) { + for (Receipt receipt : page.getResults()) { + try { + Receipt restored = getEvent(receipt.getEventId(), context, this.bizEventToReceiptService, + this.bizEventCosmosClient, this.receiptCosmosService, receipt, logger); + receiptList.add(restored); + } catch (Exception e) { + logger.error(e.getMessage(), e); + errorCounter++; + } + } + continuationToken = page.getContinuationToken(); + } + } while (continuationToken != null); + if (errorCounter > 0) { + logger.error("[{}] Error recovering {} failed receipt for status {}", + context.getFunctionName(), errorCounter, statusType); + } + return receiptList; + } +} \ No newline at end of file From 233fa478e37cc519a5eaf4a1850a75bdb9a44f5c Mon Sep 17 00:00:00 2001 From: giomella Date: Tue, 5 Dec 2023 11:11:14 +0100 Subject: [PATCH 2/5] [PRDP-267] update javadoc --- .../receipt/pdf/helpdesk/RecoverFailedReceipt.java | 12 ++++++++++-- .../pdf/helpdesk/RecoverFailedReceiptMassive.java | 11 +++++++++-- .../pdf/helpdesk/RecoverFailedReceiptScheduled.java | 9 ++++++++- .../pdf/helpdesk/RecoverNotNotifiedReceipt.java | 2 +- .../helpdesk/RecoverNotNotifiedReceiptMassive.java | 2 +- 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceipt.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceipt.java index 5d9db64..f36b844 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceipt.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceipt.java @@ -15,6 +15,7 @@ import it.gov.pagopa.receipt.pdf.helpdesk.client.BizEventCosmosClient; import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.BizEventCosmosClientImpl; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.Receipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.enumeration.ReceiptStatusType; import it.gov.pagopa.receipt.pdf.helpdesk.exception.BizEventNotFoundException; import it.gov.pagopa.receipt.pdf.helpdesk.exception.PDVTokenizerException; import it.gov.pagopa.receipt.pdf.helpdesk.model.ProblemJson; @@ -55,9 +56,16 @@ public RecoverFailedReceipt(){ } /** - * This function will be invoked when a Http Trigger occurs + * This function will be invoked when a Http Trigger occurs. + *

+ * It recovers the receipt with the specified biz event id that has the following status: + * - ({@link ReceiptStatusType#INSERTED}) + * - ({@link ReceiptStatusType#FAILED}) + * - ({@link ReceiptStatusType#NOT_QUEUE_SENT}) + *

+ * It creates the receipts if not exist and send on queue the event in order to proceed with the receipt generation. * - * @return response with HttpStatus.OK + * @return response with {@link HttpStatus#OK} if the operation succeeded */ @FunctionName("RecoverFailedReceipt") public HttpResponseMessage run ( diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptMassive.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptMassive.java index 379f3d9..7e7c790 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptMassive.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptMassive.java @@ -57,9 +57,16 @@ public RecoverFailedReceiptMassive() { } /** - * This function will be invoked when a Http Trigger occurs + * This function will be invoked when a Http Trigger occurs. + *

+ * It recovers all the receipts with the specified status that has to be one of: + * - ({@link ReceiptStatusType#INSERTED}) + * - ({@link ReceiptStatusType#FAILED}) + * - ({@link ReceiptStatusType#NOT_QUEUE_SENT}) + *

+ * It creates the receipts if not exist and send on queue the event in order to proceed with the receipt generation. * - * @return response with HttpStatus.OK + * @return response with {@link HttpStatus#OK} if the operation succeeded */ @FunctionName("RecoverFailedReceiptMassive") public HttpResponseMessage run( diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduled.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduled.java index b710629..8c24f48 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduled.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduled.java @@ -49,6 +49,13 @@ public RecoverFailedReceiptScheduled() { /** * This function will be invoked periodically according to the specified schedule. + *

+ * It recovers all the receipts with the following status: + * - ({@link ReceiptStatusType#INSERTED}) + * - ({@link ReceiptStatusType#FAILED}) + * - ({@link ReceiptStatusType#NOT_QUEUE_SENT}) + *

+ * It creates the receipts if not exist and send on queue the event in order to proceed with the receipt generation. */ @FunctionName("RecoverFailedReceiptScheduled") public void run( @@ -104,7 +111,7 @@ private List recover(ExecutionContext context, ReceiptStatusType status } } while (continuationToken != null); if (errorCounter > 0) { - logger.error("[{}] Error recovering {} failed receipt for status {}", + logger.error("[{}] Error recovering {} failed receipts for status {}", context.getFunctionName(), errorCounter, statusType); } return receiptList; diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverNotNotifiedReceipt.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverNotNotifiedReceipt.java index e31faec..70a49fb 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverNotNotifiedReceipt.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverNotNotifiedReceipt.java @@ -53,7 +53,7 @@ public RecoverNotNotifiedReceipt() { * not triggered ({@link ReceiptStatusType#GENERATED} by clearing the errors and update the status to the * previous step ({@link ReceiptStatusType#GENERATED}). * - * @return response with {@link HttpStatus#OK} if the notification succeeded + * @return response with {@link HttpStatus#OK} if the operation succeeded */ @FunctionName("RecoverNotNotifiedReceipt") public HttpResponseMessage run( diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverNotNotifiedReceiptMassive.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverNotNotifiedReceiptMassive.java index 3338e1c..8b7ce3f 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverNotNotifiedReceiptMassive.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverNotNotifiedReceiptMassive.java @@ -50,7 +50,7 @@ public RecoverNotNotifiedReceiptMassive() { * not triggered ({@link ReceiptStatusType#GENERATED} by clearing the errors and update the status to the * previous step ({@link ReceiptStatusType#GENERATED}). * - * @return response with {@link HttpStatus#OK} if the notification succeeded + * @return response with {@link HttpStatus#OK} if the operation succeeded */ @FunctionName("RecoverNotNotifiedReceiptMassive") public HttpResponseMessage run( From 148302edf962f4992d3c8ec42bff697cdf4b2e13 Mon Sep 17 00:00:00 2001 From: giomella Date: Tue, 5 Dec 2023 12:17:32 +0100 Subject: [PATCH 3/5] [PRDP-267] fixed receipt status, do some refactor to avoid duplicated code. Added unit test --- .../helpdesk/RecoverFailedReceiptMassive.java | 31 +-- .../RecoverFailedReceiptScheduled.java | 68 +++---- .../helpdesk/model/MassiveRecoverResult.java | 15 ++ .../utils/BizEventToReceiptUtils.java | 41 +++- .../RecoverFailedReceiptScheduledTest.java | 179 ++++++++++++++++++ 5 files changed, 264 insertions(+), 70 deletions(-) create mode 100644 src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/model/MassiveRecoverResult.java create mode 100644 src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduledTest.java diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptMassive.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptMassive.java index 7e7c790..6e37a9c 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptMassive.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptMassive.java @@ -1,6 +1,5 @@ package it.gov.pagopa.receipt.pdf.helpdesk; -import com.azure.cosmos.models.FeedResponse; import com.microsoft.azure.functions.ExecutionContext; import com.microsoft.azure.functions.HttpMethod; import com.microsoft.azure.functions.HttpRequestMessage; @@ -15,6 +14,7 @@ import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.BizEventCosmosClientImpl; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.Receipt; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.enumeration.ReceiptStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.model.MassiveRecoverResult; import it.gov.pagopa.receipt.pdf.helpdesk.model.ProblemJson; import it.gov.pagopa.receipt.pdf.helpdesk.service.BizEventToReceiptService; import it.gov.pagopa.receipt.pdf.helpdesk.service.ReceiptCosmosService; @@ -24,12 +24,11 @@ import org.slf4j.LoggerFactory; import java.time.LocalDateTime; -import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; import java.util.Optional; -import static it.gov.pagopa.receipt.pdf.helpdesk.utils.BizEventToReceiptUtils.getEvent; +import static it.gov.pagopa.receipt.pdf.helpdesk.utils.BizEventToReceiptUtils.massiveRecoverByStatus; /** * Azure Functions with Azure Http trigger. @@ -111,28 +110,10 @@ public HttpResponseMessage run( .build(); } - List receiptList = new ArrayList<>(); - String continuationToken = null; - int errorCounter = 0; + MassiveRecoverResult recoverResult; try { - do { - Iterable> feedResponseIterator = - this.receiptCosmosService.getFailedReceiptByStatus(continuationToken, 100, statusType); - - for (FeedResponse page : feedResponseIterator) { - for (Receipt receipt : page.getResults()) { - try { - Receipt restored = getEvent(receipt.getEventId(), context, this.bizEventToReceiptService, - this.bizEventCosmosClient, this.receiptCosmosService, receipt, logger); - receiptList.add(restored); - } catch (Exception e) { - logger.error(e.getMessage(), e); - errorCounter++; - } - } - continuationToken = page.getContinuationToken(); - } - } while (continuationToken != null); + recoverResult = massiveRecoverByStatus( + context, bizEventToReceiptService, bizEventCosmosClient, receiptCosmosService, logger, statusType); } catch (NoSuchElementException e) { logger.error("[{}] Unexpected error during recover of failed receipt", context.getFunctionName(), e); return request @@ -144,6 +125,8 @@ public HttpResponseMessage run( .build()) .build(); } + List receiptList = recoverResult.getReceiptList(); + int errorCounter = recoverResult.getErrorCounter(); documentdb.setValue(receiptList); if (errorCounter > 0) { diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduled.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduled.java index 8c24f48..0037c48 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduled.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduled.java @@ -1,18 +1,15 @@ package it.gov.pagopa.receipt.pdf.helpdesk; -import java.time.*; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.NoSuchElementException; - -import com.azure.cosmos.models.FeedResponse; -import com.microsoft.azure.functions.annotation.*; -import com.microsoft.azure.functions.*; +import com.microsoft.azure.functions.ExecutionContext; +import com.microsoft.azure.functions.OutputBinding; +import com.microsoft.azure.functions.annotation.CosmosDBOutput; +import com.microsoft.azure.functions.annotation.FunctionName; +import com.microsoft.azure.functions.annotation.TimerTrigger; import it.gov.pagopa.receipt.pdf.helpdesk.client.BizEventCosmosClient; import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.BizEventCosmosClientImpl; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.Receipt; import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.enumeration.ReceiptStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.model.MassiveRecoverResult; import it.gov.pagopa.receipt.pdf.helpdesk.service.BizEventToReceiptService; import it.gov.pagopa.receipt.pdf.helpdesk.service.ReceiptCosmosService; import it.gov.pagopa.receipt.pdf.helpdesk.service.impl.BizEventToReceiptServiceImpl; @@ -20,7 +17,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static it.gov.pagopa.receipt.pdf.helpdesk.utils.BizEventToReceiptUtils.getEvent; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.NoSuchElementException; + +import static it.gov.pagopa.receipt.pdf.helpdesk.utils.BizEventToReceiptUtils.massiveRecoverByStatus; /** * Azure Functions with Timer trigger. @@ -71,49 +74,26 @@ public void run( logger.info("[{}] function called at {}", context.getFunctionName(), LocalDateTime.now()); List receiptList = new ArrayList<>(); - receiptList.addAll(recoverFailed(context, ReceiptStatusType.INSERTED)); - receiptList.addAll(recoverFailed(context, ReceiptStatusType.FAILED)); - receiptList.addAll(recoverFailed(context, ReceiptStatusType.NOT_QUEUE_SENT)); + receiptList.addAll(recover(context, ReceiptStatusType.INSERTED)); + receiptList.addAll(recover(context, ReceiptStatusType.FAILED)); + receiptList.addAll(recover(context, ReceiptStatusType.NOT_QUEUE_SENT)); documentdb.setValue(receiptList); } - private List recoverFailed(ExecutionContext context, ReceiptStatusType statusType) { + private List recover(ExecutionContext context, ReceiptStatusType statusType) { try { - return recover(context, statusType); + MassiveRecoverResult recoverResult = massiveRecoverByStatus( + context, bizEventToReceiptService, bizEventCosmosClient, receiptCosmosService, logger, statusType); + if (recoverResult.getErrorCounter() > 0) { + logger.error("[{}] Error recovering {} failed receipts for status {}", + context.getFunctionName(), recoverResult.getErrorCounter(), statusType); + } + return recoverResult.getReceiptList(); } catch (NoSuchElementException e) { logger.error("[{}] Unexpected error during recover of failed receipt for status {}", context.getFunctionName(), statusType, e); return Collections.emptyList(); } } - - private List recover(ExecutionContext context, ReceiptStatusType statusType) { - int errorCounter = 0; - List receiptList = new ArrayList<>(); - String continuationToken = null; - do { - Iterable> feedResponseIterator = - this.receiptCosmosService.getFailedReceiptByStatus(continuationToken, 100, statusType); - - for (FeedResponse page : feedResponseIterator) { - for (Receipt receipt : page.getResults()) { - try { - Receipt restored = getEvent(receipt.getEventId(), context, this.bizEventToReceiptService, - this.bizEventCosmosClient, this.receiptCosmosService, receipt, logger); - receiptList.add(restored); - } catch (Exception e) { - logger.error(e.getMessage(), e); - errorCounter++; - } - } - continuationToken = page.getContinuationToken(); - } - } while (continuationToken != null); - if (errorCounter > 0) { - logger.error("[{}] Error recovering {} failed receipts for status {}", - context.getFunctionName(), errorCounter, statusType); - } - return receiptList; - } } \ No newline at end of file diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/model/MassiveRecoverResult.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/model/MassiveRecoverResult.java new file mode 100644 index 0000000..147e963 --- /dev/null +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/model/MassiveRecoverResult.java @@ -0,0 +1,15 @@ +package it.gov.pagopa.receipt.pdf.helpdesk.model; + +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.Receipt; +import lombok.Builder; +import lombok.Data; + +import java.util.List; + +@Data +@Builder +public class MassiveRecoverResult { + + private List receiptList; + private int errorCounter; +} diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/utils/BizEventToReceiptUtils.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/utils/BizEventToReceiptUtils.java index 65d4e1a..b6dcff1 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/utils/BizEventToReceiptUtils.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/utils/BizEventToReceiptUtils.java @@ -1,5 +1,6 @@ package it.gov.pagopa.receipt.pdf.helpdesk.utils; +import com.azure.cosmos.models.FeedResponse; import com.fasterxml.jackson.core.JsonProcessingException; import com.microsoft.azure.functions.ExecutionContext; import it.gov.pagopa.receipt.pdf.helpdesk.client.BizEventCosmosClient; @@ -13,10 +14,12 @@ import it.gov.pagopa.receipt.pdf.helpdesk.exception.BizEventNotFoundException; import it.gov.pagopa.receipt.pdf.helpdesk.exception.PDVTokenizerException; import it.gov.pagopa.receipt.pdf.helpdesk.exception.ReceiptNotFoundException; +import it.gov.pagopa.receipt.pdf.helpdesk.model.MassiveRecoverResult; import it.gov.pagopa.receipt.pdf.helpdesk.service.BizEventToReceiptService; import it.gov.pagopa.receipt.pdf.helpdesk.service.ReceiptCosmosService; import org.slf4j.Logger; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; @@ -59,9 +62,9 @@ public static Receipt getEvent( if (receipt.getEventData() == null || receipt.getEventData().getDebtorFiscalCode() == null) { tokenizeReceipt(bizEventToReceiptService, bizEvent, receipt); } + receipt.setStatus(ReceiptStatusType.INSERTED); bizEventToReceiptService.handleSendMessageToQueue(bizEvent, receipt); - if(receipt.getStatus() != ReceiptStatusType.NOT_QUEUE_SENT){ - receipt.setStatus(ReceiptStatusType.INSERTED); + if (receipt.getStatus() != ReceiptStatusType.NOT_QUEUE_SENT) { receipt.setInsertedAt(System.currentTimeMillis()); receipt.setReasonErr(null); receipt.setReasonErrPayer(null); @@ -71,6 +74,40 @@ public static Receipt getEvent( return null; } + public static MassiveRecoverResult massiveRecoverByStatus( + ExecutionContext context, + BizEventToReceiptService bizEventToReceiptService, + BizEventCosmosClient bizEventCosmosClient, + ReceiptCosmosService receiptCosmosService, + Logger logger, + ReceiptStatusType statusType) { + int errorCounter = 0; + List receiptList = new ArrayList<>(); + String continuationToken = null; + do { + Iterable> feedResponseIterator = + receiptCosmosService.getFailedReceiptByStatus(continuationToken, 100, statusType); + + for (FeedResponse page : feedResponseIterator) { + for (Receipt receipt : page.getResults()) { + try { + Receipt restored = getEvent(receipt.getEventId(), context, bizEventToReceiptService, + bizEventCosmosClient, receiptCosmosService, receipt, logger); + receiptList.add(restored); + } catch (Exception e) { + logger.error(e.getMessage(), e); + errorCounter++; + } + } + continuationToken = page.getContinuationToken(); + } + } while (continuationToken != null); + return MassiveRecoverResult.builder() + .receiptList(receiptList) + .errorCounter(errorCounter) + .build(); + } + /** * Creates a new instance of Receipt, using the tokenizer service to mask the PII, based on * the provided BizEvent diff --git a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduledTest.java b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduledTest.java new file mode 100644 index 0000000..e9a2522 --- /dev/null +++ b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduledTest.java @@ -0,0 +1,179 @@ +package it.gov.pagopa.receipt.pdf.helpdesk; + +import com.azure.cosmos.models.ModelBridgeInternal; +import com.microsoft.azure.functions.ExecutionContext; +import com.microsoft.azure.functions.OutputBinding; +import it.gov.pagopa.receipt.pdf.helpdesk.client.impl.BizEventCosmosClientImpl; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.BizEvent; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.Debtor; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.Payer; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.PaymentInfo; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.Transaction; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.TransactionDetails; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.event.enumeration.BizEventStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.CartItem; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.EventData; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.Receipt; +import it.gov.pagopa.receipt.pdf.helpdesk.entity.receipt.enumeration.ReceiptStatusType; +import it.gov.pagopa.receipt.pdf.helpdesk.exception.BizEventNotFoundException; +import it.gov.pagopa.receipt.pdf.helpdesk.service.BizEventToReceiptService; +import it.gov.pagopa.receipt.pdf.helpdesk.service.ReceiptCosmosService; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class RecoverFailedReceiptScheduledTest { + + private final String TOKENIZED_DEBTOR_FISCAL_CODE = "tokenizedDebtorFiscalCode"; + private final String TOKENIZED_PAYER_FISCAL_CODE = "tokenizedPayerFiscalCode"; + private final String EVENT_ID_1 = "a valid id 1"; + private final String EVENT_ID_2 = "a valid id 2"; + private final String EVENT_ID_3 = "a valid id 3"; + + @Mock + private ExecutionContext contextMock; + @Mock + private ReceiptCosmosService receiptCosmosServiceMock; + @Mock + private BizEventCosmosClientImpl bizEventCosmosClientMock; + @Mock + private BizEventToReceiptService bizEventToReceiptServiceMock; + + @Captor + private ArgumentCaptor> receiptCaptor; + + @Spy + private OutputBinding> documentdb; + + private AutoCloseable closeable; + + private RecoverFailedReceiptScheduled sut; + + @BeforeEach + public void openMocks() { + closeable = MockitoAnnotations.openMocks(this); + sut = spy(new RecoverFailedReceiptScheduled(bizEventToReceiptServiceMock, bizEventCosmosClientMock, receiptCosmosServiceMock)); + } + + @AfterEach + public void releaseMocks() throws Exception { + closeable.close(); + } + + @Test + void recoverFailedReceiptScheduledSuccess() throws BizEventNotFoundException { + when(receiptCosmosServiceMock.getFailedReceiptByStatus(any(), any(), eq(ReceiptStatusType.FAILED))) + .thenReturn(Collections.singletonList(ModelBridgeInternal + .createFeedResponse(Collections.singletonList( + createFailedReceipt(EVENT_ID_1, ReceiptStatusType.FAILED)), + Collections.emptyMap()))); + when(receiptCosmosServiceMock.getFailedReceiptByStatus(any(), any(), eq(ReceiptStatusType.INSERTED))) + .thenReturn(Collections.singletonList(ModelBridgeInternal + .createFeedResponse(Collections.singletonList( + createFailedReceipt(EVENT_ID_2, ReceiptStatusType.INSERTED)), + Collections.emptyMap()))); + when(receiptCosmosServiceMock.getFailedReceiptByStatus(any(), any(), eq(ReceiptStatusType.NOT_QUEUE_SENT))) + .thenReturn(Collections.singletonList(ModelBridgeInternal + .createFeedResponse(Collections.singletonList( + createFailedReceipt(EVENT_ID_3, ReceiptStatusType.NOT_QUEUE_SENT)), + Collections.emptyMap()))); + + when(bizEventCosmosClientMock.getBizEventDocument(EVENT_ID_1)) + .thenReturn(generateValidBizEvent(EVENT_ID_1)); + when(bizEventCosmosClientMock.getBizEventDocument(EVENT_ID_2)) + .thenReturn(generateValidBizEvent(EVENT_ID_2)); + when(bizEventCosmosClientMock.getBizEventDocument(EVENT_ID_3)) + .thenReturn(generateValidBizEvent(EVENT_ID_3)); + + // test execution + assertDoesNotThrow(() -> sut.run("info", documentdb, contextMock)); + + verify(documentdb).setValue(receiptCaptor.capture()); + assertEquals(3, receiptCaptor.getValue().size()); + + Receipt captured = receiptCaptor.getValue().get(0); + assertEquals(ReceiptStatusType.INSERTED, captured.getStatus()); + assertEquals(TOKENIZED_PAYER_FISCAL_CODE, captured.getEventData().getPayerFiscalCode()); + assertEquals(TOKENIZED_DEBTOR_FISCAL_CODE, captured.getEventData().getDebtorFiscalCode()); + assertNotNull(captured.getEventData().getCart()); + assertEquals(1, captured.getEventData().getCart().size()); + + captured = receiptCaptor.getValue().get(1); + assertEquals(ReceiptStatusType.INSERTED, captured.getStatus()); + assertEquals(TOKENIZED_PAYER_FISCAL_CODE, captured.getEventData().getPayerFiscalCode()); + assertEquals(TOKENIZED_DEBTOR_FISCAL_CODE, captured.getEventData().getDebtorFiscalCode()); + assertNotNull(captured.getEventData().getCart()); + assertEquals(1, captured.getEventData().getCart().size()); + + captured = receiptCaptor.getValue().get(2); + assertEquals(ReceiptStatusType.INSERTED, captured.getStatus()); + assertEquals(TOKENIZED_PAYER_FISCAL_CODE, captured.getEventData().getPayerFiscalCode()); + assertEquals(TOKENIZED_DEBTOR_FISCAL_CODE, captured.getEventData().getDebtorFiscalCode()); + assertNotNull(captured.getEventData().getCart()); + assertEquals(1, captured.getEventData().getCart().size()); + } + + private BizEvent generateValidBizEvent(String eventId){ + BizEvent item = new BizEvent(); + + Payer payer = new Payer(); + payer.setEntityUniqueIdentifierValue("a valid payer CF"); + Debtor debtor = new Debtor(); + debtor.setEntityUniqueIdentifierValue("a valid debtor CF"); + + TransactionDetails transactionDetails = new TransactionDetails(); + Transaction transaction = new Transaction(); + transaction.setCreationDate(String.valueOf(LocalDateTime.now())); + transactionDetails.setTransaction(transaction); + + PaymentInfo paymentInfo = new PaymentInfo(); + paymentInfo.setTotalNotice("1"); + + item.setEventStatus(BizEventStatusType.DONE); + item.setId(eventId); + item.setPayer(payer); + item.setDebtor(debtor); + item.setTransactionDetails(transactionDetails); + item.setPaymentInfo(paymentInfo); + + return item; + } + + private Receipt createFailedReceipt(String id, ReceiptStatusType statusType) { + Receipt receipt = new Receipt(); + + receipt.setId(id); + receipt.setEventId(id); + receipt.setVersion("1"); + + receipt.setStatus(statusType); + EventData eventData = new EventData(); + eventData.setDebtorFiscalCode(TOKENIZED_DEBTOR_FISCAL_CODE); + eventData.setPayerFiscalCode(TOKENIZED_PAYER_FISCAL_CODE); + receipt.setEventData(eventData); + + CartItem item = new CartItem(); + List cartItems = Collections.singletonList(item); + eventData.setCart(cartItems); + + return receipt; + } +} \ No newline at end of file From a719f92c59c8f9d7429250a1544ca469dfff75b5 Mon Sep 17 00:00:00 2001 From: giomella Date: Wed, 6 Dec 2023 09:36:56 +0100 Subject: [PATCH 4/5] [PRDP-267] fix unit test --- .../it/gov/pagopa/receipt/pdf/helpdesk/GetReceiptErrorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/GetReceiptErrorTest.java b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/GetReceiptErrorTest.java index a481bd7..a19147a 100644 --- a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/GetReceiptErrorTest.java +++ b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/GetReceiptErrorTest.java @@ -114,7 +114,7 @@ void shouldReturnMissingReceiptErrorMessageOnNonExistingErrorinCosmos() throws R // test assertion assertNotNull(response); - assertEquals(HttpStatus.OK, response.getStatus()); + assertEquals(HttpStatus.NOT_FOUND, response.getStatus()); assertEquals(ProblemJson.class, response.getBody().getClass()); ProblemJson responseData = (ProblemJson) response.getBody(); From db1c77dc218de330c1bff7805b2f0ce54886d510 Mon Sep 17 00:00:00 2001 From: giomella Date: Wed, 6 Dec 2023 10:06:05 +0100 Subject: [PATCH 5/5] [PRDP-267] added flag for recover failed scheduled function --- .../RecoverFailedReceiptScheduled.java | 16 +++++---- .../RecoverFailedReceiptScheduledTest.java | 36 ++++++++++++++++--- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduled.java b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduled.java index 0037c48..aa8d297 100644 --- a/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduled.java +++ b/src/main/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduled.java @@ -32,6 +32,8 @@ public class RecoverFailedReceiptScheduled { private final Logger logger = LoggerFactory.getLogger(RecoverFailedReceiptScheduled.class); + private final boolean isEnabled = Boolean.parseBoolean(System.getenv().getOrDefault("FAILED_AUTORECOVER_ENABLED", "true")); + private final BizEventToReceiptService bizEventToReceiptService; private final BizEventCosmosClient bizEventCosmosClient; private final ReceiptCosmosService receiptCosmosService; @@ -71,14 +73,16 @@ public void run( OutputBinding> documentdb, final ExecutionContext context ) { - logger.info("[{}] function called at {}", context.getFunctionName(), LocalDateTime.now()); - List receiptList = new ArrayList<>(); + if (isEnabled) { + logger.info("[{}] function called at {}", context.getFunctionName(), LocalDateTime.now()); + List receiptList = new ArrayList<>(); - receiptList.addAll(recover(context, ReceiptStatusType.INSERTED)); - receiptList.addAll(recover(context, ReceiptStatusType.FAILED)); - receiptList.addAll(recover(context, ReceiptStatusType.NOT_QUEUE_SENT)); + receiptList.addAll(recover(context, ReceiptStatusType.INSERTED)); + receiptList.addAll(recover(context, ReceiptStatusType.FAILED)); + receiptList.addAll(recover(context, ReceiptStatusType.NOT_QUEUE_SENT)); - documentdb.setValue(receiptList); + documentdb.setValue(receiptList); + } } private List recover(ExecutionContext context, ReceiptStatusType statusType) { diff --git a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduledTest.java b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduledTest.java index e9a2522..3921b69 100644 --- a/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduledTest.java +++ b/src/test/java/it/gov/pagopa/receipt/pdf/helpdesk/RecoverFailedReceiptScheduledTest.java @@ -21,11 +21,15 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; +import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; +import uk.org.webcompere.systemstubs.jupiter.SystemStub; +import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; import java.time.LocalDateTime; import java.util.Collections; @@ -35,11 +39,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +@ExtendWith(SystemStubsExtension.class) class RecoverFailedReceiptScheduledTest { private final String TOKENIZED_DEBTOR_FISCAL_CODE = "tokenizedDebtorFiscalCode"; @@ -63,6 +70,9 @@ class RecoverFailedReceiptScheduledTest { @Spy private OutputBinding> documentdb; + @SystemStub + private EnvironmentVariables environment; + private AutoCloseable closeable; private RecoverFailedReceiptScheduled sut; @@ -70,7 +80,6 @@ class RecoverFailedReceiptScheduledTest { @BeforeEach public void openMocks() { closeable = MockitoAnnotations.openMocks(this); - sut = spy(new RecoverFailedReceiptScheduled(bizEventToReceiptServiceMock, bizEventCosmosClientMock, receiptCosmosServiceMock)); } @AfterEach @@ -80,20 +89,21 @@ public void releaseMocks() throws Exception { @Test void recoverFailedReceiptScheduledSuccess() throws BizEventNotFoundException { + sut = spy(new RecoverFailedReceiptScheduled(bizEventToReceiptServiceMock, bizEventCosmosClientMock, receiptCosmosServiceMock)); when(receiptCosmosServiceMock.getFailedReceiptByStatus(any(), any(), eq(ReceiptStatusType.FAILED))) .thenReturn(Collections.singletonList(ModelBridgeInternal .createFeedResponse(Collections.singletonList( - createFailedReceipt(EVENT_ID_1, ReceiptStatusType.FAILED)), + createFailedReceipt(EVENT_ID_1, ReceiptStatusType.FAILED)), Collections.emptyMap()))); when(receiptCosmosServiceMock.getFailedReceiptByStatus(any(), any(), eq(ReceiptStatusType.INSERTED))) .thenReturn(Collections.singletonList(ModelBridgeInternal .createFeedResponse(Collections.singletonList( - createFailedReceipt(EVENT_ID_2, ReceiptStatusType.INSERTED)), + createFailedReceipt(EVENT_ID_2, ReceiptStatusType.INSERTED)), Collections.emptyMap()))); when(receiptCosmosServiceMock.getFailedReceiptByStatus(any(), any(), eq(ReceiptStatusType.NOT_QUEUE_SENT))) .thenReturn(Collections.singletonList(ModelBridgeInternal .createFeedResponse(Collections.singletonList( - createFailedReceipt(EVENT_ID_3, ReceiptStatusType.NOT_QUEUE_SENT)), + createFailedReceipt(EVENT_ID_3, ReceiptStatusType.NOT_QUEUE_SENT)), Collections.emptyMap()))); when(bizEventCosmosClientMock.getBizEventDocument(EVENT_ID_1)) @@ -131,7 +141,23 @@ void recoverFailedReceiptScheduledSuccess() throws BizEventNotFoundException { assertEquals(1, captured.getEventData().getCart().size()); } - private BizEvent generateValidBizEvent(String eventId){ + @Test + void recoverFailedReceiptScheduledDisabled() throws BizEventNotFoundException { + environment.set("FAILED_AUTORECOVER_ENABLED", "false"); + sut = spy(new RecoverFailedReceiptScheduled(bizEventToReceiptServiceMock, bizEventCosmosClientMock, receiptCosmosServiceMock)); + + assertEquals("false", System.getenv("FAILED_AUTORECOVER_ENABLED")); + + // test execution + assertDoesNotThrow(() -> sut.run("info", documentdb, contextMock)); + + verify(documentdb, never()).setValue(any()); + verify(receiptCosmosServiceMock, never()).getFailedReceiptByStatus(any(), any(), any()); + verify(bizEventCosmosClientMock, never()).getBizEventDocument(anyString()); + + } + + private BizEvent generateValidBizEvent(String eventId) { BizEvent item = new BizEvent(); Payer payer = new Payer();