Hooks
Advanced Example
ReṼoman isn’t limited to firing a collection — you can add more bells and whistles 🔔. This end-to-end example wires hooks, type-safe request/response config, dynamic variables, and execution control together:
final var pqRundown =
ReVoman.revUp( (1)
Kick.configure()
.templatePaths(PQ_TEMPLATE_PATHS) (2)
.environmentPath(PQ_ENV_PATH) (3)
.dynamicEnvironment( (4)
Map.of(
"$quoteFieldsToQuery", "LineItemCount, CalculationStatus",
"$qliFieldsToQuery", "Id, Product2Id",
"$qlrFieldsToQuery", "Id, QuoteId, MainQuoteLineId, AssociatedQuoteLineId"))
.customDynamicVariableGenerator( (5)
"$unitPrice",
(ignore1, ignore2, ignore3) -> String.valueOf(Random.Default.nextInt(999) + 1))
.nodeModulesPath("js") (6)
.haltOnFailureOfTypeExcept(
HTTP_STATUS, afterStepContainingHeader("ignoreHTTPStatusUnsuccessful")) (7)
.requestConfig( (8)
unmarshallRequest(
beforeStepContainingURIPathOfAny(PQ_URI_PATH),
PlaceQuoteInputRepresentation.class,
adapter(PlaceQuoteInputRepresentation.class)))
.responseConfig( (9)
unmarshallResponse(
afterStepContainingURIPathOfAny(PQ_URI_PATH),
PlaceQuoteOutputRepresentation.class),
unmarshallResponse(
afterStepContainingURIPathOfAny(COMPOSITE_GRAPH_URI_PATH),
CompositeGraphResponse.class,
CompositeGraphResponse.ADAPTER))
.hooks( (10)
pre(
beforeStepContainingURIPathOfAny(PQ_URI_PATH),
(step, requestInfo, rundown) -> {
if (requestInfo.containsHeader(IS_SYNC_HEADER)) {
LOGGER.info("This is a Sync step: {}", step);
}
}),
post(
afterStepContainingURIPathOfAny(PQ_URI_PATH),
(stepReport, ignore) -> validatePQResponse(stepReport)), (11)
post(
afterStepContainingURIPathOfAny(COMPOSITE_GRAPH_URI_PATH),
(stepReport, ignore) -> assertCompositeGraphResponseSuccess(stepReport)),
post(
afterStepName("query-quote-and-related-records"),
(ignore, rundown) -> assertAfterPQCreate(rundown.mutableEnv)))
.pollingConfig( (12)
poll((stepReport, rundown) ->
uriPathContains(stepReport.requestInfo, PQ_URI_PATH)
&& !containsHeader(stepReport.requestInfo, IS_SYNC_HEADER))
.request(
(stepReport, env) ->
Request.create(
Method.GET,
"%s/%s/sobjects/Quote/%s"
.formatted(
env.getAsString("baseUrl"),
env.getAsString("versionPath"),
env.getAsString("quoteId"))))
.every(Duration.ofSeconds(2))
.timeout(Duration.ofSeconds(30))
.until((response, env) -> response.bodyString().contains("Completed")))
.globalCustomTypeAdapter(IDAdapter.INSTANCE) (13)
.insecureHttp(true) (14)
.off()); // Kick-off
assertThat(pqRundown.firstUnIgnoredUnsuccessfulStepReport()).isNull(); (15)
assertThat(pqRundown.mutableEnv)
.containsAtLeastEntriesIn(
Map.of(
"quoteCalculationStatusForSkipPricing", PricingPref.Skip.completeStatus,
"quoteCalculationStatus", PricingPref.System.completeStatus,
"quoteCalculationStatusAfterAllUpdates", PricingPref.System.completeStatus));
| 1 | revUp() is the method to call passing a configuration, built as below |
| 2 | Supply the path (absolute or relative to resources) to the Template Collection JSON file/files |
| 3 | Supply the path (absolute or relative to resources) to the Environment JSON file/files |
| 4 | Supply any dynamic environment that is runtime-specific |
| 5 | Custom Dynamic variables |
| 6 | Node modules path (absolute or relative to project directory) to be used inside Pre-req and Post-res scripts |
| 7 | Execution Control |
| 8 | Request Config |
| 9 | Response Config |
| 10 | Dynamic Pre/Post-Step Hooks |
| 11 | Response Validations |
| 12 | Polling config for async steps |
| 13 | Global Custom Type Adapters |
| 14 | Ignore Java cert issues when firing HTTP calls. To be used only for local testing, like hitting localhost |
| 15 | Run more assertions on the Rundown |
Dynamic Pre-Step and Post-Step Hooks
A hook lets you fiddle with the execution by plugging in your custom JVM code before or after a Step execution.
You can pass a PreTxnStepPick/PostTxnStepPick which is a Predicate used to qualify a step for Pre-Step/Post-Step Hook respectively. The Predicate enables Dynamic hooks, which can fire for multiple qualified steps.
ReṼoman comes bundled with some predicates under PreTxnStepPick.PickUtils/PostTxnStepPick.PickUtils e.g. beforeStepContainingURIPathOfAny(), afterStepName() etc. If those don’t fit, write your own:
final var preTxnStepPick = (currentStep, requestInfo, rundown) -> LOGGER.info("Picked `preLogHook` before stepName: {}", currentStep)
final var postTxnStepPick = (stepReport, rundown) -> LOGGER.info("Picked `postLogHook` after stepName: {}", stepReport.step.displayName)
Add them to the config:
.hooks(
pre(
preTxnStepPick,
(currentStepName, requestInfo, rundown) -> {
//...code...
}),
post(
postTxnStepPick,
(currentStepName, rundown) -> {
//...code...
})
)
-
You can assert on the rundown, do Response Validations, or even mutate the environment with a programmatically derived value, so later steps pick up those changes.
-
Reserve hooks for plugging in custom code or asserting to fail-fast mid-execution. If your assertions can wait till the final rundown, it’s cleaner to write them after
revUp()returns the rundown.
Plug-in your Custom JVM code in-between executions
You can plug in custom JVM code to create/generate values for environment variables, populated and picked up by subsequent steps. For example, you may want some xyzId but you don’t have a collection step to create it — you have a Java utility instead. Invoke it in a pre-hook and set the value in rundown.mutableEnv, so later steps pick up {{xyzId}} from the environment.
When a Step qualifies for more than one hook, hooks execute in the same sequence they are configured (via hooks() or overrideHooks()). Both accept an iterable — pass an Ordered Iterable (like ArrayList) if order matters.
|
Response Validations
-
Post-Hooks are the best place to validate response right after the step.
-
If you configured a strong type via
responseConfig, write type-safe validations by extracting your type withstepReport.responseInfo.get().<TypeT>getTypedTxnObj()(ifresponseConfig()/globalCustomTypeAdapters()configured) orJsonPojoUtils.jsonToPojo(TypeT, stepReport.responseInfo.get().httpMsg.bodyString())inline. -
If your response is non-trivial and needs strategies like
fail-fastorerror-accumulation, consider a library like Vador (github.com/salesforce-misc/Vador).