diff --git a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/PintScenarioListBuilder.java b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/PintScenarioListBuilder.java index a507223a..403827dc 100644 --- a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/PintScenarioListBuilder.java +++ b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/PintScenarioListBuilder.java @@ -43,20 +43,12 @@ public static LinkedHashMap createModuleScenari initiateAndCloseTransferAction(PintResponseCode.RECE).thenEither( noAction(), retryTransfer(PintResponseCode.DUPE, SenderTransmissionClass.VALID_TRANSFER), - resignLatestEntry().then( - retryTransfer(PintResponseCode.DUPE, SenderTransmissionClass.VALID_TRANSFER) - ), - manipulateLatestTransactionParameters().then( - retryTransfer(PintResponseCode.DISE, SenderTransmissionClass.VALID_TRANSFER) - )), + retryTransfer(PintResponseCode.DUPE, SenderTransmissionClass.VALID_TRANSFER, RetryType.RESIGN), + retryTransfer(PintResponseCode.DISE, SenderTransmissionClass.VALID_TRANSFER, RetryType.MANIPULATE)), initiateAndCloseTransferAction(PintResponseCode.RECE, SenderTransmissionClass.VALID_TRANSFER).thenEither( noAction(), - resignLatestEntry().then( - retryTransfer(PintResponseCode.DUPE, SenderTransmissionClass.VALID_TRANSFER) - ), - manipulateLatestTransactionParameters().then( - retryTransfer(PintResponseCode.DISE, SenderTransmissionClass.VALID_TRANSFER) - ) + retryTransfer(PintResponseCode.DUPE, SenderTransmissionClass.VALID_TRANSFER, RetryType.RESIGN), + retryTransfer(PintResponseCode.DISE, SenderTransmissionClass.VALID_TRANSFER, RetryType.MANIPULATE) ), initiateAndCloseTransferAction(PintResponseCode.BSIG, SenderTransmissionClass.SIGNATURE_ISSUE).then( initiateAndCloseTransferAction(PintResponseCode.RECE) @@ -65,7 +57,7 @@ public static LinkedHashMap createModuleScenari ), receiverStateSetup(ScenarioClass.INVALID_RECIPIENT).then( initiateAndCloseTransferAction(PintResponseCode.BENV) - ), + )/*, receiverStateSetup(ScenarioClass.FAIL_W_503).then( initiateTransferUnsignedFailure(503, SenderTransmissionClass.VALID_TRANSFER).thenEither( resetScenarioClass(ScenarioClass.NO_ISSUES).then( @@ -73,7 +65,7 @@ public static LinkedHashMap createModuleScenari initiateTransferUnsignedFailure(503, SenderTransmissionClass.VALID_TRANSFER).then( resetScenarioClass(ScenarioClass.NO_ISSUES).then( initiateAndCloseTransferAction(PintResponseCode.RECE))) - )) + ))*/ ), supplySenderTransferScenarioParameters(2).thenEither( receiverStateSetup(ScenarioClass.NO_ISSUES) @@ -87,7 +79,7 @@ public static LinkedHashMap createModuleScenari retryTransfer(PintResponseCode.RECE, SenderTransmissionClass.VALID_TRANSFER) ) ), - resetScenarioClass(ScenarioClass.FAIL_W_503).then( + /*resetScenarioClass(ScenarioClass.FAIL_W_503).then( transferDocumentReceiverFailure().then( resetScenarioClass(ScenarioClass.NO_ISSUES).thenEither( transferDocument().then(closeTransferAction(PintResponseCode.RECE)), @@ -99,7 +91,7 @@ public static LinkedHashMap createModuleScenari ) ) ) - ), + ),*/ transferDocument(SenderDocumentTransmissionTypeCode.CORRUPTED_DOCUMENT).then( retryTransfer(1, SenderTransmissionClass.VALID_TRANSFER).then(transferDocument().then(closeTransferAction(PintResponseCode.RECE))) ), @@ -171,31 +163,6 @@ private static PintScenarioListBuilder supplySenderTransferScenarioParameters(in )); } - private static PintScenarioListBuilder manipulateLatestTransactionParameters() { - String sendingPlatform = SENDING_PLATFORM_PARTY_NAME.get(); - String receivingPlatform = RECEIVING_PLATFORM_PARTY_NAME.get(); - return new PintScenarioListBuilder( - previousAction -> - new ManipulateTransactionsAction( - receivingPlatform, - sendingPlatform, - (PintAction) previousAction - )); - } - - private static PintScenarioListBuilder resignLatestEntry() { - String sendingPlatform = SENDING_PLATFORM_PARTY_NAME.get(); - String receivingPlatform = RECEIVING_PLATFORM_PARTY_NAME.get(); - return new PintScenarioListBuilder( - previousAction -> - new ResignLatestEntryAction( - receivingPlatform, - sendingPlatform, - (PintAction) previousAction - )); - } - - private static PintScenarioListBuilder receiverStateSetup(ScenarioClass scenarioClass) { String sendingPlatform = SENDING_PLATFORM_PARTY_NAME.get(); String receivingPlatform = RECEIVING_PLATFORM_PARTY_NAME.get(); @@ -308,6 +275,10 @@ private static PintScenarioListBuilder retryTransfer(int expectedMissingDocument } private static PintScenarioListBuilder retryTransfer(PintResponseCode pintResponseCode, SenderTransmissionClass senderTransmissionClass) { + return retryTransfer(pintResponseCode, senderTransmissionClass, RetryType.NO_CHANGE); + } + + private static PintScenarioListBuilder retryTransfer(PintResponseCode pintResponseCode, SenderTransmissionClass senderTransmissionClass, RetryType retryType) { String sendingPlatform = SENDING_PLATFORM_PARTY_NAME.get(); String receivingPlatform = RECEIVING_PLATFORM_PARTY_NAME.get(); return new PintScenarioListBuilder( @@ -318,6 +289,7 @@ private static PintScenarioListBuilder retryTransfer(PintResponseCode pintRespon (PintAction) previousAction, pintResponseCode, senderTransmissionClass, + retryType, resolveMessageSchemaValidator(ENVELOPE_REQUEST_SCHEMA), resolveMessageSchemaValidator(ENVELOPE_MANIFEST_SCHEMA), resolveMessageSchemaValidator(ENVELOPE_TRANSFER_CHAIN_ENTRY_SCHEMA), diff --git a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/ManipulateTransactionsAction.java b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/ManipulateTransactionsAction.java deleted file mode 100644 index e8c8b860..00000000 --- a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/ManipulateTransactionsAction.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.dcsa.conformance.standards.eblinterop.action; - -import com.fasterxml.jackson.databind.node.ObjectNode; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; - -@Getter -@Slf4j -public class ManipulateTransactionsAction extends PintAction { - - public ManipulateTransactionsAction( - String platformPartyName, - String carrierPartyName, - PintAction previousAction) { - super( - carrierPartyName, - platformPartyName, - previousAction, - "ManipulateTransaction", - -1); - } - - @Override - public ObjectNode asJsonNode() { - var node = super.asJsonNode(); - node.set("rsp", getRsp().toJson()); - node.set("ssp", getSsp().toJson()); - node.set("dsp", getDsp().toJson()); - return node; - } - - @Override - public boolean isInputRequired() { - return true; - } - - - @Override - public String getHumanReadablePrompt() { - return ("Manipulate the latest transaction"); - } - -} diff --git a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/PintAction.java b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/PintAction.java index 8a4caa98..304076c6 100644 --- a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/PintAction.java +++ b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/PintAction.java @@ -47,6 +47,8 @@ public void reset() { super.reset(); if (previousAction != null) { this.dspReference.set(null); + this.rspReference.set(null); + this.sspReference.set(null); } } diff --git a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/PintRetryTransferAction.java b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/PintRetryTransferAction.java index e1a35fe7..41cb810f 100644 --- a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/PintRetryTransferAction.java +++ b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/PintRetryTransferAction.java @@ -66,7 +66,8 @@ public String getHumanReadablePrompt() { @Override public ObjectNode asJsonNode() { var node = super.asJsonNode() - .put("senderTransmissionClass", SenderTransmissionClass.VALID_ISSUANCE.name()); + .put("senderTransmissionClass", senderTransmissionClass.name()) + .put("retryType", RetryType.NO_CHANGE.name()); node.set("rsp", getRsp().toJson()); node.set("ssp", getSsp().toJson()); node.set("dsp", getDsp().toJson()); diff --git a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/PintRetryTransferAndCloseAction.java b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/PintRetryTransferAndCloseAction.java index ecb343b5..fc366f85 100644 --- a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/PintRetryTransferAndCloseAction.java +++ b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/PintRetryTransferAndCloseAction.java @@ -24,6 +24,7 @@ public class PintRetryTransferAndCloseAction extends PintAction { private final PintResponseCode responseCode; private final SenderTransmissionClass senderTransmissionClass; + private final RetryType retryType; private final JsonSchemaValidator requestSchemaValidator; private final JsonSchemaValidator responseSchemaValidator; private final JsonSchemaValidator envelopeEnvelopeSchemaValidator; @@ -36,6 +37,7 @@ public PintRetryTransferAndCloseAction( PintAction previousAction, PintResponseCode responseCode, SenderTransmissionClass senderTransmissionClass, + RetryType retryType, JsonSchemaValidator requestSchemaValidator, JsonSchemaValidator envelopeEnvelopeSchemaValidator, JsonSchemaValidator envelopeTransferChainEntrySchemaValidator, @@ -46,11 +48,12 @@ public PintRetryTransferAndCloseAction( sendingPlatform, receivingPlatform, previousAction, - "RetryTransfer(%s)".formatted(responseCode.name()), + "RetryTransfer(%s, %s)".formatted(responseCode.name(), retryType.name()), responseCode.getHttpResponseCode() ); this.responseCode = responseCode; this.senderTransmissionClass = senderTransmissionClass; + this.retryType = retryType; this.requestSchemaValidator = requestSchemaValidator; this.responseSchemaValidator = responseSchemaValidator; this.envelopeEnvelopeSchemaValidator = envelopeEnvelopeSchemaValidator; @@ -60,13 +63,18 @@ public PintRetryTransferAndCloseAction( @Override public String getHumanReadablePrompt() { - return ("Retry transfer-transaction request"); + return switch (retryType) { + case NO_CHANGE -> "Retry transfer-transaction request"; + case RESIGN -> "Retry the transfer-transaction request with the latest transaction entry resigned"; + case MANIPULATE -> "Retry the transfer-transaction request after manipulating (and resigning) the latest transaction"; + }; } @Override public ObjectNode asJsonNode() { var node = super.asJsonNode() - .put("senderTransmissionClass", SenderTransmissionClass.VALID_ISSUANCE.name()); + .put("senderTransmissionClass", senderTransmissionClass.name()) + .put("retryType", retryType.name()); node.set("rsp", getRsp().toJson()); node.set("ssp", getSsp().toJson()); node.set("dsp", getDsp().toJson()); diff --git a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/ResetScenarioClassAction.java b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/ResetScenarioClassAction.java index 13548153..a6bb5f0a 100644 --- a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/ResetScenarioClassAction.java +++ b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/ResetScenarioClassAction.java @@ -35,11 +35,6 @@ public ObjectNode asJsonNode() { .put("transportDocumentReference", this.getSsp().transportDocumentReference()); } - @Override - public boolean isInputRequired() { - return true; - } - @Override public String getHumanReadablePrompt() { diff --git a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/ResignLatestEntryAction.java b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/ResignLatestEntryAction.java deleted file mode 100644 index 6b5b46c9..00000000 --- a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/ResignLatestEntryAction.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.dcsa.conformance.standards.eblinterop.action; - -import com.fasterxml.jackson.databind.node.ObjectNode; -import lombok.Getter; - -@Getter -public class ResignLatestEntryAction extends PintAction { - - public ResignLatestEntryAction( - String platformPartyName, - String carrierPartyName, - PintAction previousAction) { - super( - carrierPartyName, - platformPartyName, - previousAction, - "ResignLatestEntry", - -1); - } - - @Override - public ObjectNode asJsonNode() { - var node = super.asJsonNode(); - node.set("rsp", getRsp().toJson()); - node.set("ssp", getSsp().toJson()); - node.set("dsp", getDsp().toJson()); - return node; - } - - @Override - public boolean isInputRequired() { - return true; - } - - @Override - public String getHumanReadablePrompt() { - return ("Resign the latest endorsement chain entry"); - } - -} diff --git a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/RetryType.java b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/RetryType.java new file mode 100644 index 00000000..ee3efe78 --- /dev/null +++ b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/RetryType.java @@ -0,0 +1,7 @@ +package org.dcsa.conformance.standards.eblinterop.action; + +public enum RetryType { + NO_CHANGE, + RESIGN, + MANIPULATE, +} diff --git a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/SenderSupplyScenarioParametersAction.java b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/SenderSupplyScenarioParametersAction.java index de506c42..e8e8e2c3 100644 --- a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/SenderSupplyScenarioParametersAction.java +++ b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/action/SenderSupplyScenarioParametersAction.java @@ -50,7 +50,7 @@ public JsonNode getJsonForHumanReadablePrompt() { @Override public String getHumanReadablePrompt() { - return ("Scenario details"); + return ("Please provide these scenario details. Additional documents required: %d".formatted(documentCount)); } } diff --git a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/models/TDReceiveState.java b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/models/TDReceiveState.java index 26f1b884..6a6b00c8 100644 --- a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/models/TDReceiveState.java +++ b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/models/TDReceiveState.java @@ -140,6 +140,7 @@ public JsonNode generateSignedResponse(PintResponseCode responseCode, PayloadSig receivedDocuments.add(checksum); } } + default -> {/* nothing */} } var signedPayload = payloadSigner.sign(unsignedPayload.toString()); return TextNode.valueOf(signedPayload); diff --git a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/party/PintReceivingPlatform.java b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/party/PintReceivingPlatform.java index a3767481..df681a2c 100644 --- a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/party/PintReceivingPlatform.java +++ b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/party/PintReceivingPlatform.java @@ -111,10 +111,13 @@ private void initiateState(JsonNode actionPrompt) { ); tdState.setScenarioClass(scenarioClass); tdState.save(persistentMap); + var receivingParametersJson = receivingParameters.toJson(); + addOperatorLogEntry( + "Prompt answer for initiateState: %s".formatted(receivingParametersJson)); asyncOrchestratorPostPartyInput( - actionPrompt.required("actionId").asText(), receivingParameters.toJson()); + actionPrompt.required("actionId").asText(), receivingParametersJson); addOperatorLogEntry( - "Finished ScenarioType"); + "Finished ScenarioType setup"); } private JsonNode generateReceiverParty(SenderScenarioParameters ssp, ScenarioClass scenarioClass, String expectedRecipient) { diff --git a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/party/PintSendingPlatform.java b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/party/PintSendingPlatform.java index 690058cd..227d056b 100644 --- a/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/party/PintSendingPlatform.java +++ b/pint/src/main/java/org/dcsa/conformance/standards/eblinterop/party/PintSendingPlatform.java @@ -76,11 +76,9 @@ protected void doReset() {} protected Map, Consumer> getActionPromptHandlers() { return Map.ofEntries( Map.entry(SenderSupplyScenarioParametersAction.class, this::supplyScenarioParameters), - Map.entry(ResignLatestEntryAction.class, this::resignLatestEntry), Map.entry(PintInitiateAndCloseTransferAction.class, this::initiateTransferRequest), Map.entry(PintInitiateTransferAction.class, this::initiateTransferRequest), Map.entry(PintInitiateTransferUnsignedErrorAction.class, this::initiateTransferRequest), - Map.entry(ManipulateTransactionsAction.class, this::manipulateTransactions), Map.entry(PintTransferAdditionalDocumentAction.class, this::transferActionDocument), Map.entry(PintTransferAdditionalDocumentFailureAction.class, this::transferActionDocument), Map.entry(PintRetryTransferAction.class, this::retryTransfer), @@ -149,26 +147,11 @@ private void supplyScenarioParameters(JsonNode actionPrompt) { "BOLE", payloadSigner.getPublicKeyInPemFormat(), carrierPayloadSigner.getPublicKeyInPemFormat() - ); - asyncOrchestratorPostPartyInput( - actionPrompt.required("actionId").asText(), scenarioParameters.toJson()); + ).toJson(); addOperatorLogEntry( - "Provided ScenarioParameters: %s".formatted(scenarioParameters)); - } - - private void resignLatestEntry(JsonNode actionPrompt) { - log.info( - "EblInteropSendingPlatform.resignLatestEntry(%s)" - .formatted(actionPrompt.toPrettyString())); - var ssp = SenderScenarioParameters.fromJson(actionPrompt.required("ssp")); - var tdr = ssp.transportDocumentReference(); - var sendingState = TDSendingState.load(persistentMap, tdr); - sendingState.resignLatestEntry(payloadSigner); - sendingState.save(persistentMap); + "Prompt answer for supplyScenarioParameters: %s".formatted(scenarioParameters.toString())); asyncOrchestratorPostPartyInput( - actionPrompt.required("actionId").asText(), OBJECT_MAPPER.createObjectNode()); - addOperatorLogEntry( - "Resigned latest entry for document: %s".formatted(tdr)); + actionPrompt.required("actionId").asText(), scenarioParameters); } private void manipulateTransactions(JsonNode actionPrompt) { @@ -242,8 +225,15 @@ private void retryTransfer(JsonNode actionPrompt) { log.info("EblInteropSendingPlatform.retryTransfer(%s)".formatted(actionPrompt.toPrettyString())); var ssp = SenderScenarioParameters.fromJson(actionPrompt.required("ssp")); var tdr = ssp.transportDocumentReference(); + var retryType = RetryType.valueOf(actionPrompt.required("retryType").asText()); + var rsp = ReceiverScenarioParameters.fromJson(actionPrompt.required("rsp")); var sendingState = TDSendingState.load(persistentMap, tdr); + switch (retryType) { + case RESIGN -> sendingState.resignLatestEntry(payloadSigner); + case MANIPULATE -> sendingState.manipulateLatestTransaction(payloadSigner, rsp); + } + var body = OBJECT_MAPPER.createObjectNode(); var tdPayload = loadTDR(tdr); body.set("transportDocument", tdPayload); @@ -264,7 +254,7 @@ private void retryTransfer(JsonNode actionPrompt) { } sendingState.save(persistentMap); addOperatorLogEntry( - "Re-sent an eBL with transportDocumentReference '%s'".formatted(tdr)); + "Re-sent an eBL with transportDocumentReference '%s' with type: %s".formatted(tdr, retryType.name())); } private ObjectNode loadTDR(String tdr) { diff --git a/spring-boot/src/test/java/org/dcsa/conformance/manual/ManualScenarioTest.java b/spring-boot/src/test/java/org/dcsa/conformance/manual/ManualScenarioTest.java index e909422f..4e2bfff3 100644 --- a/spring-boot/src/test/java/org/dcsa/conformance/manual/ManualScenarioTest.java +++ b/spring-boot/src/test/java/org/dcsa/conformance/manual/ManualScenarioTest.java @@ -33,9 +33,8 @@ private static Stream testStandards() { Arguments.of("JIT", true), Arguments.of("OVS", false), Arguments.of("OVS", true), -// DT-1796, PINT issue: Unknown TD Reference: j5k./hY,wZNqNDSEmJ` -// Arguments.of("PINT", true), -// Arguments.of("PINT", false), + Arguments.of("PINT", false), + Arguments.of("PINT", true), Arguments.of("TnT", false), Arguments.of("TnT", true), Arguments.of("eBL Issuance", false), diff --git a/spring-boot/src/test/java/org/dcsa/conformance/manual/ManualTestBase.java b/spring-boot/src/test/java/org/dcsa/conformance/manual/ManualTestBase.java index 3b66e6d8..b5071b5b 100644 --- a/spring-boot/src/test/java/org/dcsa/conformance/manual/ManualTestBase.java +++ b/spring-boot/src/test/java/org/dcsa/conformance/manual/ManualTestBase.java @@ -11,6 +11,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import java.util.List; + +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.dcsa.conformance.core.party.HttpHeaderConfiguration; import org.dcsa.conformance.sandbox.ConformanceWebuiHandler; @@ -318,13 +320,19 @@ void runScenario( if (inputRequired) { JsonNode jsonForPrompt = jsonNode.get("jsonForPromptText"); String jsonForPromptText = jsonForPrompt.toString(); + var promptText = jsonNode.path("promptText").asText(""); assertTrue( - jsonForPromptText.length() >= 25, "Prompt text was:" + jsonForPromptText.length()); + jsonForPromptText.length() >= 25, "Json for prompt was length: " + jsonForPromptText.length()); String promptActionId = jsonNode.get("promptActionId").textValue(); // Special flow for: eBL TD-only UC6 in Carrier mode (DT-1681) if (jsonForPromptText.contains("Insert TDR here")) { jsonForPrompt = fetchTransportDocument(sandbox2, sandbox1); + // PINT flow + } else if (promptText.contains("Please provide these scenario details. Additional documents required:")) { + jsonForPrompt = fetchPromptAnswer(sandbox2, sandbox1, "supplyScenarioParameters"); + } else if (promptText.contains("Setup the system for transfer and provide the following details for the sender.")) { + jsonForPrompt = fetchPromptAnswer(sandbox2, sandbox1, "initiateState"); } handleActionInput(sandbox1, scenarioId, promptActionId, jsonForPrompt); @@ -344,6 +352,20 @@ void runScenario( validateSandboxScenarioGroup(sandbox1, scenarioId, scenarioName); } + @SneakyThrows + private JsonNode fetchPromptAnswer(SandboxConfig sandbox2, SandboxConfig sandbox1, String answerFor) { + notifyAction(sandbox2, sandbox1); + var prompt = "Prompt answer for %s:".formatted(answerFor); + + log.debug("Fetching prompt answer for {} from sandbox2", answerFor); + var logEntry = getSandbox(sandbox2).operatorLog.stream() + .filter(text -> text.startsWith(prompt)) + .findFirst() + .orElseThrow(() -> new IllegalStateException("No transport document found")); + var json = logEntry.substring(prompt.length() + 1); + return OBJECT_MAPPER.readTree(json); + } + private JsonNode fetchTransportDocument(SandboxConfig sandbox2, SandboxConfig sandbox1) { notifyAction(sandbox2, sandbox1);