in lib/apiScenario/postmanCollectionRunnerClient.ts [770:900]
private lroPoll(
itemGroup: ItemGroup<Item>,
item: Item,
step: StepRestCall | StepArmTemplate,
baseUri: string,
postScripts: string[]
) {
const finalStateVia =
step.type === "restCall"
? step?.operation?.[xmsLongRunningOperationOptions]?.[xmsLongRunningOperationOptionsField]
: undefined;
const isManagementPlane = step.type === "armTemplateDeployment" || step.isManagementPlane;
if (this.opts.skipLroPoll) return;
const url = item.request.url;
const urlStr = `${baseUri}${url.getPathWithQuery()}`;
// For ARM put or patch operations , by default the final get is original url.
const isArmResourceCreate =
isManagementPlane && ["put", "patch"].includes(item.request.method.toLowerCase());
postScripts.push(
`
// RPC-Async-V1-06 x-ms-long-running-operation-options should indicate the type of response header to track the async operation.
function getLroFinalGetUrl(finalStateVia) {
if (!finalStateVia) {
// by default, the final url header is Location for ARM, Operation-Location for dataplane.
return ${
isArmResourceCreate
? `'${urlStr}'`
: `pm.response.headers.get("Location") || pm.response.headers.get("Operation-Location")`
}
}
switch (finalStateVia) {
case "location": {
return pm.response.headers.get("Location");
}
case "azure-async-operation": {
return pm.response.headers.get("Azure-AsyncOperation");
}
case "original-uri": {
return "${urlStr}";
}
case "operation-location": {
return pm.response.headers.get("Operation-Location");
}
default:
return "";
}
}
function getProxyUrl(url) {
return "${this.opts.testProxy ?? ""}" ? url.replace("${baseUri}","${
this.opts.testProxy ?? ""
}") : url
}
const pollingUrl = pm.response.headers.get("Azure-AsyncOperation") || pm.response.headers.get("Location") || pm.response.headers.get("Operation-Location") || ${
isArmResourceCreate ? `'${urlStr}'` : "''"
}
if (pollingUrl) {
pm.variables.set("x_polling_url", getProxyUrl(pollingUrl));
pm.variables.set("x_final_get_url", getProxyUrl(getLroFinalGetUrl("${finalStateVia ?? ""}")))
pm.variables.set("x_retry_after", "3");
}`
);
const { item: delayItem } = this.addNewItem(
"Blank",
{
name: `_${item.name}_delay`,
request: {
url: "https://postman-echo.com/delay/{{x_retry_after}}",
method: "GET",
},
},
baseUri
);
const delayItemMetadata: DelayItemMetadata = {
type: "delay",
lro_item_name: item.name,
};
delayItem.description = JSON.stringify(delayItemMetadata);
itemGroup.items.add(delayItem);
const { item: pollerItem } = this.addNewItem(
"Blank",
{
name: `_${item.name}_poller`,
request: {
url: `{{x_polling_url}}`,
method: "GET",
},
},
baseUri
);
const pollerItemMetadata: PollerItemMetadata = {
type: "poller",
lro_item_name: item.name,
};
pollerItem.description = JSON.stringify(pollerItemMetadata);
const pollerPostScripts: string[] = [];
pollerPostScripts.push(
`
try {
if (pm.response.code === 202) {
postman.setNextRequest("${delayItem.name}");
if (pm.response.headers.has("Retry-After")) {
pm.variables.set("x_retry_after", pm.response.headers.get("Retry-After"));
}
} else if (pm.response.size().body > 0) {
const terminalStatus = ["succeeded", "failed", "canceled", "cancelled", "aborted", "deleted", "completed"];
const json = pm.response.json();
if (json.status !== undefined && terminalStatus.indexOf(json.status.toLowerCase()) === -1) {
postman.setNextRequest("${delayItem.name}")
if (pm.response.headers.has("Retry-After")) {
pm.variables.set("x_retry_after", pm.response.headers.get("Retry-After"));
}
}
}
} catch (err) {
console.error(err);
}
`
);
if (postScripts.length > 0) {
PostmanHelper.addEvent(pollerItem.events, "test", pollerPostScripts);
}
generatePostmanAssertion({ step, type: "lroPolling", item: pollerItem, opts: this.opts });
itemGroup.items.add(pollerItem);
}