diff --git a/src/coreClientLro.ts b/src/coreClientLro.ts new file mode 100644 index 0000000000..fe2981f5dd --- /dev/null +++ b/src/coreClientLro.ts @@ -0,0 +1,315 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + OperationArguments, + OperationSpec, + OperationResponseMap, + FullOperationResponse +} from "@azure/core-client"; +import { + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + createGetLroStatusFromResponse, + RawResponse +} from "./lro"; + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +export const terminalStates = successStates.concat(failureStates); + +export type SendOperationFn = ( + args: OperationArguments, + spec: OperationSpec +) => Promise>; + +export function createPollingMethod( + sendOperationFn: SendOperationFn, + GetLroStatusFromResponse: GetLroStatusFromResponse, + args: OperationArguments, + spec: OperationSpec, + mode?: LroMode +): (path?: string) => Promise> { + /** + * Polling calls will always return a status object i.e. {"status": "success"} + * these intermediate responses are not described in the swagger so we need to + * pass custom mappers at runtime. + * This function replaces all the existing mappers to be able to deserialize a status object + * @param responses Original set of responses defined in the operation + */ + function getCompositeMappers(responses: { + [responseCode: string]: OperationResponseMap; + }): { + [responseCode: string]: OperationResponseMap; + } { + return Object.keys(responses).reduce((acc, statusCode) => { + return { + ...acc, + [statusCode]: { + ...responses[statusCode], + bodyMapper: { + type: { + name: "Composite", + modelProperties: { + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } + } + } + }; + }, {} as { [responseCode: string]: OperationResponseMap }); + } + let response: LroStatus | undefined = undefined; + const customerCallback = args?.options?.onResponse; + const updatedArgs = { + ...args, + options: { + ...args.options, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ): void => { + response = GetLroStatusFromResponse( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse as TResult + ); + if (response.done) { + customerCallback?.(rawResponse, flatResponse); + } + } + } + }; + // Make sure we don't send any body to the get request + const { requestBody, responses, ...restSpec } = spec; + if (mode === "AzureAsync") { + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: getCompositeMappers(responses), + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; + } + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: responses, + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; +} + +/** + * We need to selectively deserialize our responses, only deserializing if we + * are in a final Lro response, not deserializing any polling non-terminal responses + */ +export function shouldDeserializeLro(lroResourceLocationConfig?: string) { + let initialOperationInfo: LroResponseInfo | undefined; + let isInitialRequest = true; + + return (response: FullOperationResponse) => { + if (response.status < 200 || response.status >= 300) { + return true; + } + + if (!initialOperationInfo) { + initialOperationInfo = getLroData(response); + } else { + isInitialRequest = false; + } + + if ( + initialOperationInfo.azureAsyncOperation || + initialOperationInfo.operationLocation + ) { + return ( + !isInitialRequest && + isAsyncOperationFinalResponse( + response, + initialOperationInfo, + lroResourceLocationConfig + ) + ); + } + + if (initialOperationInfo.location) { + return isLocationFinalResponse(response); + } + + if (initialOperationInfo.requestMethod === "PUT") { + return isBodyPollingFinalResponse(response); + } + + return true; + }; +} + +function isAsyncOperationFinalResponse( + response: FullOperationResponse, + initialOperationInfo: LroResponseInfo, + lroResourceLocationConfig?: string +): boolean { + const status: string = response.parsedBody?.status || "Succeeded"; + if (!terminalStates.includes(status.toLowerCase())) { + return false; + } + + if (initialOperationInfo.requestMethod === "DELETE") { + return true; + } + + if ( + initialOperationInfo.requestMethod === "PUT" && + lroResourceLocationConfig && + lroResourceLocationConfig.toLowerCase() === "azure-asyncoperation" + ) { + return true; + } + + if ( + initialOperationInfo.requestMethod !== "PUT" && + !initialOperationInfo.location + ) { + return true; + } + + return false; +} + +function isLocationFinalResponse(response: FullOperationResponse): boolean { + return response.status !== 202; +} + +function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { + const provisioningState: string = + response.parsedBody?.properties?.provisioningState || "Succeeded"; + + if (terminalStates.includes(provisioningState.toLowerCase())) { + return true; + } + + return false; +} + +interface LroResponseInfo { + requestMethod: string; + azureAsyncOperation?: string; + operationLocation?: string; + location?: string; +} + +function getLroData(result: FullOperationResponse): LroResponseInfo { + return { + azureAsyncOperation: result.headers.get("azure-asyncoperation"), + operationLocation: result.headers.get("operation-location"), + location: result.headers.get("location"), + requestMethod: result.request.method + }; +} + +export function getSpecPath(spec: OperationSpec): string { + if (spec.path) { + return spec.path; + } else { + throw Error("Bad spec: request path is not found!"); + } +} + +export class CoreClientLro implements LongRunningOperation { + constructor( + private sendOperationFn: SendOperationFn, + private args: OperationArguments, + private spec: OperationSpec, + private lroResourceLocationConfig?: LroResourceLocationConfig, + public requestPath: string = spec.path!, + public requestMethod: string = spec.httpMethod + ) {} + public async sendInitialRequest( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ): Promise> { + const { onResponse, ...restOptions } = this.args.options || {}; + return this.sendOperationFn( + { + ...this.args, + options: { + ...restOptions, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ) => { + const isCompleted = initializeState( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse + ); + if (isCompleted) { + onResponse?.(rawResponse, flatResponse); + } + } + } + }, + this.spec + ); + } + + public async sendPollRequest( + config: LroConfig, + path: string + ): Promise> { + const getLroStatusFromResponse = createGetLroStatusFromResponse( + this, + config, + this.lroResourceLocationConfig + ); + return createPollingMethod( + this.sendOperationFn, + getLroStatusFromResponse, + this.args, + this.spec, + config.mode + )(path); + } + + public async retrieveAzureAsyncResource( + path?: string + ): Promise> { + const updatedArgs = { ...this.args }; + if (updatedArgs.options) { + (updatedArgs.options as any).shouldDeserialize = true; + } + return createPollingMethod( + this.sendOperationFn, + (rawResponse, flatResponse) => ({ + rawResponse, + flatResponse, + done: true + }), + updatedArgs, + this.spec + )(path); + } +} diff --git a/src/coreHttpLro.ts b/src/coreHttpLro.ts new file mode 100644 index 0000000000..5cc0d5ed2a --- /dev/null +++ b/src/coreHttpLro.ts @@ -0,0 +1,268 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + HttpOperationResponse, + OperationArguments, + OperationResponse, + OperationSpec +} from "@azure/core-http"; +import { + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + createGetLroStatusFromResponse, + RawResponse +} from "./lro"; + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +export const terminalStates = successStates.concat(failureStates); + +export type SendOperationFn = ( + args: OperationArguments, + spec: OperationSpec +) => Promise>; + +export function createPollingMethod( + sendOperationFn: SendOperationFn, + getLroStatusFromResponse: GetLroStatusFromResponse, + args: OperationArguments, + spec: OperationSpec, + mode?: LroMode +): (path?: string) => Promise> { + /** + * Polling calls will always return a status object i.e. {"status": "success"} + * these intermediate responses are not described in the swagger so we need to + * pass custom mappers at runtime. + * This function replaces all the existing mappers to be able to deserialize a status object + * @param responses Original set of responses defined in the operation + */ + function getCompositeMappers(responses: { + [responseCode: string]: OperationResponse; + }): { + [responseCode: string]: OperationResponse; + } { + return Object.keys(responses).reduce((acc, statusCode) => { + return { + ...acc, + [statusCode]: { + ...responses[statusCode], + bodyMapper: { + type: { + name: "Composite", + modelProperties: { + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } + } + } + }; + }, {} as { [responseCode: string]: OperationResponse }); + } + // Make sure we don't send any body to the get request + const { requestBody, responses, ...restSpec } = spec; + if (mode === "AzureAsync") { + return async (path?: string) => { + const { flatResponse, rawResponse } = await sendOperationFn(args, { + ...restSpec, + responses: getCompositeMappers(responses), + httpMethod: "GET", + ...(path && { path }) + }); + return getLroStatusFromResponse(rawResponse, flatResponse as TResult); + }; + } + return async (path?: string) => { + const { flatResponse, rawResponse } = await sendOperationFn(args, { + ...restSpec, + responses: responses, + httpMethod: "GET", + ...(path && { path }) + }); + return getLroStatusFromResponse(rawResponse, flatResponse as TResult); + }; +} + +/** + * We need to selectively deserialize our responses, only deserializing if we + * are in a final Lro response, not deserializing any polling non-terminal responses + */ +export function shouldDeserializeLro(lroResourceLocationConfig?: string) { + let initialOperationInfo: LroResponseInfo | undefined; + let isInitialRequest = true; + + return (response: HttpOperationResponse) => { + if (response.status < 200 || response.status >= 300) { + return true; + } + + if (!initialOperationInfo) { + initialOperationInfo = getLroData(response); + } else { + isInitialRequest = false; + } + + if ( + initialOperationInfo.azureAsyncOperation || + initialOperationInfo.operationLocation + ) { + return ( + !isInitialRequest && + isAsyncOperationFinalResponse( + response, + initialOperationInfo, + lroResourceLocationConfig + ) + ); + } + + if (initialOperationInfo.location) { + return isLocationFinalResponse(response); + } + + if (initialOperationInfo.requestMethod === "PUT") { + return isBodyPollingFinalResponse(response); + } + + return true; + }; +} + +function isAsyncOperationFinalResponse( + response: HttpOperationResponse, + initialOperationInfo: LroResponseInfo, + lroResourceLocationConfig?: string +): boolean { + const status: string = response.parsedBody?.status || "Succeeded"; + if (!terminalStates.includes(status.toLowerCase())) { + return false; + } + + if (initialOperationInfo.requestMethod === "DELETE") { + return true; + } + + if ( + initialOperationInfo.requestMethod === "PUT" && + lroResourceLocationConfig && + lroResourceLocationConfig.toLowerCase() === "azure-asyncoperation" + ) { + return true; + } + + if ( + initialOperationInfo.requestMethod !== "PUT" && + !initialOperationInfo.location + ) { + return true; + } + + return false; +} + +function isLocationFinalResponse(response: HttpOperationResponse): boolean { + return response.status !== 202; +} + +function isBodyPollingFinalResponse(response: HttpOperationResponse): boolean { + const provisioningState: string = + response.parsedBody?.properties?.provisioningState || "Succeeded"; + + if (terminalStates.includes(provisioningState.toLowerCase())) { + return true; + } + + return false; +} + +interface LroResponseInfo { + requestMethod: string; + azureAsyncOperation?: string; + operationLocation?: string; + location?: string; +} + +function getLroData(result: HttpOperationResponse): LroResponseInfo { + return { + azureAsyncOperation: result.headers.get("azure-asyncoperation"), + operationLocation: result.headers.get("operation-location"), + location: result.headers.get("location"), + requestMethod: result.request.method + }; +} + +export function getSpecPath(spec: OperationSpec): string { + if (spec.path) { + return spec.path; + } else { + throw Error("Bad spec: request path is not found!"); + } +} + +export class CoreHttpLro implements LongRunningOperation { + constructor( + private sendOperationFn: SendOperationFn, + private args: OperationArguments, + private spec: OperationSpec, + private lroResourceLocationConfig?: LroResourceLocationConfig, + public requestPath: string = spec.path!, + public requestMethod: string = spec.httpMethod + ) {} + public async sendInitialRequest( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ): Promise> { + const response = await this.sendOperationFn(this.args, this.spec); + initializeState(response.rawResponse, response.flatResponse); + return response; + } + + public async sendPollRequest( + config: LroConfig, + path: string + ): Promise> { + const getLroStatusFromResponse = createGetLroStatusFromResponse( + this, + config, + this.lroResourceLocationConfig + ); + return createPollingMethod( + this.sendOperationFn, + getLroStatusFromResponse, + this.args, + this.spec, + config.mode + )(path); + } + + public async retrieveAzureAsyncResource( + path?: string + ): Promise> { + const updatedArgs = { ...this.args }; + if (updatedArgs.options) { + (updatedArgs.options as any).shouldDeserialize = true; + } + return createPollingMethod( + this.sendOperationFn, + (rawResponse, flatResponse) => ({ + rawResponse, + flatResponse, + done: true + }), + updatedArgs, + this.spec + )(path); + } +} diff --git a/src/generators/LROGenerator.ts b/src/generators/LROGenerator.ts index ede9934d8d..89b7a56cc6 100644 --- a/src/generators/LROGenerator.ts +++ b/src/generators/LROGenerator.ts @@ -5,16 +5,18 @@ import { promises } from "fs"; import { join as joinPath } from "path"; import { getAutorestOptions } from "../autorestSession"; -export async function generateLROFiles( +export async function generateLroFiles( clientDetails: ClientDetails, project: Project ) { - const { srcPath } = getAutorestOptions(); - if (!hasAnyLRO(clientDetails.operationGroups)) { + const { srcPath, useCoreV2 } = getAutorestOptions(); + if (!hasAnyLro(clientDetails.operationGroups)) { return; } - - const lroDir = joinPath(__dirname, "..", "..", "..", "src", "lro"); + const LroClassFile = useCoreV2 ? "coreClientLro.ts" : "coreHttpLro.ts"; + const baseTargetPath = srcPath || ""; + const srcDir = joinPath(__dirname, "..", "..", "..", "src"); + const lroDir = joinPath(srcDir, "lro"); const lroFiles = await promises.readdir(lroDir); for (let i = 0; i < lroFiles.length; i++) { @@ -23,13 +25,24 @@ export async function generateLROFiles( const fileContent = await promises.readFile(filePath, "utf-8"); project.createSourceFile( - joinPath(srcPath || "", "lro", file), + joinPath(baseTargetPath, "lro", file), fileContent, { overwrite: true } ); } + const fileContent = await promises.readFile( + joinPath(srcDir, LroClassFile), + "utf-8" + ); + project.createSourceFile( + joinPath(baseTargetPath, LroClassFile), + fileContent, + { + overwrite: true + } + ); } -function hasAnyLRO(operationGroups: OperationGroupDetails[]) { - return operationGroups.some(og => og.operations.some(o => o.isLRO)); +function hasAnyLro(operationGroups: OperationGroupDetails[]) { + return operationGroups.some(og => og.operations.some(o => o.isLro)); } diff --git a/src/generators/clientContextFileGenerator.ts b/src/generators/clientContextFileGenerator.ts index 7b7fb8830d..50829d96b9 100644 --- a/src/generators/clientContextFileGenerator.ts +++ b/src/generators/clientContextFileGenerator.ts @@ -35,8 +35,8 @@ export function generateClientContext( param => param.implementationLocation === ImplementationLocation.Client ); - const hasLRO = clientDetails.operationGroups.some(og => - og.operations.some(o => o.isLRO) + const hasLro = clientDetails.operationGroups.some(og => + og.operations.some(o => o.isLro) ); const clientContextClassName = `${clientDetails.className}Context`; @@ -82,11 +82,11 @@ export function generateClientContext( clientParams, clientDetails }, - hasLRO + hasLro ); const hasCredentials = !!addCredentials; - writeImports(sourceFile, hasLRO, importedModels, hasCredentials); + writeImports(sourceFile, hasLro, importedModels, hasCredentials); sourceFile.fixUnusedIdentifiers(); } @@ -97,7 +97,7 @@ interface WriteConstructorBodyParameters { function writeImports( sourceFile: SourceFile, - hasLRO: boolean, + hasLro: boolean, importedModels: Set, hasCredentials: boolean ) { @@ -163,7 +163,7 @@ function writeClassProperties( function writeConstructorBody( classConstructor: ConstructorDeclaration, { clientParams, clientDetails }: WriteConstructorBodyParameters, - hasLRO: boolean + hasLro: boolean ) { const { useCoreV2 } = getAutorestOptions(); @@ -176,7 +176,7 @@ function writeConstructorBody( writeStatement( writeDefaultOptions( clientParams.some(p => p.name === "credentials"), - hasLRO, + hasLro, clientDetails ) ) @@ -225,7 +225,7 @@ function getCredentialScopesValue(credentialScopes?: string | string[]) { function writeDefaultOptions( hasCredentials: boolean, - hasLRO: boolean, + hasLro: boolean, clientDetails: ClientDetails ) { const { useCoreV2, credentialScopes, packageDetails } = getAutorestOptions(); diff --git a/src/generators/clientFileGenerator.ts b/src/generators/clientFileGenerator.ts index 2a760a56ea..cc3b2db2f8 100644 --- a/src/generators/clientFileGenerator.ts +++ b/src/generators/clientFileGenerator.ts @@ -108,17 +108,28 @@ export function generateClient(clientDetails: ClientDetails, project: Project) { addPagingEsNextRef(flattenedInlineOperations, clientFile); addPagingImports(flattenedInlineOperations, clientFile); - const hasLRO = inlineOperations.some(og => og.operations.some(o => o.isLRO)); + const hasLro = inlineOperations.some(og => og.operations.some(o => o.isLro)); - if (hasInlineOperations && hasLRO) { - clientFile.addImportDeclaration({ - namedImports: ["LROPoller", "shouldDeserializeLRO"], - moduleSpecifier: "./lro" - }); + if (hasInlineOperations && hasLro) { clientFile.addImportDeclaration({ namedImports: ["PollerLike", "PollOperationState"], moduleSpecifier: "@azure/core-lro" }); + clientFile.addImportDeclaration({ + namedImports: ["LroEngine"], + moduleSpecifier: `./lro` + }); + if (useCoreV2) { + clientFile.addImportDeclaration({ + namedImports: ["CoreClientLro", "shouldDeserializeLro"], + moduleSpecifier: `./coreClientLro` + }); + } else { + clientFile.addImportDeclaration({ + namedImports: ["CoreHttpLro", "shouldDeserializeLro"], + moduleSpecifier: `./coreHttpLro` + }); + } } if (hasImportedOperations) { @@ -191,7 +202,7 @@ export function generateClient(clientDetails: ClientDetails, project: Project) { clientFile, clientClass, clientDetails, - hasLRO, + hasLro, importedModels ); @@ -319,7 +330,7 @@ function writeClientOperations( file: SourceFile, classDeclaration: ClassDeclaration, clientDetails: ClientDetails, - hasLRO: boolean, + hasLro: boolean, importedModels: Set ) { const allModelsNames = getAllModelsNames(clientDetails); @@ -327,7 +338,7 @@ function writeClientOperations( const hasMappers = !!clientDetails.mappers.length; // Add top level operation groups as client properties if (!!topLevelGroup) { - if (hasLRO) { + if (hasLro) { writeGetOperationOptions(classDeclaration); } writeOperations( diff --git a/src/generators/modelsGenerator.ts b/src/generators/modelsGenerator.ts index 87c1df8a67..7ab1828266 100644 --- a/src/generators/modelsGenerator.ts +++ b/src/generators/modelsGenerator.ts @@ -143,7 +143,7 @@ function writeOptionsParameter( { mediaTypes: operationRequestMediaTypes, operationFullName: operation.fullName, - operationIsLro: operation.isLRO + operationIsLro: operation.isLro } ); } @@ -153,7 +153,7 @@ function writeOptionsParameter( * the response body and headers */ function writeResponseTypes( - { responses, name, typeDetails: operationType, isLRO }: OperationDetails, + { responses, name, typeDetails: operationType, isLro }: OperationDetails, modelsIndexFile: SourceFile, allModelsNames: Set ) { @@ -181,7 +181,7 @@ function writeResponseTypes( name: responseName, docs: [`Contains response data for the ${name} operation.`], isExported: true, - type: buildResponseType(operation, isLRO), + type: buildResponseType(operation, isLro), leadingTrivia: writer => writer.blankLine(), kind: StructureKind.TypeAlias }); diff --git a/src/generators/operationGenerator.ts b/src/generators/operationGenerator.ts index b860fd1ecf..9330f5fcd9 100644 --- a/src/generators/operationGenerator.ts +++ b/src/generators/operationGenerator.ts @@ -134,7 +134,11 @@ export function writeGetOperationOptions( : "getOperationOptions", parameters: [ { name: "options", type: "TOptions | undefined" }, - { name: "finalStateVia", type: "string", hasQuestionToken: true } + { + name: "lroResourceLocationConfig", + type: "string", + hasQuestionToken: true + } ], returnType: !useCoreV2 ? `coreHttp.RequestOptionsBase` @@ -144,7 +148,7 @@ export function writeGetOperationOptions( const operationOptions: coreHttp.OperationOptions = options || {}; operationOptions.requestOptions = { ...operationOptions.requestOptions, - shouldDeserialize: shouldDeserializeLRO(finalStateVia), + shouldDeserialize: shouldDeserializeLro(lroResourceLocationConfig), }; return coreHttp.operationOptionsToRequestOptionsBase(operationOptions); ` @@ -152,7 +156,7 @@ export function writeGetOperationOptions( const operationOptions: coreClient.OperationOptions = options || {}; operationOptions.requestOptions = { ...operationOptions.requestOptions, - shouldDeserialize: shouldDeserializeLRO(finalStateVia), + shouldDeserialize: shouldDeserializeLro(lroResourceLocationConfig), }; return operationOptions;` }); @@ -447,7 +451,7 @@ function getReturnType( modelNames ); - return operation.isLRO + return operation.isLro ? `Promise,${responseName}>>` : `Promise<${responseName}>`; } @@ -506,7 +510,7 @@ function addClass( false /** isInline */ ); - if (hasLROOperation(operationGroupDetails)) { + if (hasLroOperation(operationGroupDetails)) { writeGetOperationOptions(operationGroupClass); } @@ -579,7 +583,7 @@ export function writeOperations( docs: [ generateOperationJSDoc(baseMethodParameters, operation.description) ], - isAsync: operation.isLRO || Boolean(tracingInfo) + isAsync: operation.isLro || Boolean(tracingInfo) }); addOperationOverloads( @@ -601,7 +605,7 @@ export function writeOperations( /** * Create a simple method that blocks and waits for the result */ - if (operation.isLRO && operation.pagination === undefined) { + if (operation.isLro && operation.pagination === undefined) { const responseName = getOperationResponseType( operation, importedModels, @@ -734,18 +738,22 @@ function addOperationOverloads( /** * Convert OperationOptions to RequestBaseOptions * @param options the name of the options parameter. - * @param isLRO whether the operation is an LRO. + * @param isLro whether the operation is an Lro. */ function compileOperationOptionsToRequestOptionsBase( options: string, - isLRO: boolean, - finalStateVia: string + isLro: boolean, + lroResourceLocationConfig?: string ): string { const { useCoreV2 } = getAutorestOptions(); - // In LRO we have a couple extra properties to add that's why we use + // In Lro we have a couple extra properties to add that's why we use // the private getOperationOptions function instead of the one in core-http - return isLRO - ? `this.getOperationOptions(${options}, "${finalStateVia}")` + return isLro + ? `this.getOperationOptions(${options}${ + lroResourceLocationConfig === undefined + ? "" + : `, "${lroResourceLocationConfig}"` + })` : !useCoreV2 ? `coreHttp.operationOptionsToRequestOptionsBase(options || {})` : `options || {}`; @@ -760,7 +768,7 @@ function writeNoOverloadsOperationBody( isInline: boolean ): void { const { useCoreV2, tracingInfo } = getAutorestOptions(); - const finalStateVia = + const lroResourceLocationConfig = operation.lroOptions && operation.lroOptions["final-state-via"]; const operationSpecName = `${operation.name}OperationSpec`; @@ -782,14 +790,14 @@ function writeNoOverloadsOperationBody( // Options from createSpan should be used as operation options, updating options = compileOperationOptionsToRequestOptionsBase( updatedOptionsName, - operation.isLRO, - finalStateVia + operation.isLro, + lroResourceLocationConfig ); } else { options = compileOperationOptionsToRequestOptionsBase( vanillaOptionsName, - operation.isLRO, - finalStateVia + operation.isLro, + lroResourceLocationConfig ); } @@ -810,24 +818,24 @@ function writeNoOverloadsOperationBody( ); } - if (operation.isLRO) { + if (operation.isLro) { if (!useCoreV2) { - writeLROOperationBody( + writeLroOperationBody( "operationArguments", responseName, operationSpecName, operationMethod, - finalStateVia, + lroResourceLocationConfig, isInline, !!tracingInfo ); } else { - writeLROOperationBody( + writeLroOperationBody( `{${sendParams}}`, responseName, operationSpecName, operationMethod, - finalStateVia, + lroResourceLocationConfig, isInline, !!tracingInfo ); @@ -917,12 +925,12 @@ function getTracingTryCatchStatement( } } -function writeLROOperationBody( +function writeLroOperationBody( operationParamsName: string, responseName: string, operationSpecName: string, methodDeclaration: MethodDeclaration, - finalStateVia?: string, + lroResourceLocationConfig?: string, isInline?: boolean, isTracingEnabled = false ) { @@ -930,15 +938,25 @@ function writeLROOperationBody( const client = isInline ? "" : ".client"; const sendRequestStatement = `this${client}.sendOperationRequest(args, spec)`; - const finalStateStr = finalStateVia ? `"${finalStateVia.toLowerCase()}"` : ""; - let sendOperationStatement = !useCoreV2 - ? `const sendOperation = async (args: coreHttp.OperationArguments, spec: coreHttp.OperationSpec) => { - ${getTracingTryCatchStatement( - sendRequestStatement, - responseName, - isTracingEnabled - )} - }` + const finalStateStr = lroResourceLocationConfig + ? `"${lroResourceLocationConfig.toLowerCase()}"` + : ""; + const sendOperationStatement = !useCoreV2 + ? `const directSendOperation = async (args: coreHttp.OperationArguments, spec: coreHttp.OperationSpec): Promise<${responseName}> => { + ${getTracingTryCatchStatement( + sendRequestStatement, + responseName, + isTracingEnabled + )} + }; + const sendOperation = async (args: coreHttp.OperationArguments, spec: coreHttp.OperationSpec) => { + const response = await directSendOperation(args, spec); + return { flatResponse:response, rawResponse: { + statusCode: response._response.status, + body: (response._response as any)?.parsedBody ?? {}, + headers: response._response.headers.rawHeaders() + }}; + }` : `const directSendOperation = async (args: coreClient.OperationArguments, spec: coreClient.OperationSpec): Promise<${responseName}> => { ${getTracingTryCatchStatement( sendRequestStatement, @@ -963,17 +981,18 @@ function writeLROOperationBody( } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { flatResponse, rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + }}; }`; - + const LroClassName = useCoreV2 ? "CoreClientLro" : "CoreHttpLro"; methodDeclaration.addStatements([ sendOperationStatement, - `return new LROPoller({intervalInMs: options?.updateIntervalInMs}, - ${operationParamsName}, - ${operationSpecName}, - sendOperation, - ${finalStateStr} - );` + `const lro = new ${LroClassName}(sendOperation,${operationParamsName}, + ${operationSpecName},${finalStateStr})`, + `return new LroEngine(lro,{intervalInMs: options?.updateIntervalInMs});` ]); methodDeclaration.setReturnType( @@ -1074,7 +1093,7 @@ function writeMultiMediaTypeOperationBody( }` ]); - const finalStateVia = + const lroResourceLocationConfig = operation.lroOptions && operation.lroOptions["final-state-via"]; if (tracingInfo) { @@ -1087,21 +1106,21 @@ function writeMultiMediaTypeOperationBody( tracingStatement, `operationArguments.options = ${compileOperationOptionsToRequestOptionsBase( outputOptionsVarName, - operation.isLRO, - finalStateVia + operation.isLro, + lroResourceLocationConfig )};` ]); } else { operationMethod.addStatements([ `operationArguments.options = ${compileOperationOptionsToRequestOptionsBase( optionsVarName, - operation.isLRO, - finalStateVia + operation.isLro, + lroResourceLocationConfig )};` ]); } - if (!operation.isLRO) { + if (!operation.isLro) { writeSendOperationRequest( responseName, operationMethod, @@ -1111,12 +1130,12 @@ function writeMultiMediaTypeOperationBody( "operationArguments" ); } else { - writeLROOperationBody( + writeLroOperationBody( "operationArguments", responseName, "operationSpec", operationMethod, - finalStateVia, + lroResourceLocationConfig, isInline, !!tracingInfo ); @@ -1321,18 +1340,29 @@ function addImports( moduleSpecifier: `../${clientContextFileName}` }); - if (hasLROOperation(operationGroupDetails)) { - operationGroupFile.addImportDeclaration({ - namedImports: ["LROPoller", "shouldDeserializeLRO"], - moduleSpecifier: `../lro` - }); + if (hasLroOperation(operationGroupDetails)) { operationGroupFile.addImportDeclaration({ namedImports: ["PollerLike", "PollOperationState"], moduleSpecifier: "@azure/core-lro" }); + operationGroupFile.addImportDeclaration({ + namedImports: ["LroEngine"], + moduleSpecifier: `../lro` + }); + if (useCoreV2) { + operationGroupFile.addImportDeclaration({ + namedImports: ["CoreClientLro", "shouldDeserializeLro"], + moduleSpecifier: `../coreClientLro` + }); + } else { + operationGroupFile.addImportDeclaration({ + namedImports: ["CoreHttpLro", "shouldDeserializeLro"], + moduleSpecifier: `../coreHttpLro` + }); + } } } -export function hasLROOperation(operationGroupDetails: OperationGroupDetails) { - return operationGroupDetails.operations.some(o => o.isLRO); +export function hasLroOperation(operationGroupDetails: OperationGroupDetails) { + return operationGroupDetails.operations.some(o => o.isLro); } diff --git a/src/generators/operationInterfaceGenerator.ts b/src/generators/operationInterfaceGenerator.ts index cb72e52025..2daad1e60c 100644 --- a/src/generators/operationInterfaceGenerator.ts +++ b/src/generators/operationInterfaceGenerator.ts @@ -112,7 +112,7 @@ function getReturnType( modelNames ); - return operation.isLRO + return operation.isLro ? `Promise,${responseName}>>` : `Promise<${responseName}>`; } @@ -208,7 +208,7 @@ export function writeOperations( /** * Create a simple method that blocks and waits for the result */ - if (operation.isLRO && operation.pagination === undefined) { + if (operation.isLro && operation.pagination === undefined) { const responseName = getOperationResponseType( operation, importedModels, @@ -257,7 +257,7 @@ function addImports( }); } - if (hasLROOperation(operationGroupDetails)) { + if (hasLroOperation(operationGroupDetails)) { operationGroupFile.addImportDeclaration({ namedImports: ["PollerLike", "PollOperationState"], moduleSpecifier: "@azure/core-lro" @@ -265,6 +265,6 @@ function addImports( } } -function hasLROOperation(operationGroupDetails: OperationGroupDetails) { - return operationGroupDetails.operations.some(o => o.isLRO); +function hasLroOperation(operationGroupDetails: OperationGroupDetails) { + return operationGroupDetails.operations.some(o => o.isLro); } diff --git a/src/generators/static/packageFileGenerator.ts b/src/generators/static/packageFileGenerator.ts index 1218bc6bec..a8f83bade2 100644 --- a/src/generators/static/packageFileGenerator.ts +++ b/src/generators/static/packageFileGenerator.ts @@ -122,8 +122,8 @@ function regularAutorestPackage( azureArm, addCredentials } = getAutorestOptions(); - const hasLRO = clientDetails.operationGroups.some(og => - og.operations.some(o => o.isLRO) + const hasLro = clientDetails.operationGroups.some(og => + og.operations.some(o => o.isLro) ); const hasAsyncIterators = !disablePagingAsyncIterators && clientDetails.options.hasPaging; @@ -140,8 +140,8 @@ function regularAutorestPackage( node: ">=12.0.0" }, dependencies: { - ...(hasLRO && { "@azure/core-lro": "^1.0.5" }), - ...(hasLRO && { "@azure/abort-controller": "^1.0.0" }), + ...(hasLro && { "@azure/core-lro": "^1.0.5" }), + ...(hasLro && { "@azure/abort-controller": "^1.0.0" }), ...(hasAsyncIterators && { "@azure/core-paging": "^1.1.1" }), ...(!useCoreV2 && { "@azure/core-http": "^1.2.4" }), ...(useCoreV2 && { "@azure/core-client": "^1.1.2" }), diff --git a/src/generators/utils/operationsUtils.ts b/src/generators/utils/operationsUtils.ts index 6ca4bd9e15..8b86bd4012 100644 --- a/src/generators/utils/operationsUtils.ts +++ b/src/generators/utils/operationsUtils.ts @@ -7,7 +7,7 @@ export function calculateMethodName(operation: OperationDetails): string { NameType.Property )}`; const firstLetter = name.substr(0, 1)[0].toUpperCase(); - return operation.isLRO && operation.pagination === undefined + return operation.isLro && operation.pagination === undefined ? `begin${firstLetter}${name.substr(1)}` : name; } diff --git a/src/generators/utils/pagingOperations.ts b/src/generators/utils/pagingOperations.ts index b630d1fb31..cf39f04e2a 100644 --- a/src/generators/utils/pagingOperations.ts +++ b/src/generators/utils/pagingOperations.ts @@ -240,7 +240,7 @@ function getPublicMethodName(operation: OperationDetails) { } else { initialOperationName = normalizeName(initialOperationName, NameType.Class); } - return operation.isLRO + return operation.isLro ? `beginList${initialOperationName}AndWait` : `list${initialOperationName}`; } @@ -358,8 +358,8 @@ function writePageMethod( `let result = await this.${pagingMethodSettings.initialMethod.name}(${initialMethodParameters});` ]; - if (operation.isLRO) { - // Since this is also an LRO operation, we need to poll until done to get the result + if (operation.isLro) { + // Since this is also an Lro operation, we need to poll until done to get the result firstRequestStatements = [ `const poller = await this.${pagingMethodSettings.initialMethod.name}(${initialMethodParameters});`, `let result: any = await poller.pollUntilDone();` diff --git a/src/lro/azureAsyncPolling.ts b/src/lro/azureAsyncPolling.ts index 42f435ed18..0d114756b8 100644 --- a/src/lro/azureAsyncPolling.ts +++ b/src/lro/azureAsyncPolling.ts @@ -1,37 +1,53 @@ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { FinalStateVia, LROResult } from "./models"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroResourceLocationConfig, + LongRunningOperation, + LroBody, + LroResponse, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getResponseStatus(rawResponse: FullOperationResponse): string { - const { status } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getResponseStatus(rawResponse: RawResponse): string { + const { status } = (rawResponse.body as LroBody) ?? {}; return status?.toLowerCase() ?? "succeeded"; } -function isAzureAsyncPollingDone(rawResponse: FullOperationResponse) { +function isAzureAsyncPollingDone(rawResponse: RawResponse): boolean { const state = getResponseStatus(rawResponse); - if (failureStates.includes(state)) { + if (isUnexpectedPollingResponse(rawResponse) || failureStates.includes(state)) { throw new Error(`Operation status: ${state}`); } return successStates.includes(state); } +async function sendFinalRequest( + lro: LongRunningOperation, + lroResourceLocationConfig?: LroResourceLocationConfig, + resourceLocation?: string +): Promise | undefined> { + switch (lroResourceLocationConfig) { + case "original-uri": + return lro.retrieveAzureAsyncResource(); + case "azure-async-operation": + return Promise.resolve(undefined); + case "location": + default: + return lro.retrieveAzureAsyncResource(resourceLocation); + } +} + export function processAzureAsyncOperationResult( - restrieveResource: (path?: string) => Promise>, + lro: LongRunningOperation, resourceLocation?: string, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { - return ( - rawResponse: FullOperationResponse, - flatResponse: TResult - ): LROState => { + lroResourceLocationConfig?: LroResourceLocationConfig +): (rawResponse: RawResponse, flatResponse: TResult) => LroStatus { + return (rawResponse: RawResponse, flatResponse: TResult): LroStatus => { if (isAzureAsyncPollingDone(rawResponse)) { if (resourceLocation === undefined) { return { rawResponse, flatResponse, done: true }; @@ -41,20 +57,11 @@ export function processAzureAsyncOperationResult( flatResponse, done: false, next: async () => { - async function sendFinalRequest(): Promise< - LROResult | undefined - > { - switch (finalStateVia) { - case "original-uri": - return restrieveResource(); - case "azure-async-operation": - return Promise.resolve(undefined); - case "location": - default: - return restrieveResource(resourceLocation); - } - } - const finalResponse = await sendFinalRequest(); + const finalResponse = await sendFinalRequest( + lro, + lroResourceLocationConfig, + resourceLocation + ); return { ...(finalResponse ?? { rawResponse, diff --git a/src/lro/bodyPolling.ts b/src/lro/bodyPolling.ts index d396ca97c8..2e0fdae225 100644 --- a/src/lro/bodyPolling.ts +++ b/src/lro/bodyPolling.ts @@ -1,22 +1,19 @@ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { failureStates, LroBody, LroStatus, RawResponse, successStates } from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getProvisioningState(rawResponse: FullOperationResponse): string { - const { properties, provisioningState } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); - const state: string | undefined = - properties?.provisioningState ?? provisioningState; +function getProvisioningState(rawResponse: RawResponse): string { + const { properties, provisioningState } = (rawResponse.body as LroBody) ?? {}; + const state: string | undefined = properties?.provisioningState ?? provisioningState; return state?.toLowerCase() ?? "succeeded"; } -export function isBodyPollingDone(rawResponse: FullOperationResponse) { +export function isBodyPollingDone(rawResponse: RawResponse): boolean { const state = getProvisioningState(rawResponse); - if (failureStates.includes(state)) { - throw new Error(`Provisioning state: ${state}`); + if (isUnexpectedPollingResponse(rawResponse) || failureStates.includes(state)) { + throw new Error(`The long running operation has failed. The provisioning state: ${state}.`); } return successStates.includes(state); } @@ -26,9 +23,9 @@ export function isBodyPollingDone(rawResponse: FullOperationResponse) { * from the result to determine the current operation state */ export function processBodyPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/src/lro/index.ts b/src/lro/index.ts index 2ed31f267f..836873e640 100644 --- a/src/lro/index.ts +++ b/src/lro/index.ts @@ -1,2 +1,18 @@ -export { shouldDeserializeLRO } from "./requestUtils"; -export { LROPoller } from "./lroPoller"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { LroEngine } from "./lroEngine"; +export { createGetLroStatusFromResponse } from "./stateMachine"; +export { + LroResourceLocationConfig, + GetLroStatusFromResponse, + RawResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + LroTerminalState, + LroInProgressState, + LroEngineOptions +} from "./models"; diff --git a/src/lro/locationPolling.ts b/src/lro/locationPolling.ts index 150c571771..6159e0527d 100644 --- a/src/lro/locationPolling.ts +++ b/src/lro/locationPolling.ts @@ -1,21 +1,17 @@ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function isLocationPollingDone(rawResponse: FullOperationResponse) { - const code = rawResponse.status; - if (![202, 200].includes(code)) { - throw new Error(`Operation failed`); - } - return code !== 202; +function isLocationPollingDone(rawResponse: RawResponse): boolean { + return !isUnexpectedPollingResponse(rawResponse) && rawResponse.statusCode !== 202; } export function processLocationPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/src/lro/lroEngine.ts b/src/lro/lroEngine.ts new file mode 100644 index 0000000000..b7ad1defa3 --- /dev/null +++ b/src/lro/lroEngine.ts @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Poller, PollOperationState } from "@azure/core-lro"; +import { + LongRunningOperation, + LroEngineOptions, + ResumablePollOperationState +} from "./models"; +import { GenericPollOperation } from "./operation"; + +/** + * The LRO Engine, a class that performs polling. + */ +export class LroEngine< + TResult, + TState extends PollOperationState +> extends Poller { + private intervalInMs: number; + + constructor(lro: LongRunningOperation, options?: LroEngineOptions) { + const { intervalInMs = 2000, resumeFrom } = options || {}; + function deserializeState( + resumeFrom: string + ): TState & ResumablePollOperationState { + try { + return JSON.parse(resumeFrom).state; + } catch (e) { + throw new Error( + `LroEngine: Unable to deserialize state: ${resumeFrom}` + ); + } + } + const state: TState & ResumablePollOperationState = resumeFrom + ? deserializeState(resumeFrom) + : ({} as any); + + const operation = new GenericPollOperation(state, lro); + super(operation); + + this.intervalInMs = intervalInMs; + operation.setPollerConfig(this as any); + } + + /** + * The method used by the poller to wait before attempting to update its operation. + */ + delay(): Promise { + return new Promise(resolve => + setTimeout(() => resolve(), this.intervalInMs) + ); + } +} diff --git a/src/lro/lroPoller.ts b/src/lro/lroPoller.ts deleted file mode 100644 index 1b74e7a7c2..0000000000 --- a/src/lro/lroPoller.ts +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { Poller, PollOperationState } from "@azure/core-lro"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { FinalStateVia, SendOperationFn } from "./models"; -import { GenericPollOperation } from "./operation"; - -export interface LROPollerOptions { - /** - * Defines how much time the poller is going to wait before making a new request to the service. - */ - intervalInMs?: number; - /** - * A serialized poller which can be used to resume an existing paused Long-Running-Operation. - */ - resumeFrom?: string; -} - -export class LROPoller extends Poller< - PollOperationState, - TResult -> { - private intervalInMs: number; - - constructor( - { intervalInMs = 2000, resumeFrom }: LROPollerOptions, - initialOperationArguments: OperationArguments, - initialOperationSpec: OperationSpec, - sendOperation: SendOperationFn, - finalStateVia?: FinalStateVia - ) { - const state: PollOperationState = resumeFrom - ? JSON.parse(resumeFrom).state - : {}; - - const operation = new GenericPollOperation( - state, - initialOperationArguments, - initialOperationSpec, - sendOperation, - finalStateVia - ); - super(operation); - - this.intervalInMs = intervalInMs; - operation.setPollerConfig(this as any); - } - - /** - * The method used by the poller to wait before attempting to update its operation. - */ - delay(): Promise { - return new Promise(resolve => - setTimeout(() => resolve(), this.intervalInMs) - ); - } -} diff --git a/src/lro/models.ts b/src/lro/models.ts index 317e03be2e..0465c14d90 100644 --- a/src/lro/models.ts +++ b/src/lro/models.ts @@ -1,44 +1,165 @@ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec -} from "@azure/core-client"; import { PollOperationState } from "@azure/core-lro"; -export type FinalStateVia = +/** + * Options for the LRO poller. + */ +export interface LroEngineOptions { + /** + * Defines how much time the poller is going to wait before making a new request to the service. + */ + intervalInMs?: number; + /** + * A serialized poller which can be used to resume an existing paused Long-Running-Operation. + */ + resumeFrom?: string; +} + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +/** + * The LRO states that signal that the LRO has completed. + */ +export const terminalStates = successStates.concat(failureStates); + +/** + * The potential location of the result of the LRO if specified by the LRO extension in the swagger. + */ +export type LroResourceLocationConfig = | "azure-async-operation" | "location" | "original-uri"; -export interface LROResult { +/** + * The type of a LRO response body. This is just a convenience type for checking the status of the operation. + */ + +export interface LroBody extends Record { + /** The status of the operation. */ + status?: string; + /** The state of the provisioning process */ + provisioningState?: string; + /** The properties of the provisioning process */ + properties?: { provisioningState?: string } & Record; +} + +/** + * Simple type of the raw response. + */ +export interface RawResponse { + /** The HTTP status code */ + statusCode: number; + /** A HttpHeaders collection in the response represented as a simple JSON object where all header names have been normalized to be lower-case. */ + headers: { + [headerName: string]: string; + }; + /** The parsed response body */ + body?: unknown; +} + +/** + * The type of the response of a LRO. + */ +export interface LroResponse { + /** The flattened response */ flatResponse: T; - rawResponse: FullOperationResponse; + /** The raw response */ + rawResponse: RawResponse; } -export type LROMode = "AzureAsync" | "Location" | "Body"; +/** The type of which LRO implementation being followed by a specific API. */ +export type LroMode = "AzureAsync" | "Location" | "Body"; -export interface LROConfig { - mode?: LROMode; +/** + * The configuration of a LRO to determine how to perform polling and checking whether the operation has completed. + */ +export interface LroConfig { + /** The LRO mode */ + mode?: LroMode; + /** The path of a provisioned resource */ resourceLocation?: string; } -export type SendOperationFn = ( - args: OperationArguments, - spec: OperationSpec -) => Promise>; - /** * Type of a polling operation state that can actually be resumed. */ export type ResumablePollOperationState = PollOperationState & { - initialRawResponse?: FullOperationResponse; - config?: LROConfig; + initialRawResponse?: RawResponse; + config?: LroConfig; pollingURL?: string; }; export interface PollerConfig { intervalInMs: number; } + +/** + * The type of a terminal state of an LRO. + */ +export interface LroTerminalState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: true; +} + +/** + * The type of an in-progress state of an LRO. + */ +export interface LroInProgressState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: false; + /** + * The request to be sent next if it is different from the standard polling one. + * Notice that it will disregard any polling URLs provided to it. + */ + next?: () => Promise>; +} + +/** + * The type of an LRO state which is a tagged union of terminal and in-progress states. + */ +export type LroStatus = LroTerminalState | LroInProgressState; + +/** + * The type of the getLROStatusFromResponse method. It takes the response as input and returns along the response whether the operation has finished. + */ +export type GetLroStatusFromResponse = ( + rawResponse: RawResponse, + flatResponse: T +) => LroStatus; + +/** + * Description of a long running operation. + */ +export interface LongRunningOperation { + /** + * The request path. + */ + requestPath: string; + /** + * The HTTP request method. + */ + requestMethod: string; + /** + * A function that can be used to send initial request to the service. + */ + sendInitialRequest: ( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ) => Promise>; + /** + * A function that can be used to poll for the current status of a long running operation. + */ + sendPollRequest: (config: LroConfig, path: string) => Promise>; + /** + * A function that can be used to retrieve the provisioned azure resource. + */ + retrieveAzureAsyncResource: (path?: string) => Promise>; +} diff --git a/src/lro/operation.ts b/src/lro/operation.ts index b3a2b3a5f2..a058b2ec42 100644 --- a/src/lro/operation.ts +++ b/src/lro/operation.ts @@ -1,34 +1,32 @@ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. import { AbortSignalLike } from "@azure/abort-controller"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { PollOperation, PollOperationState } from "@azure/core-lro"; +import { PollOperationState, PollOperation } from "@azure/core-lro"; import { - FinalStateVia, PollerConfig, ResumablePollOperationState, - SendOperationFn + LongRunningOperation, + LroStatus } from "./models"; -import { getPollingURL } from "./requestUtils"; -import { createGetLROState, initializeState, LROState } from "./stateMachine"; +import { getPollingUrl } from "./requestUtils"; +import { createInitializeState, createPollForLROStatus } from "./stateMachine"; -export class GenericPollOperation - implements PollOperation, TResult> { - private getLROState?: ( +export class GenericPollOperation< + TResult, + TState extends PollOperationState +> implements PollOperation { + private getLROStatusFromResponse?: ( pollingURL: string, pollerConfig: PollerConfig - ) => Promise>; + ) => Promise>; private pollerConfig?: PollerConfig; constructor( - public state: PollOperationState, - private initialOperationArguments: OperationArguments, - private initialOperationSpec: OperationSpec, - private sendOperation: SendOperationFn, - private finalStateVia?: FinalStateVia + public state: TState & ResumablePollOperationState, + private lro: LongRunningOperation ) {} - public setPollerConfig(pollerConfig: PollerConfig) { + public setPollerConfig(pollerConfig: PollerConfig): void { this.pollerConfig = pollerConfig; } @@ -49,45 +47,36 @@ export class GenericPollOperation */ async update(options?: { abortSignal?: AbortSignalLike | undefined; - fireProgress?: ((state: PollOperationState) => void) | undefined; - }): Promise, TResult>> { - const state = this.state as ResumablePollOperationState; - const { onResponse, ...restOptions } = - this.initialOperationArguments.options || {}; + fireProgress?: ((state: TState) => void) | undefined; + }): Promise> { + const state = this.state; if (!state.isStarted) { - await this.sendOperation( - { - ...this.initialOperationArguments, - options: { - ...restOptions, - onResponse: initializeState( - state, - this.initialOperationSpec, - onResponse - ) - } - }, - this.initialOperationSpec + const initializeState = createInitializeState( + state, + this.lro.requestPath, + this.lro.requestMethod ); + await this.lro.sendInitialRequest(initializeState); } if (!state.isCompleted) { - if (this.getLROState === undefined) { + if (this.getLROStatusFromResponse === undefined) { if (state.config === undefined) { - throw new Error("Bad state: LRO mode is undefined"); + throw new Error( + "Bad state: LRO mode is undefined. Please check if the serialized state is well-formed." + ); } - this.getLROState = createGetLROState( - this.sendOperation, - this.initialOperationArguments, - this.initialOperationSpec, - state.config, - this.finalStateVia + this.getLROStatusFromResponse = createPollForLROStatus( + this.lro, + state.config ); } if (state.pollingURL === undefined) { - throw new Error("Bad state: polling URL is undefined"); + throw new Error( + "Bad state: polling URL is undefined. Please check if the serialized state is well-formed." + ); } - const currentState = await this.getLROState( + const currentState = await this.getLROStatusFromResponse( state.pollingURL, this.pollerConfig! ); @@ -95,20 +84,19 @@ export class GenericPollOperation state.result = currentState.flatResponse; state.isCompleted = true; } else { - this.getLROState = currentState.next ?? this.getLROState; - state.pollingURL = getPollingURL( + this.getLROStatusFromResponse = + currentState.next ?? this.getLROStatusFromResponse; + state.pollingURL = getPollingUrl( currentState.rawResponse, state.pollingURL ); } } - if (options?.fireProgress !== undefined) { - options.fireProgress(state); - } + options?.fireProgress?.(state); return this; } - async cancel(): Promise, TResult>> { + async cancel(): Promise> { this.state.isCancelled = true; return this; } diff --git a/src/lro/passthrough.ts b/src/lro/passthrough.ts index 4bddaf7b2c..adec2dc879 100644 --- a/src/lro/passthrough.ts +++ b/src/lro/passthrough.ts @@ -1,13 +1,12 @@ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; export function processPassthroughOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/src/lro/pollingMethod.ts b/src/lro/pollingMethod.ts deleted file mode 100644 index d16be04aa0..0000000000 --- a/src/lro/pollingMethod.ts +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - OperationArguments, - OperationSpec, - OperationResponseMap -} from "@azure/core-client"; -import { LROMode, LROResult, SendOperationFn } from "./models"; - -export function createPollingMethod( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - mode?: LROMode -): (path?: string) => Promise> { - /** - * Polling calls will always return a status object i.e. {"status": "success"} - * these intermediate responses are not described in the swagger so we need to - * pass custom mappers at runtime. - * This function replaces all the existing mappers to be able to deserialize a status object - * @param responses Original set of responses defined in the operation - */ - function getCompositeMappers(responses: { - [responseCode: string]: OperationResponseMap; - }): { - [responseCode: string]: OperationResponseMap; - } { - return Object.keys(responses).reduce((acc, statusCode) => { - return { - ...acc, - [statusCode]: { - ...responses[statusCode], - bodyMapper: { - type: { - name: "Composite", - modelProperties: { - status: { - serializedName: "status", - type: { - name: "String" - } - } - } - } - } - } - }; - }, {} as { [responseCode: string]: OperationResponseMap }); - } - // Make sure we don't send any body to the get request - const { requestBody, responses, ...restSpec } = spec; - if (mode === "AzureAsync") { - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: getCompositeMappers(responses), - httpMethod: "GET", - ...(path && { path }) - }); - }; - } - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: responses, - httpMethod: "GET", - ...(path && { path }) - }); - }; -} - -export function createRetrieveAzureAsyncResource( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec -): (path?: string) => Promise> { - const updatedArgs = { ...args }; - if (updatedArgs.options) { - (updatedArgs.options as any).shouldDeserialize = true; - } - return createPollingMethod(sendOperationFn, updatedArgs, spec); -} diff --git a/src/lro/requestUtils.ts b/src/lro/requestUtils.ts index d42bf46511..f55dfcf21e 100644 --- a/src/lro/requestUtils.ts +++ b/src/lro/requestUtils.ts @@ -1,117 +1,7 @@ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse, OperationSpec } from "@azure/core-client"; -import { LROConfig } from "./models"; -import { terminalStates } from "./stateMachine"; - -/** - * We need to selectively deserialize our responses, only deserializing if we - * are in a final LRO response, not deserializing any polling non-terminal responses - */ -export function shouldDeserializeLRO(finalStateVia?: string) { - let initialOperationInfo: LROResponseInfo | undefined; - let isInitialRequest = true; - - return (response: FullOperationResponse) => { - if (response.status < 200 || response.status >= 300) { - return true; - } - - if (!initialOperationInfo) { - initialOperationInfo = getLROData(response); - } else { - isInitialRequest = false; - } - - if ( - initialOperationInfo.azureAsyncOperation || - initialOperationInfo.operationLocation - ) { - return ( - !isInitialRequest && - isAsyncOperationFinalResponse( - response, - initialOperationInfo, - finalStateVia - ) - ); - } - - if (initialOperationInfo.location) { - return isLocationFinalResponse(response); - } - - if (initialOperationInfo.requestMethod === "PUT") { - return isBodyPollingFinalResponse(response); - } - - return true; - }; -} - -function isAsyncOperationFinalResponse( - response: FullOperationResponse, - initialOperationInfo: LROResponseInfo, - finalStateVia?: string -): boolean { - const status: string = response.parsedBody?.status || "Succeeded"; - if (!terminalStates.includes(status.toLowerCase())) { - return false; - } - - if (initialOperationInfo.requestMethod === "DELETE") { - return true; - } - - if ( - initialOperationInfo.requestMethod === "PUT" && - finalStateVia && - finalStateVia.toLowerCase() === "azure-asyncoperation" - ) { - return true; - } - - if ( - initialOperationInfo.requestMethod !== "PUT" && - !initialOperationInfo.location - ) { - return true; - } - - return false; -} - -function isLocationFinalResponse(response: FullOperationResponse): boolean { - return response.status !== 202; -} - -function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { - const provisioningState: string = - response.parsedBody?.properties?.provisioningState || "Succeeded"; - - if (terminalStates.includes(provisioningState.toLowerCase())) { - return true; - } - - return false; -} - -interface LROResponseInfo { - requestMethod: string; - azureAsyncOperation?: string; - operationLocation?: string; - location?: string; -} - -function getLROData(result: FullOperationResponse): LROResponseInfo { - return { - azureAsyncOperation: result.headers.get("azure-asyncoperation"), - operationLocation: result.headers.get("operation-location"), - location: result.headers.get("location"), - requestMethod: result.request.method - }; -} +import { LroConfig, RawResponse } from "./models"; /** * Detects where the continuation token is and returns it. Notice that azure-asyncoperation @@ -119,45 +9,38 @@ function getLROData(result: FullOperationResponse): LROResponseInfo { * where both azure-asyncoperation and location could be present in the same response but * azure-asyncoperation should be the one to use for polling. */ -export function getPollingURL( - rawResponse: FullOperationResponse, - defaultPath: string -): string { +export function getPollingUrl(rawResponse: RawResponse, defaultPath: string): string { return ( - getAzureAsyncoperation(rawResponse) ?? + getAzureAsyncOperation(rawResponse) ?? getLocation(rawResponse) ?? getOperationLocation(rawResponse) ?? defaultPath ); } -function getLocation(rawResponse: FullOperationResponse): string | undefined { - return rawResponse.headers?.get("location"); +function getLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["location"]; } -function getOperationLocation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("operation-location"); +function getOperationLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["operation-location"]; } -function getAzureAsyncoperation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("azure-asyncoperation"); +function getAzureAsyncOperation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["azure-asyncoperation"]; } -export function inferLROMode( - spec: OperationSpec, - rawResponse: FullOperationResponse -): LROConfig { - const requestMethod = spec.httpMethod; - if (getAzureAsyncoperation(rawResponse) !== undefined) { +export function inferLroMode( + requestPath: string, + requestMethod: string, + rawResponse: RawResponse +): LroConfig { + if (getAzureAsyncOperation(rawResponse) !== undefined) { return { mode: "AzureAsync", resourceLocation: requestMethod === "PUT" - ? spec.path + ? requestPath : requestMethod === "POST" ? getLocation(rawResponse) : undefined @@ -177,10 +60,35 @@ export function inferLROMode( return {}; } -export function getSpecPath(spec: OperationSpec): string { - if (spec.path) { - return spec.path; - } else { - throw Error("Bad spec: request path is not found!"); +export class RestError extends Error { + public statusCode?: number; + constructor(message: string, statusCode: number) { + super(message); + this.name = "RestError"; + this.statusCode = statusCode; + + Object.setPrototypeOf(this, RestError.prototype); + } +} + +export function isUnexpectedInitialResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![203, 204, 202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} in the initial response. This may indicate a server issue.`, + code + ); } + return false; +} + +export function isUnexpectedPollingResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} while polling. This may indicate a server issue.`, + code + ); + } + return false; } diff --git a/src/lro/stateMachine.ts b/src/lro/stateMachine.ts index d0e58bffe2..e326716771 100644 --- a/src/lro/stateMachine.ts +++ b/src/lro/stateMachine.ts @@ -1,86 +1,36 @@ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec, - RawResponseCallback -} from "@azure/core-client"; import { processAzureAsyncOperationResult } from "./azureAsyncPolling"; -import { - isBodyPollingDone, - processBodyPollingOperationResult -} from "./bodyPolling"; +import { isBodyPollingDone, processBodyPollingOperationResult } from "./bodyPolling"; import { processLocationPollingOperationResult } from "./locationPolling"; import { - FinalStateVia, - LROConfig, - LROResult, + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroStatus, PollerConfig, - ResumablePollOperationState, - SendOperationFn + RawResponse, + ResumablePollOperationState } from "./models"; import { processPassthroughOperationResult } from "./passthrough"; -import { - createPollingMethod, - createRetrieveAzureAsyncResource -} from "./pollingMethod"; -import { getPollingURL, getSpecPath, inferLROMode } from "./requestUtils"; - -export const successStates = ["succeeded"]; -export const failureStates = ["failed", "canceled", "cancelled"]; -export const terminalStates = successStates.concat(failureStates); - -/** - * The type of a terminal state of an LRO. - */ -interface LROTerminalState extends LROResult { - /** - * Whether the operation has finished. - */ - done: true; -} - -/** - * The type of an in-progress state of an LRO. - */ -interface LROInProgressState extends LROResult { - /** - * Whether the operation has finished. - */ - done: false; - /** - * The request to be sent next if it is different from the standard polling one. - * Notice that it will disregard any polling URLs provided to it. - */ - next?: () => Promise>; -} - -/** - * The type of an LRO state which is a tagged union of terminal and in-progress states. - */ -export type LROState = LROTerminalState | LROInProgressState; +import { getPollingUrl, inferLroMode, isUnexpectedInitialResponse } from "./requestUtils"; /** * creates a stepping function that maps an LRO state to another. */ -function createTransition( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { +export function createGetLroStatusFromResponse( + lroPrimitives: LongRunningOperation, + config: LroConfig, + lroResourceLocationConfig?: LroResourceLocationConfig +): GetLroStatusFromResponse { switch (config.mode) { case "AzureAsync": { return processAzureAsyncOperationResult( - createRetrieveAzureAsyncResource(sendOperationFn, args, spec), + lroPrimitives, config.resourceLocation, - finalStateVia + lroResourceLocationConfig ); } case "Location": { @@ -98,62 +48,20 @@ function createTransition( /** * Creates a polling operation that returns a LRO state. */ -export function createGetLROState( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia -): ( - pollingURL: string, - pollerConfig: PollerConfig -) => Promise> { - const step = createTransition( - sendOperationFn, - args, - spec, - config, - finalStateVia - ); - const customerCallback = args?.options?.onResponse; - let response: LROState | undefined = undefined; - let retryAfter: string | undefined = undefined; - const poll = createPollingMethod( - sendOperationFn, - { - ...args, - options: { - ...args.options, - onResponse: ( - rawResponse: FullOperationResponse, - flatResponse: unknown - ): void => { - response = step(rawResponse, flatResponse as TResult); - retryAfter = rawResponse.headers.get("Retry-After"); - if (response.done) { - customerCallback?.(rawResponse, flatResponse); - } - } - } - }, - spec, - config.mode - ); - return async ( - path: string, - pollerConfig: PollerConfig - ): Promise> => { - await poll(path); +export function createPollForLROStatus( + lroPrimitives: LongRunningOperation, + config: LroConfig +): (pollingURL: string, pollerConfig: PollerConfig) => Promise> { + return async (path: string, pollerConfig: PollerConfig): Promise> => { + const response = await lroPrimitives.sendPollRequest(config, path); + const retryAfter: string | undefined = response.rawResponse.headers["retry-after"]; if (retryAfter !== undefined) { const retryAfterInMs = parseInt(retryAfter); pollerConfig.intervalInMs = isNaN(retryAfterInMs) - ? calculatePollingIntervalFromDate( - new Date(retryAfter), - pollerConfig.intervalInMs - ) + ? calculatePollingIntervalFromDate(new Date(retryAfter), pollerConfig.intervalInMs) : retryAfterInMs; } - return response!; + return response; }; } @@ -171,38 +79,30 @@ function calculatePollingIntervalFromDate( /** * Creates a callback to be used to initialize the polling operation state. - * @param state of the polling operation - * @param operationSpec of the LRO - * @param callback callback to be called when the operation is done + * @param state - of the polling operation + * @param operationSpec - of the LRO + * @param callback - callback to be called when the operation is done * @returns callback that initializes the state of the polling operation */ -export function initializeState( +export function createInitializeState( state: ResumablePollOperationState, - operationSpec: OperationSpec, - callback?: RawResponseCallback -): (rawResponse: FullOperationResponse, flatResponse: unknown) => void { - return (rawResponse: FullOperationResponse, flatResponse: unknown) => { + requestPath: string, + requestMethod: string +): (rawResponse: RawResponse, flatResponse: unknown) => boolean { + return (rawResponse: RawResponse, flatResponse: unknown) => { + if (isUnexpectedInitialResponse(rawResponse)) return true; state.initialRawResponse = rawResponse; state.isStarted = true; - state.pollingURL = getPollingURL( - state.initialRawResponse, - getSpecPath(operationSpec) - ); - state.config = inferLROMode(operationSpec, state.initialRawResponse); + state.pollingURL = getPollingUrl(state.initialRawResponse, requestPath); + state.config = inferLroMode(requestPath, requestMethod, state.initialRawResponse); /** short circuit polling if body polling is done in the initial request */ if ( state.config.mode === undefined || - (state.config.mode === "Body" && - isBodyPollingDone(state.initialRawResponse)) + (state.config.mode === "Body" && isBodyPollingDone(state.initialRawResponse)) ) { state.result = flatResponse as TResult; state.isCompleted = true; - /** - * We need to check if the LRO operation is finished inside the - * call back so that we can call the customer-provided callback - * on that result. - */ - callback?.(rawResponse, flatResponse); } + return Boolean(state.isCompleted); }; } diff --git a/src/models/operationDetails.ts b/src/models/operationDetails.ts index e089076291..11997dad0f 100644 --- a/src/models/operationDetails.ts +++ b/src/models/operationDetails.ts @@ -73,8 +73,8 @@ export interface OperationDetails { typeDetails: TypeDetails; mediaTypes: Set; pagination?: PaginationDetails; - isLRO: boolean; - lroOptions: { "final-state-via": string }; + isLro: boolean; + lroOptions?: { "final-state-via": string }; scope?: Scope; namePrefix?: string; } diff --git a/src/transforms/extensions.ts b/src/transforms/extensions.ts index 0f24639197..d6b3edc233 100644 --- a/src/transforms/extensions.ts +++ b/src/transforms/extensions.ts @@ -164,20 +164,20 @@ function addPageableMethods(codeModel: CodeModel) { // NextLink methods should always send GET requests // More info: https://github.com/Azure/autorest/tree/master/docs/extensions#x-ms-pageable nextLinkRequestProtocol.method = "GET"; - let isLRO = false; + let isLro = false; - // NextLink method can not be LRO + // NextLink method can not be Lro if ( nextLinkMethod.extensions && "x-ms-long-running-operation" in nextLinkMethod.extensions ) { delete nextLinkMethod.extensions["x-ms-long-running-operation"]; - isLRO = true; + isLro = true; } - // Make sure there is a 200 response defined since LRO operations + // Make sure there is a 200 response defined since Lro operations // are only required to define the initial response in SWAGGER - inject200Response(nextLinkMethod, isLRO); + inject200Response(nextLinkMethod, isLro); // Create the nextLink parameter. // This will appear as a required parameter to the "Next" operation. @@ -218,16 +218,16 @@ function addPageableMethods(codeModel: CodeModel) { /** * This function injects a 200 response definition if not present. - * This is needed because SWAGGER only requires LRO operations to define + * This is needed because SWAGGER only requires Lro operations to define * the initial request response. By injecting 200 response definition we * allow core-http deserialization to handle it as success rather that failure * as by default it treats any response not defined as an error * @param nextLinkMethod method to inject the 200 response to - * @param isLRO whether or not the operation is LRO + * @param isLro whether or not the operation is Lro */ -function inject200Response(nextLinkMethod: Operation, isLRO: boolean) { - // Only inject for LRO operations - if (!isLRO) { +function inject200Response(nextLinkMethod: Operation, isLro: boolean) { + // Only inject for Lro operations + if (!isLro) { return; } @@ -249,7 +249,7 @@ function inject200Response(nextLinkMethod: Operation, isLRO: boolean) { if (!successResponse) { throw new Error( - "Expected nextLink of LRO operation to have a success response defined" + "Expected nextLink of Lro operation to have a success response defined" ); } diff --git a/src/transforms/operationTransforms.ts b/src/transforms/operationTransforms.ts index c409bee17c..06de3976d6 100644 --- a/src/transforms/operationTransforms.ts +++ b/src/transforms/operationTransforms.ts @@ -133,7 +133,13 @@ export function transformOperationSpec( return operationSpecDetails; } -export function extractHttpDetails({ path, method }: OperationRequestDetails) { +export function extractHttpDetails({ + path, + method +}: OperationRequestDetails): { + path: string; + httpMethod: HttpMethods; +} { return { path, httpMethod: method.toUpperCase() as HttpMethods @@ -143,7 +149,7 @@ export function extractHttpDetails({ path, method }: OperationRequestDetails) { export function extractSpecResponses({ name, responses, - isLRO + isLro }: OperationDetails): OperationSpecResponses { if (!responses || !responses.length) { throw new Error(`The operation ${name} contains no responses`); @@ -151,7 +157,7 @@ export function extractSpecResponses({ let enhancedResponses = responses; - if (isLRO) { + if (isLro) { enhancedResponses = injectMissingResponses(responses); } @@ -390,7 +396,7 @@ export async function transformOperation( usedModels: [typeName] }; - const isLRO: boolean = Boolean( + const isLro: boolean = Boolean( operation.extensions && operation.extensions["x-ms-long-running-operation"] ); const lroOptions = @@ -412,10 +418,10 @@ export async function transformOperation( ); const hasMultipleResponses = responses.filter(r => !r.isError).length > 1; - // If this is an LRO operation only consider the first success response, - // this is because LRO operations swagger defines initial and final operation + // If this is an Lro operation only consider the first success response, + // this is because Lro operations swagger defines initial and final operation // responses in the same operation. - if (isLRO && hasMultipleResponses) { + if (isLro && hasMultipleResponses) { const errorResponses = responses.filter(r => r.isError); responses = [responses[0], ...errorResponses]; } @@ -435,7 +441,7 @@ export async function transformOperation( responses, mediaTypes, pagination, - isLRO, + isLro, lroOptions }; } diff --git a/src/typescriptGenerator.ts b/src/typescriptGenerator.ts index 44dfcdde29..d5f9f72d48 100755 --- a/src/typescriptGenerator.ts +++ b/src/typescriptGenerator.ts @@ -21,7 +21,7 @@ import { generateRollupConfig } from "./generators/static/rollupConfigFileGenera import { generateOperations } from "./generators/operationGenerator"; import { generateOperationsInterfaces } from "./generators/operationInterfaceGenerator"; import { generateParameters } from "./generators/parametersGenerator"; -import { generateLROFiles } from "./generators/LROGenerator"; +import { generateLroFiles } from "./generators/LROGenerator"; import { generateTracingFile } from "./generators/tracingFileGenerator"; import { getAutorestOptions } from "./autorestSession"; @@ -96,7 +96,7 @@ export async function generateTypeScriptLibrary( generateOperationsInterfaces(clientDetails, project); generateParameters(clientDetails, project); generateIndexFile(clientDetails, project); - await generateLROFiles(clientDetails, project); + await generateLroFiles(clientDetails, project); generateTracingFile(project); const licenseHeader = ` diff --git a/test/integration/generated/lro/src/coreClientLro.ts b/test/integration/generated/lro/src/coreClientLro.ts new file mode 100644 index 0000000000..d793a24458 --- /dev/null +++ b/test/integration/generated/lro/src/coreClientLro.ts @@ -0,0 +1,323 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + OperationArguments, + OperationSpec, + OperationResponseMap, + FullOperationResponse +} from "@azure/core-client"; +import { + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + createGetLroStatusFromResponse, + RawResponse +} from "./lro"; + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +export const terminalStates = successStates.concat(failureStates); + +export type SendOperationFn = ( + args: OperationArguments, + spec: OperationSpec +) => Promise>; + +export function createPollingMethod( + sendOperationFn: SendOperationFn, + GetLroStatusFromResponse: GetLroStatusFromResponse, + args: OperationArguments, + spec: OperationSpec, + mode?: LroMode +): (path?: string) => Promise> { + /** + * Polling calls will always return a status object i.e. {"status": "success"} + * these intermediate responses are not described in the swagger so we need to + * pass custom mappers at runtime. + * This function replaces all the existing mappers to be able to deserialize a status object + * @param responses Original set of responses defined in the operation + */ + function getCompositeMappers(responses: { + [responseCode: string]: OperationResponseMap; + }): { + [responseCode: string]: OperationResponseMap; + } { + return Object.keys(responses).reduce((acc, statusCode) => { + return { + ...acc, + [statusCode]: { + ...responses[statusCode], + bodyMapper: { + type: { + name: "Composite", + modelProperties: { + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } + } + } + }; + }, {} as { [responseCode: string]: OperationResponseMap }); + } + let response: LroStatus | undefined = undefined; + const customerCallback = args?.options?.onResponse; + const updatedArgs = { + ...args, + options: { + ...args.options, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ): void => { + response = GetLroStatusFromResponse( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse as TResult + ); + if (response.done) { + customerCallback?.(rawResponse, flatResponse); + } + } + } + }; + // Make sure we don't send any body to the get request + const { requestBody, responses, ...restSpec } = spec; + if (mode === "AzureAsync") { + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: getCompositeMappers(responses), + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; + } + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: responses, + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; +} + +/** + * We need to selectively deserialize our responses, only deserializing if we + * are in a final Lro response, not deserializing any polling non-terminal responses + */ +export function shouldDeserializeLro(lroResourceLocationConfig?: string) { + let initialOperationInfo: LroResponseInfo | undefined; + let isInitialRequest = true; + + return (response: FullOperationResponse) => { + if (response.status < 200 || response.status >= 300) { + return true; + } + + if (!initialOperationInfo) { + initialOperationInfo = getLroData(response); + } else { + isInitialRequest = false; + } + + if ( + initialOperationInfo.azureAsyncOperation || + initialOperationInfo.operationLocation + ) { + return ( + !isInitialRequest && + isAsyncOperationFinalResponse( + response, + initialOperationInfo, + lroResourceLocationConfig + ) + ); + } + + if (initialOperationInfo.location) { + return isLocationFinalResponse(response); + } + + if (initialOperationInfo.requestMethod === "PUT") { + return isBodyPollingFinalResponse(response); + } + + return true; + }; +} + +function isAsyncOperationFinalResponse( + response: FullOperationResponse, + initialOperationInfo: LroResponseInfo, + lroResourceLocationConfig?: string +): boolean { + const status: string = response.parsedBody?.status || "Succeeded"; + if (!terminalStates.includes(status.toLowerCase())) { + return false; + } + + if (initialOperationInfo.requestMethod === "DELETE") { + return true; + } + + if ( + initialOperationInfo.requestMethod === "PUT" && + lroResourceLocationConfig && + lroResourceLocationConfig.toLowerCase() === "azure-asyncoperation" + ) { + return true; + } + + if ( + initialOperationInfo.requestMethod !== "PUT" && + !initialOperationInfo.location + ) { + return true; + } + + return false; +} + +function isLocationFinalResponse(response: FullOperationResponse): boolean { + return response.status !== 202; +} + +function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { + const provisioningState: string = + response.parsedBody?.properties?.provisioningState || "Succeeded"; + + if (terminalStates.includes(provisioningState.toLowerCase())) { + return true; + } + + return false; +} + +interface LroResponseInfo { + requestMethod: string; + azureAsyncOperation?: string; + operationLocation?: string; + location?: string; +} + +function getLroData(result: FullOperationResponse): LroResponseInfo { + return { + azureAsyncOperation: result.headers.get("azure-asyncoperation"), + operationLocation: result.headers.get("operation-location"), + location: result.headers.get("location"), + requestMethod: result.request.method + }; +} + +export function getSpecPath(spec: OperationSpec): string { + if (spec.path) { + return spec.path; + } else { + throw Error("Bad spec: request path is not found!"); + } +} + +export class CoreClientLro implements LongRunningOperation { + constructor( + private sendOperationFn: SendOperationFn, + private args: OperationArguments, + private spec: OperationSpec, + private lroResourceLocationConfig?: LroResourceLocationConfig, + public requestPath: string = spec.path!, + public requestMethod: string = spec.httpMethod + ) {} + public async sendInitialRequest( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ): Promise> { + const { onResponse, ...restOptions } = this.args.options || {}; + return this.sendOperationFn( + { + ...this.args, + options: { + ...restOptions, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ) => { + const isCompleted = initializeState( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse + ); + if (isCompleted) { + onResponse?.(rawResponse, flatResponse); + } + } + } + }, + this.spec + ); + } + + public async sendPollRequest( + config: LroConfig, + path: string + ): Promise> { + const getLroStatusFromResponse = createGetLroStatusFromResponse( + this, + config, + this.lroResourceLocationConfig + ); + return createPollingMethod( + this.sendOperationFn, + getLroStatusFromResponse, + this.args, + this.spec, + config.mode + )(path); + } + + public async retrieveAzureAsyncResource( + path?: string + ): Promise> { + const updatedArgs = { ...this.args }; + if (updatedArgs.options) { + (updatedArgs.options as any).shouldDeserialize = true; + } + return createPollingMethod( + this.sendOperationFn, + (rawResponse, flatResponse) => ({ + rawResponse, + flatResponse, + done: true + }), + updatedArgs, + this.spec + )(path); + } +} diff --git a/test/integration/generated/lro/src/lro/azureAsyncPolling.ts b/test/integration/generated/lro/src/lro/azureAsyncPolling.ts index 0d63c54f60..725578a692 100644 --- a/test/integration/generated/lro/src/lro/azureAsyncPolling.ts +++ b/test/integration/generated/lro/src/lro/azureAsyncPolling.ts @@ -7,39 +7,61 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { FinalStateVia, LROResult } from "./models"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroResourceLocationConfig, + LongRunningOperation, + LroBody, + LroResponse, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getResponseStatus(rawResponse: FullOperationResponse): string { - const { status } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getResponseStatus(rawResponse: RawResponse): string { + const { status } = (rawResponse.body as LroBody) ?? {}; return status?.toLowerCase() ?? "succeeded"; } -function isAzureAsyncPollingDone(rawResponse: FullOperationResponse) { +function isAzureAsyncPollingDone(rawResponse: RawResponse): boolean { const state = getResponseStatus(rawResponse); - if (failureStates.includes(state)) { + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { throw new Error(`Operation status: ${state}`); } return successStates.includes(state); } +async function sendFinalRequest( + lro: LongRunningOperation, + lroResourceLocationConfig?: LroResourceLocationConfig, + resourceLocation?: string +): Promise | undefined> { + switch (lroResourceLocationConfig) { + case "original-uri": + return lro.retrieveAzureAsyncResource(); + case "azure-async-operation": + return Promise.resolve(undefined); + case "location": + default: + return lro.retrieveAzureAsyncResource(resourceLocation); + } +} + export function processAzureAsyncOperationResult( - restrieveResource: (path?: string) => Promise>, + lro: LongRunningOperation, resourceLocation?: string, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { + lroResourceLocationConfig?: LroResourceLocationConfig +): (rawResponse: RawResponse, flatResponse: TResult) => LroStatus { return ( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult - ): LROState => { + ): LroStatus => { if (isAzureAsyncPollingDone(rawResponse)) { if (resourceLocation === undefined) { return { rawResponse, flatResponse, done: true }; @@ -49,20 +71,11 @@ export function processAzureAsyncOperationResult( flatResponse, done: false, next: async () => { - async function sendFinalRequest(): Promise< - LROResult | undefined - > { - switch (finalStateVia) { - case "original-uri": - return restrieveResource(); - case "azure-async-operation": - return Promise.resolve(undefined); - case "location": - default: - return restrieveResource(resourceLocation); - } - } - const finalResponse = await sendFinalRequest(); + const finalResponse = await sendFinalRequest( + lro, + lroResourceLocationConfig, + resourceLocation + ); return { ...(finalResponse ?? { rawResponse, diff --git a/test/integration/generated/lro/src/lro/bodyPolling.ts b/test/integration/generated/lro/src/lro/bodyPolling.ts index 269d8e6799..b1c87f8bc8 100644 --- a/test/integration/generated/lro/src/lro/bodyPolling.ts +++ b/test/integration/generated/lro/src/lro/bodyPolling.ts @@ -7,24 +7,33 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroBody, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getProvisioningState(rawResponse: FullOperationResponse): string { - const { properties, provisioningState } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getProvisioningState(rawResponse: RawResponse): string { + const { properties, provisioningState } = (rawResponse.body as LroBody) ?? {}; const state: string | undefined = properties?.provisioningState ?? provisioningState; return state?.toLowerCase() ?? "succeeded"; } -export function isBodyPollingDone(rawResponse: FullOperationResponse) { +export function isBodyPollingDone(rawResponse: RawResponse): boolean { const state = getProvisioningState(rawResponse); - if (failureStates.includes(state)) { - throw new Error(`Provisioning state: ${state}`); + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { + throw new Error( + `The long running operation has failed. The provisioning state: ${state}.` + ); } return successStates.includes(state); } @@ -34,9 +43,9 @@ export function isBodyPollingDone(rawResponse: FullOperationResponse) { * from the result to determine the current operation state */ export function processBodyPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/integration/generated/lro/src/lro/index.ts b/test/integration/generated/lro/src/lro/index.ts index 85c2187669..20df608fc8 100644 --- a/test/integration/generated/lro/src/lro/index.ts +++ b/test/integration/generated/lro/src/lro/index.ts @@ -6,5 +6,21 @@ * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ -export { shouldDeserializeLRO } from "./requestUtils"; -export { LROPoller } from "./lroPoller"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { LroEngine } from "./lroEngine"; +export { createGetLroStatusFromResponse } from "./stateMachine"; +export { + LroResourceLocationConfig, + GetLroStatusFromResponse, + RawResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + LroTerminalState, + LroInProgressState, + LroEngineOptions +} from "./models"; diff --git a/test/integration/generated/lro/src/lro/locationPolling.ts b/test/integration/generated/lro/src/lro/locationPolling.ts index 6fef619384..9d1aadfbde 100644 --- a/test/integration/generated/lro/src/lro/locationPolling.ts +++ b/test/integration/generated/lro/src/lro/locationPolling.ts @@ -7,23 +7,21 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function isLocationPollingDone(rawResponse: FullOperationResponse) { - const code = rawResponse.status; - if (![202, 200].includes(code)) { - throw new Error(`Operation failed`); - } - return code !== 202; +function isLocationPollingDone(rawResponse: RawResponse): boolean { + return ( + !isUnexpectedPollingResponse(rawResponse) && rawResponse.statusCode !== 202 + ); } export function processLocationPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/integration/generated/lro/src/lro/lroEngine.ts b/test/integration/generated/lro/src/lro/lroEngine.ts new file mode 100644 index 0000000000..85cc15e609 --- /dev/null +++ b/test/integration/generated/lro/src/lro/lroEngine.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Poller, PollOperationState } from "@azure/core-lro"; +import { + LongRunningOperation, + LroEngineOptions, + ResumablePollOperationState +} from "./models"; +import { GenericPollOperation } from "./operation"; + +/** + * The LRO Engine, a class that performs polling. + */ +export class LroEngine< + TResult, + TState extends PollOperationState +> extends Poller { + private intervalInMs: number; + + constructor(lro: LongRunningOperation, options?: LroEngineOptions) { + const { intervalInMs = 2000, resumeFrom } = options || {}; + function deserializeState( + resumeFrom: string + ): TState & ResumablePollOperationState { + try { + return JSON.parse(resumeFrom).state; + } catch (e) { + throw new Error( + `LroEngine: Unable to deserialize state: ${resumeFrom}` + ); + } + } + const state: TState & ResumablePollOperationState = resumeFrom + ? deserializeState(resumeFrom) + : ({} as any); + + const operation = new GenericPollOperation(state, lro); + super(operation); + + this.intervalInMs = intervalInMs; + operation.setPollerConfig(this as any); + } + + /** + * The method used by the poller to wait before attempting to update its operation. + */ + delay(): Promise { + return new Promise((resolve) => + setTimeout(() => resolve(), this.intervalInMs) + ); + } +} diff --git a/test/integration/generated/lro/src/lro/lroPoller.ts b/test/integration/generated/lro/src/lro/lroPoller.ts deleted file mode 100644 index cd1cd64fe8..0000000000 --- a/test/integration/generated/lro/src/lro/lroPoller.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { Poller, PollOperationState } from "@azure/core-lro"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { FinalStateVia, SendOperationFn } from "./models"; -import { GenericPollOperation } from "./operation"; - -export interface LROPollerOptions { - /** - * Defines how much time the poller is going to wait before making a new request to the service. - */ - intervalInMs?: number; - /** - * A serialized poller which can be used to resume an existing paused Long-Running-Operation. - */ - resumeFrom?: string; -} - -export class LROPoller extends Poller< - PollOperationState, - TResult -> { - private intervalInMs: number; - - constructor( - { intervalInMs = 2000, resumeFrom }: LROPollerOptions, - initialOperationArguments: OperationArguments, - initialOperationSpec: OperationSpec, - sendOperation: SendOperationFn, - finalStateVia?: FinalStateVia - ) { - const state: PollOperationState = resumeFrom - ? JSON.parse(resumeFrom).state - : {}; - - const operation = new GenericPollOperation( - state, - initialOperationArguments, - initialOperationSpec, - sendOperation, - finalStateVia - ); - super(operation); - - this.intervalInMs = intervalInMs; - operation.setPollerConfig(this as any); - } - - /** - * The method used by the poller to wait before attempting to update its operation. - */ - delay(): Promise { - return new Promise((resolve) => - setTimeout(() => resolve(), this.intervalInMs) - ); - } -} diff --git a/test/integration/generated/lro/src/lro/models.ts b/test/integration/generated/lro/src/lro/models.ts index a4a5a5abd6..93c3437c8e 100644 --- a/test/integration/generated/lro/src/lro/models.ts +++ b/test/integration/generated/lro/src/lro/models.ts @@ -7,46 +7,167 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec -} from "@azure/core-client"; import { PollOperationState } from "@azure/core-lro"; -export type FinalStateVia = +/** + * Options for the LRO poller. + */ +export interface LroEngineOptions { + /** + * Defines how much time the poller is going to wait before making a new request to the service. + */ + intervalInMs?: number; + /** + * A serialized poller which can be used to resume an existing paused Long-Running-Operation. + */ + resumeFrom?: string; +} + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +/** + * The LRO states that signal that the LRO has completed. + */ +export const terminalStates = successStates.concat(failureStates); + +/** + * The potential location of the result of the LRO if specified by the LRO extension in the swagger. + */ +export type LroResourceLocationConfig = | "azure-async-operation" | "location" | "original-uri"; -export interface LROResult { +/** + * The type of a LRO response body. This is just a convenience type for checking the status of the operation. + */ + +export interface LroBody extends Record { + /** The status of the operation. */ + status?: string; + /** The state of the provisioning process */ + provisioningState?: string; + /** The properties of the provisioning process */ + properties?: { provisioningState?: string } & Record; +} + +/** + * Simple type of the raw response. + */ +export interface RawResponse { + /** The HTTP status code */ + statusCode: number; + /** A HttpHeaders collection in the response represented as a simple JSON object where all header names have been normalized to be lower-case. */ + headers: { + [headerName: string]: string; + }; + /** The parsed response body */ + body?: unknown; +} + +/** + * The type of the response of a LRO. + */ +export interface LroResponse { + /** The flattened response */ flatResponse: T; - rawResponse: FullOperationResponse; + /** The raw response */ + rawResponse: RawResponse; } -export type LROMode = "AzureAsync" | "Location" | "Body"; +/** The type of which LRO implementation being followed by a specific API. */ +export type LroMode = "AzureAsync" | "Location" | "Body"; -export interface LROConfig { - mode?: LROMode; +/** + * The configuration of a LRO to determine how to perform polling and checking whether the operation has completed. + */ +export interface LroConfig { + /** The LRO mode */ + mode?: LroMode; + /** The path of a provisioned resource */ resourceLocation?: string; } -export type SendOperationFn = ( - args: OperationArguments, - spec: OperationSpec -) => Promise>; - /** * Type of a polling operation state that can actually be resumed. */ export type ResumablePollOperationState = PollOperationState & { - initialRawResponse?: FullOperationResponse; - config?: LROConfig; + initialRawResponse?: RawResponse; + config?: LroConfig; pollingURL?: string; }; export interface PollerConfig { intervalInMs: number; } + +/** + * The type of a terminal state of an LRO. + */ +export interface LroTerminalState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: true; +} + +/** + * The type of an in-progress state of an LRO. + */ +export interface LroInProgressState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: false; + /** + * The request to be sent next if it is different from the standard polling one. + * Notice that it will disregard any polling URLs provided to it. + */ + next?: () => Promise>; +} + +/** + * The type of an LRO state which is a tagged union of terminal and in-progress states. + */ +export type LroStatus = LroTerminalState | LroInProgressState; + +/** + * The type of the getLROStatusFromResponse method. It takes the response as input and returns along the response whether the operation has finished. + */ +export type GetLroStatusFromResponse = ( + rawResponse: RawResponse, + flatResponse: T +) => LroStatus; + +/** + * Description of a long running operation. + */ +export interface LongRunningOperation { + /** + * The request path. + */ + requestPath: string; + /** + * The HTTP request method. + */ + requestMethod: string; + /** + * A function that can be used to send initial request to the service. + */ + sendInitialRequest: ( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ) => Promise>; + /** + * A function that can be used to poll for the current status of a long running operation. + */ + sendPollRequest: (config: LroConfig, path: string) => Promise>; + /** + * A function that can be used to retrieve the provisioned azure resource. + */ + retrieveAzureAsyncResource: (path?: string) => Promise>; +} diff --git a/test/integration/generated/lro/src/lro/operation.ts b/test/integration/generated/lro/src/lro/operation.ts index 801d03e720..3ea7b76d89 100644 --- a/test/integration/generated/lro/src/lro/operation.ts +++ b/test/integration/generated/lro/src/lro/operation.ts @@ -7,36 +7,34 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. import { AbortSignalLike } from "@azure/abort-controller"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { PollOperation, PollOperationState } from "@azure/core-lro"; +import { PollOperationState, PollOperation } from "@azure/core-lro"; import { - FinalStateVia, PollerConfig, ResumablePollOperationState, - SendOperationFn + LongRunningOperation, + LroStatus } from "./models"; -import { getPollingURL } from "./requestUtils"; -import { createGetLROState, initializeState, LROState } from "./stateMachine"; +import { getPollingUrl } from "./requestUtils"; +import { createInitializeState, createPollForLROStatus } from "./stateMachine"; -export class GenericPollOperation - implements PollOperation, TResult> { - private getLROState?: ( +export class GenericPollOperation< + TResult, + TState extends PollOperationState +> implements PollOperation { + private getLROStatusFromResponse?: ( pollingURL: string, pollerConfig: PollerConfig - ) => Promise>; + ) => Promise>; private pollerConfig?: PollerConfig; constructor( - public state: PollOperationState, - private initialOperationArguments: OperationArguments, - private initialOperationSpec: OperationSpec, - private sendOperation: SendOperationFn, - private finalStateVia?: FinalStateVia + public state: TState & ResumablePollOperationState, + private lro: LongRunningOperation ) {} - public setPollerConfig(pollerConfig: PollerConfig) { + public setPollerConfig(pollerConfig: PollerConfig): void { this.pollerConfig = pollerConfig; } @@ -57,45 +55,36 @@ export class GenericPollOperation */ async update(options?: { abortSignal?: AbortSignalLike | undefined; - fireProgress?: ((state: PollOperationState) => void) | undefined; - }): Promise, TResult>> { - const state = this.state as ResumablePollOperationState; - const { onResponse, ...restOptions } = - this.initialOperationArguments.options || {}; + fireProgress?: ((state: TState) => void) | undefined; + }): Promise> { + const state = this.state; if (!state.isStarted) { - await this.sendOperation( - { - ...this.initialOperationArguments, - options: { - ...restOptions, - onResponse: initializeState( - state, - this.initialOperationSpec, - onResponse - ) - } - }, - this.initialOperationSpec + const initializeState = createInitializeState( + state, + this.lro.requestPath, + this.lro.requestMethod ); + await this.lro.sendInitialRequest(initializeState); } if (!state.isCompleted) { - if (this.getLROState === undefined) { + if (this.getLROStatusFromResponse === undefined) { if (state.config === undefined) { - throw new Error("Bad state: LRO mode is undefined"); + throw new Error( + "Bad state: LRO mode is undefined. Please check if the serialized state is well-formed." + ); } - this.getLROState = createGetLROState( - this.sendOperation, - this.initialOperationArguments, - this.initialOperationSpec, - state.config, - this.finalStateVia + this.getLROStatusFromResponse = createPollForLROStatus( + this.lro, + state.config ); } if (state.pollingURL === undefined) { - throw new Error("Bad state: polling URL is undefined"); + throw new Error( + "Bad state: polling URL is undefined. Please check if the serialized state is well-formed." + ); } - const currentState = await this.getLROState( + const currentState = await this.getLROStatusFromResponse( state.pollingURL, this.pollerConfig! ); @@ -103,20 +92,19 @@ export class GenericPollOperation state.result = currentState.flatResponse; state.isCompleted = true; } else { - this.getLROState = currentState.next ?? this.getLROState; - state.pollingURL = getPollingURL( + this.getLROStatusFromResponse = + currentState.next ?? this.getLROStatusFromResponse; + state.pollingURL = getPollingUrl( currentState.rawResponse, state.pollingURL ); } } - if (options?.fireProgress !== undefined) { - options.fireProgress(state); - } + options?.fireProgress?.(state); return this; } - async cancel(): Promise, TResult>> { + async cancel(): Promise> { this.state.isCancelled = true; return this; } diff --git a/test/integration/generated/lro/src/lro/passthrough.ts b/test/integration/generated/lro/src/lro/passthrough.ts index 64c10380c1..ae7f87d384 100644 --- a/test/integration/generated/lro/src/lro/passthrough.ts +++ b/test/integration/generated/lro/src/lro/passthrough.ts @@ -7,15 +7,14 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; export function processPassthroughOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/integration/generated/lro/src/lro/pollingMethod.ts b/test/integration/generated/lro/src/lro/pollingMethod.ts deleted file mode 100644 index cb6482bbde..0000000000 --- a/test/integration/generated/lro/src/lro/pollingMethod.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - OperationArguments, - OperationSpec, - OperationResponseMap -} from "@azure/core-client"; -import { LROMode, LROResult, SendOperationFn } from "./models"; - -export function createPollingMethod( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - mode?: LROMode -): (path?: string) => Promise> { - /** - * Polling calls will always return a status object i.e. {"status": "success"} - * these intermediate responses are not described in the swagger so we need to - * pass custom mappers at runtime. - * This function replaces all the existing mappers to be able to deserialize a status object - * @param responses Original set of responses defined in the operation - */ - function getCompositeMappers(responses: { - [responseCode: string]: OperationResponseMap; - }): { - [responseCode: string]: OperationResponseMap; - } { - return Object.keys(responses).reduce((acc, statusCode) => { - return { - ...acc, - [statusCode]: { - ...responses[statusCode], - bodyMapper: { - type: { - name: "Composite", - modelProperties: { - status: { - serializedName: "status", - type: { - name: "String" - } - } - } - } - } - } - }; - }, {} as { [responseCode: string]: OperationResponseMap }); - } - // Make sure we don't send any body to the get request - const { requestBody, responses, ...restSpec } = spec; - if (mode === "AzureAsync") { - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: getCompositeMappers(responses), - httpMethod: "GET", - ...(path && { path }) - }); - }; - } - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: responses, - httpMethod: "GET", - ...(path && { path }) - }); - }; -} - -export function createRetrieveAzureAsyncResource( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec -): (path?: string) => Promise> { - const updatedArgs = { ...args }; - if (updatedArgs.options) { - (updatedArgs.options as any).shouldDeserialize = true; - } - return createPollingMethod(sendOperationFn, updatedArgs, spec); -} diff --git a/test/integration/generated/lro/src/lro/requestUtils.ts b/test/integration/generated/lro/src/lro/requestUtils.ts index 9162f66339..40d993686f 100644 --- a/test/integration/generated/lro/src/lro/requestUtils.ts +++ b/test/integration/generated/lro/src/lro/requestUtils.ts @@ -7,119 +7,9 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse, OperationSpec } from "@azure/core-client"; -import { LROConfig } from "./models"; -import { terminalStates } from "./stateMachine"; - -/** - * We need to selectively deserialize our responses, only deserializing if we - * are in a final LRO response, not deserializing any polling non-terminal responses - */ -export function shouldDeserializeLRO(finalStateVia?: string) { - let initialOperationInfo: LROResponseInfo | undefined; - let isInitialRequest = true; - - return (response: FullOperationResponse) => { - if (response.status < 200 || response.status >= 300) { - return true; - } - - if (!initialOperationInfo) { - initialOperationInfo = getLROData(response); - } else { - isInitialRequest = false; - } - - if ( - initialOperationInfo.azureAsyncOperation || - initialOperationInfo.operationLocation - ) { - return ( - !isInitialRequest && - isAsyncOperationFinalResponse( - response, - initialOperationInfo, - finalStateVia - ) - ); - } - - if (initialOperationInfo.location) { - return isLocationFinalResponse(response); - } - - if (initialOperationInfo.requestMethod === "PUT") { - return isBodyPollingFinalResponse(response); - } - - return true; - }; -} - -function isAsyncOperationFinalResponse( - response: FullOperationResponse, - initialOperationInfo: LROResponseInfo, - finalStateVia?: string -): boolean { - const status: string = response.parsedBody?.status || "Succeeded"; - if (!terminalStates.includes(status.toLowerCase())) { - return false; - } - - if (initialOperationInfo.requestMethod === "DELETE") { - return true; - } - - if ( - initialOperationInfo.requestMethod === "PUT" && - finalStateVia && - finalStateVia.toLowerCase() === "azure-asyncoperation" - ) { - return true; - } - - if ( - initialOperationInfo.requestMethod !== "PUT" && - !initialOperationInfo.location - ) { - return true; - } - - return false; -} - -function isLocationFinalResponse(response: FullOperationResponse): boolean { - return response.status !== 202; -} - -function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { - const provisioningState: string = - response.parsedBody?.properties?.provisioningState || "Succeeded"; - - if (terminalStates.includes(provisioningState.toLowerCase())) { - return true; - } - - return false; -} - -interface LROResponseInfo { - requestMethod: string; - azureAsyncOperation?: string; - operationLocation?: string; - location?: string; -} - -function getLROData(result: FullOperationResponse): LROResponseInfo { - return { - azureAsyncOperation: result.headers.get("azure-asyncoperation"), - operationLocation: result.headers.get("operation-location"), - location: result.headers.get("location"), - requestMethod: result.request.method - }; -} +import { LroConfig, RawResponse } from "./models"; /** * Detects where the continuation token is and returns it. Notice that azure-asyncoperation @@ -127,45 +17,41 @@ function getLROData(result: FullOperationResponse): LROResponseInfo { * where both azure-asyncoperation and location could be present in the same response but * azure-asyncoperation should be the one to use for polling. */ -export function getPollingURL( - rawResponse: FullOperationResponse, +export function getPollingUrl( + rawResponse: RawResponse, defaultPath: string ): string { return ( - getAzureAsyncoperation(rawResponse) ?? + getAzureAsyncOperation(rawResponse) ?? getLocation(rawResponse) ?? getOperationLocation(rawResponse) ?? defaultPath ); } -function getLocation(rawResponse: FullOperationResponse): string | undefined { - return rawResponse.headers?.get("location"); +function getLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["location"]; } -function getOperationLocation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("operation-location"); +function getOperationLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["operation-location"]; } -function getAzureAsyncoperation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("azure-asyncoperation"); +function getAzureAsyncOperation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["azure-asyncoperation"]; } -export function inferLROMode( - spec: OperationSpec, - rawResponse: FullOperationResponse -): LROConfig { - const requestMethod = spec.httpMethod; - if (getAzureAsyncoperation(rawResponse) !== undefined) { +export function inferLroMode( + requestPath: string, + requestMethod: string, + rawResponse: RawResponse +): LroConfig { + if (getAzureAsyncOperation(rawResponse) !== undefined) { return { mode: "AzureAsync", resourceLocation: requestMethod === "PUT" - ? spec.path + ? requestPath : requestMethod === "POST" ? getLocation(rawResponse) : undefined @@ -185,10 +71,35 @@ export function inferLROMode( return {}; } -export function getSpecPath(spec: OperationSpec): string { - if (spec.path) { - return spec.path; - } else { - throw Error("Bad spec: request path is not found!"); +export class RestError extends Error { + public statusCode?: number; + constructor(message: string, statusCode: number) { + super(message); + this.name = "RestError"; + this.statusCode = statusCode; + + Object.setPrototypeOf(this, RestError.prototype); + } +} + +export function isUnexpectedInitialResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![203, 204, 202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} in the initial response. This may indicate a server issue.`, + code + ); } + return false; +} + +export function isUnexpectedPollingResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} while polling. This may indicate a server issue.`, + code + ); + } + return false; } diff --git a/test/integration/generated/lro/src/lro/stateMachine.ts b/test/integration/generated/lro/src/lro/stateMachine.ts index b2a69b5546..19a8f67470 100644 --- a/test/integration/generated/lro/src/lro/stateMachine.ts +++ b/test/integration/generated/lro/src/lro/stateMachine.ts @@ -7,14 +7,8 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec, - RawResponseCallback -} from "@azure/core-client"; import { processAzureAsyncOperationResult } from "./azureAsyncPolling"; import { isBodyPollingDone, @@ -22,73 +16,36 @@ import { } from "./bodyPolling"; import { processLocationPollingOperationResult } from "./locationPolling"; import { - FinalStateVia, - LROConfig, - LROResult, + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroStatus, PollerConfig, - ResumablePollOperationState, - SendOperationFn + RawResponse, + ResumablePollOperationState } from "./models"; import { processPassthroughOperationResult } from "./passthrough"; import { - createPollingMethod, - createRetrieveAzureAsyncResource -} from "./pollingMethod"; -import { getPollingURL, getSpecPath, inferLROMode } from "./requestUtils"; - -export const successStates = ["succeeded"]; -export const failureStates = ["failed", "canceled", "cancelled"]; -export const terminalStates = successStates.concat(failureStates); - -/** - * The type of a terminal state of an LRO. - */ -interface LROTerminalState extends LROResult { - /** - * Whether the operation has finished. - */ - done: true; -} - -/** - * The type of an in-progress state of an LRO. - */ -interface LROInProgressState extends LROResult { - /** - * Whether the operation has finished. - */ - done: false; - /** - * The request to be sent next if it is different from the standard polling one. - * Notice that it will disregard any polling URLs provided to it. - */ - next?: () => Promise>; -} - -/** - * The type of an LRO state which is a tagged union of terminal and in-progress states. - */ -export type LROState = LROTerminalState | LROInProgressState; + getPollingUrl, + inferLroMode, + isUnexpectedInitialResponse +} from "./requestUtils"; /** * creates a stepping function that maps an LRO state to another. */ -function createTransition( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { +export function createGetLroStatusFromResponse( + lroPrimitives: LongRunningOperation, + config: LroConfig, + lroResourceLocationConfig?: LroResourceLocationConfig +): GetLroStatusFromResponse { switch (config.mode) { case "AzureAsync": { return processAzureAsyncOperationResult( - createRetrieveAzureAsyncResource(sendOperationFn, args, spec), + lroPrimitives, config.resourceLocation, - finalStateVia + lroResourceLocationConfig ); } case "Location": { @@ -106,52 +63,20 @@ function createTransition( /** * Creates a polling operation that returns a LRO state. */ -export function createGetLROState( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia +export function createPollForLROStatus( + lroPrimitives: LongRunningOperation, + config: LroConfig ): ( pollingURL: string, pollerConfig: PollerConfig -) => Promise> { - const step = createTransition( - sendOperationFn, - args, - spec, - config, - finalStateVia - ); - const customerCallback = args?.options?.onResponse; - let response: LROState | undefined = undefined; - let retryAfter: string | undefined = undefined; - const poll = createPollingMethod( - sendOperationFn, - { - ...args, - options: { - ...args.options, - onResponse: ( - rawResponse: FullOperationResponse, - flatResponse: unknown - ): void => { - response = step(rawResponse, flatResponse as TResult); - retryAfter = rawResponse.headers.get("Retry-After"); - if (response.done) { - customerCallback?.(rawResponse, flatResponse); - } - } - } - }, - spec, - config.mode - ); +) => Promise> { return async ( path: string, pollerConfig: PollerConfig - ): Promise> => { - await poll(path); + ): Promise> => { + const response = await lroPrimitives.sendPollRequest(config, path); + const retryAfter: string | undefined = + response.rawResponse.headers["retry-after"]; if (retryAfter !== undefined) { const retryAfterInMs = parseInt(retryAfter); pollerConfig.intervalInMs = isNaN(retryAfterInMs) @@ -161,7 +86,7 @@ export function createGetLROState( ) : retryAfterInMs; } - return response!; + return response; }; } @@ -179,24 +104,26 @@ function calculatePollingIntervalFromDate( /** * Creates a callback to be used to initialize the polling operation state. - * @param state of the polling operation - * @param operationSpec of the LRO - * @param callback callback to be called when the operation is done + * @param state - of the polling operation + * @param operationSpec - of the LRO + * @param callback - callback to be called when the operation is done * @returns callback that initializes the state of the polling operation */ -export function initializeState( +export function createInitializeState( state: ResumablePollOperationState, - operationSpec: OperationSpec, - callback?: RawResponseCallback -): (rawResponse: FullOperationResponse, flatResponse: unknown) => void { - return (rawResponse: FullOperationResponse, flatResponse: unknown) => { + requestPath: string, + requestMethod: string +): (rawResponse: RawResponse, flatResponse: unknown) => boolean { + return (rawResponse: RawResponse, flatResponse: unknown) => { + if (isUnexpectedInitialResponse(rawResponse)) return true; state.initialRawResponse = rawResponse; state.isStarted = true; - state.pollingURL = getPollingURL( - state.initialRawResponse, - getSpecPath(operationSpec) + state.pollingURL = getPollingUrl(state.initialRawResponse, requestPath); + state.config = inferLroMode( + requestPath, + requestMethod, + state.initialRawResponse ); - state.config = inferLROMode(operationSpec, state.initialRawResponse); /** short circuit polling if body polling is done in the initial request */ if ( state.config.mode === undefined || @@ -205,12 +132,7 @@ export function initializeState( ) { state.result = flatResponse as TResult; state.isCompleted = true; - /** - * We need to check if the LRO operation is finished inside the - * call back so that we can call the customer-provided callback - * on that result. - */ - callback?.(rawResponse, flatResponse); } + return Boolean(state.isCompleted); }; } diff --git a/test/integration/generated/lro/src/operations/lRORetrys.ts b/test/integration/generated/lro/src/operations/lRORetrys.ts index dccb8dc475..b2229a49a7 100644 --- a/test/integration/generated/lro/src/operations/lRORetrys.ts +++ b/test/integration/generated/lro/src/operations/lRORetrys.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { LROClientContext } from "../lROClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { LRORetrysPut201CreatingSucceeded200OptionalParams, LRORetrysPut201CreatingSucceeded200Response, @@ -85,15 +86,22 @@ export class LRORetrysImpl implements LRORetrys { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - put201CreatingSucceeded200OperationSpec, - sendOperation + put201CreatingSucceeded200OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -152,15 +160,22 @@ export class LRORetrysImpl implements LRORetrys { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putAsyncRelativeRetrySucceededOperationSpec, - sendOperation + putAsyncRelativeRetrySucceededOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -221,15 +236,22 @@ export class LRORetrysImpl implements LRORetrys { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - deleteProvisioning202Accepted200SucceededOperationSpec, - sendOperation + deleteProvisioning202Accepted200SucceededOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -289,15 +311,22 @@ export class LRORetrysImpl implements LRORetrys { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - delete202Retry200OperationSpec, - sendOperation + delete202Retry200OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -354,15 +383,22 @@ export class LRORetrysImpl implements LRORetrys { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - deleteAsyncRelativeRetrySucceededOperationSpec, - sendOperation + deleteAsyncRelativeRetrySucceededOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -419,15 +455,22 @@ export class LRORetrysImpl implements LRORetrys { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - post202Retry200OperationSpec, - sendOperation + post202Retry200OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -485,15 +528,22 @@ export class LRORetrysImpl implements LRORetrys { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - postAsyncRelativeRetrySucceededOperationSpec, - sendOperation + postAsyncRelativeRetrySucceededOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/integration/generated/lro/src/operations/lROs.ts b/test/integration/generated/lro/src/operations/lROs.ts index a580395603..d583b61ab7 100644 --- a/test/integration/generated/lro/src/operations/lROs.ts +++ b/test/integration/generated/lro/src/operations/lROs.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { LROClientContext } from "../lROClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { LROsPut200SucceededOptionalParams, LROsPut200SucceededResponse, @@ -151,15 +152,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - put200SucceededOperationSpec, - sendOperation + put200SucceededOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -216,15 +224,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - put201SucceededOperationSpec, - sendOperation + put201SucceededOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -281,15 +296,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - post202ListOperationSpec, - sendOperation + post202ListOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -346,15 +368,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - put200SucceededNoStateOperationSpec, - sendOperation + put200SucceededNoStateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -411,15 +440,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - put202Retry200OperationSpec, - sendOperation + put202Retry200OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -477,15 +513,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - put201CreatingSucceeded200OperationSpec, - sendOperation + put201CreatingSucceeded200OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -544,15 +587,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - put200UpdatingSucceeded204OperationSpec, - sendOperation + put200UpdatingSucceeded204OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -611,15 +661,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - put201CreatingFailed200OperationSpec, - sendOperation + put201CreatingFailed200OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -678,15 +735,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - put200Acceptedcanceled200OperationSpec, - sendOperation + put200Acceptedcanceled200OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -744,15 +808,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putNoHeaderInRetryOperationSpec, - sendOperation + putNoHeaderInRetryOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -810,15 +881,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putAsyncRetrySucceededOperationSpec, - sendOperation + putAsyncRetrySucceededOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -877,15 +955,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putAsyncNoRetrySucceededOperationSpec, - sendOperation + putAsyncNoRetrySucceededOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -944,15 +1029,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putAsyncRetryFailedOperationSpec, - sendOperation + putAsyncRetryFailedOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1011,15 +1103,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putAsyncNoRetrycanceledOperationSpec, - sendOperation + putAsyncNoRetrycanceledOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1077,15 +1176,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putAsyncNoHeaderInRetryOperationSpec, - sendOperation + putAsyncNoHeaderInRetryOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1141,15 +1247,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putNonResourceOperationSpec, - sendOperation + putNonResourceOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1204,15 +1317,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putAsyncNonResourceOperationSpec, - sendOperation + putAsyncNonResourceOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1267,15 +1387,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putSubResourceOperationSpec, - sendOperation + putSubResourceOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1330,15 +1457,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putAsyncSubResourceOperationSpec, - sendOperation + putAsyncSubResourceOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1395,15 +1529,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - deleteProvisioning202Accepted200SucceededOperationSpec, - sendOperation + deleteProvisioning202Accepted200SucceededOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1464,15 +1605,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - deleteProvisioning202DeletingFailed200OperationSpec, - sendOperation + deleteProvisioning202DeletingFailed200OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1533,15 +1681,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - deleteProvisioning202Deletingcanceled200OperationSpec, - sendOperation + deleteProvisioning202Deletingcanceled200OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1595,15 +1750,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - delete204SucceededOperationSpec, - sendOperation + delete204SucceededOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1659,15 +1821,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - delete202Retry200OperationSpec, - sendOperation + delete202Retry200OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1724,15 +1893,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - delete202NoRetry204OperationSpec, - sendOperation + delete202NoRetry204OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1789,15 +1965,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - deleteNoHeaderInRetryOperationSpec, - sendOperation + deleteNoHeaderInRetryOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1854,15 +2037,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - deleteAsyncNoHeaderInRetryOperationSpec, - sendOperation + deleteAsyncNoHeaderInRetryOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1919,15 +2109,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - deleteAsyncRetrySucceededOperationSpec, - sendOperation + deleteAsyncRetrySucceededOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1984,15 +2181,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - deleteAsyncNoRetrySucceededOperationSpec, - sendOperation + deleteAsyncNoRetrySucceededOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -2049,15 +2253,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - deleteAsyncRetryFailedOperationSpec, - sendOperation + deleteAsyncRetryFailedOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -2114,15 +2325,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - deleteAsyncRetrycanceledOperationSpec, - sendOperation + deleteAsyncRetrycanceledOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -2179,15 +2397,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - post200WithPayloadOperationSpec, - sendOperation + post200WithPayloadOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -2244,15 +2469,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - post202Retry200OperationSpec, - sendOperation + post202Retry200OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -2309,15 +2541,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - post202NoRetry204OperationSpec, - sendOperation + post202NoRetry204OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -2374,16 +2613,23 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, postDoubleHeadersFinalLocationGetOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -2441,16 +2687,23 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, postDoubleHeadersFinalAzureHeaderGetOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -2513,15 +2766,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - postDoubleHeadersFinalAzureHeaderGetDefaultOperationSpec, - sendOperation + postDoubleHeadersFinalAzureHeaderGetDefaultOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -2582,15 +2842,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - postAsyncRetrySucceededOperationSpec, - sendOperation + postAsyncRetrySucceededOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -2649,15 +2916,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - postAsyncNoRetrySucceededOperationSpec, - sendOperation + postAsyncNoRetrySucceededOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -2716,15 +2990,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - postAsyncRetryFailedOperationSpec, - sendOperation + postAsyncRetryFailedOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -2783,15 +3064,22 @@ export class LROsImpl implements LROs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - postAsyncRetrycanceledOperationSpec, - sendOperation + postAsyncRetrycanceledOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/integration/generated/lro/src/operations/lROsCustomHeader.ts b/test/integration/generated/lro/src/operations/lROsCustomHeader.ts index 7cad76b7d4..89e0f9e0cf 100644 --- a/test/integration/generated/lro/src/operations/lROsCustomHeader.ts +++ b/test/integration/generated/lro/src/operations/lROsCustomHeader.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { LROClientContext } from "../lROClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { LROsCustomHeaderPutAsyncRetrySucceededOptionalParams, LROsCustomHeaderPutAsyncRetrySucceededResponse, @@ -80,15 +81,22 @@ export class LROsCustomHeaderImpl implements LROsCustomHeader { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putAsyncRetrySucceededOperationSpec, - sendOperation + putAsyncRetrySucceededOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -149,15 +157,22 @@ export class LROsCustomHeaderImpl implements LROsCustomHeader { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - put201CreatingSucceeded200OperationSpec, - sendOperation + put201CreatingSucceeded200OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -217,15 +232,22 @@ export class LROsCustomHeaderImpl implements LROsCustomHeader { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - post202Retry200OperationSpec, - sendOperation + post202Retry200OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -285,15 +307,22 @@ export class LROsCustomHeaderImpl implements LROsCustomHeader { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - postAsyncRetrySucceededOperationSpec, - sendOperation + postAsyncRetrySucceededOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/integration/generated/lro/src/operations/lrosaDs.ts b/test/integration/generated/lro/src/operations/lrosaDs.ts index ab3b2cb2d5..ac8be946f5 100644 --- a/test/integration/generated/lro/src/operations/lrosaDs.ts +++ b/test/integration/generated/lro/src/operations/lrosaDs.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { LROClientContext } from "../lROClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { LrosaDsPutNonRetry400OptionalParams, LrosaDsPutNonRetry400Response, @@ -120,15 +121,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putNonRetry400OperationSpec, - sendOperation + putNonRetry400OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -184,15 +192,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putNonRetry201Creating400OperationSpec, - sendOperation + putNonRetry201Creating400OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -249,15 +264,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putNonRetry201Creating400InvalidJsonOperationSpec, - sendOperation + putNonRetry201Creating400InvalidJsonOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -316,15 +338,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putAsyncRelativeRetry400OperationSpec, - sendOperation + putAsyncRelativeRetry400OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -380,15 +409,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - deleteNonRetry400OperationSpec, - sendOperation + deleteNonRetry400OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -443,15 +479,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - delete202NonRetry400OperationSpec, - sendOperation + delete202NonRetry400OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -507,15 +550,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - deleteAsyncRelativeRetry400OperationSpec, - sendOperation + deleteAsyncRelativeRetry400OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -571,15 +621,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - postNonRetry400OperationSpec, - sendOperation + postNonRetry400OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -634,15 +691,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - post202NonRetry400OperationSpec, - sendOperation + post202NonRetry400OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -698,15 +762,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - postAsyncRelativeRetry400OperationSpec, - sendOperation + postAsyncRelativeRetry400OperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -762,15 +833,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putError201NoProvisioningStatePayloadOperationSpec, - sendOperation + putError201NoProvisioningStatePayloadOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -829,15 +907,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putAsyncRelativeRetryNoStatusOperationSpec, - sendOperation + putAsyncRelativeRetryNoStatusOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -896,15 +981,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putAsyncRelativeRetryNoStatusPayloadOperationSpec, - sendOperation + putAsyncRelativeRetryNoStatusPayloadOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -958,15 +1050,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - delete204SucceededOperationSpec, - sendOperation + delete204SucceededOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1022,15 +1121,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - deleteAsyncRelativeRetryNoStatusOperationSpec, - sendOperation + deleteAsyncRelativeRetryNoStatusOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1086,15 +1192,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - post202NoLocationOperationSpec, - sendOperation + post202NoLocationOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1151,15 +1264,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - postAsyncRelativeRetryNoPayloadOperationSpec, - sendOperation + postAsyncRelativeRetryNoPayloadOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1217,15 +1337,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - put200InvalidJsonOperationSpec, - sendOperation + put200InvalidJsonOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1282,15 +1409,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putAsyncRelativeRetryInvalidHeaderOperationSpec, - sendOperation + putAsyncRelativeRetryInvalidHeaderOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1350,15 +1484,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - putAsyncRelativeRetryInvalidJsonPollingOperationSpec, - sendOperation + putAsyncRelativeRetryInvalidJsonPollingOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1418,15 +1559,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - delete202RetryInvalidHeaderOperationSpec, - sendOperation + delete202RetryInvalidHeaderOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1483,15 +1631,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - deleteAsyncRelativeRetryInvalidHeaderOperationSpec, - sendOperation + deleteAsyncRelativeRetryInvalidHeaderOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1552,15 +1707,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - deleteAsyncRelativeRetryInvalidJsonPollingOperationSpec, - sendOperation + deleteAsyncRelativeRetryInvalidJsonPollingOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1619,15 +1781,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - post202RetryInvalidHeaderOperationSpec, - sendOperation + post202RetryInvalidHeaderOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1685,15 +1854,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - postAsyncRelativeRetryInvalidHeaderOperationSpec, - sendOperation + postAsyncRelativeRetryInvalidHeaderOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1754,15 +1930,22 @@ export class LrosaDsImpl implements LrosaDs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - postAsyncRelativeRetryInvalidJsonPollingOperationSpec, - sendOperation + postAsyncRelativeRetryInvalidJsonPollingOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/integration/generated/lroParametrizedEndpoints/src/coreClientLro.ts b/test/integration/generated/lroParametrizedEndpoints/src/coreClientLro.ts new file mode 100644 index 0000000000..d793a24458 --- /dev/null +++ b/test/integration/generated/lroParametrizedEndpoints/src/coreClientLro.ts @@ -0,0 +1,323 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + OperationArguments, + OperationSpec, + OperationResponseMap, + FullOperationResponse +} from "@azure/core-client"; +import { + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + createGetLroStatusFromResponse, + RawResponse +} from "./lro"; + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +export const terminalStates = successStates.concat(failureStates); + +export type SendOperationFn = ( + args: OperationArguments, + spec: OperationSpec +) => Promise>; + +export function createPollingMethod( + sendOperationFn: SendOperationFn, + GetLroStatusFromResponse: GetLroStatusFromResponse, + args: OperationArguments, + spec: OperationSpec, + mode?: LroMode +): (path?: string) => Promise> { + /** + * Polling calls will always return a status object i.e. {"status": "success"} + * these intermediate responses are not described in the swagger so we need to + * pass custom mappers at runtime. + * This function replaces all the existing mappers to be able to deserialize a status object + * @param responses Original set of responses defined in the operation + */ + function getCompositeMappers(responses: { + [responseCode: string]: OperationResponseMap; + }): { + [responseCode: string]: OperationResponseMap; + } { + return Object.keys(responses).reduce((acc, statusCode) => { + return { + ...acc, + [statusCode]: { + ...responses[statusCode], + bodyMapper: { + type: { + name: "Composite", + modelProperties: { + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } + } + } + }; + }, {} as { [responseCode: string]: OperationResponseMap }); + } + let response: LroStatus | undefined = undefined; + const customerCallback = args?.options?.onResponse; + const updatedArgs = { + ...args, + options: { + ...args.options, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ): void => { + response = GetLroStatusFromResponse( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse as TResult + ); + if (response.done) { + customerCallback?.(rawResponse, flatResponse); + } + } + } + }; + // Make sure we don't send any body to the get request + const { requestBody, responses, ...restSpec } = spec; + if (mode === "AzureAsync") { + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: getCompositeMappers(responses), + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; + } + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: responses, + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; +} + +/** + * We need to selectively deserialize our responses, only deserializing if we + * are in a final Lro response, not deserializing any polling non-terminal responses + */ +export function shouldDeserializeLro(lroResourceLocationConfig?: string) { + let initialOperationInfo: LroResponseInfo | undefined; + let isInitialRequest = true; + + return (response: FullOperationResponse) => { + if (response.status < 200 || response.status >= 300) { + return true; + } + + if (!initialOperationInfo) { + initialOperationInfo = getLroData(response); + } else { + isInitialRequest = false; + } + + if ( + initialOperationInfo.azureAsyncOperation || + initialOperationInfo.operationLocation + ) { + return ( + !isInitialRequest && + isAsyncOperationFinalResponse( + response, + initialOperationInfo, + lroResourceLocationConfig + ) + ); + } + + if (initialOperationInfo.location) { + return isLocationFinalResponse(response); + } + + if (initialOperationInfo.requestMethod === "PUT") { + return isBodyPollingFinalResponse(response); + } + + return true; + }; +} + +function isAsyncOperationFinalResponse( + response: FullOperationResponse, + initialOperationInfo: LroResponseInfo, + lroResourceLocationConfig?: string +): boolean { + const status: string = response.parsedBody?.status || "Succeeded"; + if (!terminalStates.includes(status.toLowerCase())) { + return false; + } + + if (initialOperationInfo.requestMethod === "DELETE") { + return true; + } + + if ( + initialOperationInfo.requestMethod === "PUT" && + lroResourceLocationConfig && + lroResourceLocationConfig.toLowerCase() === "azure-asyncoperation" + ) { + return true; + } + + if ( + initialOperationInfo.requestMethod !== "PUT" && + !initialOperationInfo.location + ) { + return true; + } + + return false; +} + +function isLocationFinalResponse(response: FullOperationResponse): boolean { + return response.status !== 202; +} + +function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { + const provisioningState: string = + response.parsedBody?.properties?.provisioningState || "Succeeded"; + + if (terminalStates.includes(provisioningState.toLowerCase())) { + return true; + } + + return false; +} + +interface LroResponseInfo { + requestMethod: string; + azureAsyncOperation?: string; + operationLocation?: string; + location?: string; +} + +function getLroData(result: FullOperationResponse): LroResponseInfo { + return { + azureAsyncOperation: result.headers.get("azure-asyncoperation"), + operationLocation: result.headers.get("operation-location"), + location: result.headers.get("location"), + requestMethod: result.request.method + }; +} + +export function getSpecPath(spec: OperationSpec): string { + if (spec.path) { + return spec.path; + } else { + throw Error("Bad spec: request path is not found!"); + } +} + +export class CoreClientLro implements LongRunningOperation { + constructor( + private sendOperationFn: SendOperationFn, + private args: OperationArguments, + private spec: OperationSpec, + private lroResourceLocationConfig?: LroResourceLocationConfig, + public requestPath: string = spec.path!, + public requestMethod: string = spec.httpMethod + ) {} + public async sendInitialRequest( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ): Promise> { + const { onResponse, ...restOptions } = this.args.options || {}; + return this.sendOperationFn( + { + ...this.args, + options: { + ...restOptions, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ) => { + const isCompleted = initializeState( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse + ); + if (isCompleted) { + onResponse?.(rawResponse, flatResponse); + } + } + } + }, + this.spec + ); + } + + public async sendPollRequest( + config: LroConfig, + path: string + ): Promise> { + const getLroStatusFromResponse = createGetLroStatusFromResponse( + this, + config, + this.lroResourceLocationConfig + ); + return createPollingMethod( + this.sendOperationFn, + getLroStatusFromResponse, + this.args, + this.spec, + config.mode + )(path); + } + + public async retrieveAzureAsyncResource( + path?: string + ): Promise> { + const updatedArgs = { ...this.args }; + if (updatedArgs.options) { + (updatedArgs.options as any).shouldDeserialize = true; + } + return createPollingMethod( + this.sendOperationFn, + (rawResponse, flatResponse) => ({ + rawResponse, + flatResponse, + done: true + }), + updatedArgs, + this.spec + )(path); + } +} diff --git a/test/integration/generated/lroParametrizedEndpoints/src/lro/azureAsyncPolling.ts b/test/integration/generated/lroParametrizedEndpoints/src/lro/azureAsyncPolling.ts index 0d63c54f60..725578a692 100644 --- a/test/integration/generated/lroParametrizedEndpoints/src/lro/azureAsyncPolling.ts +++ b/test/integration/generated/lroParametrizedEndpoints/src/lro/azureAsyncPolling.ts @@ -7,39 +7,61 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { FinalStateVia, LROResult } from "./models"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroResourceLocationConfig, + LongRunningOperation, + LroBody, + LroResponse, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getResponseStatus(rawResponse: FullOperationResponse): string { - const { status } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getResponseStatus(rawResponse: RawResponse): string { + const { status } = (rawResponse.body as LroBody) ?? {}; return status?.toLowerCase() ?? "succeeded"; } -function isAzureAsyncPollingDone(rawResponse: FullOperationResponse) { +function isAzureAsyncPollingDone(rawResponse: RawResponse): boolean { const state = getResponseStatus(rawResponse); - if (failureStates.includes(state)) { + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { throw new Error(`Operation status: ${state}`); } return successStates.includes(state); } +async function sendFinalRequest( + lro: LongRunningOperation, + lroResourceLocationConfig?: LroResourceLocationConfig, + resourceLocation?: string +): Promise | undefined> { + switch (lroResourceLocationConfig) { + case "original-uri": + return lro.retrieveAzureAsyncResource(); + case "azure-async-operation": + return Promise.resolve(undefined); + case "location": + default: + return lro.retrieveAzureAsyncResource(resourceLocation); + } +} + export function processAzureAsyncOperationResult( - restrieveResource: (path?: string) => Promise>, + lro: LongRunningOperation, resourceLocation?: string, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { + lroResourceLocationConfig?: LroResourceLocationConfig +): (rawResponse: RawResponse, flatResponse: TResult) => LroStatus { return ( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult - ): LROState => { + ): LroStatus => { if (isAzureAsyncPollingDone(rawResponse)) { if (resourceLocation === undefined) { return { rawResponse, flatResponse, done: true }; @@ -49,20 +71,11 @@ export function processAzureAsyncOperationResult( flatResponse, done: false, next: async () => { - async function sendFinalRequest(): Promise< - LROResult | undefined - > { - switch (finalStateVia) { - case "original-uri": - return restrieveResource(); - case "azure-async-operation": - return Promise.resolve(undefined); - case "location": - default: - return restrieveResource(resourceLocation); - } - } - const finalResponse = await sendFinalRequest(); + const finalResponse = await sendFinalRequest( + lro, + lroResourceLocationConfig, + resourceLocation + ); return { ...(finalResponse ?? { rawResponse, diff --git a/test/integration/generated/lroParametrizedEndpoints/src/lro/bodyPolling.ts b/test/integration/generated/lroParametrizedEndpoints/src/lro/bodyPolling.ts index 269d8e6799..b1c87f8bc8 100644 --- a/test/integration/generated/lroParametrizedEndpoints/src/lro/bodyPolling.ts +++ b/test/integration/generated/lroParametrizedEndpoints/src/lro/bodyPolling.ts @@ -7,24 +7,33 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroBody, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getProvisioningState(rawResponse: FullOperationResponse): string { - const { properties, provisioningState } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getProvisioningState(rawResponse: RawResponse): string { + const { properties, provisioningState } = (rawResponse.body as LroBody) ?? {}; const state: string | undefined = properties?.provisioningState ?? provisioningState; return state?.toLowerCase() ?? "succeeded"; } -export function isBodyPollingDone(rawResponse: FullOperationResponse) { +export function isBodyPollingDone(rawResponse: RawResponse): boolean { const state = getProvisioningState(rawResponse); - if (failureStates.includes(state)) { - throw new Error(`Provisioning state: ${state}`); + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { + throw new Error( + `The long running operation has failed. The provisioning state: ${state}.` + ); } return successStates.includes(state); } @@ -34,9 +43,9 @@ export function isBodyPollingDone(rawResponse: FullOperationResponse) { * from the result to determine the current operation state */ export function processBodyPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/integration/generated/lroParametrizedEndpoints/src/lro/index.ts b/test/integration/generated/lroParametrizedEndpoints/src/lro/index.ts index 85c2187669..20df608fc8 100644 --- a/test/integration/generated/lroParametrizedEndpoints/src/lro/index.ts +++ b/test/integration/generated/lroParametrizedEndpoints/src/lro/index.ts @@ -6,5 +6,21 @@ * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ -export { shouldDeserializeLRO } from "./requestUtils"; -export { LROPoller } from "./lroPoller"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { LroEngine } from "./lroEngine"; +export { createGetLroStatusFromResponse } from "./stateMachine"; +export { + LroResourceLocationConfig, + GetLroStatusFromResponse, + RawResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + LroTerminalState, + LroInProgressState, + LroEngineOptions +} from "./models"; diff --git a/test/integration/generated/lroParametrizedEndpoints/src/lro/locationPolling.ts b/test/integration/generated/lroParametrizedEndpoints/src/lro/locationPolling.ts index 6fef619384..9d1aadfbde 100644 --- a/test/integration/generated/lroParametrizedEndpoints/src/lro/locationPolling.ts +++ b/test/integration/generated/lroParametrizedEndpoints/src/lro/locationPolling.ts @@ -7,23 +7,21 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function isLocationPollingDone(rawResponse: FullOperationResponse) { - const code = rawResponse.status; - if (![202, 200].includes(code)) { - throw new Error(`Operation failed`); - } - return code !== 202; +function isLocationPollingDone(rawResponse: RawResponse): boolean { + return ( + !isUnexpectedPollingResponse(rawResponse) && rawResponse.statusCode !== 202 + ); } export function processLocationPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/integration/generated/lroParametrizedEndpoints/src/lro/lroEngine.ts b/test/integration/generated/lroParametrizedEndpoints/src/lro/lroEngine.ts new file mode 100644 index 0000000000..85cc15e609 --- /dev/null +++ b/test/integration/generated/lroParametrizedEndpoints/src/lro/lroEngine.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Poller, PollOperationState } from "@azure/core-lro"; +import { + LongRunningOperation, + LroEngineOptions, + ResumablePollOperationState +} from "./models"; +import { GenericPollOperation } from "./operation"; + +/** + * The LRO Engine, a class that performs polling. + */ +export class LroEngine< + TResult, + TState extends PollOperationState +> extends Poller { + private intervalInMs: number; + + constructor(lro: LongRunningOperation, options?: LroEngineOptions) { + const { intervalInMs = 2000, resumeFrom } = options || {}; + function deserializeState( + resumeFrom: string + ): TState & ResumablePollOperationState { + try { + return JSON.parse(resumeFrom).state; + } catch (e) { + throw new Error( + `LroEngine: Unable to deserialize state: ${resumeFrom}` + ); + } + } + const state: TState & ResumablePollOperationState = resumeFrom + ? deserializeState(resumeFrom) + : ({} as any); + + const operation = new GenericPollOperation(state, lro); + super(operation); + + this.intervalInMs = intervalInMs; + operation.setPollerConfig(this as any); + } + + /** + * The method used by the poller to wait before attempting to update its operation. + */ + delay(): Promise { + return new Promise((resolve) => + setTimeout(() => resolve(), this.intervalInMs) + ); + } +} diff --git a/test/integration/generated/lroParametrizedEndpoints/src/lro/lroPoller.ts b/test/integration/generated/lroParametrizedEndpoints/src/lro/lroPoller.ts deleted file mode 100644 index cd1cd64fe8..0000000000 --- a/test/integration/generated/lroParametrizedEndpoints/src/lro/lroPoller.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { Poller, PollOperationState } from "@azure/core-lro"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { FinalStateVia, SendOperationFn } from "./models"; -import { GenericPollOperation } from "./operation"; - -export interface LROPollerOptions { - /** - * Defines how much time the poller is going to wait before making a new request to the service. - */ - intervalInMs?: number; - /** - * A serialized poller which can be used to resume an existing paused Long-Running-Operation. - */ - resumeFrom?: string; -} - -export class LROPoller extends Poller< - PollOperationState, - TResult -> { - private intervalInMs: number; - - constructor( - { intervalInMs = 2000, resumeFrom }: LROPollerOptions, - initialOperationArguments: OperationArguments, - initialOperationSpec: OperationSpec, - sendOperation: SendOperationFn, - finalStateVia?: FinalStateVia - ) { - const state: PollOperationState = resumeFrom - ? JSON.parse(resumeFrom).state - : {}; - - const operation = new GenericPollOperation( - state, - initialOperationArguments, - initialOperationSpec, - sendOperation, - finalStateVia - ); - super(operation); - - this.intervalInMs = intervalInMs; - operation.setPollerConfig(this as any); - } - - /** - * The method used by the poller to wait before attempting to update its operation. - */ - delay(): Promise { - return new Promise((resolve) => - setTimeout(() => resolve(), this.intervalInMs) - ); - } -} diff --git a/test/integration/generated/lroParametrizedEndpoints/src/lro/models.ts b/test/integration/generated/lroParametrizedEndpoints/src/lro/models.ts index a4a5a5abd6..93c3437c8e 100644 --- a/test/integration/generated/lroParametrizedEndpoints/src/lro/models.ts +++ b/test/integration/generated/lroParametrizedEndpoints/src/lro/models.ts @@ -7,46 +7,167 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec -} from "@azure/core-client"; import { PollOperationState } from "@azure/core-lro"; -export type FinalStateVia = +/** + * Options for the LRO poller. + */ +export interface LroEngineOptions { + /** + * Defines how much time the poller is going to wait before making a new request to the service. + */ + intervalInMs?: number; + /** + * A serialized poller which can be used to resume an existing paused Long-Running-Operation. + */ + resumeFrom?: string; +} + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +/** + * The LRO states that signal that the LRO has completed. + */ +export const terminalStates = successStates.concat(failureStates); + +/** + * The potential location of the result of the LRO if specified by the LRO extension in the swagger. + */ +export type LroResourceLocationConfig = | "azure-async-operation" | "location" | "original-uri"; -export interface LROResult { +/** + * The type of a LRO response body. This is just a convenience type for checking the status of the operation. + */ + +export interface LroBody extends Record { + /** The status of the operation. */ + status?: string; + /** The state of the provisioning process */ + provisioningState?: string; + /** The properties of the provisioning process */ + properties?: { provisioningState?: string } & Record; +} + +/** + * Simple type of the raw response. + */ +export interface RawResponse { + /** The HTTP status code */ + statusCode: number; + /** A HttpHeaders collection in the response represented as a simple JSON object where all header names have been normalized to be lower-case. */ + headers: { + [headerName: string]: string; + }; + /** The parsed response body */ + body?: unknown; +} + +/** + * The type of the response of a LRO. + */ +export interface LroResponse { + /** The flattened response */ flatResponse: T; - rawResponse: FullOperationResponse; + /** The raw response */ + rawResponse: RawResponse; } -export type LROMode = "AzureAsync" | "Location" | "Body"; +/** The type of which LRO implementation being followed by a specific API. */ +export type LroMode = "AzureAsync" | "Location" | "Body"; -export interface LROConfig { - mode?: LROMode; +/** + * The configuration of a LRO to determine how to perform polling and checking whether the operation has completed. + */ +export interface LroConfig { + /** The LRO mode */ + mode?: LroMode; + /** The path of a provisioned resource */ resourceLocation?: string; } -export type SendOperationFn = ( - args: OperationArguments, - spec: OperationSpec -) => Promise>; - /** * Type of a polling operation state that can actually be resumed. */ export type ResumablePollOperationState = PollOperationState & { - initialRawResponse?: FullOperationResponse; - config?: LROConfig; + initialRawResponse?: RawResponse; + config?: LroConfig; pollingURL?: string; }; export interface PollerConfig { intervalInMs: number; } + +/** + * The type of a terminal state of an LRO. + */ +export interface LroTerminalState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: true; +} + +/** + * The type of an in-progress state of an LRO. + */ +export interface LroInProgressState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: false; + /** + * The request to be sent next if it is different from the standard polling one. + * Notice that it will disregard any polling URLs provided to it. + */ + next?: () => Promise>; +} + +/** + * The type of an LRO state which is a tagged union of terminal and in-progress states. + */ +export type LroStatus = LroTerminalState | LroInProgressState; + +/** + * The type of the getLROStatusFromResponse method. It takes the response as input and returns along the response whether the operation has finished. + */ +export type GetLroStatusFromResponse = ( + rawResponse: RawResponse, + flatResponse: T +) => LroStatus; + +/** + * Description of a long running operation. + */ +export interface LongRunningOperation { + /** + * The request path. + */ + requestPath: string; + /** + * The HTTP request method. + */ + requestMethod: string; + /** + * A function that can be used to send initial request to the service. + */ + sendInitialRequest: ( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ) => Promise>; + /** + * A function that can be used to poll for the current status of a long running operation. + */ + sendPollRequest: (config: LroConfig, path: string) => Promise>; + /** + * A function that can be used to retrieve the provisioned azure resource. + */ + retrieveAzureAsyncResource: (path?: string) => Promise>; +} diff --git a/test/integration/generated/lroParametrizedEndpoints/src/lro/operation.ts b/test/integration/generated/lroParametrizedEndpoints/src/lro/operation.ts index 801d03e720..3ea7b76d89 100644 --- a/test/integration/generated/lroParametrizedEndpoints/src/lro/operation.ts +++ b/test/integration/generated/lroParametrizedEndpoints/src/lro/operation.ts @@ -7,36 +7,34 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. import { AbortSignalLike } from "@azure/abort-controller"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { PollOperation, PollOperationState } from "@azure/core-lro"; +import { PollOperationState, PollOperation } from "@azure/core-lro"; import { - FinalStateVia, PollerConfig, ResumablePollOperationState, - SendOperationFn + LongRunningOperation, + LroStatus } from "./models"; -import { getPollingURL } from "./requestUtils"; -import { createGetLROState, initializeState, LROState } from "./stateMachine"; +import { getPollingUrl } from "./requestUtils"; +import { createInitializeState, createPollForLROStatus } from "./stateMachine"; -export class GenericPollOperation - implements PollOperation, TResult> { - private getLROState?: ( +export class GenericPollOperation< + TResult, + TState extends PollOperationState +> implements PollOperation { + private getLROStatusFromResponse?: ( pollingURL: string, pollerConfig: PollerConfig - ) => Promise>; + ) => Promise>; private pollerConfig?: PollerConfig; constructor( - public state: PollOperationState, - private initialOperationArguments: OperationArguments, - private initialOperationSpec: OperationSpec, - private sendOperation: SendOperationFn, - private finalStateVia?: FinalStateVia + public state: TState & ResumablePollOperationState, + private lro: LongRunningOperation ) {} - public setPollerConfig(pollerConfig: PollerConfig) { + public setPollerConfig(pollerConfig: PollerConfig): void { this.pollerConfig = pollerConfig; } @@ -57,45 +55,36 @@ export class GenericPollOperation */ async update(options?: { abortSignal?: AbortSignalLike | undefined; - fireProgress?: ((state: PollOperationState) => void) | undefined; - }): Promise, TResult>> { - const state = this.state as ResumablePollOperationState; - const { onResponse, ...restOptions } = - this.initialOperationArguments.options || {}; + fireProgress?: ((state: TState) => void) | undefined; + }): Promise> { + const state = this.state; if (!state.isStarted) { - await this.sendOperation( - { - ...this.initialOperationArguments, - options: { - ...restOptions, - onResponse: initializeState( - state, - this.initialOperationSpec, - onResponse - ) - } - }, - this.initialOperationSpec + const initializeState = createInitializeState( + state, + this.lro.requestPath, + this.lro.requestMethod ); + await this.lro.sendInitialRequest(initializeState); } if (!state.isCompleted) { - if (this.getLROState === undefined) { + if (this.getLROStatusFromResponse === undefined) { if (state.config === undefined) { - throw new Error("Bad state: LRO mode is undefined"); + throw new Error( + "Bad state: LRO mode is undefined. Please check if the serialized state is well-formed." + ); } - this.getLROState = createGetLROState( - this.sendOperation, - this.initialOperationArguments, - this.initialOperationSpec, - state.config, - this.finalStateVia + this.getLROStatusFromResponse = createPollForLROStatus( + this.lro, + state.config ); } if (state.pollingURL === undefined) { - throw new Error("Bad state: polling URL is undefined"); + throw new Error( + "Bad state: polling URL is undefined. Please check if the serialized state is well-formed." + ); } - const currentState = await this.getLROState( + const currentState = await this.getLROStatusFromResponse( state.pollingURL, this.pollerConfig! ); @@ -103,20 +92,19 @@ export class GenericPollOperation state.result = currentState.flatResponse; state.isCompleted = true; } else { - this.getLROState = currentState.next ?? this.getLROState; - state.pollingURL = getPollingURL( + this.getLROStatusFromResponse = + currentState.next ?? this.getLROStatusFromResponse; + state.pollingURL = getPollingUrl( currentState.rawResponse, state.pollingURL ); } } - if (options?.fireProgress !== undefined) { - options.fireProgress(state); - } + options?.fireProgress?.(state); return this; } - async cancel(): Promise, TResult>> { + async cancel(): Promise> { this.state.isCancelled = true; return this; } diff --git a/test/integration/generated/lroParametrizedEndpoints/src/lro/passthrough.ts b/test/integration/generated/lroParametrizedEndpoints/src/lro/passthrough.ts index 64c10380c1..ae7f87d384 100644 --- a/test/integration/generated/lroParametrizedEndpoints/src/lro/passthrough.ts +++ b/test/integration/generated/lroParametrizedEndpoints/src/lro/passthrough.ts @@ -7,15 +7,14 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; export function processPassthroughOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/integration/generated/lroParametrizedEndpoints/src/lro/pollingMethod.ts b/test/integration/generated/lroParametrizedEndpoints/src/lro/pollingMethod.ts deleted file mode 100644 index cb6482bbde..0000000000 --- a/test/integration/generated/lroParametrizedEndpoints/src/lro/pollingMethod.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - OperationArguments, - OperationSpec, - OperationResponseMap -} from "@azure/core-client"; -import { LROMode, LROResult, SendOperationFn } from "./models"; - -export function createPollingMethod( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - mode?: LROMode -): (path?: string) => Promise> { - /** - * Polling calls will always return a status object i.e. {"status": "success"} - * these intermediate responses are not described in the swagger so we need to - * pass custom mappers at runtime. - * This function replaces all the existing mappers to be able to deserialize a status object - * @param responses Original set of responses defined in the operation - */ - function getCompositeMappers(responses: { - [responseCode: string]: OperationResponseMap; - }): { - [responseCode: string]: OperationResponseMap; - } { - return Object.keys(responses).reduce((acc, statusCode) => { - return { - ...acc, - [statusCode]: { - ...responses[statusCode], - bodyMapper: { - type: { - name: "Composite", - modelProperties: { - status: { - serializedName: "status", - type: { - name: "String" - } - } - } - } - } - } - }; - }, {} as { [responseCode: string]: OperationResponseMap }); - } - // Make sure we don't send any body to the get request - const { requestBody, responses, ...restSpec } = spec; - if (mode === "AzureAsync") { - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: getCompositeMappers(responses), - httpMethod: "GET", - ...(path && { path }) - }); - }; - } - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: responses, - httpMethod: "GET", - ...(path && { path }) - }); - }; -} - -export function createRetrieveAzureAsyncResource( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec -): (path?: string) => Promise> { - const updatedArgs = { ...args }; - if (updatedArgs.options) { - (updatedArgs.options as any).shouldDeserialize = true; - } - return createPollingMethod(sendOperationFn, updatedArgs, spec); -} diff --git a/test/integration/generated/lroParametrizedEndpoints/src/lro/requestUtils.ts b/test/integration/generated/lroParametrizedEndpoints/src/lro/requestUtils.ts index 9162f66339..40d993686f 100644 --- a/test/integration/generated/lroParametrizedEndpoints/src/lro/requestUtils.ts +++ b/test/integration/generated/lroParametrizedEndpoints/src/lro/requestUtils.ts @@ -7,119 +7,9 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse, OperationSpec } from "@azure/core-client"; -import { LROConfig } from "./models"; -import { terminalStates } from "./stateMachine"; - -/** - * We need to selectively deserialize our responses, only deserializing if we - * are in a final LRO response, not deserializing any polling non-terminal responses - */ -export function shouldDeserializeLRO(finalStateVia?: string) { - let initialOperationInfo: LROResponseInfo | undefined; - let isInitialRequest = true; - - return (response: FullOperationResponse) => { - if (response.status < 200 || response.status >= 300) { - return true; - } - - if (!initialOperationInfo) { - initialOperationInfo = getLROData(response); - } else { - isInitialRequest = false; - } - - if ( - initialOperationInfo.azureAsyncOperation || - initialOperationInfo.operationLocation - ) { - return ( - !isInitialRequest && - isAsyncOperationFinalResponse( - response, - initialOperationInfo, - finalStateVia - ) - ); - } - - if (initialOperationInfo.location) { - return isLocationFinalResponse(response); - } - - if (initialOperationInfo.requestMethod === "PUT") { - return isBodyPollingFinalResponse(response); - } - - return true; - }; -} - -function isAsyncOperationFinalResponse( - response: FullOperationResponse, - initialOperationInfo: LROResponseInfo, - finalStateVia?: string -): boolean { - const status: string = response.parsedBody?.status || "Succeeded"; - if (!terminalStates.includes(status.toLowerCase())) { - return false; - } - - if (initialOperationInfo.requestMethod === "DELETE") { - return true; - } - - if ( - initialOperationInfo.requestMethod === "PUT" && - finalStateVia && - finalStateVia.toLowerCase() === "azure-asyncoperation" - ) { - return true; - } - - if ( - initialOperationInfo.requestMethod !== "PUT" && - !initialOperationInfo.location - ) { - return true; - } - - return false; -} - -function isLocationFinalResponse(response: FullOperationResponse): boolean { - return response.status !== 202; -} - -function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { - const provisioningState: string = - response.parsedBody?.properties?.provisioningState || "Succeeded"; - - if (terminalStates.includes(provisioningState.toLowerCase())) { - return true; - } - - return false; -} - -interface LROResponseInfo { - requestMethod: string; - azureAsyncOperation?: string; - operationLocation?: string; - location?: string; -} - -function getLROData(result: FullOperationResponse): LROResponseInfo { - return { - azureAsyncOperation: result.headers.get("azure-asyncoperation"), - operationLocation: result.headers.get("operation-location"), - location: result.headers.get("location"), - requestMethod: result.request.method - }; -} +import { LroConfig, RawResponse } from "./models"; /** * Detects where the continuation token is and returns it. Notice that azure-asyncoperation @@ -127,45 +17,41 @@ function getLROData(result: FullOperationResponse): LROResponseInfo { * where both azure-asyncoperation and location could be present in the same response but * azure-asyncoperation should be the one to use for polling. */ -export function getPollingURL( - rawResponse: FullOperationResponse, +export function getPollingUrl( + rawResponse: RawResponse, defaultPath: string ): string { return ( - getAzureAsyncoperation(rawResponse) ?? + getAzureAsyncOperation(rawResponse) ?? getLocation(rawResponse) ?? getOperationLocation(rawResponse) ?? defaultPath ); } -function getLocation(rawResponse: FullOperationResponse): string | undefined { - return rawResponse.headers?.get("location"); +function getLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["location"]; } -function getOperationLocation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("operation-location"); +function getOperationLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["operation-location"]; } -function getAzureAsyncoperation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("azure-asyncoperation"); +function getAzureAsyncOperation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["azure-asyncoperation"]; } -export function inferLROMode( - spec: OperationSpec, - rawResponse: FullOperationResponse -): LROConfig { - const requestMethod = spec.httpMethod; - if (getAzureAsyncoperation(rawResponse) !== undefined) { +export function inferLroMode( + requestPath: string, + requestMethod: string, + rawResponse: RawResponse +): LroConfig { + if (getAzureAsyncOperation(rawResponse) !== undefined) { return { mode: "AzureAsync", resourceLocation: requestMethod === "PUT" - ? spec.path + ? requestPath : requestMethod === "POST" ? getLocation(rawResponse) : undefined @@ -185,10 +71,35 @@ export function inferLROMode( return {}; } -export function getSpecPath(spec: OperationSpec): string { - if (spec.path) { - return spec.path; - } else { - throw Error("Bad spec: request path is not found!"); +export class RestError extends Error { + public statusCode?: number; + constructor(message: string, statusCode: number) { + super(message); + this.name = "RestError"; + this.statusCode = statusCode; + + Object.setPrototypeOf(this, RestError.prototype); + } +} + +export function isUnexpectedInitialResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![203, 204, 202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} in the initial response. This may indicate a server issue.`, + code + ); } + return false; +} + +export function isUnexpectedPollingResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} while polling. This may indicate a server issue.`, + code + ); + } + return false; } diff --git a/test/integration/generated/lroParametrizedEndpoints/src/lro/stateMachine.ts b/test/integration/generated/lroParametrizedEndpoints/src/lro/stateMachine.ts index b2a69b5546..19a8f67470 100644 --- a/test/integration/generated/lroParametrizedEndpoints/src/lro/stateMachine.ts +++ b/test/integration/generated/lroParametrizedEndpoints/src/lro/stateMachine.ts @@ -7,14 +7,8 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec, - RawResponseCallback -} from "@azure/core-client"; import { processAzureAsyncOperationResult } from "./azureAsyncPolling"; import { isBodyPollingDone, @@ -22,73 +16,36 @@ import { } from "./bodyPolling"; import { processLocationPollingOperationResult } from "./locationPolling"; import { - FinalStateVia, - LROConfig, - LROResult, + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroStatus, PollerConfig, - ResumablePollOperationState, - SendOperationFn + RawResponse, + ResumablePollOperationState } from "./models"; import { processPassthroughOperationResult } from "./passthrough"; import { - createPollingMethod, - createRetrieveAzureAsyncResource -} from "./pollingMethod"; -import { getPollingURL, getSpecPath, inferLROMode } from "./requestUtils"; - -export const successStates = ["succeeded"]; -export const failureStates = ["failed", "canceled", "cancelled"]; -export const terminalStates = successStates.concat(failureStates); - -/** - * The type of a terminal state of an LRO. - */ -interface LROTerminalState extends LROResult { - /** - * Whether the operation has finished. - */ - done: true; -} - -/** - * The type of an in-progress state of an LRO. - */ -interface LROInProgressState extends LROResult { - /** - * Whether the operation has finished. - */ - done: false; - /** - * The request to be sent next if it is different from the standard polling one. - * Notice that it will disregard any polling URLs provided to it. - */ - next?: () => Promise>; -} - -/** - * The type of an LRO state which is a tagged union of terminal and in-progress states. - */ -export type LROState = LROTerminalState | LROInProgressState; + getPollingUrl, + inferLroMode, + isUnexpectedInitialResponse +} from "./requestUtils"; /** * creates a stepping function that maps an LRO state to another. */ -function createTransition( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { +export function createGetLroStatusFromResponse( + lroPrimitives: LongRunningOperation, + config: LroConfig, + lroResourceLocationConfig?: LroResourceLocationConfig +): GetLroStatusFromResponse { switch (config.mode) { case "AzureAsync": { return processAzureAsyncOperationResult( - createRetrieveAzureAsyncResource(sendOperationFn, args, spec), + lroPrimitives, config.resourceLocation, - finalStateVia + lroResourceLocationConfig ); } case "Location": { @@ -106,52 +63,20 @@ function createTransition( /** * Creates a polling operation that returns a LRO state. */ -export function createGetLROState( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia +export function createPollForLROStatus( + lroPrimitives: LongRunningOperation, + config: LroConfig ): ( pollingURL: string, pollerConfig: PollerConfig -) => Promise> { - const step = createTransition( - sendOperationFn, - args, - spec, - config, - finalStateVia - ); - const customerCallback = args?.options?.onResponse; - let response: LROState | undefined = undefined; - let retryAfter: string | undefined = undefined; - const poll = createPollingMethod( - sendOperationFn, - { - ...args, - options: { - ...args.options, - onResponse: ( - rawResponse: FullOperationResponse, - flatResponse: unknown - ): void => { - response = step(rawResponse, flatResponse as TResult); - retryAfter = rawResponse.headers.get("Retry-After"); - if (response.done) { - customerCallback?.(rawResponse, flatResponse); - } - } - } - }, - spec, - config.mode - ); +) => Promise> { return async ( path: string, pollerConfig: PollerConfig - ): Promise> => { - await poll(path); + ): Promise> => { + const response = await lroPrimitives.sendPollRequest(config, path); + const retryAfter: string | undefined = + response.rawResponse.headers["retry-after"]; if (retryAfter !== undefined) { const retryAfterInMs = parseInt(retryAfter); pollerConfig.intervalInMs = isNaN(retryAfterInMs) @@ -161,7 +86,7 @@ export function createGetLROState( ) : retryAfterInMs; } - return response!; + return response; }; } @@ -179,24 +104,26 @@ function calculatePollingIntervalFromDate( /** * Creates a callback to be used to initialize the polling operation state. - * @param state of the polling operation - * @param operationSpec of the LRO - * @param callback callback to be called when the operation is done + * @param state - of the polling operation + * @param operationSpec - of the LRO + * @param callback - callback to be called when the operation is done * @returns callback that initializes the state of the polling operation */ -export function initializeState( +export function createInitializeState( state: ResumablePollOperationState, - operationSpec: OperationSpec, - callback?: RawResponseCallback -): (rawResponse: FullOperationResponse, flatResponse: unknown) => void { - return (rawResponse: FullOperationResponse, flatResponse: unknown) => { + requestPath: string, + requestMethod: string +): (rawResponse: RawResponse, flatResponse: unknown) => boolean { + return (rawResponse: RawResponse, flatResponse: unknown) => { + if (isUnexpectedInitialResponse(rawResponse)) return true; state.initialRawResponse = rawResponse; state.isStarted = true; - state.pollingURL = getPollingURL( - state.initialRawResponse, - getSpecPath(operationSpec) + state.pollingURL = getPollingUrl(state.initialRawResponse, requestPath); + state.config = inferLroMode( + requestPath, + requestMethod, + state.initialRawResponse ); - state.config = inferLROMode(operationSpec, state.initialRawResponse); /** short circuit polling if body polling is done in the initial request */ if ( state.config.mode === undefined || @@ -205,12 +132,7 @@ export function initializeState( ) { state.result = flatResponse as TResult; state.isCompleted = true; - /** - * We need to check if the LRO operation is finished inside the - * call back so that we can call the customer-provided callback - * on that result. - */ - callback?.(rawResponse, flatResponse); } + return Boolean(state.isCompleted); }; } diff --git a/test/integration/generated/lroParametrizedEndpoints/src/lroParametrizedEndpointsClient.ts b/test/integration/generated/lroParametrizedEndpoints/src/lroParametrizedEndpointsClient.ts index 73093e522f..9108a2d999 100644 --- a/test/integration/generated/lroParametrizedEndpoints/src/lroParametrizedEndpointsClient.ts +++ b/test/integration/generated/lroParametrizedEndpoints/src/lroParametrizedEndpointsClient.ts @@ -7,8 +7,9 @@ */ import * as coreClient from "@azure/core-client"; -import { LROPoller, shouldDeserializeLRO } from "./lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "./lro"; +import { CoreClientLro, shouldDeserializeLro } from "./coreClientLro"; import * as Parameters from "./models/parameters"; import * as Mappers from "./models/mappers"; import { LroParametrizedEndpointsClientContext } from "./lroParametrizedEndpointsClientContext"; @@ -72,16 +73,23 @@ export class LroParametrizedEndpointsClient extends LroParametrizedEndpointsClie } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { accountName, options }, pollWithParameterizedEndpointsOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/integration/generated/mediaTypesV3Lro/src/coreClientLro.ts b/test/integration/generated/mediaTypesV3Lro/src/coreClientLro.ts new file mode 100644 index 0000000000..d793a24458 --- /dev/null +++ b/test/integration/generated/mediaTypesV3Lro/src/coreClientLro.ts @@ -0,0 +1,323 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + OperationArguments, + OperationSpec, + OperationResponseMap, + FullOperationResponse +} from "@azure/core-client"; +import { + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + createGetLroStatusFromResponse, + RawResponse +} from "./lro"; + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +export const terminalStates = successStates.concat(failureStates); + +export type SendOperationFn = ( + args: OperationArguments, + spec: OperationSpec +) => Promise>; + +export function createPollingMethod( + sendOperationFn: SendOperationFn, + GetLroStatusFromResponse: GetLroStatusFromResponse, + args: OperationArguments, + spec: OperationSpec, + mode?: LroMode +): (path?: string) => Promise> { + /** + * Polling calls will always return a status object i.e. {"status": "success"} + * these intermediate responses are not described in the swagger so we need to + * pass custom mappers at runtime. + * This function replaces all the existing mappers to be able to deserialize a status object + * @param responses Original set of responses defined in the operation + */ + function getCompositeMappers(responses: { + [responseCode: string]: OperationResponseMap; + }): { + [responseCode: string]: OperationResponseMap; + } { + return Object.keys(responses).reduce((acc, statusCode) => { + return { + ...acc, + [statusCode]: { + ...responses[statusCode], + bodyMapper: { + type: { + name: "Composite", + modelProperties: { + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } + } + } + }; + }, {} as { [responseCode: string]: OperationResponseMap }); + } + let response: LroStatus | undefined = undefined; + const customerCallback = args?.options?.onResponse; + const updatedArgs = { + ...args, + options: { + ...args.options, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ): void => { + response = GetLroStatusFromResponse( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse as TResult + ); + if (response.done) { + customerCallback?.(rawResponse, flatResponse); + } + } + } + }; + // Make sure we don't send any body to the get request + const { requestBody, responses, ...restSpec } = spec; + if (mode === "AzureAsync") { + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: getCompositeMappers(responses), + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; + } + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: responses, + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; +} + +/** + * We need to selectively deserialize our responses, only deserializing if we + * are in a final Lro response, not deserializing any polling non-terminal responses + */ +export function shouldDeserializeLro(lroResourceLocationConfig?: string) { + let initialOperationInfo: LroResponseInfo | undefined; + let isInitialRequest = true; + + return (response: FullOperationResponse) => { + if (response.status < 200 || response.status >= 300) { + return true; + } + + if (!initialOperationInfo) { + initialOperationInfo = getLroData(response); + } else { + isInitialRequest = false; + } + + if ( + initialOperationInfo.azureAsyncOperation || + initialOperationInfo.operationLocation + ) { + return ( + !isInitialRequest && + isAsyncOperationFinalResponse( + response, + initialOperationInfo, + lroResourceLocationConfig + ) + ); + } + + if (initialOperationInfo.location) { + return isLocationFinalResponse(response); + } + + if (initialOperationInfo.requestMethod === "PUT") { + return isBodyPollingFinalResponse(response); + } + + return true; + }; +} + +function isAsyncOperationFinalResponse( + response: FullOperationResponse, + initialOperationInfo: LroResponseInfo, + lroResourceLocationConfig?: string +): boolean { + const status: string = response.parsedBody?.status || "Succeeded"; + if (!terminalStates.includes(status.toLowerCase())) { + return false; + } + + if (initialOperationInfo.requestMethod === "DELETE") { + return true; + } + + if ( + initialOperationInfo.requestMethod === "PUT" && + lroResourceLocationConfig && + lroResourceLocationConfig.toLowerCase() === "azure-asyncoperation" + ) { + return true; + } + + if ( + initialOperationInfo.requestMethod !== "PUT" && + !initialOperationInfo.location + ) { + return true; + } + + return false; +} + +function isLocationFinalResponse(response: FullOperationResponse): boolean { + return response.status !== 202; +} + +function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { + const provisioningState: string = + response.parsedBody?.properties?.provisioningState || "Succeeded"; + + if (terminalStates.includes(provisioningState.toLowerCase())) { + return true; + } + + return false; +} + +interface LroResponseInfo { + requestMethod: string; + azureAsyncOperation?: string; + operationLocation?: string; + location?: string; +} + +function getLroData(result: FullOperationResponse): LroResponseInfo { + return { + azureAsyncOperation: result.headers.get("azure-asyncoperation"), + operationLocation: result.headers.get("operation-location"), + location: result.headers.get("location"), + requestMethod: result.request.method + }; +} + +export function getSpecPath(spec: OperationSpec): string { + if (spec.path) { + return spec.path; + } else { + throw Error("Bad spec: request path is not found!"); + } +} + +export class CoreClientLro implements LongRunningOperation { + constructor( + private sendOperationFn: SendOperationFn, + private args: OperationArguments, + private spec: OperationSpec, + private lroResourceLocationConfig?: LroResourceLocationConfig, + public requestPath: string = spec.path!, + public requestMethod: string = spec.httpMethod + ) {} + public async sendInitialRequest( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ): Promise> { + const { onResponse, ...restOptions } = this.args.options || {}; + return this.sendOperationFn( + { + ...this.args, + options: { + ...restOptions, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ) => { + const isCompleted = initializeState( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse + ); + if (isCompleted) { + onResponse?.(rawResponse, flatResponse); + } + } + } + }, + this.spec + ); + } + + public async sendPollRequest( + config: LroConfig, + path: string + ): Promise> { + const getLroStatusFromResponse = createGetLroStatusFromResponse( + this, + config, + this.lroResourceLocationConfig + ); + return createPollingMethod( + this.sendOperationFn, + getLroStatusFromResponse, + this.args, + this.spec, + config.mode + )(path); + } + + public async retrieveAzureAsyncResource( + path?: string + ): Promise> { + const updatedArgs = { ...this.args }; + if (updatedArgs.options) { + (updatedArgs.options as any).shouldDeserialize = true; + } + return createPollingMethod( + this.sendOperationFn, + (rawResponse, flatResponse) => ({ + rawResponse, + flatResponse, + done: true + }), + updatedArgs, + this.spec + )(path); + } +} diff --git a/test/integration/generated/mediaTypesV3Lro/src/lro/azureAsyncPolling.ts b/test/integration/generated/mediaTypesV3Lro/src/lro/azureAsyncPolling.ts index 0d63c54f60..725578a692 100644 --- a/test/integration/generated/mediaTypesV3Lro/src/lro/azureAsyncPolling.ts +++ b/test/integration/generated/mediaTypesV3Lro/src/lro/azureAsyncPolling.ts @@ -7,39 +7,61 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { FinalStateVia, LROResult } from "./models"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroResourceLocationConfig, + LongRunningOperation, + LroBody, + LroResponse, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getResponseStatus(rawResponse: FullOperationResponse): string { - const { status } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getResponseStatus(rawResponse: RawResponse): string { + const { status } = (rawResponse.body as LroBody) ?? {}; return status?.toLowerCase() ?? "succeeded"; } -function isAzureAsyncPollingDone(rawResponse: FullOperationResponse) { +function isAzureAsyncPollingDone(rawResponse: RawResponse): boolean { const state = getResponseStatus(rawResponse); - if (failureStates.includes(state)) { + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { throw new Error(`Operation status: ${state}`); } return successStates.includes(state); } +async function sendFinalRequest( + lro: LongRunningOperation, + lroResourceLocationConfig?: LroResourceLocationConfig, + resourceLocation?: string +): Promise | undefined> { + switch (lroResourceLocationConfig) { + case "original-uri": + return lro.retrieveAzureAsyncResource(); + case "azure-async-operation": + return Promise.resolve(undefined); + case "location": + default: + return lro.retrieveAzureAsyncResource(resourceLocation); + } +} + export function processAzureAsyncOperationResult( - restrieveResource: (path?: string) => Promise>, + lro: LongRunningOperation, resourceLocation?: string, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { + lroResourceLocationConfig?: LroResourceLocationConfig +): (rawResponse: RawResponse, flatResponse: TResult) => LroStatus { return ( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult - ): LROState => { + ): LroStatus => { if (isAzureAsyncPollingDone(rawResponse)) { if (resourceLocation === undefined) { return { rawResponse, flatResponse, done: true }; @@ -49,20 +71,11 @@ export function processAzureAsyncOperationResult( flatResponse, done: false, next: async () => { - async function sendFinalRequest(): Promise< - LROResult | undefined - > { - switch (finalStateVia) { - case "original-uri": - return restrieveResource(); - case "azure-async-operation": - return Promise.resolve(undefined); - case "location": - default: - return restrieveResource(resourceLocation); - } - } - const finalResponse = await sendFinalRequest(); + const finalResponse = await sendFinalRequest( + lro, + lroResourceLocationConfig, + resourceLocation + ); return { ...(finalResponse ?? { rawResponse, diff --git a/test/integration/generated/mediaTypesV3Lro/src/lro/bodyPolling.ts b/test/integration/generated/mediaTypesV3Lro/src/lro/bodyPolling.ts index 269d8e6799..b1c87f8bc8 100644 --- a/test/integration/generated/mediaTypesV3Lro/src/lro/bodyPolling.ts +++ b/test/integration/generated/mediaTypesV3Lro/src/lro/bodyPolling.ts @@ -7,24 +7,33 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroBody, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getProvisioningState(rawResponse: FullOperationResponse): string { - const { properties, provisioningState } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getProvisioningState(rawResponse: RawResponse): string { + const { properties, provisioningState } = (rawResponse.body as LroBody) ?? {}; const state: string | undefined = properties?.provisioningState ?? provisioningState; return state?.toLowerCase() ?? "succeeded"; } -export function isBodyPollingDone(rawResponse: FullOperationResponse) { +export function isBodyPollingDone(rawResponse: RawResponse): boolean { const state = getProvisioningState(rawResponse); - if (failureStates.includes(state)) { - throw new Error(`Provisioning state: ${state}`); + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { + throw new Error( + `The long running operation has failed. The provisioning state: ${state}.` + ); } return successStates.includes(state); } @@ -34,9 +43,9 @@ export function isBodyPollingDone(rawResponse: FullOperationResponse) { * from the result to determine the current operation state */ export function processBodyPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/integration/generated/mediaTypesV3Lro/src/lro/index.ts b/test/integration/generated/mediaTypesV3Lro/src/lro/index.ts index 85c2187669..20df608fc8 100644 --- a/test/integration/generated/mediaTypesV3Lro/src/lro/index.ts +++ b/test/integration/generated/mediaTypesV3Lro/src/lro/index.ts @@ -6,5 +6,21 @@ * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ -export { shouldDeserializeLRO } from "./requestUtils"; -export { LROPoller } from "./lroPoller"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { LroEngine } from "./lroEngine"; +export { createGetLroStatusFromResponse } from "./stateMachine"; +export { + LroResourceLocationConfig, + GetLroStatusFromResponse, + RawResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + LroTerminalState, + LroInProgressState, + LroEngineOptions +} from "./models"; diff --git a/test/integration/generated/mediaTypesV3Lro/src/lro/locationPolling.ts b/test/integration/generated/mediaTypesV3Lro/src/lro/locationPolling.ts index 6fef619384..9d1aadfbde 100644 --- a/test/integration/generated/mediaTypesV3Lro/src/lro/locationPolling.ts +++ b/test/integration/generated/mediaTypesV3Lro/src/lro/locationPolling.ts @@ -7,23 +7,21 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function isLocationPollingDone(rawResponse: FullOperationResponse) { - const code = rawResponse.status; - if (![202, 200].includes(code)) { - throw new Error(`Operation failed`); - } - return code !== 202; +function isLocationPollingDone(rawResponse: RawResponse): boolean { + return ( + !isUnexpectedPollingResponse(rawResponse) && rawResponse.statusCode !== 202 + ); } export function processLocationPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/integration/generated/mediaTypesV3Lro/src/lro/lroEngine.ts b/test/integration/generated/mediaTypesV3Lro/src/lro/lroEngine.ts new file mode 100644 index 0000000000..85cc15e609 --- /dev/null +++ b/test/integration/generated/mediaTypesV3Lro/src/lro/lroEngine.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Poller, PollOperationState } from "@azure/core-lro"; +import { + LongRunningOperation, + LroEngineOptions, + ResumablePollOperationState +} from "./models"; +import { GenericPollOperation } from "./operation"; + +/** + * The LRO Engine, a class that performs polling. + */ +export class LroEngine< + TResult, + TState extends PollOperationState +> extends Poller { + private intervalInMs: number; + + constructor(lro: LongRunningOperation, options?: LroEngineOptions) { + const { intervalInMs = 2000, resumeFrom } = options || {}; + function deserializeState( + resumeFrom: string + ): TState & ResumablePollOperationState { + try { + return JSON.parse(resumeFrom).state; + } catch (e) { + throw new Error( + `LroEngine: Unable to deserialize state: ${resumeFrom}` + ); + } + } + const state: TState & ResumablePollOperationState = resumeFrom + ? deserializeState(resumeFrom) + : ({} as any); + + const operation = new GenericPollOperation(state, lro); + super(operation); + + this.intervalInMs = intervalInMs; + operation.setPollerConfig(this as any); + } + + /** + * The method used by the poller to wait before attempting to update its operation. + */ + delay(): Promise { + return new Promise((resolve) => + setTimeout(() => resolve(), this.intervalInMs) + ); + } +} diff --git a/test/integration/generated/mediaTypesV3Lro/src/lro/lroPoller.ts b/test/integration/generated/mediaTypesV3Lro/src/lro/lroPoller.ts deleted file mode 100644 index cd1cd64fe8..0000000000 --- a/test/integration/generated/mediaTypesV3Lro/src/lro/lroPoller.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { Poller, PollOperationState } from "@azure/core-lro"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { FinalStateVia, SendOperationFn } from "./models"; -import { GenericPollOperation } from "./operation"; - -export interface LROPollerOptions { - /** - * Defines how much time the poller is going to wait before making a new request to the service. - */ - intervalInMs?: number; - /** - * A serialized poller which can be used to resume an existing paused Long-Running-Operation. - */ - resumeFrom?: string; -} - -export class LROPoller extends Poller< - PollOperationState, - TResult -> { - private intervalInMs: number; - - constructor( - { intervalInMs = 2000, resumeFrom }: LROPollerOptions, - initialOperationArguments: OperationArguments, - initialOperationSpec: OperationSpec, - sendOperation: SendOperationFn, - finalStateVia?: FinalStateVia - ) { - const state: PollOperationState = resumeFrom - ? JSON.parse(resumeFrom).state - : {}; - - const operation = new GenericPollOperation( - state, - initialOperationArguments, - initialOperationSpec, - sendOperation, - finalStateVia - ); - super(operation); - - this.intervalInMs = intervalInMs; - operation.setPollerConfig(this as any); - } - - /** - * The method used by the poller to wait before attempting to update its operation. - */ - delay(): Promise { - return new Promise((resolve) => - setTimeout(() => resolve(), this.intervalInMs) - ); - } -} diff --git a/test/integration/generated/mediaTypesV3Lro/src/lro/models.ts b/test/integration/generated/mediaTypesV3Lro/src/lro/models.ts index a4a5a5abd6..93c3437c8e 100644 --- a/test/integration/generated/mediaTypesV3Lro/src/lro/models.ts +++ b/test/integration/generated/mediaTypesV3Lro/src/lro/models.ts @@ -7,46 +7,167 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec -} from "@azure/core-client"; import { PollOperationState } from "@azure/core-lro"; -export type FinalStateVia = +/** + * Options for the LRO poller. + */ +export interface LroEngineOptions { + /** + * Defines how much time the poller is going to wait before making a new request to the service. + */ + intervalInMs?: number; + /** + * A serialized poller which can be used to resume an existing paused Long-Running-Operation. + */ + resumeFrom?: string; +} + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +/** + * The LRO states that signal that the LRO has completed. + */ +export const terminalStates = successStates.concat(failureStates); + +/** + * The potential location of the result of the LRO if specified by the LRO extension in the swagger. + */ +export type LroResourceLocationConfig = | "azure-async-operation" | "location" | "original-uri"; -export interface LROResult { +/** + * The type of a LRO response body. This is just a convenience type for checking the status of the operation. + */ + +export interface LroBody extends Record { + /** The status of the operation. */ + status?: string; + /** The state of the provisioning process */ + provisioningState?: string; + /** The properties of the provisioning process */ + properties?: { provisioningState?: string } & Record; +} + +/** + * Simple type of the raw response. + */ +export interface RawResponse { + /** The HTTP status code */ + statusCode: number; + /** A HttpHeaders collection in the response represented as a simple JSON object where all header names have been normalized to be lower-case. */ + headers: { + [headerName: string]: string; + }; + /** The parsed response body */ + body?: unknown; +} + +/** + * The type of the response of a LRO. + */ +export interface LroResponse { + /** The flattened response */ flatResponse: T; - rawResponse: FullOperationResponse; + /** The raw response */ + rawResponse: RawResponse; } -export type LROMode = "AzureAsync" | "Location" | "Body"; +/** The type of which LRO implementation being followed by a specific API. */ +export type LroMode = "AzureAsync" | "Location" | "Body"; -export interface LROConfig { - mode?: LROMode; +/** + * The configuration of a LRO to determine how to perform polling and checking whether the operation has completed. + */ +export interface LroConfig { + /** The LRO mode */ + mode?: LroMode; + /** The path of a provisioned resource */ resourceLocation?: string; } -export type SendOperationFn = ( - args: OperationArguments, - spec: OperationSpec -) => Promise>; - /** * Type of a polling operation state that can actually be resumed. */ export type ResumablePollOperationState = PollOperationState & { - initialRawResponse?: FullOperationResponse; - config?: LROConfig; + initialRawResponse?: RawResponse; + config?: LroConfig; pollingURL?: string; }; export interface PollerConfig { intervalInMs: number; } + +/** + * The type of a terminal state of an LRO. + */ +export interface LroTerminalState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: true; +} + +/** + * The type of an in-progress state of an LRO. + */ +export interface LroInProgressState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: false; + /** + * The request to be sent next if it is different from the standard polling one. + * Notice that it will disregard any polling URLs provided to it. + */ + next?: () => Promise>; +} + +/** + * The type of an LRO state which is a tagged union of terminal and in-progress states. + */ +export type LroStatus = LroTerminalState | LroInProgressState; + +/** + * The type of the getLROStatusFromResponse method. It takes the response as input and returns along the response whether the operation has finished. + */ +export type GetLroStatusFromResponse = ( + rawResponse: RawResponse, + flatResponse: T +) => LroStatus; + +/** + * Description of a long running operation. + */ +export interface LongRunningOperation { + /** + * The request path. + */ + requestPath: string; + /** + * The HTTP request method. + */ + requestMethod: string; + /** + * A function that can be used to send initial request to the service. + */ + sendInitialRequest: ( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ) => Promise>; + /** + * A function that can be used to poll for the current status of a long running operation. + */ + sendPollRequest: (config: LroConfig, path: string) => Promise>; + /** + * A function that can be used to retrieve the provisioned azure resource. + */ + retrieveAzureAsyncResource: (path?: string) => Promise>; +} diff --git a/test/integration/generated/mediaTypesV3Lro/src/lro/operation.ts b/test/integration/generated/mediaTypesV3Lro/src/lro/operation.ts index 801d03e720..3ea7b76d89 100644 --- a/test/integration/generated/mediaTypesV3Lro/src/lro/operation.ts +++ b/test/integration/generated/mediaTypesV3Lro/src/lro/operation.ts @@ -7,36 +7,34 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. import { AbortSignalLike } from "@azure/abort-controller"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { PollOperation, PollOperationState } from "@azure/core-lro"; +import { PollOperationState, PollOperation } from "@azure/core-lro"; import { - FinalStateVia, PollerConfig, ResumablePollOperationState, - SendOperationFn + LongRunningOperation, + LroStatus } from "./models"; -import { getPollingURL } from "./requestUtils"; -import { createGetLROState, initializeState, LROState } from "./stateMachine"; +import { getPollingUrl } from "./requestUtils"; +import { createInitializeState, createPollForLROStatus } from "./stateMachine"; -export class GenericPollOperation - implements PollOperation, TResult> { - private getLROState?: ( +export class GenericPollOperation< + TResult, + TState extends PollOperationState +> implements PollOperation { + private getLROStatusFromResponse?: ( pollingURL: string, pollerConfig: PollerConfig - ) => Promise>; + ) => Promise>; private pollerConfig?: PollerConfig; constructor( - public state: PollOperationState, - private initialOperationArguments: OperationArguments, - private initialOperationSpec: OperationSpec, - private sendOperation: SendOperationFn, - private finalStateVia?: FinalStateVia + public state: TState & ResumablePollOperationState, + private lro: LongRunningOperation ) {} - public setPollerConfig(pollerConfig: PollerConfig) { + public setPollerConfig(pollerConfig: PollerConfig): void { this.pollerConfig = pollerConfig; } @@ -57,45 +55,36 @@ export class GenericPollOperation */ async update(options?: { abortSignal?: AbortSignalLike | undefined; - fireProgress?: ((state: PollOperationState) => void) | undefined; - }): Promise, TResult>> { - const state = this.state as ResumablePollOperationState; - const { onResponse, ...restOptions } = - this.initialOperationArguments.options || {}; + fireProgress?: ((state: TState) => void) | undefined; + }): Promise> { + const state = this.state; if (!state.isStarted) { - await this.sendOperation( - { - ...this.initialOperationArguments, - options: { - ...restOptions, - onResponse: initializeState( - state, - this.initialOperationSpec, - onResponse - ) - } - }, - this.initialOperationSpec + const initializeState = createInitializeState( + state, + this.lro.requestPath, + this.lro.requestMethod ); + await this.lro.sendInitialRequest(initializeState); } if (!state.isCompleted) { - if (this.getLROState === undefined) { + if (this.getLROStatusFromResponse === undefined) { if (state.config === undefined) { - throw new Error("Bad state: LRO mode is undefined"); + throw new Error( + "Bad state: LRO mode is undefined. Please check if the serialized state is well-formed." + ); } - this.getLROState = createGetLROState( - this.sendOperation, - this.initialOperationArguments, - this.initialOperationSpec, - state.config, - this.finalStateVia + this.getLROStatusFromResponse = createPollForLROStatus( + this.lro, + state.config ); } if (state.pollingURL === undefined) { - throw new Error("Bad state: polling URL is undefined"); + throw new Error( + "Bad state: polling URL is undefined. Please check if the serialized state is well-formed." + ); } - const currentState = await this.getLROState( + const currentState = await this.getLROStatusFromResponse( state.pollingURL, this.pollerConfig! ); @@ -103,20 +92,19 @@ export class GenericPollOperation state.result = currentState.flatResponse; state.isCompleted = true; } else { - this.getLROState = currentState.next ?? this.getLROState; - state.pollingURL = getPollingURL( + this.getLROStatusFromResponse = + currentState.next ?? this.getLROStatusFromResponse; + state.pollingURL = getPollingUrl( currentState.rawResponse, state.pollingURL ); } } - if (options?.fireProgress !== undefined) { - options.fireProgress(state); - } + options?.fireProgress?.(state); return this; } - async cancel(): Promise, TResult>> { + async cancel(): Promise> { this.state.isCancelled = true; return this; } diff --git a/test/integration/generated/mediaTypesV3Lro/src/lro/passthrough.ts b/test/integration/generated/mediaTypesV3Lro/src/lro/passthrough.ts index 64c10380c1..ae7f87d384 100644 --- a/test/integration/generated/mediaTypesV3Lro/src/lro/passthrough.ts +++ b/test/integration/generated/mediaTypesV3Lro/src/lro/passthrough.ts @@ -7,15 +7,14 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; export function processPassthroughOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/integration/generated/mediaTypesV3Lro/src/lro/pollingMethod.ts b/test/integration/generated/mediaTypesV3Lro/src/lro/pollingMethod.ts deleted file mode 100644 index cb6482bbde..0000000000 --- a/test/integration/generated/mediaTypesV3Lro/src/lro/pollingMethod.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - OperationArguments, - OperationSpec, - OperationResponseMap -} from "@azure/core-client"; -import { LROMode, LROResult, SendOperationFn } from "./models"; - -export function createPollingMethod( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - mode?: LROMode -): (path?: string) => Promise> { - /** - * Polling calls will always return a status object i.e. {"status": "success"} - * these intermediate responses are not described in the swagger so we need to - * pass custom mappers at runtime. - * This function replaces all the existing mappers to be able to deserialize a status object - * @param responses Original set of responses defined in the operation - */ - function getCompositeMappers(responses: { - [responseCode: string]: OperationResponseMap; - }): { - [responseCode: string]: OperationResponseMap; - } { - return Object.keys(responses).reduce((acc, statusCode) => { - return { - ...acc, - [statusCode]: { - ...responses[statusCode], - bodyMapper: { - type: { - name: "Composite", - modelProperties: { - status: { - serializedName: "status", - type: { - name: "String" - } - } - } - } - } - } - }; - }, {} as { [responseCode: string]: OperationResponseMap }); - } - // Make sure we don't send any body to the get request - const { requestBody, responses, ...restSpec } = spec; - if (mode === "AzureAsync") { - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: getCompositeMappers(responses), - httpMethod: "GET", - ...(path && { path }) - }); - }; - } - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: responses, - httpMethod: "GET", - ...(path && { path }) - }); - }; -} - -export function createRetrieveAzureAsyncResource( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec -): (path?: string) => Promise> { - const updatedArgs = { ...args }; - if (updatedArgs.options) { - (updatedArgs.options as any).shouldDeserialize = true; - } - return createPollingMethod(sendOperationFn, updatedArgs, spec); -} diff --git a/test/integration/generated/mediaTypesV3Lro/src/lro/requestUtils.ts b/test/integration/generated/mediaTypesV3Lro/src/lro/requestUtils.ts index 9162f66339..40d993686f 100644 --- a/test/integration/generated/mediaTypesV3Lro/src/lro/requestUtils.ts +++ b/test/integration/generated/mediaTypesV3Lro/src/lro/requestUtils.ts @@ -7,119 +7,9 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse, OperationSpec } from "@azure/core-client"; -import { LROConfig } from "./models"; -import { terminalStates } from "./stateMachine"; - -/** - * We need to selectively deserialize our responses, only deserializing if we - * are in a final LRO response, not deserializing any polling non-terminal responses - */ -export function shouldDeserializeLRO(finalStateVia?: string) { - let initialOperationInfo: LROResponseInfo | undefined; - let isInitialRequest = true; - - return (response: FullOperationResponse) => { - if (response.status < 200 || response.status >= 300) { - return true; - } - - if (!initialOperationInfo) { - initialOperationInfo = getLROData(response); - } else { - isInitialRequest = false; - } - - if ( - initialOperationInfo.azureAsyncOperation || - initialOperationInfo.operationLocation - ) { - return ( - !isInitialRequest && - isAsyncOperationFinalResponse( - response, - initialOperationInfo, - finalStateVia - ) - ); - } - - if (initialOperationInfo.location) { - return isLocationFinalResponse(response); - } - - if (initialOperationInfo.requestMethod === "PUT") { - return isBodyPollingFinalResponse(response); - } - - return true; - }; -} - -function isAsyncOperationFinalResponse( - response: FullOperationResponse, - initialOperationInfo: LROResponseInfo, - finalStateVia?: string -): boolean { - const status: string = response.parsedBody?.status || "Succeeded"; - if (!terminalStates.includes(status.toLowerCase())) { - return false; - } - - if (initialOperationInfo.requestMethod === "DELETE") { - return true; - } - - if ( - initialOperationInfo.requestMethod === "PUT" && - finalStateVia && - finalStateVia.toLowerCase() === "azure-asyncoperation" - ) { - return true; - } - - if ( - initialOperationInfo.requestMethod !== "PUT" && - !initialOperationInfo.location - ) { - return true; - } - - return false; -} - -function isLocationFinalResponse(response: FullOperationResponse): boolean { - return response.status !== 202; -} - -function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { - const provisioningState: string = - response.parsedBody?.properties?.provisioningState || "Succeeded"; - - if (terminalStates.includes(provisioningState.toLowerCase())) { - return true; - } - - return false; -} - -interface LROResponseInfo { - requestMethod: string; - azureAsyncOperation?: string; - operationLocation?: string; - location?: string; -} - -function getLROData(result: FullOperationResponse): LROResponseInfo { - return { - azureAsyncOperation: result.headers.get("azure-asyncoperation"), - operationLocation: result.headers.get("operation-location"), - location: result.headers.get("location"), - requestMethod: result.request.method - }; -} +import { LroConfig, RawResponse } from "./models"; /** * Detects where the continuation token is and returns it. Notice that azure-asyncoperation @@ -127,45 +17,41 @@ function getLROData(result: FullOperationResponse): LROResponseInfo { * where both azure-asyncoperation and location could be present in the same response but * azure-asyncoperation should be the one to use for polling. */ -export function getPollingURL( - rawResponse: FullOperationResponse, +export function getPollingUrl( + rawResponse: RawResponse, defaultPath: string ): string { return ( - getAzureAsyncoperation(rawResponse) ?? + getAzureAsyncOperation(rawResponse) ?? getLocation(rawResponse) ?? getOperationLocation(rawResponse) ?? defaultPath ); } -function getLocation(rawResponse: FullOperationResponse): string | undefined { - return rawResponse.headers?.get("location"); +function getLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["location"]; } -function getOperationLocation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("operation-location"); +function getOperationLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["operation-location"]; } -function getAzureAsyncoperation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("azure-asyncoperation"); +function getAzureAsyncOperation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["azure-asyncoperation"]; } -export function inferLROMode( - spec: OperationSpec, - rawResponse: FullOperationResponse -): LROConfig { - const requestMethod = spec.httpMethod; - if (getAzureAsyncoperation(rawResponse) !== undefined) { +export function inferLroMode( + requestPath: string, + requestMethod: string, + rawResponse: RawResponse +): LroConfig { + if (getAzureAsyncOperation(rawResponse) !== undefined) { return { mode: "AzureAsync", resourceLocation: requestMethod === "PUT" - ? spec.path + ? requestPath : requestMethod === "POST" ? getLocation(rawResponse) : undefined @@ -185,10 +71,35 @@ export function inferLROMode( return {}; } -export function getSpecPath(spec: OperationSpec): string { - if (spec.path) { - return spec.path; - } else { - throw Error("Bad spec: request path is not found!"); +export class RestError extends Error { + public statusCode?: number; + constructor(message: string, statusCode: number) { + super(message); + this.name = "RestError"; + this.statusCode = statusCode; + + Object.setPrototypeOf(this, RestError.prototype); + } +} + +export function isUnexpectedInitialResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![203, 204, 202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} in the initial response. This may indicate a server issue.`, + code + ); } + return false; +} + +export function isUnexpectedPollingResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} while polling. This may indicate a server issue.`, + code + ); + } + return false; } diff --git a/test/integration/generated/mediaTypesV3Lro/src/lro/stateMachine.ts b/test/integration/generated/mediaTypesV3Lro/src/lro/stateMachine.ts index b2a69b5546..19a8f67470 100644 --- a/test/integration/generated/mediaTypesV3Lro/src/lro/stateMachine.ts +++ b/test/integration/generated/mediaTypesV3Lro/src/lro/stateMachine.ts @@ -7,14 +7,8 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec, - RawResponseCallback -} from "@azure/core-client"; import { processAzureAsyncOperationResult } from "./azureAsyncPolling"; import { isBodyPollingDone, @@ -22,73 +16,36 @@ import { } from "./bodyPolling"; import { processLocationPollingOperationResult } from "./locationPolling"; import { - FinalStateVia, - LROConfig, - LROResult, + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroStatus, PollerConfig, - ResumablePollOperationState, - SendOperationFn + RawResponse, + ResumablePollOperationState } from "./models"; import { processPassthroughOperationResult } from "./passthrough"; import { - createPollingMethod, - createRetrieveAzureAsyncResource -} from "./pollingMethod"; -import { getPollingURL, getSpecPath, inferLROMode } from "./requestUtils"; - -export const successStates = ["succeeded"]; -export const failureStates = ["failed", "canceled", "cancelled"]; -export const terminalStates = successStates.concat(failureStates); - -/** - * The type of a terminal state of an LRO. - */ -interface LROTerminalState extends LROResult { - /** - * Whether the operation has finished. - */ - done: true; -} - -/** - * The type of an in-progress state of an LRO. - */ -interface LROInProgressState extends LROResult { - /** - * Whether the operation has finished. - */ - done: false; - /** - * The request to be sent next if it is different from the standard polling one. - * Notice that it will disregard any polling URLs provided to it. - */ - next?: () => Promise>; -} - -/** - * The type of an LRO state which is a tagged union of terminal and in-progress states. - */ -export type LROState = LROTerminalState | LROInProgressState; + getPollingUrl, + inferLroMode, + isUnexpectedInitialResponse +} from "./requestUtils"; /** * creates a stepping function that maps an LRO state to another. */ -function createTransition( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { +export function createGetLroStatusFromResponse( + lroPrimitives: LongRunningOperation, + config: LroConfig, + lroResourceLocationConfig?: LroResourceLocationConfig +): GetLroStatusFromResponse { switch (config.mode) { case "AzureAsync": { return processAzureAsyncOperationResult( - createRetrieveAzureAsyncResource(sendOperationFn, args, spec), + lroPrimitives, config.resourceLocation, - finalStateVia + lroResourceLocationConfig ); } case "Location": { @@ -106,52 +63,20 @@ function createTransition( /** * Creates a polling operation that returns a LRO state. */ -export function createGetLROState( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia +export function createPollForLROStatus( + lroPrimitives: LongRunningOperation, + config: LroConfig ): ( pollingURL: string, pollerConfig: PollerConfig -) => Promise> { - const step = createTransition( - sendOperationFn, - args, - spec, - config, - finalStateVia - ); - const customerCallback = args?.options?.onResponse; - let response: LROState | undefined = undefined; - let retryAfter: string | undefined = undefined; - const poll = createPollingMethod( - sendOperationFn, - { - ...args, - options: { - ...args.options, - onResponse: ( - rawResponse: FullOperationResponse, - flatResponse: unknown - ): void => { - response = step(rawResponse, flatResponse as TResult); - retryAfter = rawResponse.headers.get("Retry-After"); - if (response.done) { - customerCallback?.(rawResponse, flatResponse); - } - } - } - }, - spec, - config.mode - ); +) => Promise> { return async ( path: string, pollerConfig: PollerConfig - ): Promise> => { - await poll(path); + ): Promise> => { + const response = await lroPrimitives.sendPollRequest(config, path); + const retryAfter: string | undefined = + response.rawResponse.headers["retry-after"]; if (retryAfter !== undefined) { const retryAfterInMs = parseInt(retryAfter); pollerConfig.intervalInMs = isNaN(retryAfterInMs) @@ -161,7 +86,7 @@ export function createGetLROState( ) : retryAfterInMs; } - return response!; + return response; }; } @@ -179,24 +104,26 @@ function calculatePollingIntervalFromDate( /** * Creates a callback to be used to initialize the polling operation state. - * @param state of the polling operation - * @param operationSpec of the LRO - * @param callback callback to be called when the operation is done + * @param state - of the polling operation + * @param operationSpec - of the LRO + * @param callback - callback to be called when the operation is done * @returns callback that initializes the state of the polling operation */ -export function initializeState( +export function createInitializeState( state: ResumablePollOperationState, - operationSpec: OperationSpec, - callback?: RawResponseCallback -): (rawResponse: FullOperationResponse, flatResponse: unknown) => void { - return (rawResponse: FullOperationResponse, flatResponse: unknown) => { + requestPath: string, + requestMethod: string +): (rawResponse: RawResponse, flatResponse: unknown) => boolean { + return (rawResponse: RawResponse, flatResponse: unknown) => { + if (isUnexpectedInitialResponse(rawResponse)) return true; state.initialRawResponse = rawResponse; state.isStarted = true; - state.pollingURL = getPollingURL( - state.initialRawResponse, - getSpecPath(operationSpec) + state.pollingURL = getPollingUrl(state.initialRawResponse, requestPath); + state.config = inferLroMode( + requestPath, + requestMethod, + state.initialRawResponse ); - state.config = inferLROMode(operationSpec, state.initialRawResponse); /** short circuit polling if body polling is done in the initial request */ if ( state.config.mode === undefined || @@ -205,12 +132,7 @@ export function initializeState( ) { state.result = flatResponse as TResult; state.isCompleted = true; - /** - * We need to check if the LRO operation is finished inside the - * call back so that we can call the customer-provided callback - * on that result. - */ - callback?.(rawResponse, flatResponse); } + return Boolean(state.isCompleted); }; } diff --git a/test/integration/generated/mediaTypesV3Lro/src/mediaTypesV3LROClient.ts b/test/integration/generated/mediaTypesV3Lro/src/mediaTypesV3LROClient.ts index 308d7aae49..cbcbe7bd5e 100644 --- a/test/integration/generated/mediaTypesV3Lro/src/mediaTypesV3LROClient.ts +++ b/test/integration/generated/mediaTypesV3Lro/src/mediaTypesV3LROClient.ts @@ -8,8 +8,9 @@ import * as coreClient from "@azure/core-client"; import * as coreRestPipeline from "@azure/core-rest-pipeline"; -import { LROPoller, shouldDeserializeLRO } from "./lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "./lro"; +import { CoreClientLro, shouldDeserializeLro } from "./coreClientLro"; import * as Parameters from "./models/parameters"; import { MediaTypesV3LROClientContext } from "./mediaTypesV3LROClientContext"; import { @@ -33,12 +34,12 @@ export class MediaTypesV3LROClient extends MediaTypesV3LROClientContext { private getOperationOptions( options: TOptions | undefined, - finalStateVia?: string + lroResourceLocationConfig?: string ): coreClient.OperationOptions { const operationOptions: coreClient.OperationOptions = options || {}; operationOptions.requestOptions = { ...operationOptions.requestOptions, - shouldDeserialize: shouldDeserializeLRO(finalStateVia) + shouldDeserialize: shouldDeserializeLro(lroResourceLocationConfig) }; return operationOptions; } @@ -106,7 +107,7 @@ export class MediaTypesV3LROClient extends MediaTypesV3LROClientContext { `"contentType" must be a valid value but instead was "${args[0]}".` ); } - operationArguments.options = this.getOperationOptions(options, "undefined"); + operationArguments.options = this.getOperationOptions(options); const directSendOperation = async ( args: coreClient.OperationArguments, spec: coreClient.OperationSpec @@ -136,15 +137,22 @@ export class MediaTypesV3LROClient extends MediaTypesV3LROClientContext { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, operationArguments, - operationSpec, - sendOperation + operationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/integration/generated/paging/src/coreClientLro.ts b/test/integration/generated/paging/src/coreClientLro.ts new file mode 100644 index 0000000000..d793a24458 --- /dev/null +++ b/test/integration/generated/paging/src/coreClientLro.ts @@ -0,0 +1,323 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + OperationArguments, + OperationSpec, + OperationResponseMap, + FullOperationResponse +} from "@azure/core-client"; +import { + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + createGetLroStatusFromResponse, + RawResponse +} from "./lro"; + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +export const terminalStates = successStates.concat(failureStates); + +export type SendOperationFn = ( + args: OperationArguments, + spec: OperationSpec +) => Promise>; + +export function createPollingMethod( + sendOperationFn: SendOperationFn, + GetLroStatusFromResponse: GetLroStatusFromResponse, + args: OperationArguments, + spec: OperationSpec, + mode?: LroMode +): (path?: string) => Promise> { + /** + * Polling calls will always return a status object i.e. {"status": "success"} + * these intermediate responses are not described in the swagger so we need to + * pass custom mappers at runtime. + * This function replaces all the existing mappers to be able to deserialize a status object + * @param responses Original set of responses defined in the operation + */ + function getCompositeMappers(responses: { + [responseCode: string]: OperationResponseMap; + }): { + [responseCode: string]: OperationResponseMap; + } { + return Object.keys(responses).reduce((acc, statusCode) => { + return { + ...acc, + [statusCode]: { + ...responses[statusCode], + bodyMapper: { + type: { + name: "Composite", + modelProperties: { + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } + } + } + }; + }, {} as { [responseCode: string]: OperationResponseMap }); + } + let response: LroStatus | undefined = undefined; + const customerCallback = args?.options?.onResponse; + const updatedArgs = { + ...args, + options: { + ...args.options, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ): void => { + response = GetLroStatusFromResponse( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse as TResult + ); + if (response.done) { + customerCallback?.(rawResponse, flatResponse); + } + } + } + }; + // Make sure we don't send any body to the get request + const { requestBody, responses, ...restSpec } = spec; + if (mode === "AzureAsync") { + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: getCompositeMappers(responses), + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; + } + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: responses, + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; +} + +/** + * We need to selectively deserialize our responses, only deserializing if we + * are in a final Lro response, not deserializing any polling non-terminal responses + */ +export function shouldDeserializeLro(lroResourceLocationConfig?: string) { + let initialOperationInfo: LroResponseInfo | undefined; + let isInitialRequest = true; + + return (response: FullOperationResponse) => { + if (response.status < 200 || response.status >= 300) { + return true; + } + + if (!initialOperationInfo) { + initialOperationInfo = getLroData(response); + } else { + isInitialRequest = false; + } + + if ( + initialOperationInfo.azureAsyncOperation || + initialOperationInfo.operationLocation + ) { + return ( + !isInitialRequest && + isAsyncOperationFinalResponse( + response, + initialOperationInfo, + lroResourceLocationConfig + ) + ); + } + + if (initialOperationInfo.location) { + return isLocationFinalResponse(response); + } + + if (initialOperationInfo.requestMethod === "PUT") { + return isBodyPollingFinalResponse(response); + } + + return true; + }; +} + +function isAsyncOperationFinalResponse( + response: FullOperationResponse, + initialOperationInfo: LroResponseInfo, + lroResourceLocationConfig?: string +): boolean { + const status: string = response.parsedBody?.status || "Succeeded"; + if (!terminalStates.includes(status.toLowerCase())) { + return false; + } + + if (initialOperationInfo.requestMethod === "DELETE") { + return true; + } + + if ( + initialOperationInfo.requestMethod === "PUT" && + lroResourceLocationConfig && + lroResourceLocationConfig.toLowerCase() === "azure-asyncoperation" + ) { + return true; + } + + if ( + initialOperationInfo.requestMethod !== "PUT" && + !initialOperationInfo.location + ) { + return true; + } + + return false; +} + +function isLocationFinalResponse(response: FullOperationResponse): boolean { + return response.status !== 202; +} + +function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { + const provisioningState: string = + response.parsedBody?.properties?.provisioningState || "Succeeded"; + + if (terminalStates.includes(provisioningState.toLowerCase())) { + return true; + } + + return false; +} + +interface LroResponseInfo { + requestMethod: string; + azureAsyncOperation?: string; + operationLocation?: string; + location?: string; +} + +function getLroData(result: FullOperationResponse): LroResponseInfo { + return { + azureAsyncOperation: result.headers.get("azure-asyncoperation"), + operationLocation: result.headers.get("operation-location"), + location: result.headers.get("location"), + requestMethod: result.request.method + }; +} + +export function getSpecPath(spec: OperationSpec): string { + if (spec.path) { + return spec.path; + } else { + throw Error("Bad spec: request path is not found!"); + } +} + +export class CoreClientLro implements LongRunningOperation { + constructor( + private sendOperationFn: SendOperationFn, + private args: OperationArguments, + private spec: OperationSpec, + private lroResourceLocationConfig?: LroResourceLocationConfig, + public requestPath: string = spec.path!, + public requestMethod: string = spec.httpMethod + ) {} + public async sendInitialRequest( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ): Promise> { + const { onResponse, ...restOptions } = this.args.options || {}; + return this.sendOperationFn( + { + ...this.args, + options: { + ...restOptions, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ) => { + const isCompleted = initializeState( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse + ); + if (isCompleted) { + onResponse?.(rawResponse, flatResponse); + } + } + } + }, + this.spec + ); + } + + public async sendPollRequest( + config: LroConfig, + path: string + ): Promise> { + const getLroStatusFromResponse = createGetLroStatusFromResponse( + this, + config, + this.lroResourceLocationConfig + ); + return createPollingMethod( + this.sendOperationFn, + getLroStatusFromResponse, + this.args, + this.spec, + config.mode + )(path); + } + + public async retrieveAzureAsyncResource( + path?: string + ): Promise> { + const updatedArgs = { ...this.args }; + if (updatedArgs.options) { + (updatedArgs.options as any).shouldDeserialize = true; + } + return createPollingMethod( + this.sendOperationFn, + (rawResponse, flatResponse) => ({ + rawResponse, + flatResponse, + done: true + }), + updatedArgs, + this.spec + )(path); + } +} diff --git a/test/integration/generated/paging/src/lro/azureAsyncPolling.ts b/test/integration/generated/paging/src/lro/azureAsyncPolling.ts index 0d63c54f60..725578a692 100644 --- a/test/integration/generated/paging/src/lro/azureAsyncPolling.ts +++ b/test/integration/generated/paging/src/lro/azureAsyncPolling.ts @@ -7,39 +7,61 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { FinalStateVia, LROResult } from "./models"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroResourceLocationConfig, + LongRunningOperation, + LroBody, + LroResponse, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getResponseStatus(rawResponse: FullOperationResponse): string { - const { status } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getResponseStatus(rawResponse: RawResponse): string { + const { status } = (rawResponse.body as LroBody) ?? {}; return status?.toLowerCase() ?? "succeeded"; } -function isAzureAsyncPollingDone(rawResponse: FullOperationResponse) { +function isAzureAsyncPollingDone(rawResponse: RawResponse): boolean { const state = getResponseStatus(rawResponse); - if (failureStates.includes(state)) { + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { throw new Error(`Operation status: ${state}`); } return successStates.includes(state); } +async function sendFinalRequest( + lro: LongRunningOperation, + lroResourceLocationConfig?: LroResourceLocationConfig, + resourceLocation?: string +): Promise | undefined> { + switch (lroResourceLocationConfig) { + case "original-uri": + return lro.retrieveAzureAsyncResource(); + case "azure-async-operation": + return Promise.resolve(undefined); + case "location": + default: + return lro.retrieveAzureAsyncResource(resourceLocation); + } +} + export function processAzureAsyncOperationResult( - restrieveResource: (path?: string) => Promise>, + lro: LongRunningOperation, resourceLocation?: string, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { + lroResourceLocationConfig?: LroResourceLocationConfig +): (rawResponse: RawResponse, flatResponse: TResult) => LroStatus { return ( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult - ): LROState => { + ): LroStatus => { if (isAzureAsyncPollingDone(rawResponse)) { if (resourceLocation === undefined) { return { rawResponse, flatResponse, done: true }; @@ -49,20 +71,11 @@ export function processAzureAsyncOperationResult( flatResponse, done: false, next: async () => { - async function sendFinalRequest(): Promise< - LROResult | undefined - > { - switch (finalStateVia) { - case "original-uri": - return restrieveResource(); - case "azure-async-operation": - return Promise.resolve(undefined); - case "location": - default: - return restrieveResource(resourceLocation); - } - } - const finalResponse = await sendFinalRequest(); + const finalResponse = await sendFinalRequest( + lro, + lroResourceLocationConfig, + resourceLocation + ); return { ...(finalResponse ?? { rawResponse, diff --git a/test/integration/generated/paging/src/lro/bodyPolling.ts b/test/integration/generated/paging/src/lro/bodyPolling.ts index 269d8e6799..b1c87f8bc8 100644 --- a/test/integration/generated/paging/src/lro/bodyPolling.ts +++ b/test/integration/generated/paging/src/lro/bodyPolling.ts @@ -7,24 +7,33 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroBody, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getProvisioningState(rawResponse: FullOperationResponse): string { - const { properties, provisioningState } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getProvisioningState(rawResponse: RawResponse): string { + const { properties, provisioningState } = (rawResponse.body as LroBody) ?? {}; const state: string | undefined = properties?.provisioningState ?? provisioningState; return state?.toLowerCase() ?? "succeeded"; } -export function isBodyPollingDone(rawResponse: FullOperationResponse) { +export function isBodyPollingDone(rawResponse: RawResponse): boolean { const state = getProvisioningState(rawResponse); - if (failureStates.includes(state)) { - throw new Error(`Provisioning state: ${state}`); + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { + throw new Error( + `The long running operation has failed. The provisioning state: ${state}.` + ); } return successStates.includes(state); } @@ -34,9 +43,9 @@ export function isBodyPollingDone(rawResponse: FullOperationResponse) { * from the result to determine the current operation state */ export function processBodyPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/integration/generated/paging/src/lro/index.ts b/test/integration/generated/paging/src/lro/index.ts index 85c2187669..20df608fc8 100644 --- a/test/integration/generated/paging/src/lro/index.ts +++ b/test/integration/generated/paging/src/lro/index.ts @@ -6,5 +6,21 @@ * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ -export { shouldDeserializeLRO } from "./requestUtils"; -export { LROPoller } from "./lroPoller"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { LroEngine } from "./lroEngine"; +export { createGetLroStatusFromResponse } from "./stateMachine"; +export { + LroResourceLocationConfig, + GetLroStatusFromResponse, + RawResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + LroTerminalState, + LroInProgressState, + LroEngineOptions +} from "./models"; diff --git a/test/integration/generated/paging/src/lro/locationPolling.ts b/test/integration/generated/paging/src/lro/locationPolling.ts index 6fef619384..9d1aadfbde 100644 --- a/test/integration/generated/paging/src/lro/locationPolling.ts +++ b/test/integration/generated/paging/src/lro/locationPolling.ts @@ -7,23 +7,21 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function isLocationPollingDone(rawResponse: FullOperationResponse) { - const code = rawResponse.status; - if (![202, 200].includes(code)) { - throw new Error(`Operation failed`); - } - return code !== 202; +function isLocationPollingDone(rawResponse: RawResponse): boolean { + return ( + !isUnexpectedPollingResponse(rawResponse) && rawResponse.statusCode !== 202 + ); } export function processLocationPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/integration/generated/paging/src/lro/lroEngine.ts b/test/integration/generated/paging/src/lro/lroEngine.ts new file mode 100644 index 0000000000..85cc15e609 --- /dev/null +++ b/test/integration/generated/paging/src/lro/lroEngine.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Poller, PollOperationState } from "@azure/core-lro"; +import { + LongRunningOperation, + LroEngineOptions, + ResumablePollOperationState +} from "./models"; +import { GenericPollOperation } from "./operation"; + +/** + * The LRO Engine, a class that performs polling. + */ +export class LroEngine< + TResult, + TState extends PollOperationState +> extends Poller { + private intervalInMs: number; + + constructor(lro: LongRunningOperation, options?: LroEngineOptions) { + const { intervalInMs = 2000, resumeFrom } = options || {}; + function deserializeState( + resumeFrom: string + ): TState & ResumablePollOperationState { + try { + return JSON.parse(resumeFrom).state; + } catch (e) { + throw new Error( + `LroEngine: Unable to deserialize state: ${resumeFrom}` + ); + } + } + const state: TState & ResumablePollOperationState = resumeFrom + ? deserializeState(resumeFrom) + : ({} as any); + + const operation = new GenericPollOperation(state, lro); + super(operation); + + this.intervalInMs = intervalInMs; + operation.setPollerConfig(this as any); + } + + /** + * The method used by the poller to wait before attempting to update its operation. + */ + delay(): Promise { + return new Promise((resolve) => + setTimeout(() => resolve(), this.intervalInMs) + ); + } +} diff --git a/test/integration/generated/paging/src/lro/lroPoller.ts b/test/integration/generated/paging/src/lro/lroPoller.ts deleted file mode 100644 index cd1cd64fe8..0000000000 --- a/test/integration/generated/paging/src/lro/lroPoller.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { Poller, PollOperationState } from "@azure/core-lro"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { FinalStateVia, SendOperationFn } from "./models"; -import { GenericPollOperation } from "./operation"; - -export interface LROPollerOptions { - /** - * Defines how much time the poller is going to wait before making a new request to the service. - */ - intervalInMs?: number; - /** - * A serialized poller which can be used to resume an existing paused Long-Running-Operation. - */ - resumeFrom?: string; -} - -export class LROPoller extends Poller< - PollOperationState, - TResult -> { - private intervalInMs: number; - - constructor( - { intervalInMs = 2000, resumeFrom }: LROPollerOptions, - initialOperationArguments: OperationArguments, - initialOperationSpec: OperationSpec, - sendOperation: SendOperationFn, - finalStateVia?: FinalStateVia - ) { - const state: PollOperationState = resumeFrom - ? JSON.parse(resumeFrom).state - : {}; - - const operation = new GenericPollOperation( - state, - initialOperationArguments, - initialOperationSpec, - sendOperation, - finalStateVia - ); - super(operation); - - this.intervalInMs = intervalInMs; - operation.setPollerConfig(this as any); - } - - /** - * The method used by the poller to wait before attempting to update its operation. - */ - delay(): Promise { - return new Promise((resolve) => - setTimeout(() => resolve(), this.intervalInMs) - ); - } -} diff --git a/test/integration/generated/paging/src/lro/models.ts b/test/integration/generated/paging/src/lro/models.ts index a4a5a5abd6..93c3437c8e 100644 --- a/test/integration/generated/paging/src/lro/models.ts +++ b/test/integration/generated/paging/src/lro/models.ts @@ -7,46 +7,167 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec -} from "@azure/core-client"; import { PollOperationState } from "@azure/core-lro"; -export type FinalStateVia = +/** + * Options for the LRO poller. + */ +export interface LroEngineOptions { + /** + * Defines how much time the poller is going to wait before making a new request to the service. + */ + intervalInMs?: number; + /** + * A serialized poller which can be used to resume an existing paused Long-Running-Operation. + */ + resumeFrom?: string; +} + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +/** + * The LRO states that signal that the LRO has completed. + */ +export const terminalStates = successStates.concat(failureStates); + +/** + * The potential location of the result of the LRO if specified by the LRO extension in the swagger. + */ +export type LroResourceLocationConfig = | "azure-async-operation" | "location" | "original-uri"; -export interface LROResult { +/** + * The type of a LRO response body. This is just a convenience type for checking the status of the operation. + */ + +export interface LroBody extends Record { + /** The status of the operation. */ + status?: string; + /** The state of the provisioning process */ + provisioningState?: string; + /** The properties of the provisioning process */ + properties?: { provisioningState?: string } & Record; +} + +/** + * Simple type of the raw response. + */ +export interface RawResponse { + /** The HTTP status code */ + statusCode: number; + /** A HttpHeaders collection in the response represented as a simple JSON object where all header names have been normalized to be lower-case. */ + headers: { + [headerName: string]: string; + }; + /** The parsed response body */ + body?: unknown; +} + +/** + * The type of the response of a LRO. + */ +export interface LroResponse { + /** The flattened response */ flatResponse: T; - rawResponse: FullOperationResponse; + /** The raw response */ + rawResponse: RawResponse; } -export type LROMode = "AzureAsync" | "Location" | "Body"; +/** The type of which LRO implementation being followed by a specific API. */ +export type LroMode = "AzureAsync" | "Location" | "Body"; -export interface LROConfig { - mode?: LROMode; +/** + * The configuration of a LRO to determine how to perform polling and checking whether the operation has completed. + */ +export interface LroConfig { + /** The LRO mode */ + mode?: LroMode; + /** The path of a provisioned resource */ resourceLocation?: string; } -export type SendOperationFn = ( - args: OperationArguments, - spec: OperationSpec -) => Promise>; - /** * Type of a polling operation state that can actually be resumed. */ export type ResumablePollOperationState = PollOperationState & { - initialRawResponse?: FullOperationResponse; - config?: LROConfig; + initialRawResponse?: RawResponse; + config?: LroConfig; pollingURL?: string; }; export interface PollerConfig { intervalInMs: number; } + +/** + * The type of a terminal state of an LRO. + */ +export interface LroTerminalState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: true; +} + +/** + * The type of an in-progress state of an LRO. + */ +export interface LroInProgressState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: false; + /** + * The request to be sent next if it is different from the standard polling one. + * Notice that it will disregard any polling URLs provided to it. + */ + next?: () => Promise>; +} + +/** + * The type of an LRO state which is a tagged union of terminal and in-progress states. + */ +export type LroStatus = LroTerminalState | LroInProgressState; + +/** + * The type of the getLROStatusFromResponse method. It takes the response as input and returns along the response whether the operation has finished. + */ +export type GetLroStatusFromResponse = ( + rawResponse: RawResponse, + flatResponse: T +) => LroStatus; + +/** + * Description of a long running operation. + */ +export interface LongRunningOperation { + /** + * The request path. + */ + requestPath: string; + /** + * The HTTP request method. + */ + requestMethod: string; + /** + * A function that can be used to send initial request to the service. + */ + sendInitialRequest: ( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ) => Promise>; + /** + * A function that can be used to poll for the current status of a long running operation. + */ + sendPollRequest: (config: LroConfig, path: string) => Promise>; + /** + * A function that can be used to retrieve the provisioned azure resource. + */ + retrieveAzureAsyncResource: (path?: string) => Promise>; +} diff --git a/test/integration/generated/paging/src/lro/operation.ts b/test/integration/generated/paging/src/lro/operation.ts index 801d03e720..3ea7b76d89 100644 --- a/test/integration/generated/paging/src/lro/operation.ts +++ b/test/integration/generated/paging/src/lro/operation.ts @@ -7,36 +7,34 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. import { AbortSignalLike } from "@azure/abort-controller"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { PollOperation, PollOperationState } from "@azure/core-lro"; +import { PollOperationState, PollOperation } from "@azure/core-lro"; import { - FinalStateVia, PollerConfig, ResumablePollOperationState, - SendOperationFn + LongRunningOperation, + LroStatus } from "./models"; -import { getPollingURL } from "./requestUtils"; -import { createGetLROState, initializeState, LROState } from "./stateMachine"; +import { getPollingUrl } from "./requestUtils"; +import { createInitializeState, createPollForLROStatus } from "./stateMachine"; -export class GenericPollOperation - implements PollOperation, TResult> { - private getLROState?: ( +export class GenericPollOperation< + TResult, + TState extends PollOperationState +> implements PollOperation { + private getLROStatusFromResponse?: ( pollingURL: string, pollerConfig: PollerConfig - ) => Promise>; + ) => Promise>; private pollerConfig?: PollerConfig; constructor( - public state: PollOperationState, - private initialOperationArguments: OperationArguments, - private initialOperationSpec: OperationSpec, - private sendOperation: SendOperationFn, - private finalStateVia?: FinalStateVia + public state: TState & ResumablePollOperationState, + private lro: LongRunningOperation ) {} - public setPollerConfig(pollerConfig: PollerConfig) { + public setPollerConfig(pollerConfig: PollerConfig): void { this.pollerConfig = pollerConfig; } @@ -57,45 +55,36 @@ export class GenericPollOperation */ async update(options?: { abortSignal?: AbortSignalLike | undefined; - fireProgress?: ((state: PollOperationState) => void) | undefined; - }): Promise, TResult>> { - const state = this.state as ResumablePollOperationState; - const { onResponse, ...restOptions } = - this.initialOperationArguments.options || {}; + fireProgress?: ((state: TState) => void) | undefined; + }): Promise> { + const state = this.state; if (!state.isStarted) { - await this.sendOperation( - { - ...this.initialOperationArguments, - options: { - ...restOptions, - onResponse: initializeState( - state, - this.initialOperationSpec, - onResponse - ) - } - }, - this.initialOperationSpec + const initializeState = createInitializeState( + state, + this.lro.requestPath, + this.lro.requestMethod ); + await this.lro.sendInitialRequest(initializeState); } if (!state.isCompleted) { - if (this.getLROState === undefined) { + if (this.getLROStatusFromResponse === undefined) { if (state.config === undefined) { - throw new Error("Bad state: LRO mode is undefined"); + throw new Error( + "Bad state: LRO mode is undefined. Please check if the serialized state is well-formed." + ); } - this.getLROState = createGetLROState( - this.sendOperation, - this.initialOperationArguments, - this.initialOperationSpec, - state.config, - this.finalStateVia + this.getLROStatusFromResponse = createPollForLROStatus( + this.lro, + state.config ); } if (state.pollingURL === undefined) { - throw new Error("Bad state: polling URL is undefined"); + throw new Error( + "Bad state: polling URL is undefined. Please check if the serialized state is well-formed." + ); } - const currentState = await this.getLROState( + const currentState = await this.getLROStatusFromResponse( state.pollingURL, this.pollerConfig! ); @@ -103,20 +92,19 @@ export class GenericPollOperation state.result = currentState.flatResponse; state.isCompleted = true; } else { - this.getLROState = currentState.next ?? this.getLROState; - state.pollingURL = getPollingURL( + this.getLROStatusFromResponse = + currentState.next ?? this.getLROStatusFromResponse; + state.pollingURL = getPollingUrl( currentState.rawResponse, state.pollingURL ); } } - if (options?.fireProgress !== undefined) { - options.fireProgress(state); - } + options?.fireProgress?.(state); return this; } - async cancel(): Promise, TResult>> { + async cancel(): Promise> { this.state.isCancelled = true; return this; } diff --git a/test/integration/generated/paging/src/lro/passthrough.ts b/test/integration/generated/paging/src/lro/passthrough.ts index 64c10380c1..ae7f87d384 100644 --- a/test/integration/generated/paging/src/lro/passthrough.ts +++ b/test/integration/generated/paging/src/lro/passthrough.ts @@ -7,15 +7,14 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; export function processPassthroughOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/integration/generated/paging/src/lro/pollingMethod.ts b/test/integration/generated/paging/src/lro/pollingMethod.ts deleted file mode 100644 index cb6482bbde..0000000000 --- a/test/integration/generated/paging/src/lro/pollingMethod.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - OperationArguments, - OperationSpec, - OperationResponseMap -} from "@azure/core-client"; -import { LROMode, LROResult, SendOperationFn } from "./models"; - -export function createPollingMethod( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - mode?: LROMode -): (path?: string) => Promise> { - /** - * Polling calls will always return a status object i.e. {"status": "success"} - * these intermediate responses are not described in the swagger so we need to - * pass custom mappers at runtime. - * This function replaces all the existing mappers to be able to deserialize a status object - * @param responses Original set of responses defined in the operation - */ - function getCompositeMappers(responses: { - [responseCode: string]: OperationResponseMap; - }): { - [responseCode: string]: OperationResponseMap; - } { - return Object.keys(responses).reduce((acc, statusCode) => { - return { - ...acc, - [statusCode]: { - ...responses[statusCode], - bodyMapper: { - type: { - name: "Composite", - modelProperties: { - status: { - serializedName: "status", - type: { - name: "String" - } - } - } - } - } - } - }; - }, {} as { [responseCode: string]: OperationResponseMap }); - } - // Make sure we don't send any body to the get request - const { requestBody, responses, ...restSpec } = spec; - if (mode === "AzureAsync") { - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: getCompositeMappers(responses), - httpMethod: "GET", - ...(path && { path }) - }); - }; - } - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: responses, - httpMethod: "GET", - ...(path && { path }) - }); - }; -} - -export function createRetrieveAzureAsyncResource( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec -): (path?: string) => Promise> { - const updatedArgs = { ...args }; - if (updatedArgs.options) { - (updatedArgs.options as any).shouldDeserialize = true; - } - return createPollingMethod(sendOperationFn, updatedArgs, spec); -} diff --git a/test/integration/generated/paging/src/lro/requestUtils.ts b/test/integration/generated/paging/src/lro/requestUtils.ts index 9162f66339..40d993686f 100644 --- a/test/integration/generated/paging/src/lro/requestUtils.ts +++ b/test/integration/generated/paging/src/lro/requestUtils.ts @@ -7,119 +7,9 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse, OperationSpec } from "@azure/core-client"; -import { LROConfig } from "./models"; -import { terminalStates } from "./stateMachine"; - -/** - * We need to selectively deserialize our responses, only deserializing if we - * are in a final LRO response, not deserializing any polling non-terminal responses - */ -export function shouldDeserializeLRO(finalStateVia?: string) { - let initialOperationInfo: LROResponseInfo | undefined; - let isInitialRequest = true; - - return (response: FullOperationResponse) => { - if (response.status < 200 || response.status >= 300) { - return true; - } - - if (!initialOperationInfo) { - initialOperationInfo = getLROData(response); - } else { - isInitialRequest = false; - } - - if ( - initialOperationInfo.azureAsyncOperation || - initialOperationInfo.operationLocation - ) { - return ( - !isInitialRequest && - isAsyncOperationFinalResponse( - response, - initialOperationInfo, - finalStateVia - ) - ); - } - - if (initialOperationInfo.location) { - return isLocationFinalResponse(response); - } - - if (initialOperationInfo.requestMethod === "PUT") { - return isBodyPollingFinalResponse(response); - } - - return true; - }; -} - -function isAsyncOperationFinalResponse( - response: FullOperationResponse, - initialOperationInfo: LROResponseInfo, - finalStateVia?: string -): boolean { - const status: string = response.parsedBody?.status || "Succeeded"; - if (!terminalStates.includes(status.toLowerCase())) { - return false; - } - - if (initialOperationInfo.requestMethod === "DELETE") { - return true; - } - - if ( - initialOperationInfo.requestMethod === "PUT" && - finalStateVia && - finalStateVia.toLowerCase() === "azure-asyncoperation" - ) { - return true; - } - - if ( - initialOperationInfo.requestMethod !== "PUT" && - !initialOperationInfo.location - ) { - return true; - } - - return false; -} - -function isLocationFinalResponse(response: FullOperationResponse): boolean { - return response.status !== 202; -} - -function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { - const provisioningState: string = - response.parsedBody?.properties?.provisioningState || "Succeeded"; - - if (terminalStates.includes(provisioningState.toLowerCase())) { - return true; - } - - return false; -} - -interface LROResponseInfo { - requestMethod: string; - azureAsyncOperation?: string; - operationLocation?: string; - location?: string; -} - -function getLROData(result: FullOperationResponse): LROResponseInfo { - return { - azureAsyncOperation: result.headers.get("azure-asyncoperation"), - operationLocation: result.headers.get("operation-location"), - location: result.headers.get("location"), - requestMethod: result.request.method - }; -} +import { LroConfig, RawResponse } from "./models"; /** * Detects where the continuation token is and returns it. Notice that azure-asyncoperation @@ -127,45 +17,41 @@ function getLROData(result: FullOperationResponse): LROResponseInfo { * where both azure-asyncoperation and location could be present in the same response but * azure-asyncoperation should be the one to use for polling. */ -export function getPollingURL( - rawResponse: FullOperationResponse, +export function getPollingUrl( + rawResponse: RawResponse, defaultPath: string ): string { return ( - getAzureAsyncoperation(rawResponse) ?? + getAzureAsyncOperation(rawResponse) ?? getLocation(rawResponse) ?? getOperationLocation(rawResponse) ?? defaultPath ); } -function getLocation(rawResponse: FullOperationResponse): string | undefined { - return rawResponse.headers?.get("location"); +function getLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["location"]; } -function getOperationLocation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("operation-location"); +function getOperationLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["operation-location"]; } -function getAzureAsyncoperation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("azure-asyncoperation"); +function getAzureAsyncOperation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["azure-asyncoperation"]; } -export function inferLROMode( - spec: OperationSpec, - rawResponse: FullOperationResponse -): LROConfig { - const requestMethod = spec.httpMethod; - if (getAzureAsyncoperation(rawResponse) !== undefined) { +export function inferLroMode( + requestPath: string, + requestMethod: string, + rawResponse: RawResponse +): LroConfig { + if (getAzureAsyncOperation(rawResponse) !== undefined) { return { mode: "AzureAsync", resourceLocation: requestMethod === "PUT" - ? spec.path + ? requestPath : requestMethod === "POST" ? getLocation(rawResponse) : undefined @@ -185,10 +71,35 @@ export function inferLROMode( return {}; } -export function getSpecPath(spec: OperationSpec): string { - if (spec.path) { - return spec.path; - } else { - throw Error("Bad spec: request path is not found!"); +export class RestError extends Error { + public statusCode?: number; + constructor(message: string, statusCode: number) { + super(message); + this.name = "RestError"; + this.statusCode = statusCode; + + Object.setPrototypeOf(this, RestError.prototype); + } +} + +export function isUnexpectedInitialResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![203, 204, 202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} in the initial response. This may indicate a server issue.`, + code + ); } + return false; +} + +export function isUnexpectedPollingResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} while polling. This may indicate a server issue.`, + code + ); + } + return false; } diff --git a/test/integration/generated/paging/src/lro/stateMachine.ts b/test/integration/generated/paging/src/lro/stateMachine.ts index b2a69b5546..19a8f67470 100644 --- a/test/integration/generated/paging/src/lro/stateMachine.ts +++ b/test/integration/generated/paging/src/lro/stateMachine.ts @@ -7,14 +7,8 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec, - RawResponseCallback -} from "@azure/core-client"; import { processAzureAsyncOperationResult } from "./azureAsyncPolling"; import { isBodyPollingDone, @@ -22,73 +16,36 @@ import { } from "./bodyPolling"; import { processLocationPollingOperationResult } from "./locationPolling"; import { - FinalStateVia, - LROConfig, - LROResult, + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroStatus, PollerConfig, - ResumablePollOperationState, - SendOperationFn + RawResponse, + ResumablePollOperationState } from "./models"; import { processPassthroughOperationResult } from "./passthrough"; import { - createPollingMethod, - createRetrieveAzureAsyncResource -} from "./pollingMethod"; -import { getPollingURL, getSpecPath, inferLROMode } from "./requestUtils"; - -export const successStates = ["succeeded"]; -export const failureStates = ["failed", "canceled", "cancelled"]; -export const terminalStates = successStates.concat(failureStates); - -/** - * The type of a terminal state of an LRO. - */ -interface LROTerminalState extends LROResult { - /** - * Whether the operation has finished. - */ - done: true; -} - -/** - * The type of an in-progress state of an LRO. - */ -interface LROInProgressState extends LROResult { - /** - * Whether the operation has finished. - */ - done: false; - /** - * The request to be sent next if it is different from the standard polling one. - * Notice that it will disregard any polling URLs provided to it. - */ - next?: () => Promise>; -} - -/** - * The type of an LRO state which is a tagged union of terminal and in-progress states. - */ -export type LROState = LROTerminalState | LROInProgressState; + getPollingUrl, + inferLroMode, + isUnexpectedInitialResponse +} from "./requestUtils"; /** * creates a stepping function that maps an LRO state to another. */ -function createTransition( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { +export function createGetLroStatusFromResponse( + lroPrimitives: LongRunningOperation, + config: LroConfig, + lroResourceLocationConfig?: LroResourceLocationConfig +): GetLroStatusFromResponse { switch (config.mode) { case "AzureAsync": { return processAzureAsyncOperationResult( - createRetrieveAzureAsyncResource(sendOperationFn, args, spec), + lroPrimitives, config.resourceLocation, - finalStateVia + lroResourceLocationConfig ); } case "Location": { @@ -106,52 +63,20 @@ function createTransition( /** * Creates a polling operation that returns a LRO state. */ -export function createGetLROState( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia +export function createPollForLROStatus( + lroPrimitives: LongRunningOperation, + config: LroConfig ): ( pollingURL: string, pollerConfig: PollerConfig -) => Promise> { - const step = createTransition( - sendOperationFn, - args, - spec, - config, - finalStateVia - ); - const customerCallback = args?.options?.onResponse; - let response: LROState | undefined = undefined; - let retryAfter: string | undefined = undefined; - const poll = createPollingMethod( - sendOperationFn, - { - ...args, - options: { - ...args.options, - onResponse: ( - rawResponse: FullOperationResponse, - flatResponse: unknown - ): void => { - response = step(rawResponse, flatResponse as TResult); - retryAfter = rawResponse.headers.get("Retry-After"); - if (response.done) { - customerCallback?.(rawResponse, flatResponse); - } - } - } - }, - spec, - config.mode - ); +) => Promise> { return async ( path: string, pollerConfig: PollerConfig - ): Promise> => { - await poll(path); + ): Promise> => { + const response = await lroPrimitives.sendPollRequest(config, path); + const retryAfter: string | undefined = + response.rawResponse.headers["retry-after"]; if (retryAfter !== undefined) { const retryAfterInMs = parseInt(retryAfter); pollerConfig.intervalInMs = isNaN(retryAfterInMs) @@ -161,7 +86,7 @@ export function createGetLROState( ) : retryAfterInMs; } - return response!; + return response; }; } @@ -179,24 +104,26 @@ function calculatePollingIntervalFromDate( /** * Creates a callback to be used to initialize the polling operation state. - * @param state of the polling operation - * @param operationSpec of the LRO - * @param callback callback to be called when the operation is done + * @param state - of the polling operation + * @param operationSpec - of the LRO + * @param callback - callback to be called when the operation is done * @returns callback that initializes the state of the polling operation */ -export function initializeState( +export function createInitializeState( state: ResumablePollOperationState, - operationSpec: OperationSpec, - callback?: RawResponseCallback -): (rawResponse: FullOperationResponse, flatResponse: unknown) => void { - return (rawResponse: FullOperationResponse, flatResponse: unknown) => { + requestPath: string, + requestMethod: string +): (rawResponse: RawResponse, flatResponse: unknown) => boolean { + return (rawResponse: RawResponse, flatResponse: unknown) => { + if (isUnexpectedInitialResponse(rawResponse)) return true; state.initialRawResponse = rawResponse; state.isStarted = true; - state.pollingURL = getPollingURL( - state.initialRawResponse, - getSpecPath(operationSpec) + state.pollingURL = getPollingUrl(state.initialRawResponse, requestPath); + state.config = inferLroMode( + requestPath, + requestMethod, + state.initialRawResponse ); - state.config = inferLROMode(operationSpec, state.initialRawResponse); /** short circuit polling if body polling is done in the initial request */ if ( state.config.mode === undefined || @@ -205,12 +132,7 @@ export function initializeState( ) { state.result = flatResponse as TResult; state.isCompleted = true; - /** - * We need to check if the LRO operation is finished inside the - * call back so that we can call the customer-provided callback - * on that result. - */ - callback?.(rawResponse, flatResponse); } + return Boolean(state.isCompleted); }; } diff --git a/test/integration/generated/paging/src/operations/paging.ts b/test/integration/generated/paging/src/operations/paging.ts index bad6b8e071..0db64d53bf 100644 --- a/test/integration/generated/paging/src/operations/paging.ts +++ b/test/integration/generated/paging/src/operations/paging.ts @@ -15,8 +15,9 @@ import * as coreTracing from "@azure/core-tracing"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { PagingClientContext } from "../pagingClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { Product, PagingGetNoItemNamePagesNextOptionalParams, @@ -1600,15 +1601,22 @@ export class PagingImpl implements Paging { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - getMultiplePagesLROOperationSpec, - sendOperation + getMultiplePagesLROOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/integration/generated/pagingNoIterators/src/coreClientLro.ts b/test/integration/generated/pagingNoIterators/src/coreClientLro.ts new file mode 100644 index 0000000000..d793a24458 --- /dev/null +++ b/test/integration/generated/pagingNoIterators/src/coreClientLro.ts @@ -0,0 +1,323 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + OperationArguments, + OperationSpec, + OperationResponseMap, + FullOperationResponse +} from "@azure/core-client"; +import { + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + createGetLroStatusFromResponse, + RawResponse +} from "./lro"; + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +export const terminalStates = successStates.concat(failureStates); + +export type SendOperationFn = ( + args: OperationArguments, + spec: OperationSpec +) => Promise>; + +export function createPollingMethod( + sendOperationFn: SendOperationFn, + GetLroStatusFromResponse: GetLroStatusFromResponse, + args: OperationArguments, + spec: OperationSpec, + mode?: LroMode +): (path?: string) => Promise> { + /** + * Polling calls will always return a status object i.e. {"status": "success"} + * these intermediate responses are not described in the swagger so we need to + * pass custom mappers at runtime. + * This function replaces all the existing mappers to be able to deserialize a status object + * @param responses Original set of responses defined in the operation + */ + function getCompositeMappers(responses: { + [responseCode: string]: OperationResponseMap; + }): { + [responseCode: string]: OperationResponseMap; + } { + return Object.keys(responses).reduce((acc, statusCode) => { + return { + ...acc, + [statusCode]: { + ...responses[statusCode], + bodyMapper: { + type: { + name: "Composite", + modelProperties: { + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } + } + } + }; + }, {} as { [responseCode: string]: OperationResponseMap }); + } + let response: LroStatus | undefined = undefined; + const customerCallback = args?.options?.onResponse; + const updatedArgs = { + ...args, + options: { + ...args.options, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ): void => { + response = GetLroStatusFromResponse( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse as TResult + ); + if (response.done) { + customerCallback?.(rawResponse, flatResponse); + } + } + } + }; + // Make sure we don't send any body to the get request + const { requestBody, responses, ...restSpec } = spec; + if (mode === "AzureAsync") { + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: getCompositeMappers(responses), + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; + } + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: responses, + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; +} + +/** + * We need to selectively deserialize our responses, only deserializing if we + * are in a final Lro response, not deserializing any polling non-terminal responses + */ +export function shouldDeserializeLro(lroResourceLocationConfig?: string) { + let initialOperationInfo: LroResponseInfo | undefined; + let isInitialRequest = true; + + return (response: FullOperationResponse) => { + if (response.status < 200 || response.status >= 300) { + return true; + } + + if (!initialOperationInfo) { + initialOperationInfo = getLroData(response); + } else { + isInitialRequest = false; + } + + if ( + initialOperationInfo.azureAsyncOperation || + initialOperationInfo.operationLocation + ) { + return ( + !isInitialRequest && + isAsyncOperationFinalResponse( + response, + initialOperationInfo, + lroResourceLocationConfig + ) + ); + } + + if (initialOperationInfo.location) { + return isLocationFinalResponse(response); + } + + if (initialOperationInfo.requestMethod === "PUT") { + return isBodyPollingFinalResponse(response); + } + + return true; + }; +} + +function isAsyncOperationFinalResponse( + response: FullOperationResponse, + initialOperationInfo: LroResponseInfo, + lroResourceLocationConfig?: string +): boolean { + const status: string = response.parsedBody?.status || "Succeeded"; + if (!terminalStates.includes(status.toLowerCase())) { + return false; + } + + if (initialOperationInfo.requestMethod === "DELETE") { + return true; + } + + if ( + initialOperationInfo.requestMethod === "PUT" && + lroResourceLocationConfig && + lroResourceLocationConfig.toLowerCase() === "azure-asyncoperation" + ) { + return true; + } + + if ( + initialOperationInfo.requestMethod !== "PUT" && + !initialOperationInfo.location + ) { + return true; + } + + return false; +} + +function isLocationFinalResponse(response: FullOperationResponse): boolean { + return response.status !== 202; +} + +function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { + const provisioningState: string = + response.parsedBody?.properties?.provisioningState || "Succeeded"; + + if (terminalStates.includes(provisioningState.toLowerCase())) { + return true; + } + + return false; +} + +interface LroResponseInfo { + requestMethod: string; + azureAsyncOperation?: string; + operationLocation?: string; + location?: string; +} + +function getLroData(result: FullOperationResponse): LroResponseInfo { + return { + azureAsyncOperation: result.headers.get("azure-asyncoperation"), + operationLocation: result.headers.get("operation-location"), + location: result.headers.get("location"), + requestMethod: result.request.method + }; +} + +export function getSpecPath(spec: OperationSpec): string { + if (spec.path) { + return spec.path; + } else { + throw Error("Bad spec: request path is not found!"); + } +} + +export class CoreClientLro implements LongRunningOperation { + constructor( + private sendOperationFn: SendOperationFn, + private args: OperationArguments, + private spec: OperationSpec, + private lroResourceLocationConfig?: LroResourceLocationConfig, + public requestPath: string = spec.path!, + public requestMethod: string = spec.httpMethod + ) {} + public async sendInitialRequest( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ): Promise> { + const { onResponse, ...restOptions } = this.args.options || {}; + return this.sendOperationFn( + { + ...this.args, + options: { + ...restOptions, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ) => { + const isCompleted = initializeState( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse + ); + if (isCompleted) { + onResponse?.(rawResponse, flatResponse); + } + } + } + }, + this.spec + ); + } + + public async sendPollRequest( + config: LroConfig, + path: string + ): Promise> { + const getLroStatusFromResponse = createGetLroStatusFromResponse( + this, + config, + this.lroResourceLocationConfig + ); + return createPollingMethod( + this.sendOperationFn, + getLroStatusFromResponse, + this.args, + this.spec, + config.mode + )(path); + } + + public async retrieveAzureAsyncResource( + path?: string + ): Promise> { + const updatedArgs = { ...this.args }; + if (updatedArgs.options) { + (updatedArgs.options as any).shouldDeserialize = true; + } + return createPollingMethod( + this.sendOperationFn, + (rawResponse, flatResponse) => ({ + rawResponse, + flatResponse, + done: true + }), + updatedArgs, + this.spec + )(path); + } +} diff --git a/test/integration/generated/pagingNoIterators/src/lro/azureAsyncPolling.ts b/test/integration/generated/pagingNoIterators/src/lro/azureAsyncPolling.ts index 0d63c54f60..725578a692 100644 --- a/test/integration/generated/pagingNoIterators/src/lro/azureAsyncPolling.ts +++ b/test/integration/generated/pagingNoIterators/src/lro/azureAsyncPolling.ts @@ -7,39 +7,61 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { FinalStateVia, LROResult } from "./models"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroResourceLocationConfig, + LongRunningOperation, + LroBody, + LroResponse, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getResponseStatus(rawResponse: FullOperationResponse): string { - const { status } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getResponseStatus(rawResponse: RawResponse): string { + const { status } = (rawResponse.body as LroBody) ?? {}; return status?.toLowerCase() ?? "succeeded"; } -function isAzureAsyncPollingDone(rawResponse: FullOperationResponse) { +function isAzureAsyncPollingDone(rawResponse: RawResponse): boolean { const state = getResponseStatus(rawResponse); - if (failureStates.includes(state)) { + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { throw new Error(`Operation status: ${state}`); } return successStates.includes(state); } +async function sendFinalRequest( + lro: LongRunningOperation, + lroResourceLocationConfig?: LroResourceLocationConfig, + resourceLocation?: string +): Promise | undefined> { + switch (lroResourceLocationConfig) { + case "original-uri": + return lro.retrieveAzureAsyncResource(); + case "azure-async-operation": + return Promise.resolve(undefined); + case "location": + default: + return lro.retrieveAzureAsyncResource(resourceLocation); + } +} + export function processAzureAsyncOperationResult( - restrieveResource: (path?: string) => Promise>, + lro: LongRunningOperation, resourceLocation?: string, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { + lroResourceLocationConfig?: LroResourceLocationConfig +): (rawResponse: RawResponse, flatResponse: TResult) => LroStatus { return ( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult - ): LROState => { + ): LroStatus => { if (isAzureAsyncPollingDone(rawResponse)) { if (resourceLocation === undefined) { return { rawResponse, flatResponse, done: true }; @@ -49,20 +71,11 @@ export function processAzureAsyncOperationResult( flatResponse, done: false, next: async () => { - async function sendFinalRequest(): Promise< - LROResult | undefined - > { - switch (finalStateVia) { - case "original-uri": - return restrieveResource(); - case "azure-async-operation": - return Promise.resolve(undefined); - case "location": - default: - return restrieveResource(resourceLocation); - } - } - const finalResponse = await sendFinalRequest(); + const finalResponse = await sendFinalRequest( + lro, + lroResourceLocationConfig, + resourceLocation + ); return { ...(finalResponse ?? { rawResponse, diff --git a/test/integration/generated/pagingNoIterators/src/lro/bodyPolling.ts b/test/integration/generated/pagingNoIterators/src/lro/bodyPolling.ts index 269d8e6799..b1c87f8bc8 100644 --- a/test/integration/generated/pagingNoIterators/src/lro/bodyPolling.ts +++ b/test/integration/generated/pagingNoIterators/src/lro/bodyPolling.ts @@ -7,24 +7,33 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroBody, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getProvisioningState(rawResponse: FullOperationResponse): string { - const { properties, provisioningState } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getProvisioningState(rawResponse: RawResponse): string { + const { properties, provisioningState } = (rawResponse.body as LroBody) ?? {}; const state: string | undefined = properties?.provisioningState ?? provisioningState; return state?.toLowerCase() ?? "succeeded"; } -export function isBodyPollingDone(rawResponse: FullOperationResponse) { +export function isBodyPollingDone(rawResponse: RawResponse): boolean { const state = getProvisioningState(rawResponse); - if (failureStates.includes(state)) { - throw new Error(`Provisioning state: ${state}`); + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { + throw new Error( + `The long running operation has failed. The provisioning state: ${state}.` + ); } return successStates.includes(state); } @@ -34,9 +43,9 @@ export function isBodyPollingDone(rawResponse: FullOperationResponse) { * from the result to determine the current operation state */ export function processBodyPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/integration/generated/pagingNoIterators/src/lro/index.ts b/test/integration/generated/pagingNoIterators/src/lro/index.ts index 85c2187669..20df608fc8 100644 --- a/test/integration/generated/pagingNoIterators/src/lro/index.ts +++ b/test/integration/generated/pagingNoIterators/src/lro/index.ts @@ -6,5 +6,21 @@ * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ -export { shouldDeserializeLRO } from "./requestUtils"; -export { LROPoller } from "./lroPoller"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { LroEngine } from "./lroEngine"; +export { createGetLroStatusFromResponse } from "./stateMachine"; +export { + LroResourceLocationConfig, + GetLroStatusFromResponse, + RawResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + LroTerminalState, + LroInProgressState, + LroEngineOptions +} from "./models"; diff --git a/test/integration/generated/pagingNoIterators/src/lro/locationPolling.ts b/test/integration/generated/pagingNoIterators/src/lro/locationPolling.ts index 6fef619384..9d1aadfbde 100644 --- a/test/integration/generated/pagingNoIterators/src/lro/locationPolling.ts +++ b/test/integration/generated/pagingNoIterators/src/lro/locationPolling.ts @@ -7,23 +7,21 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function isLocationPollingDone(rawResponse: FullOperationResponse) { - const code = rawResponse.status; - if (![202, 200].includes(code)) { - throw new Error(`Operation failed`); - } - return code !== 202; +function isLocationPollingDone(rawResponse: RawResponse): boolean { + return ( + !isUnexpectedPollingResponse(rawResponse) && rawResponse.statusCode !== 202 + ); } export function processLocationPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/integration/generated/pagingNoIterators/src/lro/lroEngine.ts b/test/integration/generated/pagingNoIterators/src/lro/lroEngine.ts new file mode 100644 index 0000000000..85cc15e609 --- /dev/null +++ b/test/integration/generated/pagingNoIterators/src/lro/lroEngine.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Poller, PollOperationState } from "@azure/core-lro"; +import { + LongRunningOperation, + LroEngineOptions, + ResumablePollOperationState +} from "./models"; +import { GenericPollOperation } from "./operation"; + +/** + * The LRO Engine, a class that performs polling. + */ +export class LroEngine< + TResult, + TState extends PollOperationState +> extends Poller { + private intervalInMs: number; + + constructor(lro: LongRunningOperation, options?: LroEngineOptions) { + const { intervalInMs = 2000, resumeFrom } = options || {}; + function deserializeState( + resumeFrom: string + ): TState & ResumablePollOperationState { + try { + return JSON.parse(resumeFrom).state; + } catch (e) { + throw new Error( + `LroEngine: Unable to deserialize state: ${resumeFrom}` + ); + } + } + const state: TState & ResumablePollOperationState = resumeFrom + ? deserializeState(resumeFrom) + : ({} as any); + + const operation = new GenericPollOperation(state, lro); + super(operation); + + this.intervalInMs = intervalInMs; + operation.setPollerConfig(this as any); + } + + /** + * The method used by the poller to wait before attempting to update its operation. + */ + delay(): Promise { + return new Promise((resolve) => + setTimeout(() => resolve(), this.intervalInMs) + ); + } +} diff --git a/test/integration/generated/pagingNoIterators/src/lro/lroPoller.ts b/test/integration/generated/pagingNoIterators/src/lro/lroPoller.ts deleted file mode 100644 index cd1cd64fe8..0000000000 --- a/test/integration/generated/pagingNoIterators/src/lro/lroPoller.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { Poller, PollOperationState } from "@azure/core-lro"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { FinalStateVia, SendOperationFn } from "./models"; -import { GenericPollOperation } from "./operation"; - -export interface LROPollerOptions { - /** - * Defines how much time the poller is going to wait before making a new request to the service. - */ - intervalInMs?: number; - /** - * A serialized poller which can be used to resume an existing paused Long-Running-Operation. - */ - resumeFrom?: string; -} - -export class LROPoller extends Poller< - PollOperationState, - TResult -> { - private intervalInMs: number; - - constructor( - { intervalInMs = 2000, resumeFrom }: LROPollerOptions, - initialOperationArguments: OperationArguments, - initialOperationSpec: OperationSpec, - sendOperation: SendOperationFn, - finalStateVia?: FinalStateVia - ) { - const state: PollOperationState = resumeFrom - ? JSON.parse(resumeFrom).state - : {}; - - const operation = new GenericPollOperation( - state, - initialOperationArguments, - initialOperationSpec, - sendOperation, - finalStateVia - ); - super(operation); - - this.intervalInMs = intervalInMs; - operation.setPollerConfig(this as any); - } - - /** - * The method used by the poller to wait before attempting to update its operation. - */ - delay(): Promise { - return new Promise((resolve) => - setTimeout(() => resolve(), this.intervalInMs) - ); - } -} diff --git a/test/integration/generated/pagingNoIterators/src/lro/models.ts b/test/integration/generated/pagingNoIterators/src/lro/models.ts index a4a5a5abd6..93c3437c8e 100644 --- a/test/integration/generated/pagingNoIterators/src/lro/models.ts +++ b/test/integration/generated/pagingNoIterators/src/lro/models.ts @@ -7,46 +7,167 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec -} from "@azure/core-client"; import { PollOperationState } from "@azure/core-lro"; -export type FinalStateVia = +/** + * Options for the LRO poller. + */ +export interface LroEngineOptions { + /** + * Defines how much time the poller is going to wait before making a new request to the service. + */ + intervalInMs?: number; + /** + * A serialized poller which can be used to resume an existing paused Long-Running-Operation. + */ + resumeFrom?: string; +} + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +/** + * The LRO states that signal that the LRO has completed. + */ +export const terminalStates = successStates.concat(failureStates); + +/** + * The potential location of the result of the LRO if specified by the LRO extension in the swagger. + */ +export type LroResourceLocationConfig = | "azure-async-operation" | "location" | "original-uri"; -export interface LROResult { +/** + * The type of a LRO response body. This is just a convenience type for checking the status of the operation. + */ + +export interface LroBody extends Record { + /** The status of the operation. */ + status?: string; + /** The state of the provisioning process */ + provisioningState?: string; + /** The properties of the provisioning process */ + properties?: { provisioningState?: string } & Record; +} + +/** + * Simple type of the raw response. + */ +export interface RawResponse { + /** The HTTP status code */ + statusCode: number; + /** A HttpHeaders collection in the response represented as a simple JSON object where all header names have been normalized to be lower-case. */ + headers: { + [headerName: string]: string; + }; + /** The parsed response body */ + body?: unknown; +} + +/** + * The type of the response of a LRO. + */ +export interface LroResponse { + /** The flattened response */ flatResponse: T; - rawResponse: FullOperationResponse; + /** The raw response */ + rawResponse: RawResponse; } -export type LROMode = "AzureAsync" | "Location" | "Body"; +/** The type of which LRO implementation being followed by a specific API. */ +export type LroMode = "AzureAsync" | "Location" | "Body"; -export interface LROConfig { - mode?: LROMode; +/** + * The configuration of a LRO to determine how to perform polling and checking whether the operation has completed. + */ +export interface LroConfig { + /** The LRO mode */ + mode?: LroMode; + /** The path of a provisioned resource */ resourceLocation?: string; } -export type SendOperationFn = ( - args: OperationArguments, - spec: OperationSpec -) => Promise>; - /** * Type of a polling operation state that can actually be resumed. */ export type ResumablePollOperationState = PollOperationState & { - initialRawResponse?: FullOperationResponse; - config?: LROConfig; + initialRawResponse?: RawResponse; + config?: LroConfig; pollingURL?: string; }; export interface PollerConfig { intervalInMs: number; } + +/** + * The type of a terminal state of an LRO. + */ +export interface LroTerminalState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: true; +} + +/** + * The type of an in-progress state of an LRO. + */ +export interface LroInProgressState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: false; + /** + * The request to be sent next if it is different from the standard polling one. + * Notice that it will disregard any polling URLs provided to it. + */ + next?: () => Promise>; +} + +/** + * The type of an LRO state which is a tagged union of terminal and in-progress states. + */ +export type LroStatus = LroTerminalState | LroInProgressState; + +/** + * The type of the getLROStatusFromResponse method. It takes the response as input and returns along the response whether the operation has finished. + */ +export type GetLroStatusFromResponse = ( + rawResponse: RawResponse, + flatResponse: T +) => LroStatus; + +/** + * Description of a long running operation. + */ +export interface LongRunningOperation { + /** + * The request path. + */ + requestPath: string; + /** + * The HTTP request method. + */ + requestMethod: string; + /** + * A function that can be used to send initial request to the service. + */ + sendInitialRequest: ( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ) => Promise>; + /** + * A function that can be used to poll for the current status of a long running operation. + */ + sendPollRequest: (config: LroConfig, path: string) => Promise>; + /** + * A function that can be used to retrieve the provisioned azure resource. + */ + retrieveAzureAsyncResource: (path?: string) => Promise>; +} diff --git a/test/integration/generated/pagingNoIterators/src/lro/operation.ts b/test/integration/generated/pagingNoIterators/src/lro/operation.ts index 801d03e720..3ea7b76d89 100644 --- a/test/integration/generated/pagingNoIterators/src/lro/operation.ts +++ b/test/integration/generated/pagingNoIterators/src/lro/operation.ts @@ -7,36 +7,34 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. import { AbortSignalLike } from "@azure/abort-controller"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { PollOperation, PollOperationState } from "@azure/core-lro"; +import { PollOperationState, PollOperation } from "@azure/core-lro"; import { - FinalStateVia, PollerConfig, ResumablePollOperationState, - SendOperationFn + LongRunningOperation, + LroStatus } from "./models"; -import { getPollingURL } from "./requestUtils"; -import { createGetLROState, initializeState, LROState } from "./stateMachine"; +import { getPollingUrl } from "./requestUtils"; +import { createInitializeState, createPollForLROStatus } from "./stateMachine"; -export class GenericPollOperation - implements PollOperation, TResult> { - private getLROState?: ( +export class GenericPollOperation< + TResult, + TState extends PollOperationState +> implements PollOperation { + private getLROStatusFromResponse?: ( pollingURL: string, pollerConfig: PollerConfig - ) => Promise>; + ) => Promise>; private pollerConfig?: PollerConfig; constructor( - public state: PollOperationState, - private initialOperationArguments: OperationArguments, - private initialOperationSpec: OperationSpec, - private sendOperation: SendOperationFn, - private finalStateVia?: FinalStateVia + public state: TState & ResumablePollOperationState, + private lro: LongRunningOperation ) {} - public setPollerConfig(pollerConfig: PollerConfig) { + public setPollerConfig(pollerConfig: PollerConfig): void { this.pollerConfig = pollerConfig; } @@ -57,45 +55,36 @@ export class GenericPollOperation */ async update(options?: { abortSignal?: AbortSignalLike | undefined; - fireProgress?: ((state: PollOperationState) => void) | undefined; - }): Promise, TResult>> { - const state = this.state as ResumablePollOperationState; - const { onResponse, ...restOptions } = - this.initialOperationArguments.options || {}; + fireProgress?: ((state: TState) => void) | undefined; + }): Promise> { + const state = this.state; if (!state.isStarted) { - await this.sendOperation( - { - ...this.initialOperationArguments, - options: { - ...restOptions, - onResponse: initializeState( - state, - this.initialOperationSpec, - onResponse - ) - } - }, - this.initialOperationSpec + const initializeState = createInitializeState( + state, + this.lro.requestPath, + this.lro.requestMethod ); + await this.lro.sendInitialRequest(initializeState); } if (!state.isCompleted) { - if (this.getLROState === undefined) { + if (this.getLROStatusFromResponse === undefined) { if (state.config === undefined) { - throw new Error("Bad state: LRO mode is undefined"); + throw new Error( + "Bad state: LRO mode is undefined. Please check if the serialized state is well-formed." + ); } - this.getLROState = createGetLROState( - this.sendOperation, - this.initialOperationArguments, - this.initialOperationSpec, - state.config, - this.finalStateVia + this.getLROStatusFromResponse = createPollForLROStatus( + this.lro, + state.config ); } if (state.pollingURL === undefined) { - throw new Error("Bad state: polling URL is undefined"); + throw new Error( + "Bad state: polling URL is undefined. Please check if the serialized state is well-formed." + ); } - const currentState = await this.getLROState( + const currentState = await this.getLROStatusFromResponse( state.pollingURL, this.pollerConfig! ); @@ -103,20 +92,19 @@ export class GenericPollOperation state.result = currentState.flatResponse; state.isCompleted = true; } else { - this.getLROState = currentState.next ?? this.getLROState; - state.pollingURL = getPollingURL( + this.getLROStatusFromResponse = + currentState.next ?? this.getLROStatusFromResponse; + state.pollingURL = getPollingUrl( currentState.rawResponse, state.pollingURL ); } } - if (options?.fireProgress !== undefined) { - options.fireProgress(state); - } + options?.fireProgress?.(state); return this; } - async cancel(): Promise, TResult>> { + async cancel(): Promise> { this.state.isCancelled = true; return this; } diff --git a/test/integration/generated/pagingNoIterators/src/lro/passthrough.ts b/test/integration/generated/pagingNoIterators/src/lro/passthrough.ts index 64c10380c1..ae7f87d384 100644 --- a/test/integration/generated/pagingNoIterators/src/lro/passthrough.ts +++ b/test/integration/generated/pagingNoIterators/src/lro/passthrough.ts @@ -7,15 +7,14 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; export function processPassthroughOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/integration/generated/pagingNoIterators/src/lro/pollingMethod.ts b/test/integration/generated/pagingNoIterators/src/lro/pollingMethod.ts deleted file mode 100644 index cb6482bbde..0000000000 --- a/test/integration/generated/pagingNoIterators/src/lro/pollingMethod.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - OperationArguments, - OperationSpec, - OperationResponseMap -} from "@azure/core-client"; -import { LROMode, LROResult, SendOperationFn } from "./models"; - -export function createPollingMethod( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - mode?: LROMode -): (path?: string) => Promise> { - /** - * Polling calls will always return a status object i.e. {"status": "success"} - * these intermediate responses are not described in the swagger so we need to - * pass custom mappers at runtime. - * This function replaces all the existing mappers to be able to deserialize a status object - * @param responses Original set of responses defined in the operation - */ - function getCompositeMappers(responses: { - [responseCode: string]: OperationResponseMap; - }): { - [responseCode: string]: OperationResponseMap; - } { - return Object.keys(responses).reduce((acc, statusCode) => { - return { - ...acc, - [statusCode]: { - ...responses[statusCode], - bodyMapper: { - type: { - name: "Composite", - modelProperties: { - status: { - serializedName: "status", - type: { - name: "String" - } - } - } - } - } - } - }; - }, {} as { [responseCode: string]: OperationResponseMap }); - } - // Make sure we don't send any body to the get request - const { requestBody, responses, ...restSpec } = spec; - if (mode === "AzureAsync") { - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: getCompositeMappers(responses), - httpMethod: "GET", - ...(path && { path }) - }); - }; - } - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: responses, - httpMethod: "GET", - ...(path && { path }) - }); - }; -} - -export function createRetrieveAzureAsyncResource( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec -): (path?: string) => Promise> { - const updatedArgs = { ...args }; - if (updatedArgs.options) { - (updatedArgs.options as any).shouldDeserialize = true; - } - return createPollingMethod(sendOperationFn, updatedArgs, spec); -} diff --git a/test/integration/generated/pagingNoIterators/src/lro/requestUtils.ts b/test/integration/generated/pagingNoIterators/src/lro/requestUtils.ts index 9162f66339..40d993686f 100644 --- a/test/integration/generated/pagingNoIterators/src/lro/requestUtils.ts +++ b/test/integration/generated/pagingNoIterators/src/lro/requestUtils.ts @@ -7,119 +7,9 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse, OperationSpec } from "@azure/core-client"; -import { LROConfig } from "./models"; -import { terminalStates } from "./stateMachine"; - -/** - * We need to selectively deserialize our responses, only deserializing if we - * are in a final LRO response, not deserializing any polling non-terminal responses - */ -export function shouldDeserializeLRO(finalStateVia?: string) { - let initialOperationInfo: LROResponseInfo | undefined; - let isInitialRequest = true; - - return (response: FullOperationResponse) => { - if (response.status < 200 || response.status >= 300) { - return true; - } - - if (!initialOperationInfo) { - initialOperationInfo = getLROData(response); - } else { - isInitialRequest = false; - } - - if ( - initialOperationInfo.azureAsyncOperation || - initialOperationInfo.operationLocation - ) { - return ( - !isInitialRequest && - isAsyncOperationFinalResponse( - response, - initialOperationInfo, - finalStateVia - ) - ); - } - - if (initialOperationInfo.location) { - return isLocationFinalResponse(response); - } - - if (initialOperationInfo.requestMethod === "PUT") { - return isBodyPollingFinalResponse(response); - } - - return true; - }; -} - -function isAsyncOperationFinalResponse( - response: FullOperationResponse, - initialOperationInfo: LROResponseInfo, - finalStateVia?: string -): boolean { - const status: string = response.parsedBody?.status || "Succeeded"; - if (!terminalStates.includes(status.toLowerCase())) { - return false; - } - - if (initialOperationInfo.requestMethod === "DELETE") { - return true; - } - - if ( - initialOperationInfo.requestMethod === "PUT" && - finalStateVia && - finalStateVia.toLowerCase() === "azure-asyncoperation" - ) { - return true; - } - - if ( - initialOperationInfo.requestMethod !== "PUT" && - !initialOperationInfo.location - ) { - return true; - } - - return false; -} - -function isLocationFinalResponse(response: FullOperationResponse): boolean { - return response.status !== 202; -} - -function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { - const provisioningState: string = - response.parsedBody?.properties?.provisioningState || "Succeeded"; - - if (terminalStates.includes(provisioningState.toLowerCase())) { - return true; - } - - return false; -} - -interface LROResponseInfo { - requestMethod: string; - azureAsyncOperation?: string; - operationLocation?: string; - location?: string; -} - -function getLROData(result: FullOperationResponse): LROResponseInfo { - return { - azureAsyncOperation: result.headers.get("azure-asyncoperation"), - operationLocation: result.headers.get("operation-location"), - location: result.headers.get("location"), - requestMethod: result.request.method - }; -} +import { LroConfig, RawResponse } from "./models"; /** * Detects where the continuation token is and returns it. Notice that azure-asyncoperation @@ -127,45 +17,41 @@ function getLROData(result: FullOperationResponse): LROResponseInfo { * where both azure-asyncoperation and location could be present in the same response but * azure-asyncoperation should be the one to use for polling. */ -export function getPollingURL( - rawResponse: FullOperationResponse, +export function getPollingUrl( + rawResponse: RawResponse, defaultPath: string ): string { return ( - getAzureAsyncoperation(rawResponse) ?? + getAzureAsyncOperation(rawResponse) ?? getLocation(rawResponse) ?? getOperationLocation(rawResponse) ?? defaultPath ); } -function getLocation(rawResponse: FullOperationResponse): string | undefined { - return rawResponse.headers?.get("location"); +function getLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["location"]; } -function getOperationLocation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("operation-location"); +function getOperationLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["operation-location"]; } -function getAzureAsyncoperation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("azure-asyncoperation"); +function getAzureAsyncOperation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["azure-asyncoperation"]; } -export function inferLROMode( - spec: OperationSpec, - rawResponse: FullOperationResponse -): LROConfig { - const requestMethod = spec.httpMethod; - if (getAzureAsyncoperation(rawResponse) !== undefined) { +export function inferLroMode( + requestPath: string, + requestMethod: string, + rawResponse: RawResponse +): LroConfig { + if (getAzureAsyncOperation(rawResponse) !== undefined) { return { mode: "AzureAsync", resourceLocation: requestMethod === "PUT" - ? spec.path + ? requestPath : requestMethod === "POST" ? getLocation(rawResponse) : undefined @@ -185,10 +71,35 @@ export function inferLROMode( return {}; } -export function getSpecPath(spec: OperationSpec): string { - if (spec.path) { - return spec.path; - } else { - throw Error("Bad spec: request path is not found!"); +export class RestError extends Error { + public statusCode?: number; + constructor(message: string, statusCode: number) { + super(message); + this.name = "RestError"; + this.statusCode = statusCode; + + Object.setPrototypeOf(this, RestError.prototype); + } +} + +export function isUnexpectedInitialResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![203, 204, 202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} in the initial response. This may indicate a server issue.`, + code + ); } + return false; +} + +export function isUnexpectedPollingResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} while polling. This may indicate a server issue.`, + code + ); + } + return false; } diff --git a/test/integration/generated/pagingNoIterators/src/lro/stateMachine.ts b/test/integration/generated/pagingNoIterators/src/lro/stateMachine.ts index b2a69b5546..19a8f67470 100644 --- a/test/integration/generated/pagingNoIterators/src/lro/stateMachine.ts +++ b/test/integration/generated/pagingNoIterators/src/lro/stateMachine.ts @@ -7,14 +7,8 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec, - RawResponseCallback -} from "@azure/core-client"; import { processAzureAsyncOperationResult } from "./azureAsyncPolling"; import { isBodyPollingDone, @@ -22,73 +16,36 @@ import { } from "./bodyPolling"; import { processLocationPollingOperationResult } from "./locationPolling"; import { - FinalStateVia, - LROConfig, - LROResult, + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroStatus, PollerConfig, - ResumablePollOperationState, - SendOperationFn + RawResponse, + ResumablePollOperationState } from "./models"; import { processPassthroughOperationResult } from "./passthrough"; import { - createPollingMethod, - createRetrieveAzureAsyncResource -} from "./pollingMethod"; -import { getPollingURL, getSpecPath, inferLROMode } from "./requestUtils"; - -export const successStates = ["succeeded"]; -export const failureStates = ["failed", "canceled", "cancelled"]; -export const terminalStates = successStates.concat(failureStates); - -/** - * The type of a terminal state of an LRO. - */ -interface LROTerminalState extends LROResult { - /** - * Whether the operation has finished. - */ - done: true; -} - -/** - * The type of an in-progress state of an LRO. - */ -interface LROInProgressState extends LROResult { - /** - * Whether the operation has finished. - */ - done: false; - /** - * The request to be sent next if it is different from the standard polling one. - * Notice that it will disregard any polling URLs provided to it. - */ - next?: () => Promise>; -} - -/** - * The type of an LRO state which is a tagged union of terminal and in-progress states. - */ -export type LROState = LROTerminalState | LROInProgressState; + getPollingUrl, + inferLroMode, + isUnexpectedInitialResponse +} from "./requestUtils"; /** * creates a stepping function that maps an LRO state to another. */ -function createTransition( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { +export function createGetLroStatusFromResponse( + lroPrimitives: LongRunningOperation, + config: LroConfig, + lroResourceLocationConfig?: LroResourceLocationConfig +): GetLroStatusFromResponse { switch (config.mode) { case "AzureAsync": { return processAzureAsyncOperationResult( - createRetrieveAzureAsyncResource(sendOperationFn, args, spec), + lroPrimitives, config.resourceLocation, - finalStateVia + lroResourceLocationConfig ); } case "Location": { @@ -106,52 +63,20 @@ function createTransition( /** * Creates a polling operation that returns a LRO state. */ -export function createGetLROState( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia +export function createPollForLROStatus( + lroPrimitives: LongRunningOperation, + config: LroConfig ): ( pollingURL: string, pollerConfig: PollerConfig -) => Promise> { - const step = createTransition( - sendOperationFn, - args, - spec, - config, - finalStateVia - ); - const customerCallback = args?.options?.onResponse; - let response: LROState | undefined = undefined; - let retryAfter: string | undefined = undefined; - const poll = createPollingMethod( - sendOperationFn, - { - ...args, - options: { - ...args.options, - onResponse: ( - rawResponse: FullOperationResponse, - flatResponse: unknown - ): void => { - response = step(rawResponse, flatResponse as TResult); - retryAfter = rawResponse.headers.get("Retry-After"); - if (response.done) { - customerCallback?.(rawResponse, flatResponse); - } - } - } - }, - spec, - config.mode - ); +) => Promise> { return async ( path: string, pollerConfig: PollerConfig - ): Promise> => { - await poll(path); + ): Promise> => { + const response = await lroPrimitives.sendPollRequest(config, path); + const retryAfter: string | undefined = + response.rawResponse.headers["retry-after"]; if (retryAfter !== undefined) { const retryAfterInMs = parseInt(retryAfter); pollerConfig.intervalInMs = isNaN(retryAfterInMs) @@ -161,7 +86,7 @@ export function createGetLROState( ) : retryAfterInMs; } - return response!; + return response; }; } @@ -179,24 +104,26 @@ function calculatePollingIntervalFromDate( /** * Creates a callback to be used to initialize the polling operation state. - * @param state of the polling operation - * @param operationSpec of the LRO - * @param callback callback to be called when the operation is done + * @param state - of the polling operation + * @param operationSpec - of the LRO + * @param callback - callback to be called when the operation is done * @returns callback that initializes the state of the polling operation */ -export function initializeState( +export function createInitializeState( state: ResumablePollOperationState, - operationSpec: OperationSpec, - callback?: RawResponseCallback -): (rawResponse: FullOperationResponse, flatResponse: unknown) => void { - return (rawResponse: FullOperationResponse, flatResponse: unknown) => { + requestPath: string, + requestMethod: string +): (rawResponse: RawResponse, flatResponse: unknown) => boolean { + return (rawResponse: RawResponse, flatResponse: unknown) => { + if (isUnexpectedInitialResponse(rawResponse)) return true; state.initialRawResponse = rawResponse; state.isStarted = true; - state.pollingURL = getPollingURL( - state.initialRawResponse, - getSpecPath(operationSpec) + state.pollingURL = getPollingUrl(state.initialRawResponse, requestPath); + state.config = inferLroMode( + requestPath, + requestMethod, + state.initialRawResponse ); - state.config = inferLROMode(operationSpec, state.initialRawResponse); /** short circuit polling if body polling is done in the initial request */ if ( state.config.mode === undefined || @@ -205,12 +132,7 @@ export function initializeState( ) { state.result = flatResponse as TResult; state.isCompleted = true; - /** - * We need to check if the LRO operation is finished inside the - * call back so that we can call the customer-provided callback - * on that result. - */ - callback?.(rawResponse, flatResponse); } + return Boolean(state.isCompleted); }; } diff --git a/test/integration/generated/pagingNoIterators/src/operations/paging.ts b/test/integration/generated/pagingNoIterators/src/operations/paging.ts index 70d723e4eb..bd44eb9369 100644 --- a/test/integration/generated/pagingNoIterators/src/operations/paging.ts +++ b/test/integration/generated/pagingNoIterators/src/operations/paging.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { PagingNoIteratorsClientContext } from "../pagingNoIteratorsClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { PagingGetNoItemNamePagesOptionalParams, PagingGetNoItemNamePagesResponse, @@ -359,15 +360,22 @@ export class PagingImpl implements Paging { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { options }, - getMultiplePagesLROOperationSpec, - sendOperation + getMultiplePagesLROOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/integration/lro.spec.ts b/test/integration/lro.spec.ts index 7352e321a8..5358bbf13c 100644 --- a/test/integration/lro.spec.ts +++ b/test/integration/lro.spec.ts @@ -145,7 +145,10 @@ describe("LROs", () => { await client.lROs.beginPut200Acceptedcanceled200AndWait(LROOptions); throw new Error("should have thrown instead"); } catch (e) { - assert.equal(e.message, "Provisioning state: canceled"); + assert.equal( + e.message, + "The long running operation has failed. The provisioning state: canceled." + ); } }); @@ -163,7 +166,10 @@ describe("LROs", () => { await client.lROs.beginPut201CreatingFailed200AndWait(LROOptions); throw new Error("should have thrown instead"); } catch (e) { - assert.equal(e.message, "Provisioning state: failed"); + assert.equal( + e.message, + "The long running operation has failed. The provisioning state: failed." + ); } }); }); @@ -181,7 +187,10 @@ describe("LROs", () => { await client.lROs.beginPost202NoRetry204AndWait(LROOptions); throw new Error("should have thrown instead"); } catch (e) { - assert.equal(e.message, "Operation failed"); + assert.equal( + e.message, + "Received unexpected HTTP status code 204 while polling. This may indicate a server issue." + ); } }); @@ -190,7 +199,10 @@ describe("LROs", () => { await client.lROs.beginDeleteNoHeaderInRetryAndWait(LROOptions); throw new Error("should have thrown instead"); } catch (e) { - assert.equal(e.message, "Operation failed"); + assert.equal( + e.message, + "Received unexpected HTTP status code 204 while polling. This may indicate a server issue." + ); } }); @@ -234,7 +246,10 @@ describe("LROs", () => { await client.lROs.beginDelete202NoRetry204AndWait(LROOptions); throw new Error("should have thrown instead"); } catch (e) { - assert.equal(e.message, "Operation failed"); + assert.equal( + e.message, + "Received unexpected HTTP status code 204 while polling. This may indicate a server issue." + ); } }); diff --git a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/coreClientLro.ts b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/coreClientLro.ts new file mode 100644 index 0000000000..d793a24458 --- /dev/null +++ b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/coreClientLro.ts @@ -0,0 +1,323 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + OperationArguments, + OperationSpec, + OperationResponseMap, + FullOperationResponse +} from "@azure/core-client"; +import { + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + createGetLroStatusFromResponse, + RawResponse +} from "./lro"; + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +export const terminalStates = successStates.concat(failureStates); + +export type SendOperationFn = ( + args: OperationArguments, + spec: OperationSpec +) => Promise>; + +export function createPollingMethod( + sendOperationFn: SendOperationFn, + GetLroStatusFromResponse: GetLroStatusFromResponse, + args: OperationArguments, + spec: OperationSpec, + mode?: LroMode +): (path?: string) => Promise> { + /** + * Polling calls will always return a status object i.e. {"status": "success"} + * these intermediate responses are not described in the swagger so we need to + * pass custom mappers at runtime. + * This function replaces all the existing mappers to be able to deserialize a status object + * @param responses Original set of responses defined in the operation + */ + function getCompositeMappers(responses: { + [responseCode: string]: OperationResponseMap; + }): { + [responseCode: string]: OperationResponseMap; + } { + return Object.keys(responses).reduce((acc, statusCode) => { + return { + ...acc, + [statusCode]: { + ...responses[statusCode], + bodyMapper: { + type: { + name: "Composite", + modelProperties: { + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } + } + } + }; + }, {} as { [responseCode: string]: OperationResponseMap }); + } + let response: LroStatus | undefined = undefined; + const customerCallback = args?.options?.onResponse; + const updatedArgs = { + ...args, + options: { + ...args.options, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ): void => { + response = GetLroStatusFromResponse( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse as TResult + ); + if (response.done) { + customerCallback?.(rawResponse, flatResponse); + } + } + } + }; + // Make sure we don't send any body to the get request + const { requestBody, responses, ...restSpec } = spec; + if (mode === "AzureAsync") { + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: getCompositeMappers(responses), + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; + } + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: responses, + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; +} + +/** + * We need to selectively deserialize our responses, only deserializing if we + * are in a final Lro response, not deserializing any polling non-terminal responses + */ +export function shouldDeserializeLro(lroResourceLocationConfig?: string) { + let initialOperationInfo: LroResponseInfo | undefined; + let isInitialRequest = true; + + return (response: FullOperationResponse) => { + if (response.status < 200 || response.status >= 300) { + return true; + } + + if (!initialOperationInfo) { + initialOperationInfo = getLroData(response); + } else { + isInitialRequest = false; + } + + if ( + initialOperationInfo.azureAsyncOperation || + initialOperationInfo.operationLocation + ) { + return ( + !isInitialRequest && + isAsyncOperationFinalResponse( + response, + initialOperationInfo, + lroResourceLocationConfig + ) + ); + } + + if (initialOperationInfo.location) { + return isLocationFinalResponse(response); + } + + if (initialOperationInfo.requestMethod === "PUT") { + return isBodyPollingFinalResponse(response); + } + + return true; + }; +} + +function isAsyncOperationFinalResponse( + response: FullOperationResponse, + initialOperationInfo: LroResponseInfo, + lroResourceLocationConfig?: string +): boolean { + const status: string = response.parsedBody?.status || "Succeeded"; + if (!terminalStates.includes(status.toLowerCase())) { + return false; + } + + if (initialOperationInfo.requestMethod === "DELETE") { + return true; + } + + if ( + initialOperationInfo.requestMethod === "PUT" && + lroResourceLocationConfig && + lroResourceLocationConfig.toLowerCase() === "azure-asyncoperation" + ) { + return true; + } + + if ( + initialOperationInfo.requestMethod !== "PUT" && + !initialOperationInfo.location + ) { + return true; + } + + return false; +} + +function isLocationFinalResponse(response: FullOperationResponse): boolean { + return response.status !== 202; +} + +function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { + const provisioningState: string = + response.parsedBody?.properties?.provisioningState || "Succeeded"; + + if (terminalStates.includes(provisioningState.toLowerCase())) { + return true; + } + + return false; +} + +interface LroResponseInfo { + requestMethod: string; + azureAsyncOperation?: string; + operationLocation?: string; + location?: string; +} + +function getLroData(result: FullOperationResponse): LroResponseInfo { + return { + azureAsyncOperation: result.headers.get("azure-asyncoperation"), + operationLocation: result.headers.get("operation-location"), + location: result.headers.get("location"), + requestMethod: result.request.method + }; +} + +export function getSpecPath(spec: OperationSpec): string { + if (spec.path) { + return spec.path; + } else { + throw Error("Bad spec: request path is not found!"); + } +} + +export class CoreClientLro implements LongRunningOperation { + constructor( + private sendOperationFn: SendOperationFn, + private args: OperationArguments, + private spec: OperationSpec, + private lroResourceLocationConfig?: LroResourceLocationConfig, + public requestPath: string = spec.path!, + public requestMethod: string = spec.httpMethod + ) {} + public async sendInitialRequest( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ): Promise> { + const { onResponse, ...restOptions } = this.args.options || {}; + return this.sendOperationFn( + { + ...this.args, + options: { + ...restOptions, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ) => { + const isCompleted = initializeState( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse + ); + if (isCompleted) { + onResponse?.(rawResponse, flatResponse); + } + } + } + }, + this.spec + ); + } + + public async sendPollRequest( + config: LroConfig, + path: string + ): Promise> { + const getLroStatusFromResponse = createGetLroStatusFromResponse( + this, + config, + this.lroResourceLocationConfig + ); + return createPollingMethod( + this.sendOperationFn, + getLroStatusFromResponse, + this.args, + this.spec, + config.mode + )(path); + } + + public async retrieveAzureAsyncResource( + path?: string + ): Promise> { + const updatedArgs = { ...this.args }; + if (updatedArgs.options) { + (updatedArgs.options as any).shouldDeserialize = true; + } + return createPollingMethod( + this.sendOperationFn, + (rawResponse, flatResponse) => ({ + rawResponse, + flatResponse, + done: true + }), + updatedArgs, + this.spec + )(path); + } +} diff --git a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/azureAsyncPolling.ts b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/azureAsyncPolling.ts index 0d63c54f60..725578a692 100644 --- a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/azureAsyncPolling.ts +++ b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/azureAsyncPolling.ts @@ -7,39 +7,61 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { FinalStateVia, LROResult } from "./models"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroResourceLocationConfig, + LongRunningOperation, + LroBody, + LroResponse, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getResponseStatus(rawResponse: FullOperationResponse): string { - const { status } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getResponseStatus(rawResponse: RawResponse): string { + const { status } = (rawResponse.body as LroBody) ?? {}; return status?.toLowerCase() ?? "succeeded"; } -function isAzureAsyncPollingDone(rawResponse: FullOperationResponse) { +function isAzureAsyncPollingDone(rawResponse: RawResponse): boolean { const state = getResponseStatus(rawResponse); - if (failureStates.includes(state)) { + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { throw new Error(`Operation status: ${state}`); } return successStates.includes(state); } +async function sendFinalRequest( + lro: LongRunningOperation, + lroResourceLocationConfig?: LroResourceLocationConfig, + resourceLocation?: string +): Promise | undefined> { + switch (lroResourceLocationConfig) { + case "original-uri": + return lro.retrieveAzureAsyncResource(); + case "azure-async-operation": + return Promise.resolve(undefined); + case "location": + default: + return lro.retrieveAzureAsyncResource(resourceLocation); + } +} + export function processAzureAsyncOperationResult( - restrieveResource: (path?: string) => Promise>, + lro: LongRunningOperation, resourceLocation?: string, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { + lroResourceLocationConfig?: LroResourceLocationConfig +): (rawResponse: RawResponse, flatResponse: TResult) => LroStatus { return ( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult - ): LROState => { + ): LroStatus => { if (isAzureAsyncPollingDone(rawResponse)) { if (resourceLocation === undefined) { return { rawResponse, flatResponse, done: true }; @@ -49,20 +71,11 @@ export function processAzureAsyncOperationResult( flatResponse, done: false, next: async () => { - async function sendFinalRequest(): Promise< - LROResult | undefined - > { - switch (finalStateVia) { - case "original-uri": - return restrieveResource(); - case "azure-async-operation": - return Promise.resolve(undefined); - case "location": - default: - return restrieveResource(resourceLocation); - } - } - const finalResponse = await sendFinalRequest(); + const finalResponse = await sendFinalRequest( + lro, + lroResourceLocationConfig, + resourceLocation + ); return { ...(finalResponse ?? { rawResponse, diff --git a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/bodyPolling.ts b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/bodyPolling.ts index 269d8e6799..b1c87f8bc8 100644 --- a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/bodyPolling.ts +++ b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/bodyPolling.ts @@ -7,24 +7,33 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroBody, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getProvisioningState(rawResponse: FullOperationResponse): string { - const { properties, provisioningState } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getProvisioningState(rawResponse: RawResponse): string { + const { properties, provisioningState } = (rawResponse.body as LroBody) ?? {}; const state: string | undefined = properties?.provisioningState ?? provisioningState; return state?.toLowerCase() ?? "succeeded"; } -export function isBodyPollingDone(rawResponse: FullOperationResponse) { +export function isBodyPollingDone(rawResponse: RawResponse): boolean { const state = getProvisioningState(rawResponse); - if (failureStates.includes(state)) { - throw new Error(`Provisioning state: ${state}`); + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { + throw new Error( + `The long running operation has failed. The provisioning state: ${state}.` + ); } return successStates.includes(state); } @@ -34,9 +43,9 @@ export function isBodyPollingDone(rawResponse: FullOperationResponse) { * from the result to determine the current operation state */ export function processBodyPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/index.ts b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/index.ts index 85c2187669..20df608fc8 100644 --- a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/index.ts +++ b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/index.ts @@ -6,5 +6,21 @@ * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ -export { shouldDeserializeLRO } from "./requestUtils"; -export { LROPoller } from "./lroPoller"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { LroEngine } from "./lroEngine"; +export { createGetLroStatusFromResponse } from "./stateMachine"; +export { + LroResourceLocationConfig, + GetLroStatusFromResponse, + RawResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + LroTerminalState, + LroInProgressState, + LroEngineOptions +} from "./models"; diff --git a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/locationPolling.ts b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/locationPolling.ts index 6fef619384..9d1aadfbde 100644 --- a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/locationPolling.ts +++ b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/locationPolling.ts @@ -7,23 +7,21 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function isLocationPollingDone(rawResponse: FullOperationResponse) { - const code = rawResponse.status; - if (![202, 200].includes(code)) { - throw new Error(`Operation failed`); - } - return code !== 202; +function isLocationPollingDone(rawResponse: RawResponse): boolean { + return ( + !isUnexpectedPollingResponse(rawResponse) && rawResponse.statusCode !== 202 + ); } export function processLocationPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/lroEngine.ts b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/lroEngine.ts new file mode 100644 index 0000000000..85cc15e609 --- /dev/null +++ b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/lroEngine.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Poller, PollOperationState } from "@azure/core-lro"; +import { + LongRunningOperation, + LroEngineOptions, + ResumablePollOperationState +} from "./models"; +import { GenericPollOperation } from "./operation"; + +/** + * The LRO Engine, a class that performs polling. + */ +export class LroEngine< + TResult, + TState extends PollOperationState +> extends Poller { + private intervalInMs: number; + + constructor(lro: LongRunningOperation, options?: LroEngineOptions) { + const { intervalInMs = 2000, resumeFrom } = options || {}; + function deserializeState( + resumeFrom: string + ): TState & ResumablePollOperationState { + try { + return JSON.parse(resumeFrom).state; + } catch (e) { + throw new Error( + `LroEngine: Unable to deserialize state: ${resumeFrom}` + ); + } + } + const state: TState & ResumablePollOperationState = resumeFrom + ? deserializeState(resumeFrom) + : ({} as any); + + const operation = new GenericPollOperation(state, lro); + super(operation); + + this.intervalInMs = intervalInMs; + operation.setPollerConfig(this as any); + } + + /** + * The method used by the poller to wait before attempting to update its operation. + */ + delay(): Promise { + return new Promise((resolve) => + setTimeout(() => resolve(), this.intervalInMs) + ); + } +} diff --git a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/lroPoller.ts b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/lroPoller.ts deleted file mode 100644 index cd1cd64fe8..0000000000 --- a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/lroPoller.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { Poller, PollOperationState } from "@azure/core-lro"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { FinalStateVia, SendOperationFn } from "./models"; -import { GenericPollOperation } from "./operation"; - -export interface LROPollerOptions { - /** - * Defines how much time the poller is going to wait before making a new request to the service. - */ - intervalInMs?: number; - /** - * A serialized poller which can be used to resume an existing paused Long-Running-Operation. - */ - resumeFrom?: string; -} - -export class LROPoller extends Poller< - PollOperationState, - TResult -> { - private intervalInMs: number; - - constructor( - { intervalInMs = 2000, resumeFrom }: LROPollerOptions, - initialOperationArguments: OperationArguments, - initialOperationSpec: OperationSpec, - sendOperation: SendOperationFn, - finalStateVia?: FinalStateVia - ) { - const state: PollOperationState = resumeFrom - ? JSON.parse(resumeFrom).state - : {}; - - const operation = new GenericPollOperation( - state, - initialOperationArguments, - initialOperationSpec, - sendOperation, - finalStateVia - ); - super(operation); - - this.intervalInMs = intervalInMs; - operation.setPollerConfig(this as any); - } - - /** - * The method used by the poller to wait before attempting to update its operation. - */ - delay(): Promise { - return new Promise((resolve) => - setTimeout(() => resolve(), this.intervalInMs) - ); - } -} diff --git a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/models.ts b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/models.ts index a4a5a5abd6..93c3437c8e 100644 --- a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/models.ts +++ b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/models.ts @@ -7,46 +7,167 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec -} from "@azure/core-client"; import { PollOperationState } from "@azure/core-lro"; -export type FinalStateVia = +/** + * Options for the LRO poller. + */ +export interface LroEngineOptions { + /** + * Defines how much time the poller is going to wait before making a new request to the service. + */ + intervalInMs?: number; + /** + * A serialized poller which can be used to resume an existing paused Long-Running-Operation. + */ + resumeFrom?: string; +} + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +/** + * The LRO states that signal that the LRO has completed. + */ +export const terminalStates = successStates.concat(failureStates); + +/** + * The potential location of the result of the LRO if specified by the LRO extension in the swagger. + */ +export type LroResourceLocationConfig = | "azure-async-operation" | "location" | "original-uri"; -export interface LROResult { +/** + * The type of a LRO response body. This is just a convenience type for checking the status of the operation. + */ + +export interface LroBody extends Record { + /** The status of the operation. */ + status?: string; + /** The state of the provisioning process */ + provisioningState?: string; + /** The properties of the provisioning process */ + properties?: { provisioningState?: string } & Record; +} + +/** + * Simple type of the raw response. + */ +export interface RawResponse { + /** The HTTP status code */ + statusCode: number; + /** A HttpHeaders collection in the response represented as a simple JSON object where all header names have been normalized to be lower-case. */ + headers: { + [headerName: string]: string; + }; + /** The parsed response body */ + body?: unknown; +} + +/** + * The type of the response of a LRO. + */ +export interface LroResponse { + /** The flattened response */ flatResponse: T; - rawResponse: FullOperationResponse; + /** The raw response */ + rawResponse: RawResponse; } -export type LROMode = "AzureAsync" | "Location" | "Body"; +/** The type of which LRO implementation being followed by a specific API. */ +export type LroMode = "AzureAsync" | "Location" | "Body"; -export interface LROConfig { - mode?: LROMode; +/** + * The configuration of a LRO to determine how to perform polling and checking whether the operation has completed. + */ +export interface LroConfig { + /** The LRO mode */ + mode?: LroMode; + /** The path of a provisioned resource */ resourceLocation?: string; } -export type SendOperationFn = ( - args: OperationArguments, - spec: OperationSpec -) => Promise>; - /** * Type of a polling operation state that can actually be resumed. */ export type ResumablePollOperationState = PollOperationState & { - initialRawResponse?: FullOperationResponse; - config?: LROConfig; + initialRawResponse?: RawResponse; + config?: LroConfig; pollingURL?: string; }; export interface PollerConfig { intervalInMs: number; } + +/** + * The type of a terminal state of an LRO. + */ +export interface LroTerminalState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: true; +} + +/** + * The type of an in-progress state of an LRO. + */ +export interface LroInProgressState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: false; + /** + * The request to be sent next if it is different from the standard polling one. + * Notice that it will disregard any polling URLs provided to it. + */ + next?: () => Promise>; +} + +/** + * The type of an LRO state which is a tagged union of terminal and in-progress states. + */ +export type LroStatus = LroTerminalState | LroInProgressState; + +/** + * The type of the getLROStatusFromResponse method. It takes the response as input and returns along the response whether the operation has finished. + */ +export type GetLroStatusFromResponse = ( + rawResponse: RawResponse, + flatResponse: T +) => LroStatus; + +/** + * Description of a long running operation. + */ +export interface LongRunningOperation { + /** + * The request path. + */ + requestPath: string; + /** + * The HTTP request method. + */ + requestMethod: string; + /** + * A function that can be used to send initial request to the service. + */ + sendInitialRequest: ( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ) => Promise>; + /** + * A function that can be used to poll for the current status of a long running operation. + */ + sendPollRequest: (config: LroConfig, path: string) => Promise>; + /** + * A function that can be used to retrieve the provisioned azure resource. + */ + retrieveAzureAsyncResource: (path?: string) => Promise>; +} diff --git a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/operation.ts b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/operation.ts index 801d03e720..3ea7b76d89 100644 --- a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/operation.ts +++ b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/operation.ts @@ -7,36 +7,34 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. import { AbortSignalLike } from "@azure/abort-controller"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { PollOperation, PollOperationState } from "@azure/core-lro"; +import { PollOperationState, PollOperation } from "@azure/core-lro"; import { - FinalStateVia, PollerConfig, ResumablePollOperationState, - SendOperationFn + LongRunningOperation, + LroStatus } from "./models"; -import { getPollingURL } from "./requestUtils"; -import { createGetLROState, initializeState, LROState } from "./stateMachine"; +import { getPollingUrl } from "./requestUtils"; +import { createInitializeState, createPollForLROStatus } from "./stateMachine"; -export class GenericPollOperation - implements PollOperation, TResult> { - private getLROState?: ( +export class GenericPollOperation< + TResult, + TState extends PollOperationState +> implements PollOperation { + private getLROStatusFromResponse?: ( pollingURL: string, pollerConfig: PollerConfig - ) => Promise>; + ) => Promise>; private pollerConfig?: PollerConfig; constructor( - public state: PollOperationState, - private initialOperationArguments: OperationArguments, - private initialOperationSpec: OperationSpec, - private sendOperation: SendOperationFn, - private finalStateVia?: FinalStateVia + public state: TState & ResumablePollOperationState, + private lro: LongRunningOperation ) {} - public setPollerConfig(pollerConfig: PollerConfig) { + public setPollerConfig(pollerConfig: PollerConfig): void { this.pollerConfig = pollerConfig; } @@ -57,45 +55,36 @@ export class GenericPollOperation */ async update(options?: { abortSignal?: AbortSignalLike | undefined; - fireProgress?: ((state: PollOperationState) => void) | undefined; - }): Promise, TResult>> { - const state = this.state as ResumablePollOperationState; - const { onResponse, ...restOptions } = - this.initialOperationArguments.options || {}; + fireProgress?: ((state: TState) => void) | undefined; + }): Promise> { + const state = this.state; if (!state.isStarted) { - await this.sendOperation( - { - ...this.initialOperationArguments, - options: { - ...restOptions, - onResponse: initializeState( - state, - this.initialOperationSpec, - onResponse - ) - } - }, - this.initialOperationSpec + const initializeState = createInitializeState( + state, + this.lro.requestPath, + this.lro.requestMethod ); + await this.lro.sendInitialRequest(initializeState); } if (!state.isCompleted) { - if (this.getLROState === undefined) { + if (this.getLROStatusFromResponse === undefined) { if (state.config === undefined) { - throw new Error("Bad state: LRO mode is undefined"); + throw new Error( + "Bad state: LRO mode is undefined. Please check if the serialized state is well-formed." + ); } - this.getLROState = createGetLROState( - this.sendOperation, - this.initialOperationArguments, - this.initialOperationSpec, - state.config, - this.finalStateVia + this.getLROStatusFromResponse = createPollForLROStatus( + this.lro, + state.config ); } if (state.pollingURL === undefined) { - throw new Error("Bad state: polling URL is undefined"); + throw new Error( + "Bad state: polling URL is undefined. Please check if the serialized state is well-formed." + ); } - const currentState = await this.getLROState( + const currentState = await this.getLROStatusFromResponse( state.pollingURL, this.pollerConfig! ); @@ -103,20 +92,19 @@ export class GenericPollOperation state.result = currentState.flatResponse; state.isCompleted = true; } else { - this.getLROState = currentState.next ?? this.getLROState; - state.pollingURL = getPollingURL( + this.getLROStatusFromResponse = + currentState.next ?? this.getLROStatusFromResponse; + state.pollingURL = getPollingUrl( currentState.rawResponse, state.pollingURL ); } } - if (options?.fireProgress !== undefined) { - options.fireProgress(state); - } + options?.fireProgress?.(state); return this; } - async cancel(): Promise, TResult>> { + async cancel(): Promise> { this.state.isCancelled = true; return this; } diff --git a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/passthrough.ts b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/passthrough.ts index 64c10380c1..ae7f87d384 100644 --- a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/passthrough.ts +++ b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/passthrough.ts @@ -7,15 +7,14 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; export function processPassthroughOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/pollingMethod.ts b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/pollingMethod.ts deleted file mode 100644 index cb6482bbde..0000000000 --- a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/pollingMethod.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - OperationArguments, - OperationSpec, - OperationResponseMap -} from "@azure/core-client"; -import { LROMode, LROResult, SendOperationFn } from "./models"; - -export function createPollingMethod( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - mode?: LROMode -): (path?: string) => Promise> { - /** - * Polling calls will always return a status object i.e. {"status": "success"} - * these intermediate responses are not described in the swagger so we need to - * pass custom mappers at runtime. - * This function replaces all the existing mappers to be able to deserialize a status object - * @param responses Original set of responses defined in the operation - */ - function getCompositeMappers(responses: { - [responseCode: string]: OperationResponseMap; - }): { - [responseCode: string]: OperationResponseMap; - } { - return Object.keys(responses).reduce((acc, statusCode) => { - return { - ...acc, - [statusCode]: { - ...responses[statusCode], - bodyMapper: { - type: { - name: "Composite", - modelProperties: { - status: { - serializedName: "status", - type: { - name: "String" - } - } - } - } - } - } - }; - }, {} as { [responseCode: string]: OperationResponseMap }); - } - // Make sure we don't send any body to the get request - const { requestBody, responses, ...restSpec } = spec; - if (mode === "AzureAsync") { - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: getCompositeMappers(responses), - httpMethod: "GET", - ...(path && { path }) - }); - }; - } - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: responses, - httpMethod: "GET", - ...(path && { path }) - }); - }; -} - -export function createRetrieveAzureAsyncResource( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec -): (path?: string) => Promise> { - const updatedArgs = { ...args }; - if (updatedArgs.options) { - (updatedArgs.options as any).shouldDeserialize = true; - } - return createPollingMethod(sendOperationFn, updatedArgs, spec); -} diff --git a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/requestUtils.ts b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/requestUtils.ts index 9162f66339..40d993686f 100644 --- a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/requestUtils.ts +++ b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/requestUtils.ts @@ -7,119 +7,9 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse, OperationSpec } from "@azure/core-client"; -import { LROConfig } from "./models"; -import { terminalStates } from "./stateMachine"; - -/** - * We need to selectively deserialize our responses, only deserializing if we - * are in a final LRO response, not deserializing any polling non-terminal responses - */ -export function shouldDeserializeLRO(finalStateVia?: string) { - let initialOperationInfo: LROResponseInfo | undefined; - let isInitialRequest = true; - - return (response: FullOperationResponse) => { - if (response.status < 200 || response.status >= 300) { - return true; - } - - if (!initialOperationInfo) { - initialOperationInfo = getLROData(response); - } else { - isInitialRequest = false; - } - - if ( - initialOperationInfo.azureAsyncOperation || - initialOperationInfo.operationLocation - ) { - return ( - !isInitialRequest && - isAsyncOperationFinalResponse( - response, - initialOperationInfo, - finalStateVia - ) - ); - } - - if (initialOperationInfo.location) { - return isLocationFinalResponse(response); - } - - if (initialOperationInfo.requestMethod === "PUT") { - return isBodyPollingFinalResponse(response); - } - - return true; - }; -} - -function isAsyncOperationFinalResponse( - response: FullOperationResponse, - initialOperationInfo: LROResponseInfo, - finalStateVia?: string -): boolean { - const status: string = response.parsedBody?.status || "Succeeded"; - if (!terminalStates.includes(status.toLowerCase())) { - return false; - } - - if (initialOperationInfo.requestMethod === "DELETE") { - return true; - } - - if ( - initialOperationInfo.requestMethod === "PUT" && - finalStateVia && - finalStateVia.toLowerCase() === "azure-asyncoperation" - ) { - return true; - } - - if ( - initialOperationInfo.requestMethod !== "PUT" && - !initialOperationInfo.location - ) { - return true; - } - - return false; -} - -function isLocationFinalResponse(response: FullOperationResponse): boolean { - return response.status !== 202; -} - -function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { - const provisioningState: string = - response.parsedBody?.properties?.provisioningState || "Succeeded"; - - if (terminalStates.includes(provisioningState.toLowerCase())) { - return true; - } - - return false; -} - -interface LROResponseInfo { - requestMethod: string; - azureAsyncOperation?: string; - operationLocation?: string; - location?: string; -} - -function getLROData(result: FullOperationResponse): LROResponseInfo { - return { - azureAsyncOperation: result.headers.get("azure-asyncoperation"), - operationLocation: result.headers.get("operation-location"), - location: result.headers.get("location"), - requestMethod: result.request.method - }; -} +import { LroConfig, RawResponse } from "./models"; /** * Detects where the continuation token is and returns it. Notice that azure-asyncoperation @@ -127,45 +17,41 @@ function getLROData(result: FullOperationResponse): LROResponseInfo { * where both azure-asyncoperation and location could be present in the same response but * azure-asyncoperation should be the one to use for polling. */ -export function getPollingURL( - rawResponse: FullOperationResponse, +export function getPollingUrl( + rawResponse: RawResponse, defaultPath: string ): string { return ( - getAzureAsyncoperation(rawResponse) ?? + getAzureAsyncOperation(rawResponse) ?? getLocation(rawResponse) ?? getOperationLocation(rawResponse) ?? defaultPath ); } -function getLocation(rawResponse: FullOperationResponse): string | undefined { - return rawResponse.headers?.get("location"); +function getLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["location"]; } -function getOperationLocation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("operation-location"); +function getOperationLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["operation-location"]; } -function getAzureAsyncoperation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("azure-asyncoperation"); +function getAzureAsyncOperation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["azure-asyncoperation"]; } -export function inferLROMode( - spec: OperationSpec, - rawResponse: FullOperationResponse -): LROConfig { - const requestMethod = spec.httpMethod; - if (getAzureAsyncoperation(rawResponse) !== undefined) { +export function inferLroMode( + requestPath: string, + requestMethod: string, + rawResponse: RawResponse +): LroConfig { + if (getAzureAsyncOperation(rawResponse) !== undefined) { return { mode: "AzureAsync", resourceLocation: requestMethod === "PUT" - ? spec.path + ? requestPath : requestMethod === "POST" ? getLocation(rawResponse) : undefined @@ -185,10 +71,35 @@ export function inferLROMode( return {}; } -export function getSpecPath(spec: OperationSpec): string { - if (spec.path) { - return spec.path; - } else { - throw Error("Bad spec: request path is not found!"); +export class RestError extends Error { + public statusCode?: number; + constructor(message: string, statusCode: number) { + super(message); + this.name = "RestError"; + this.statusCode = statusCode; + + Object.setPrototypeOf(this, RestError.prototype); + } +} + +export function isUnexpectedInitialResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![203, 204, 202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} in the initial response. This may indicate a server issue.`, + code + ); } + return false; +} + +export function isUnexpectedPollingResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} while polling. This may indicate a server issue.`, + code + ); + } + return false; } diff --git a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/stateMachine.ts b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/stateMachine.ts index b2a69b5546..19a8f67470 100644 --- a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/stateMachine.ts +++ b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/lro/stateMachine.ts @@ -7,14 +7,8 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec, - RawResponseCallback -} from "@azure/core-client"; import { processAzureAsyncOperationResult } from "./azureAsyncPolling"; import { isBodyPollingDone, @@ -22,73 +16,36 @@ import { } from "./bodyPolling"; import { processLocationPollingOperationResult } from "./locationPolling"; import { - FinalStateVia, - LROConfig, - LROResult, + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroStatus, PollerConfig, - ResumablePollOperationState, - SendOperationFn + RawResponse, + ResumablePollOperationState } from "./models"; import { processPassthroughOperationResult } from "./passthrough"; import { - createPollingMethod, - createRetrieveAzureAsyncResource -} from "./pollingMethod"; -import { getPollingURL, getSpecPath, inferLROMode } from "./requestUtils"; - -export const successStates = ["succeeded"]; -export const failureStates = ["failed", "canceled", "cancelled"]; -export const terminalStates = successStates.concat(failureStates); - -/** - * The type of a terminal state of an LRO. - */ -interface LROTerminalState extends LROResult { - /** - * Whether the operation has finished. - */ - done: true; -} - -/** - * The type of an in-progress state of an LRO. - */ -interface LROInProgressState extends LROResult { - /** - * Whether the operation has finished. - */ - done: false; - /** - * The request to be sent next if it is different from the standard polling one. - * Notice that it will disregard any polling URLs provided to it. - */ - next?: () => Promise>; -} - -/** - * The type of an LRO state which is a tagged union of terminal and in-progress states. - */ -export type LROState = LROTerminalState | LROInProgressState; + getPollingUrl, + inferLroMode, + isUnexpectedInitialResponse +} from "./requestUtils"; /** * creates a stepping function that maps an LRO state to another. */ -function createTransition( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { +export function createGetLroStatusFromResponse( + lroPrimitives: LongRunningOperation, + config: LroConfig, + lroResourceLocationConfig?: LroResourceLocationConfig +): GetLroStatusFromResponse { switch (config.mode) { case "AzureAsync": { return processAzureAsyncOperationResult( - createRetrieveAzureAsyncResource(sendOperationFn, args, spec), + lroPrimitives, config.resourceLocation, - finalStateVia + lroResourceLocationConfig ); } case "Location": { @@ -106,52 +63,20 @@ function createTransition( /** * Creates a polling operation that returns a LRO state. */ -export function createGetLROState( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia +export function createPollForLROStatus( + lroPrimitives: LongRunningOperation, + config: LroConfig ): ( pollingURL: string, pollerConfig: PollerConfig -) => Promise> { - const step = createTransition( - sendOperationFn, - args, - spec, - config, - finalStateVia - ); - const customerCallback = args?.options?.onResponse; - let response: LROState | undefined = undefined; - let retryAfter: string | undefined = undefined; - const poll = createPollingMethod( - sendOperationFn, - { - ...args, - options: { - ...args.options, - onResponse: ( - rawResponse: FullOperationResponse, - flatResponse: unknown - ): void => { - response = step(rawResponse, flatResponse as TResult); - retryAfter = rawResponse.headers.get("Retry-After"); - if (response.done) { - customerCallback?.(rawResponse, flatResponse); - } - } - } - }, - spec, - config.mode - ); +) => Promise> { return async ( path: string, pollerConfig: PollerConfig - ): Promise> => { - await poll(path); + ): Promise> => { + const response = await lroPrimitives.sendPollRequest(config, path); + const retryAfter: string | undefined = + response.rawResponse.headers["retry-after"]; if (retryAfter !== undefined) { const retryAfterInMs = parseInt(retryAfter); pollerConfig.intervalInMs = isNaN(retryAfterInMs) @@ -161,7 +86,7 @@ export function createGetLROState( ) : retryAfterInMs; } - return response!; + return response; }; } @@ -179,24 +104,26 @@ function calculatePollingIntervalFromDate( /** * Creates a callback to be used to initialize the polling operation state. - * @param state of the polling operation - * @param operationSpec of the LRO - * @param callback callback to be called when the operation is done + * @param state - of the polling operation + * @param operationSpec - of the LRO + * @param callback - callback to be called when the operation is done * @returns callback that initializes the state of the polling operation */ -export function initializeState( +export function createInitializeState( state: ResumablePollOperationState, - operationSpec: OperationSpec, - callback?: RawResponseCallback -): (rawResponse: FullOperationResponse, flatResponse: unknown) => void { - return (rawResponse: FullOperationResponse, flatResponse: unknown) => { + requestPath: string, + requestMethod: string +): (rawResponse: RawResponse, flatResponse: unknown) => boolean { + return (rawResponse: RawResponse, flatResponse: unknown) => { + if (isUnexpectedInitialResponse(rawResponse)) return true; state.initialRawResponse = rawResponse; state.isStarted = true; - state.pollingURL = getPollingURL( - state.initialRawResponse, - getSpecPath(operationSpec) + state.pollingURL = getPollingUrl(state.initialRawResponse, requestPath); + state.config = inferLroMode( + requestPath, + requestMethod, + state.initialRawResponse ); - state.config = inferLROMode(operationSpec, state.initialRawResponse); /** short circuit polling if body polling is done in the initial request */ if ( state.config.mode === undefined || @@ -205,12 +132,7 @@ export function initializeState( ) { state.result = flatResponse as TResult; state.isCompleted = true; - /** - * We need to check if the LRO operation is finished inside the - * call back so that we can call the customer-provided callback - * on that result. - */ - callback?.(rawResponse, flatResponse); } + return Boolean(state.isCompleted); }; } diff --git a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/operations/deploymentScripts.ts b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/operations/deploymentScripts.ts index 3efb950bd5..782d48fea4 100644 --- a/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/operations/deploymentScripts.ts +++ b/test/smoke/generated/arm-package-deploymentscripts-2019-10-preview/src/operations/deploymentScripts.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { DeploymentScriptsClientContext } from "../deploymentScriptsClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { DeploymentScriptUnion, DeploymentScriptsListBySubscriptionNextOptionalParams, @@ -193,15 +194,22 @@ export class DeploymentScriptsImpl implements DeploymentScripts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, scriptName, deploymentScript, options }, - createOperationSpec, - sendOperation + createOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/arm-package-managedapplications-2018-06/src/coreClientLro.ts b/test/smoke/generated/arm-package-managedapplications-2018-06/src/coreClientLro.ts new file mode 100644 index 0000000000..d793a24458 --- /dev/null +++ b/test/smoke/generated/arm-package-managedapplications-2018-06/src/coreClientLro.ts @@ -0,0 +1,323 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + OperationArguments, + OperationSpec, + OperationResponseMap, + FullOperationResponse +} from "@azure/core-client"; +import { + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + createGetLroStatusFromResponse, + RawResponse +} from "./lro"; + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +export const terminalStates = successStates.concat(failureStates); + +export type SendOperationFn = ( + args: OperationArguments, + spec: OperationSpec +) => Promise>; + +export function createPollingMethod( + sendOperationFn: SendOperationFn, + GetLroStatusFromResponse: GetLroStatusFromResponse, + args: OperationArguments, + spec: OperationSpec, + mode?: LroMode +): (path?: string) => Promise> { + /** + * Polling calls will always return a status object i.e. {"status": "success"} + * these intermediate responses are not described in the swagger so we need to + * pass custom mappers at runtime. + * This function replaces all the existing mappers to be able to deserialize a status object + * @param responses Original set of responses defined in the operation + */ + function getCompositeMappers(responses: { + [responseCode: string]: OperationResponseMap; + }): { + [responseCode: string]: OperationResponseMap; + } { + return Object.keys(responses).reduce((acc, statusCode) => { + return { + ...acc, + [statusCode]: { + ...responses[statusCode], + bodyMapper: { + type: { + name: "Composite", + modelProperties: { + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } + } + } + }; + }, {} as { [responseCode: string]: OperationResponseMap }); + } + let response: LroStatus | undefined = undefined; + const customerCallback = args?.options?.onResponse; + const updatedArgs = { + ...args, + options: { + ...args.options, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ): void => { + response = GetLroStatusFromResponse( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse as TResult + ); + if (response.done) { + customerCallback?.(rawResponse, flatResponse); + } + } + } + }; + // Make sure we don't send any body to the get request + const { requestBody, responses, ...restSpec } = spec; + if (mode === "AzureAsync") { + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: getCompositeMappers(responses), + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; + } + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: responses, + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; +} + +/** + * We need to selectively deserialize our responses, only deserializing if we + * are in a final Lro response, not deserializing any polling non-terminal responses + */ +export function shouldDeserializeLro(lroResourceLocationConfig?: string) { + let initialOperationInfo: LroResponseInfo | undefined; + let isInitialRequest = true; + + return (response: FullOperationResponse) => { + if (response.status < 200 || response.status >= 300) { + return true; + } + + if (!initialOperationInfo) { + initialOperationInfo = getLroData(response); + } else { + isInitialRequest = false; + } + + if ( + initialOperationInfo.azureAsyncOperation || + initialOperationInfo.operationLocation + ) { + return ( + !isInitialRequest && + isAsyncOperationFinalResponse( + response, + initialOperationInfo, + lroResourceLocationConfig + ) + ); + } + + if (initialOperationInfo.location) { + return isLocationFinalResponse(response); + } + + if (initialOperationInfo.requestMethod === "PUT") { + return isBodyPollingFinalResponse(response); + } + + return true; + }; +} + +function isAsyncOperationFinalResponse( + response: FullOperationResponse, + initialOperationInfo: LroResponseInfo, + lroResourceLocationConfig?: string +): boolean { + const status: string = response.parsedBody?.status || "Succeeded"; + if (!terminalStates.includes(status.toLowerCase())) { + return false; + } + + if (initialOperationInfo.requestMethod === "DELETE") { + return true; + } + + if ( + initialOperationInfo.requestMethod === "PUT" && + lroResourceLocationConfig && + lroResourceLocationConfig.toLowerCase() === "azure-asyncoperation" + ) { + return true; + } + + if ( + initialOperationInfo.requestMethod !== "PUT" && + !initialOperationInfo.location + ) { + return true; + } + + return false; +} + +function isLocationFinalResponse(response: FullOperationResponse): boolean { + return response.status !== 202; +} + +function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { + const provisioningState: string = + response.parsedBody?.properties?.provisioningState || "Succeeded"; + + if (terminalStates.includes(provisioningState.toLowerCase())) { + return true; + } + + return false; +} + +interface LroResponseInfo { + requestMethod: string; + azureAsyncOperation?: string; + operationLocation?: string; + location?: string; +} + +function getLroData(result: FullOperationResponse): LroResponseInfo { + return { + azureAsyncOperation: result.headers.get("azure-asyncoperation"), + operationLocation: result.headers.get("operation-location"), + location: result.headers.get("location"), + requestMethod: result.request.method + }; +} + +export function getSpecPath(spec: OperationSpec): string { + if (spec.path) { + return spec.path; + } else { + throw Error("Bad spec: request path is not found!"); + } +} + +export class CoreClientLro implements LongRunningOperation { + constructor( + private sendOperationFn: SendOperationFn, + private args: OperationArguments, + private spec: OperationSpec, + private lroResourceLocationConfig?: LroResourceLocationConfig, + public requestPath: string = spec.path!, + public requestMethod: string = spec.httpMethod + ) {} + public async sendInitialRequest( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ): Promise> { + const { onResponse, ...restOptions } = this.args.options || {}; + return this.sendOperationFn( + { + ...this.args, + options: { + ...restOptions, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ) => { + const isCompleted = initializeState( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse + ); + if (isCompleted) { + onResponse?.(rawResponse, flatResponse); + } + } + } + }, + this.spec + ); + } + + public async sendPollRequest( + config: LroConfig, + path: string + ): Promise> { + const getLroStatusFromResponse = createGetLroStatusFromResponse( + this, + config, + this.lroResourceLocationConfig + ); + return createPollingMethod( + this.sendOperationFn, + getLroStatusFromResponse, + this.args, + this.spec, + config.mode + )(path); + } + + public async retrieveAzureAsyncResource( + path?: string + ): Promise> { + const updatedArgs = { ...this.args }; + if (updatedArgs.options) { + (updatedArgs.options as any).shouldDeserialize = true; + } + return createPollingMethod( + this.sendOperationFn, + (rawResponse, flatResponse) => ({ + rawResponse, + flatResponse, + done: true + }), + updatedArgs, + this.spec + )(path); + } +} diff --git a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/azureAsyncPolling.ts b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/azureAsyncPolling.ts index 0d63c54f60..725578a692 100644 --- a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/azureAsyncPolling.ts +++ b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/azureAsyncPolling.ts @@ -7,39 +7,61 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { FinalStateVia, LROResult } from "./models"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroResourceLocationConfig, + LongRunningOperation, + LroBody, + LroResponse, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getResponseStatus(rawResponse: FullOperationResponse): string { - const { status } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getResponseStatus(rawResponse: RawResponse): string { + const { status } = (rawResponse.body as LroBody) ?? {}; return status?.toLowerCase() ?? "succeeded"; } -function isAzureAsyncPollingDone(rawResponse: FullOperationResponse) { +function isAzureAsyncPollingDone(rawResponse: RawResponse): boolean { const state = getResponseStatus(rawResponse); - if (failureStates.includes(state)) { + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { throw new Error(`Operation status: ${state}`); } return successStates.includes(state); } +async function sendFinalRequest( + lro: LongRunningOperation, + lroResourceLocationConfig?: LroResourceLocationConfig, + resourceLocation?: string +): Promise | undefined> { + switch (lroResourceLocationConfig) { + case "original-uri": + return lro.retrieveAzureAsyncResource(); + case "azure-async-operation": + return Promise.resolve(undefined); + case "location": + default: + return lro.retrieveAzureAsyncResource(resourceLocation); + } +} + export function processAzureAsyncOperationResult( - restrieveResource: (path?: string) => Promise>, + lro: LongRunningOperation, resourceLocation?: string, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { + lroResourceLocationConfig?: LroResourceLocationConfig +): (rawResponse: RawResponse, flatResponse: TResult) => LroStatus { return ( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult - ): LROState => { + ): LroStatus => { if (isAzureAsyncPollingDone(rawResponse)) { if (resourceLocation === undefined) { return { rawResponse, flatResponse, done: true }; @@ -49,20 +71,11 @@ export function processAzureAsyncOperationResult( flatResponse, done: false, next: async () => { - async function sendFinalRequest(): Promise< - LROResult | undefined - > { - switch (finalStateVia) { - case "original-uri": - return restrieveResource(); - case "azure-async-operation": - return Promise.resolve(undefined); - case "location": - default: - return restrieveResource(resourceLocation); - } - } - const finalResponse = await sendFinalRequest(); + const finalResponse = await sendFinalRequest( + lro, + lroResourceLocationConfig, + resourceLocation + ); return { ...(finalResponse ?? { rawResponse, diff --git a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/bodyPolling.ts b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/bodyPolling.ts index 269d8e6799..b1c87f8bc8 100644 --- a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/bodyPolling.ts +++ b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/bodyPolling.ts @@ -7,24 +7,33 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroBody, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getProvisioningState(rawResponse: FullOperationResponse): string { - const { properties, provisioningState } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getProvisioningState(rawResponse: RawResponse): string { + const { properties, provisioningState } = (rawResponse.body as LroBody) ?? {}; const state: string | undefined = properties?.provisioningState ?? provisioningState; return state?.toLowerCase() ?? "succeeded"; } -export function isBodyPollingDone(rawResponse: FullOperationResponse) { +export function isBodyPollingDone(rawResponse: RawResponse): boolean { const state = getProvisioningState(rawResponse); - if (failureStates.includes(state)) { - throw new Error(`Provisioning state: ${state}`); + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { + throw new Error( + `The long running operation has failed. The provisioning state: ${state}.` + ); } return successStates.includes(state); } @@ -34,9 +43,9 @@ export function isBodyPollingDone(rawResponse: FullOperationResponse) { * from the result to determine the current operation state */ export function processBodyPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/index.ts b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/index.ts index 85c2187669..20df608fc8 100644 --- a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/index.ts +++ b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/index.ts @@ -6,5 +6,21 @@ * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ -export { shouldDeserializeLRO } from "./requestUtils"; -export { LROPoller } from "./lroPoller"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { LroEngine } from "./lroEngine"; +export { createGetLroStatusFromResponse } from "./stateMachine"; +export { + LroResourceLocationConfig, + GetLroStatusFromResponse, + RawResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + LroTerminalState, + LroInProgressState, + LroEngineOptions +} from "./models"; diff --git a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/locationPolling.ts b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/locationPolling.ts index 6fef619384..9d1aadfbde 100644 --- a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/locationPolling.ts +++ b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/locationPolling.ts @@ -7,23 +7,21 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function isLocationPollingDone(rawResponse: FullOperationResponse) { - const code = rawResponse.status; - if (![202, 200].includes(code)) { - throw new Error(`Operation failed`); - } - return code !== 202; +function isLocationPollingDone(rawResponse: RawResponse): boolean { + return ( + !isUnexpectedPollingResponse(rawResponse) && rawResponse.statusCode !== 202 + ); } export function processLocationPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/lroEngine.ts b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/lroEngine.ts new file mode 100644 index 0000000000..85cc15e609 --- /dev/null +++ b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/lroEngine.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Poller, PollOperationState } from "@azure/core-lro"; +import { + LongRunningOperation, + LroEngineOptions, + ResumablePollOperationState +} from "./models"; +import { GenericPollOperation } from "./operation"; + +/** + * The LRO Engine, a class that performs polling. + */ +export class LroEngine< + TResult, + TState extends PollOperationState +> extends Poller { + private intervalInMs: number; + + constructor(lro: LongRunningOperation, options?: LroEngineOptions) { + const { intervalInMs = 2000, resumeFrom } = options || {}; + function deserializeState( + resumeFrom: string + ): TState & ResumablePollOperationState { + try { + return JSON.parse(resumeFrom).state; + } catch (e) { + throw new Error( + `LroEngine: Unable to deserialize state: ${resumeFrom}` + ); + } + } + const state: TState & ResumablePollOperationState = resumeFrom + ? deserializeState(resumeFrom) + : ({} as any); + + const operation = new GenericPollOperation(state, lro); + super(operation); + + this.intervalInMs = intervalInMs; + operation.setPollerConfig(this as any); + } + + /** + * The method used by the poller to wait before attempting to update its operation. + */ + delay(): Promise { + return new Promise((resolve) => + setTimeout(() => resolve(), this.intervalInMs) + ); + } +} diff --git a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/lroPoller.ts b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/lroPoller.ts deleted file mode 100644 index cd1cd64fe8..0000000000 --- a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/lroPoller.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { Poller, PollOperationState } from "@azure/core-lro"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { FinalStateVia, SendOperationFn } from "./models"; -import { GenericPollOperation } from "./operation"; - -export interface LROPollerOptions { - /** - * Defines how much time the poller is going to wait before making a new request to the service. - */ - intervalInMs?: number; - /** - * A serialized poller which can be used to resume an existing paused Long-Running-Operation. - */ - resumeFrom?: string; -} - -export class LROPoller extends Poller< - PollOperationState, - TResult -> { - private intervalInMs: number; - - constructor( - { intervalInMs = 2000, resumeFrom }: LROPollerOptions, - initialOperationArguments: OperationArguments, - initialOperationSpec: OperationSpec, - sendOperation: SendOperationFn, - finalStateVia?: FinalStateVia - ) { - const state: PollOperationState = resumeFrom - ? JSON.parse(resumeFrom).state - : {}; - - const operation = new GenericPollOperation( - state, - initialOperationArguments, - initialOperationSpec, - sendOperation, - finalStateVia - ); - super(operation); - - this.intervalInMs = intervalInMs; - operation.setPollerConfig(this as any); - } - - /** - * The method used by the poller to wait before attempting to update its operation. - */ - delay(): Promise { - return new Promise((resolve) => - setTimeout(() => resolve(), this.intervalInMs) - ); - } -} diff --git a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/models.ts b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/models.ts index a4a5a5abd6..93c3437c8e 100644 --- a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/models.ts +++ b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/models.ts @@ -7,46 +7,167 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec -} from "@azure/core-client"; import { PollOperationState } from "@azure/core-lro"; -export type FinalStateVia = +/** + * Options for the LRO poller. + */ +export interface LroEngineOptions { + /** + * Defines how much time the poller is going to wait before making a new request to the service. + */ + intervalInMs?: number; + /** + * A serialized poller which can be used to resume an existing paused Long-Running-Operation. + */ + resumeFrom?: string; +} + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +/** + * The LRO states that signal that the LRO has completed. + */ +export const terminalStates = successStates.concat(failureStates); + +/** + * The potential location of the result of the LRO if specified by the LRO extension in the swagger. + */ +export type LroResourceLocationConfig = | "azure-async-operation" | "location" | "original-uri"; -export interface LROResult { +/** + * The type of a LRO response body. This is just a convenience type for checking the status of the operation. + */ + +export interface LroBody extends Record { + /** The status of the operation. */ + status?: string; + /** The state of the provisioning process */ + provisioningState?: string; + /** The properties of the provisioning process */ + properties?: { provisioningState?: string } & Record; +} + +/** + * Simple type of the raw response. + */ +export interface RawResponse { + /** The HTTP status code */ + statusCode: number; + /** A HttpHeaders collection in the response represented as a simple JSON object where all header names have been normalized to be lower-case. */ + headers: { + [headerName: string]: string; + }; + /** The parsed response body */ + body?: unknown; +} + +/** + * The type of the response of a LRO. + */ +export interface LroResponse { + /** The flattened response */ flatResponse: T; - rawResponse: FullOperationResponse; + /** The raw response */ + rawResponse: RawResponse; } -export type LROMode = "AzureAsync" | "Location" | "Body"; +/** The type of which LRO implementation being followed by a specific API. */ +export type LroMode = "AzureAsync" | "Location" | "Body"; -export interface LROConfig { - mode?: LROMode; +/** + * The configuration of a LRO to determine how to perform polling and checking whether the operation has completed. + */ +export interface LroConfig { + /** The LRO mode */ + mode?: LroMode; + /** The path of a provisioned resource */ resourceLocation?: string; } -export type SendOperationFn = ( - args: OperationArguments, - spec: OperationSpec -) => Promise>; - /** * Type of a polling operation state that can actually be resumed. */ export type ResumablePollOperationState = PollOperationState & { - initialRawResponse?: FullOperationResponse; - config?: LROConfig; + initialRawResponse?: RawResponse; + config?: LroConfig; pollingURL?: string; }; export interface PollerConfig { intervalInMs: number; } + +/** + * The type of a terminal state of an LRO. + */ +export interface LroTerminalState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: true; +} + +/** + * The type of an in-progress state of an LRO. + */ +export interface LroInProgressState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: false; + /** + * The request to be sent next if it is different from the standard polling one. + * Notice that it will disregard any polling URLs provided to it. + */ + next?: () => Promise>; +} + +/** + * The type of an LRO state which is a tagged union of terminal and in-progress states. + */ +export type LroStatus = LroTerminalState | LroInProgressState; + +/** + * The type of the getLROStatusFromResponse method. It takes the response as input and returns along the response whether the operation has finished. + */ +export type GetLroStatusFromResponse = ( + rawResponse: RawResponse, + flatResponse: T +) => LroStatus; + +/** + * Description of a long running operation. + */ +export interface LongRunningOperation { + /** + * The request path. + */ + requestPath: string; + /** + * The HTTP request method. + */ + requestMethod: string; + /** + * A function that can be used to send initial request to the service. + */ + sendInitialRequest: ( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ) => Promise>; + /** + * A function that can be used to poll for the current status of a long running operation. + */ + sendPollRequest: (config: LroConfig, path: string) => Promise>; + /** + * A function that can be used to retrieve the provisioned azure resource. + */ + retrieveAzureAsyncResource: (path?: string) => Promise>; +} diff --git a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/operation.ts b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/operation.ts index 801d03e720..3ea7b76d89 100644 --- a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/operation.ts +++ b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/operation.ts @@ -7,36 +7,34 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. import { AbortSignalLike } from "@azure/abort-controller"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { PollOperation, PollOperationState } from "@azure/core-lro"; +import { PollOperationState, PollOperation } from "@azure/core-lro"; import { - FinalStateVia, PollerConfig, ResumablePollOperationState, - SendOperationFn + LongRunningOperation, + LroStatus } from "./models"; -import { getPollingURL } from "./requestUtils"; -import { createGetLROState, initializeState, LROState } from "./stateMachine"; +import { getPollingUrl } from "./requestUtils"; +import { createInitializeState, createPollForLROStatus } from "./stateMachine"; -export class GenericPollOperation - implements PollOperation, TResult> { - private getLROState?: ( +export class GenericPollOperation< + TResult, + TState extends PollOperationState +> implements PollOperation { + private getLROStatusFromResponse?: ( pollingURL: string, pollerConfig: PollerConfig - ) => Promise>; + ) => Promise>; private pollerConfig?: PollerConfig; constructor( - public state: PollOperationState, - private initialOperationArguments: OperationArguments, - private initialOperationSpec: OperationSpec, - private sendOperation: SendOperationFn, - private finalStateVia?: FinalStateVia + public state: TState & ResumablePollOperationState, + private lro: LongRunningOperation ) {} - public setPollerConfig(pollerConfig: PollerConfig) { + public setPollerConfig(pollerConfig: PollerConfig): void { this.pollerConfig = pollerConfig; } @@ -57,45 +55,36 @@ export class GenericPollOperation */ async update(options?: { abortSignal?: AbortSignalLike | undefined; - fireProgress?: ((state: PollOperationState) => void) | undefined; - }): Promise, TResult>> { - const state = this.state as ResumablePollOperationState; - const { onResponse, ...restOptions } = - this.initialOperationArguments.options || {}; + fireProgress?: ((state: TState) => void) | undefined; + }): Promise> { + const state = this.state; if (!state.isStarted) { - await this.sendOperation( - { - ...this.initialOperationArguments, - options: { - ...restOptions, - onResponse: initializeState( - state, - this.initialOperationSpec, - onResponse - ) - } - }, - this.initialOperationSpec + const initializeState = createInitializeState( + state, + this.lro.requestPath, + this.lro.requestMethod ); + await this.lro.sendInitialRequest(initializeState); } if (!state.isCompleted) { - if (this.getLROState === undefined) { + if (this.getLROStatusFromResponse === undefined) { if (state.config === undefined) { - throw new Error("Bad state: LRO mode is undefined"); + throw new Error( + "Bad state: LRO mode is undefined. Please check if the serialized state is well-formed." + ); } - this.getLROState = createGetLROState( - this.sendOperation, - this.initialOperationArguments, - this.initialOperationSpec, - state.config, - this.finalStateVia + this.getLROStatusFromResponse = createPollForLROStatus( + this.lro, + state.config ); } if (state.pollingURL === undefined) { - throw new Error("Bad state: polling URL is undefined"); + throw new Error( + "Bad state: polling URL is undefined. Please check if the serialized state is well-formed." + ); } - const currentState = await this.getLROState( + const currentState = await this.getLROStatusFromResponse( state.pollingURL, this.pollerConfig! ); @@ -103,20 +92,19 @@ export class GenericPollOperation state.result = currentState.flatResponse; state.isCompleted = true; } else { - this.getLROState = currentState.next ?? this.getLROState; - state.pollingURL = getPollingURL( + this.getLROStatusFromResponse = + currentState.next ?? this.getLROStatusFromResponse; + state.pollingURL = getPollingUrl( currentState.rawResponse, state.pollingURL ); } } - if (options?.fireProgress !== undefined) { - options.fireProgress(state); - } + options?.fireProgress?.(state); return this; } - async cancel(): Promise, TResult>> { + async cancel(): Promise> { this.state.isCancelled = true; return this; } diff --git a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/passthrough.ts b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/passthrough.ts index 64c10380c1..ae7f87d384 100644 --- a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/passthrough.ts +++ b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/passthrough.ts @@ -7,15 +7,14 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; export function processPassthroughOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/pollingMethod.ts b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/pollingMethod.ts deleted file mode 100644 index cb6482bbde..0000000000 --- a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/pollingMethod.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - OperationArguments, - OperationSpec, - OperationResponseMap -} from "@azure/core-client"; -import { LROMode, LROResult, SendOperationFn } from "./models"; - -export function createPollingMethod( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - mode?: LROMode -): (path?: string) => Promise> { - /** - * Polling calls will always return a status object i.e. {"status": "success"} - * these intermediate responses are not described in the swagger so we need to - * pass custom mappers at runtime. - * This function replaces all the existing mappers to be able to deserialize a status object - * @param responses Original set of responses defined in the operation - */ - function getCompositeMappers(responses: { - [responseCode: string]: OperationResponseMap; - }): { - [responseCode: string]: OperationResponseMap; - } { - return Object.keys(responses).reduce((acc, statusCode) => { - return { - ...acc, - [statusCode]: { - ...responses[statusCode], - bodyMapper: { - type: { - name: "Composite", - modelProperties: { - status: { - serializedName: "status", - type: { - name: "String" - } - } - } - } - } - } - }; - }, {} as { [responseCode: string]: OperationResponseMap }); - } - // Make sure we don't send any body to the get request - const { requestBody, responses, ...restSpec } = spec; - if (mode === "AzureAsync") { - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: getCompositeMappers(responses), - httpMethod: "GET", - ...(path && { path }) - }); - }; - } - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: responses, - httpMethod: "GET", - ...(path && { path }) - }); - }; -} - -export function createRetrieveAzureAsyncResource( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec -): (path?: string) => Promise> { - const updatedArgs = { ...args }; - if (updatedArgs.options) { - (updatedArgs.options as any).shouldDeserialize = true; - } - return createPollingMethod(sendOperationFn, updatedArgs, spec); -} diff --git a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/requestUtils.ts b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/requestUtils.ts index 9162f66339..40d993686f 100644 --- a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/requestUtils.ts +++ b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/requestUtils.ts @@ -7,119 +7,9 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse, OperationSpec } from "@azure/core-client"; -import { LROConfig } from "./models"; -import { terminalStates } from "./stateMachine"; - -/** - * We need to selectively deserialize our responses, only deserializing if we - * are in a final LRO response, not deserializing any polling non-terminal responses - */ -export function shouldDeserializeLRO(finalStateVia?: string) { - let initialOperationInfo: LROResponseInfo | undefined; - let isInitialRequest = true; - - return (response: FullOperationResponse) => { - if (response.status < 200 || response.status >= 300) { - return true; - } - - if (!initialOperationInfo) { - initialOperationInfo = getLROData(response); - } else { - isInitialRequest = false; - } - - if ( - initialOperationInfo.azureAsyncOperation || - initialOperationInfo.operationLocation - ) { - return ( - !isInitialRequest && - isAsyncOperationFinalResponse( - response, - initialOperationInfo, - finalStateVia - ) - ); - } - - if (initialOperationInfo.location) { - return isLocationFinalResponse(response); - } - - if (initialOperationInfo.requestMethod === "PUT") { - return isBodyPollingFinalResponse(response); - } - - return true; - }; -} - -function isAsyncOperationFinalResponse( - response: FullOperationResponse, - initialOperationInfo: LROResponseInfo, - finalStateVia?: string -): boolean { - const status: string = response.parsedBody?.status || "Succeeded"; - if (!terminalStates.includes(status.toLowerCase())) { - return false; - } - - if (initialOperationInfo.requestMethod === "DELETE") { - return true; - } - - if ( - initialOperationInfo.requestMethod === "PUT" && - finalStateVia && - finalStateVia.toLowerCase() === "azure-asyncoperation" - ) { - return true; - } - - if ( - initialOperationInfo.requestMethod !== "PUT" && - !initialOperationInfo.location - ) { - return true; - } - - return false; -} - -function isLocationFinalResponse(response: FullOperationResponse): boolean { - return response.status !== 202; -} - -function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { - const provisioningState: string = - response.parsedBody?.properties?.provisioningState || "Succeeded"; - - if (terminalStates.includes(provisioningState.toLowerCase())) { - return true; - } - - return false; -} - -interface LROResponseInfo { - requestMethod: string; - azureAsyncOperation?: string; - operationLocation?: string; - location?: string; -} - -function getLROData(result: FullOperationResponse): LROResponseInfo { - return { - azureAsyncOperation: result.headers.get("azure-asyncoperation"), - operationLocation: result.headers.get("operation-location"), - location: result.headers.get("location"), - requestMethod: result.request.method - }; -} +import { LroConfig, RawResponse } from "./models"; /** * Detects where the continuation token is and returns it. Notice that azure-asyncoperation @@ -127,45 +17,41 @@ function getLROData(result: FullOperationResponse): LROResponseInfo { * where both azure-asyncoperation and location could be present in the same response but * azure-asyncoperation should be the one to use for polling. */ -export function getPollingURL( - rawResponse: FullOperationResponse, +export function getPollingUrl( + rawResponse: RawResponse, defaultPath: string ): string { return ( - getAzureAsyncoperation(rawResponse) ?? + getAzureAsyncOperation(rawResponse) ?? getLocation(rawResponse) ?? getOperationLocation(rawResponse) ?? defaultPath ); } -function getLocation(rawResponse: FullOperationResponse): string | undefined { - return rawResponse.headers?.get("location"); +function getLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["location"]; } -function getOperationLocation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("operation-location"); +function getOperationLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["operation-location"]; } -function getAzureAsyncoperation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("azure-asyncoperation"); +function getAzureAsyncOperation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["azure-asyncoperation"]; } -export function inferLROMode( - spec: OperationSpec, - rawResponse: FullOperationResponse -): LROConfig { - const requestMethod = spec.httpMethod; - if (getAzureAsyncoperation(rawResponse) !== undefined) { +export function inferLroMode( + requestPath: string, + requestMethod: string, + rawResponse: RawResponse +): LroConfig { + if (getAzureAsyncOperation(rawResponse) !== undefined) { return { mode: "AzureAsync", resourceLocation: requestMethod === "PUT" - ? spec.path + ? requestPath : requestMethod === "POST" ? getLocation(rawResponse) : undefined @@ -185,10 +71,35 @@ export function inferLROMode( return {}; } -export function getSpecPath(spec: OperationSpec): string { - if (spec.path) { - return spec.path; - } else { - throw Error("Bad spec: request path is not found!"); +export class RestError extends Error { + public statusCode?: number; + constructor(message: string, statusCode: number) { + super(message); + this.name = "RestError"; + this.statusCode = statusCode; + + Object.setPrototypeOf(this, RestError.prototype); + } +} + +export function isUnexpectedInitialResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![203, 204, 202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} in the initial response. This may indicate a server issue.`, + code + ); } + return false; +} + +export function isUnexpectedPollingResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} while polling. This may indicate a server issue.`, + code + ); + } + return false; } diff --git a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/stateMachine.ts b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/stateMachine.ts index b2a69b5546..19a8f67470 100644 --- a/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/stateMachine.ts +++ b/test/smoke/generated/arm-package-managedapplications-2018-06/src/lro/stateMachine.ts @@ -7,14 +7,8 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec, - RawResponseCallback -} from "@azure/core-client"; import { processAzureAsyncOperationResult } from "./azureAsyncPolling"; import { isBodyPollingDone, @@ -22,73 +16,36 @@ import { } from "./bodyPolling"; import { processLocationPollingOperationResult } from "./locationPolling"; import { - FinalStateVia, - LROConfig, - LROResult, + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroStatus, PollerConfig, - ResumablePollOperationState, - SendOperationFn + RawResponse, + ResumablePollOperationState } from "./models"; import { processPassthroughOperationResult } from "./passthrough"; import { - createPollingMethod, - createRetrieveAzureAsyncResource -} from "./pollingMethod"; -import { getPollingURL, getSpecPath, inferLROMode } from "./requestUtils"; - -export const successStates = ["succeeded"]; -export const failureStates = ["failed", "canceled", "cancelled"]; -export const terminalStates = successStates.concat(failureStates); - -/** - * The type of a terminal state of an LRO. - */ -interface LROTerminalState extends LROResult { - /** - * Whether the operation has finished. - */ - done: true; -} - -/** - * The type of an in-progress state of an LRO. - */ -interface LROInProgressState extends LROResult { - /** - * Whether the operation has finished. - */ - done: false; - /** - * The request to be sent next if it is different from the standard polling one. - * Notice that it will disregard any polling URLs provided to it. - */ - next?: () => Promise>; -} - -/** - * The type of an LRO state which is a tagged union of terminal and in-progress states. - */ -export type LROState = LROTerminalState | LROInProgressState; + getPollingUrl, + inferLroMode, + isUnexpectedInitialResponse +} from "./requestUtils"; /** * creates a stepping function that maps an LRO state to another. */ -function createTransition( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { +export function createGetLroStatusFromResponse( + lroPrimitives: LongRunningOperation, + config: LroConfig, + lroResourceLocationConfig?: LroResourceLocationConfig +): GetLroStatusFromResponse { switch (config.mode) { case "AzureAsync": { return processAzureAsyncOperationResult( - createRetrieveAzureAsyncResource(sendOperationFn, args, spec), + lroPrimitives, config.resourceLocation, - finalStateVia + lroResourceLocationConfig ); } case "Location": { @@ -106,52 +63,20 @@ function createTransition( /** * Creates a polling operation that returns a LRO state. */ -export function createGetLROState( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia +export function createPollForLROStatus( + lroPrimitives: LongRunningOperation, + config: LroConfig ): ( pollingURL: string, pollerConfig: PollerConfig -) => Promise> { - const step = createTransition( - sendOperationFn, - args, - spec, - config, - finalStateVia - ); - const customerCallback = args?.options?.onResponse; - let response: LROState | undefined = undefined; - let retryAfter: string | undefined = undefined; - const poll = createPollingMethod( - sendOperationFn, - { - ...args, - options: { - ...args.options, - onResponse: ( - rawResponse: FullOperationResponse, - flatResponse: unknown - ): void => { - response = step(rawResponse, flatResponse as TResult); - retryAfter = rawResponse.headers.get("Retry-After"); - if (response.done) { - customerCallback?.(rawResponse, flatResponse); - } - } - } - }, - spec, - config.mode - ); +) => Promise> { return async ( path: string, pollerConfig: PollerConfig - ): Promise> => { - await poll(path); + ): Promise> => { + const response = await lroPrimitives.sendPollRequest(config, path); + const retryAfter: string | undefined = + response.rawResponse.headers["retry-after"]; if (retryAfter !== undefined) { const retryAfterInMs = parseInt(retryAfter); pollerConfig.intervalInMs = isNaN(retryAfterInMs) @@ -161,7 +86,7 @@ export function createGetLROState( ) : retryAfterInMs; } - return response!; + return response; }; } @@ -179,24 +104,26 @@ function calculatePollingIntervalFromDate( /** * Creates a callback to be used to initialize the polling operation state. - * @param state of the polling operation - * @param operationSpec of the LRO - * @param callback callback to be called when the operation is done + * @param state - of the polling operation + * @param operationSpec - of the LRO + * @param callback - callback to be called when the operation is done * @returns callback that initializes the state of the polling operation */ -export function initializeState( +export function createInitializeState( state: ResumablePollOperationState, - operationSpec: OperationSpec, - callback?: RawResponseCallback -): (rawResponse: FullOperationResponse, flatResponse: unknown) => void { - return (rawResponse: FullOperationResponse, flatResponse: unknown) => { + requestPath: string, + requestMethod: string +): (rawResponse: RawResponse, flatResponse: unknown) => boolean { + return (rawResponse: RawResponse, flatResponse: unknown) => { + if (isUnexpectedInitialResponse(rawResponse)) return true; state.initialRawResponse = rawResponse; state.isStarted = true; - state.pollingURL = getPollingURL( - state.initialRawResponse, - getSpecPath(operationSpec) + state.pollingURL = getPollingUrl(state.initialRawResponse, requestPath); + state.config = inferLroMode( + requestPath, + requestMethod, + state.initialRawResponse ); - state.config = inferLROMode(operationSpec, state.initialRawResponse); /** short circuit polling if body polling is done in the initial request */ if ( state.config.mode === undefined || @@ -205,12 +132,7 @@ export function initializeState( ) { state.result = flatResponse as TResult; state.isCompleted = true; - /** - * We need to check if the LRO operation is finished inside the - * call back so that we can call the customer-provided callback - * on that result. - */ - callback?.(rawResponse, flatResponse); } + return Boolean(state.isCompleted); }; } diff --git a/test/smoke/generated/arm-package-managedapplications-2018-06/src/operations/applicationDefinitions.ts b/test/smoke/generated/arm-package-managedapplications-2018-06/src/operations/applicationDefinitions.ts index 5e49a0c5a7..c64e04f310 100644 --- a/test/smoke/generated/arm-package-managedapplications-2018-06/src/operations/applicationDefinitions.ts +++ b/test/smoke/generated/arm-package-managedapplications-2018-06/src/operations/applicationDefinitions.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ApplicationClientContext } from "../applicationClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ApplicationDefinition, ApplicationDefinitionsListByResourceGroupNextOptionalParams, @@ -156,15 +157,22 @@ export class ApplicationDefinitionsImpl implements ApplicationDefinitions { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, applicationDefinitionName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -233,15 +241,22 @@ export class ApplicationDefinitionsImpl implements ApplicationDefinitions { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, applicationDefinitionName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -340,15 +355,22 @@ export class ApplicationDefinitionsImpl implements ApplicationDefinitions { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { applicationDefinitionId, options }, - deleteByIdOperationSpec, - sendOperation + deleteByIdOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -415,15 +437,22 @@ export class ApplicationDefinitionsImpl implements ApplicationDefinitions { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { applicationDefinitionId, parameters, options }, - createOrUpdateByIdOperationSpec, - sendOperation + createOrUpdateByIdOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/arm-package-managedapplications-2018-06/src/operations/applications.ts b/test/smoke/generated/arm-package-managedapplications-2018-06/src/operations/applications.ts index 6471b883b1..37d02a93be 100644 --- a/test/smoke/generated/arm-package-managedapplications-2018-06/src/operations/applications.ts +++ b/test/smoke/generated/arm-package-managedapplications-2018-06/src/operations/applications.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ApplicationClientContext } from "../applicationClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { Application, ApplicationsListByResourceGroupNextOptionalParams, @@ -206,15 +207,22 @@ export class ApplicationsImpl implements Applications { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, applicationName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -283,15 +291,22 @@ export class ApplicationsImpl implements Applications { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, applicationName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -419,15 +434,22 @@ export class ApplicationsImpl implements Applications { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { applicationId, options }, - deleteByIdOperationSpec, - sendOperation + deleteByIdOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -492,15 +514,22 @@ export class ApplicationsImpl implements Applications { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { applicationId, parameters, options }, - createOrUpdateByIdOperationSpec, - sendOperation + createOrUpdateByIdOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/arm-package-resources-2019-08/src/coreClientLro.ts b/test/smoke/generated/arm-package-resources-2019-08/src/coreClientLro.ts new file mode 100644 index 0000000000..d793a24458 --- /dev/null +++ b/test/smoke/generated/arm-package-resources-2019-08/src/coreClientLro.ts @@ -0,0 +1,323 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + OperationArguments, + OperationSpec, + OperationResponseMap, + FullOperationResponse +} from "@azure/core-client"; +import { + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + createGetLroStatusFromResponse, + RawResponse +} from "./lro"; + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +export const terminalStates = successStates.concat(failureStates); + +export type SendOperationFn = ( + args: OperationArguments, + spec: OperationSpec +) => Promise>; + +export function createPollingMethod( + sendOperationFn: SendOperationFn, + GetLroStatusFromResponse: GetLroStatusFromResponse, + args: OperationArguments, + spec: OperationSpec, + mode?: LroMode +): (path?: string) => Promise> { + /** + * Polling calls will always return a status object i.e. {"status": "success"} + * these intermediate responses are not described in the swagger so we need to + * pass custom mappers at runtime. + * This function replaces all the existing mappers to be able to deserialize a status object + * @param responses Original set of responses defined in the operation + */ + function getCompositeMappers(responses: { + [responseCode: string]: OperationResponseMap; + }): { + [responseCode: string]: OperationResponseMap; + } { + return Object.keys(responses).reduce((acc, statusCode) => { + return { + ...acc, + [statusCode]: { + ...responses[statusCode], + bodyMapper: { + type: { + name: "Composite", + modelProperties: { + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } + } + } + }; + }, {} as { [responseCode: string]: OperationResponseMap }); + } + let response: LroStatus | undefined = undefined; + const customerCallback = args?.options?.onResponse; + const updatedArgs = { + ...args, + options: { + ...args.options, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ): void => { + response = GetLroStatusFromResponse( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse as TResult + ); + if (response.done) { + customerCallback?.(rawResponse, flatResponse); + } + } + } + }; + // Make sure we don't send any body to the get request + const { requestBody, responses, ...restSpec } = spec; + if (mode === "AzureAsync") { + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: getCompositeMappers(responses), + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; + } + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: responses, + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; +} + +/** + * We need to selectively deserialize our responses, only deserializing if we + * are in a final Lro response, not deserializing any polling non-terminal responses + */ +export function shouldDeserializeLro(lroResourceLocationConfig?: string) { + let initialOperationInfo: LroResponseInfo | undefined; + let isInitialRequest = true; + + return (response: FullOperationResponse) => { + if (response.status < 200 || response.status >= 300) { + return true; + } + + if (!initialOperationInfo) { + initialOperationInfo = getLroData(response); + } else { + isInitialRequest = false; + } + + if ( + initialOperationInfo.azureAsyncOperation || + initialOperationInfo.operationLocation + ) { + return ( + !isInitialRequest && + isAsyncOperationFinalResponse( + response, + initialOperationInfo, + lroResourceLocationConfig + ) + ); + } + + if (initialOperationInfo.location) { + return isLocationFinalResponse(response); + } + + if (initialOperationInfo.requestMethod === "PUT") { + return isBodyPollingFinalResponse(response); + } + + return true; + }; +} + +function isAsyncOperationFinalResponse( + response: FullOperationResponse, + initialOperationInfo: LroResponseInfo, + lroResourceLocationConfig?: string +): boolean { + const status: string = response.parsedBody?.status || "Succeeded"; + if (!terminalStates.includes(status.toLowerCase())) { + return false; + } + + if (initialOperationInfo.requestMethod === "DELETE") { + return true; + } + + if ( + initialOperationInfo.requestMethod === "PUT" && + lroResourceLocationConfig && + lroResourceLocationConfig.toLowerCase() === "azure-asyncoperation" + ) { + return true; + } + + if ( + initialOperationInfo.requestMethod !== "PUT" && + !initialOperationInfo.location + ) { + return true; + } + + return false; +} + +function isLocationFinalResponse(response: FullOperationResponse): boolean { + return response.status !== 202; +} + +function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { + const provisioningState: string = + response.parsedBody?.properties?.provisioningState || "Succeeded"; + + if (terminalStates.includes(provisioningState.toLowerCase())) { + return true; + } + + return false; +} + +interface LroResponseInfo { + requestMethod: string; + azureAsyncOperation?: string; + operationLocation?: string; + location?: string; +} + +function getLroData(result: FullOperationResponse): LroResponseInfo { + return { + azureAsyncOperation: result.headers.get("azure-asyncoperation"), + operationLocation: result.headers.get("operation-location"), + location: result.headers.get("location"), + requestMethod: result.request.method + }; +} + +export function getSpecPath(spec: OperationSpec): string { + if (spec.path) { + return spec.path; + } else { + throw Error("Bad spec: request path is not found!"); + } +} + +export class CoreClientLro implements LongRunningOperation { + constructor( + private sendOperationFn: SendOperationFn, + private args: OperationArguments, + private spec: OperationSpec, + private lroResourceLocationConfig?: LroResourceLocationConfig, + public requestPath: string = spec.path!, + public requestMethod: string = spec.httpMethod + ) {} + public async sendInitialRequest( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ): Promise> { + const { onResponse, ...restOptions } = this.args.options || {}; + return this.sendOperationFn( + { + ...this.args, + options: { + ...restOptions, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ) => { + const isCompleted = initializeState( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse + ); + if (isCompleted) { + onResponse?.(rawResponse, flatResponse); + } + } + } + }, + this.spec + ); + } + + public async sendPollRequest( + config: LroConfig, + path: string + ): Promise> { + const getLroStatusFromResponse = createGetLroStatusFromResponse( + this, + config, + this.lroResourceLocationConfig + ); + return createPollingMethod( + this.sendOperationFn, + getLroStatusFromResponse, + this.args, + this.spec, + config.mode + )(path); + } + + public async retrieveAzureAsyncResource( + path?: string + ): Promise> { + const updatedArgs = { ...this.args }; + if (updatedArgs.options) { + (updatedArgs.options as any).shouldDeserialize = true; + } + return createPollingMethod( + this.sendOperationFn, + (rawResponse, flatResponse) => ({ + rawResponse, + flatResponse, + done: true + }), + updatedArgs, + this.spec + )(path); + } +} diff --git a/test/smoke/generated/arm-package-resources-2019-08/src/lro/azureAsyncPolling.ts b/test/smoke/generated/arm-package-resources-2019-08/src/lro/azureAsyncPolling.ts index 0d63c54f60..725578a692 100644 --- a/test/smoke/generated/arm-package-resources-2019-08/src/lro/azureAsyncPolling.ts +++ b/test/smoke/generated/arm-package-resources-2019-08/src/lro/azureAsyncPolling.ts @@ -7,39 +7,61 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { FinalStateVia, LROResult } from "./models"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroResourceLocationConfig, + LongRunningOperation, + LroBody, + LroResponse, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getResponseStatus(rawResponse: FullOperationResponse): string { - const { status } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getResponseStatus(rawResponse: RawResponse): string { + const { status } = (rawResponse.body as LroBody) ?? {}; return status?.toLowerCase() ?? "succeeded"; } -function isAzureAsyncPollingDone(rawResponse: FullOperationResponse) { +function isAzureAsyncPollingDone(rawResponse: RawResponse): boolean { const state = getResponseStatus(rawResponse); - if (failureStates.includes(state)) { + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { throw new Error(`Operation status: ${state}`); } return successStates.includes(state); } +async function sendFinalRequest( + lro: LongRunningOperation, + lroResourceLocationConfig?: LroResourceLocationConfig, + resourceLocation?: string +): Promise | undefined> { + switch (lroResourceLocationConfig) { + case "original-uri": + return lro.retrieveAzureAsyncResource(); + case "azure-async-operation": + return Promise.resolve(undefined); + case "location": + default: + return lro.retrieveAzureAsyncResource(resourceLocation); + } +} + export function processAzureAsyncOperationResult( - restrieveResource: (path?: string) => Promise>, + lro: LongRunningOperation, resourceLocation?: string, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { + lroResourceLocationConfig?: LroResourceLocationConfig +): (rawResponse: RawResponse, flatResponse: TResult) => LroStatus { return ( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult - ): LROState => { + ): LroStatus => { if (isAzureAsyncPollingDone(rawResponse)) { if (resourceLocation === undefined) { return { rawResponse, flatResponse, done: true }; @@ -49,20 +71,11 @@ export function processAzureAsyncOperationResult( flatResponse, done: false, next: async () => { - async function sendFinalRequest(): Promise< - LROResult | undefined - > { - switch (finalStateVia) { - case "original-uri": - return restrieveResource(); - case "azure-async-operation": - return Promise.resolve(undefined); - case "location": - default: - return restrieveResource(resourceLocation); - } - } - const finalResponse = await sendFinalRequest(); + const finalResponse = await sendFinalRequest( + lro, + lroResourceLocationConfig, + resourceLocation + ); return { ...(finalResponse ?? { rawResponse, diff --git a/test/smoke/generated/arm-package-resources-2019-08/src/lro/bodyPolling.ts b/test/smoke/generated/arm-package-resources-2019-08/src/lro/bodyPolling.ts index 269d8e6799..b1c87f8bc8 100644 --- a/test/smoke/generated/arm-package-resources-2019-08/src/lro/bodyPolling.ts +++ b/test/smoke/generated/arm-package-resources-2019-08/src/lro/bodyPolling.ts @@ -7,24 +7,33 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroBody, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getProvisioningState(rawResponse: FullOperationResponse): string { - const { properties, provisioningState } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getProvisioningState(rawResponse: RawResponse): string { + const { properties, provisioningState } = (rawResponse.body as LroBody) ?? {}; const state: string | undefined = properties?.provisioningState ?? provisioningState; return state?.toLowerCase() ?? "succeeded"; } -export function isBodyPollingDone(rawResponse: FullOperationResponse) { +export function isBodyPollingDone(rawResponse: RawResponse): boolean { const state = getProvisioningState(rawResponse); - if (failureStates.includes(state)) { - throw new Error(`Provisioning state: ${state}`); + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { + throw new Error( + `The long running operation has failed. The provisioning state: ${state}.` + ); } return successStates.includes(state); } @@ -34,9 +43,9 @@ export function isBodyPollingDone(rawResponse: FullOperationResponse) { * from the result to determine the current operation state */ export function processBodyPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/arm-package-resources-2019-08/src/lro/index.ts b/test/smoke/generated/arm-package-resources-2019-08/src/lro/index.ts index 85c2187669..20df608fc8 100644 --- a/test/smoke/generated/arm-package-resources-2019-08/src/lro/index.ts +++ b/test/smoke/generated/arm-package-resources-2019-08/src/lro/index.ts @@ -6,5 +6,21 @@ * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ -export { shouldDeserializeLRO } from "./requestUtils"; -export { LROPoller } from "./lroPoller"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { LroEngine } from "./lroEngine"; +export { createGetLroStatusFromResponse } from "./stateMachine"; +export { + LroResourceLocationConfig, + GetLroStatusFromResponse, + RawResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + LroTerminalState, + LroInProgressState, + LroEngineOptions +} from "./models"; diff --git a/test/smoke/generated/arm-package-resources-2019-08/src/lro/locationPolling.ts b/test/smoke/generated/arm-package-resources-2019-08/src/lro/locationPolling.ts index 6fef619384..9d1aadfbde 100644 --- a/test/smoke/generated/arm-package-resources-2019-08/src/lro/locationPolling.ts +++ b/test/smoke/generated/arm-package-resources-2019-08/src/lro/locationPolling.ts @@ -7,23 +7,21 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function isLocationPollingDone(rawResponse: FullOperationResponse) { - const code = rawResponse.status; - if (![202, 200].includes(code)) { - throw new Error(`Operation failed`); - } - return code !== 202; +function isLocationPollingDone(rawResponse: RawResponse): boolean { + return ( + !isUnexpectedPollingResponse(rawResponse) && rawResponse.statusCode !== 202 + ); } export function processLocationPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/arm-package-resources-2019-08/src/lro/lroEngine.ts b/test/smoke/generated/arm-package-resources-2019-08/src/lro/lroEngine.ts new file mode 100644 index 0000000000..85cc15e609 --- /dev/null +++ b/test/smoke/generated/arm-package-resources-2019-08/src/lro/lroEngine.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Poller, PollOperationState } from "@azure/core-lro"; +import { + LongRunningOperation, + LroEngineOptions, + ResumablePollOperationState +} from "./models"; +import { GenericPollOperation } from "./operation"; + +/** + * The LRO Engine, a class that performs polling. + */ +export class LroEngine< + TResult, + TState extends PollOperationState +> extends Poller { + private intervalInMs: number; + + constructor(lro: LongRunningOperation, options?: LroEngineOptions) { + const { intervalInMs = 2000, resumeFrom } = options || {}; + function deserializeState( + resumeFrom: string + ): TState & ResumablePollOperationState { + try { + return JSON.parse(resumeFrom).state; + } catch (e) { + throw new Error( + `LroEngine: Unable to deserialize state: ${resumeFrom}` + ); + } + } + const state: TState & ResumablePollOperationState = resumeFrom + ? deserializeState(resumeFrom) + : ({} as any); + + const operation = new GenericPollOperation(state, lro); + super(operation); + + this.intervalInMs = intervalInMs; + operation.setPollerConfig(this as any); + } + + /** + * The method used by the poller to wait before attempting to update its operation. + */ + delay(): Promise { + return new Promise((resolve) => + setTimeout(() => resolve(), this.intervalInMs) + ); + } +} diff --git a/test/smoke/generated/arm-package-resources-2019-08/src/lro/lroPoller.ts b/test/smoke/generated/arm-package-resources-2019-08/src/lro/lroPoller.ts deleted file mode 100644 index cd1cd64fe8..0000000000 --- a/test/smoke/generated/arm-package-resources-2019-08/src/lro/lroPoller.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { Poller, PollOperationState } from "@azure/core-lro"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { FinalStateVia, SendOperationFn } from "./models"; -import { GenericPollOperation } from "./operation"; - -export interface LROPollerOptions { - /** - * Defines how much time the poller is going to wait before making a new request to the service. - */ - intervalInMs?: number; - /** - * A serialized poller which can be used to resume an existing paused Long-Running-Operation. - */ - resumeFrom?: string; -} - -export class LROPoller extends Poller< - PollOperationState, - TResult -> { - private intervalInMs: number; - - constructor( - { intervalInMs = 2000, resumeFrom }: LROPollerOptions, - initialOperationArguments: OperationArguments, - initialOperationSpec: OperationSpec, - sendOperation: SendOperationFn, - finalStateVia?: FinalStateVia - ) { - const state: PollOperationState = resumeFrom - ? JSON.parse(resumeFrom).state - : {}; - - const operation = new GenericPollOperation( - state, - initialOperationArguments, - initialOperationSpec, - sendOperation, - finalStateVia - ); - super(operation); - - this.intervalInMs = intervalInMs; - operation.setPollerConfig(this as any); - } - - /** - * The method used by the poller to wait before attempting to update its operation. - */ - delay(): Promise { - return new Promise((resolve) => - setTimeout(() => resolve(), this.intervalInMs) - ); - } -} diff --git a/test/smoke/generated/arm-package-resources-2019-08/src/lro/models.ts b/test/smoke/generated/arm-package-resources-2019-08/src/lro/models.ts index a4a5a5abd6..93c3437c8e 100644 --- a/test/smoke/generated/arm-package-resources-2019-08/src/lro/models.ts +++ b/test/smoke/generated/arm-package-resources-2019-08/src/lro/models.ts @@ -7,46 +7,167 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec -} from "@azure/core-client"; import { PollOperationState } from "@azure/core-lro"; -export type FinalStateVia = +/** + * Options for the LRO poller. + */ +export interface LroEngineOptions { + /** + * Defines how much time the poller is going to wait before making a new request to the service. + */ + intervalInMs?: number; + /** + * A serialized poller which can be used to resume an existing paused Long-Running-Operation. + */ + resumeFrom?: string; +} + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +/** + * The LRO states that signal that the LRO has completed. + */ +export const terminalStates = successStates.concat(failureStates); + +/** + * The potential location of the result of the LRO if specified by the LRO extension in the swagger. + */ +export type LroResourceLocationConfig = | "azure-async-operation" | "location" | "original-uri"; -export interface LROResult { +/** + * The type of a LRO response body. This is just a convenience type for checking the status of the operation. + */ + +export interface LroBody extends Record { + /** The status of the operation. */ + status?: string; + /** The state of the provisioning process */ + provisioningState?: string; + /** The properties of the provisioning process */ + properties?: { provisioningState?: string } & Record; +} + +/** + * Simple type of the raw response. + */ +export interface RawResponse { + /** The HTTP status code */ + statusCode: number; + /** A HttpHeaders collection in the response represented as a simple JSON object where all header names have been normalized to be lower-case. */ + headers: { + [headerName: string]: string; + }; + /** The parsed response body */ + body?: unknown; +} + +/** + * The type of the response of a LRO. + */ +export interface LroResponse { + /** The flattened response */ flatResponse: T; - rawResponse: FullOperationResponse; + /** The raw response */ + rawResponse: RawResponse; } -export type LROMode = "AzureAsync" | "Location" | "Body"; +/** The type of which LRO implementation being followed by a specific API. */ +export type LroMode = "AzureAsync" | "Location" | "Body"; -export interface LROConfig { - mode?: LROMode; +/** + * The configuration of a LRO to determine how to perform polling and checking whether the operation has completed. + */ +export interface LroConfig { + /** The LRO mode */ + mode?: LroMode; + /** The path of a provisioned resource */ resourceLocation?: string; } -export type SendOperationFn = ( - args: OperationArguments, - spec: OperationSpec -) => Promise>; - /** * Type of a polling operation state that can actually be resumed. */ export type ResumablePollOperationState = PollOperationState & { - initialRawResponse?: FullOperationResponse; - config?: LROConfig; + initialRawResponse?: RawResponse; + config?: LroConfig; pollingURL?: string; }; export interface PollerConfig { intervalInMs: number; } + +/** + * The type of a terminal state of an LRO. + */ +export interface LroTerminalState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: true; +} + +/** + * The type of an in-progress state of an LRO. + */ +export interface LroInProgressState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: false; + /** + * The request to be sent next if it is different from the standard polling one. + * Notice that it will disregard any polling URLs provided to it. + */ + next?: () => Promise>; +} + +/** + * The type of an LRO state which is a tagged union of terminal and in-progress states. + */ +export type LroStatus = LroTerminalState | LroInProgressState; + +/** + * The type of the getLROStatusFromResponse method. It takes the response as input and returns along the response whether the operation has finished. + */ +export type GetLroStatusFromResponse = ( + rawResponse: RawResponse, + flatResponse: T +) => LroStatus; + +/** + * Description of a long running operation. + */ +export interface LongRunningOperation { + /** + * The request path. + */ + requestPath: string; + /** + * The HTTP request method. + */ + requestMethod: string; + /** + * A function that can be used to send initial request to the service. + */ + sendInitialRequest: ( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ) => Promise>; + /** + * A function that can be used to poll for the current status of a long running operation. + */ + sendPollRequest: (config: LroConfig, path: string) => Promise>; + /** + * A function that can be used to retrieve the provisioned azure resource. + */ + retrieveAzureAsyncResource: (path?: string) => Promise>; +} diff --git a/test/smoke/generated/arm-package-resources-2019-08/src/lro/operation.ts b/test/smoke/generated/arm-package-resources-2019-08/src/lro/operation.ts index 801d03e720..3ea7b76d89 100644 --- a/test/smoke/generated/arm-package-resources-2019-08/src/lro/operation.ts +++ b/test/smoke/generated/arm-package-resources-2019-08/src/lro/operation.ts @@ -7,36 +7,34 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. import { AbortSignalLike } from "@azure/abort-controller"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { PollOperation, PollOperationState } from "@azure/core-lro"; +import { PollOperationState, PollOperation } from "@azure/core-lro"; import { - FinalStateVia, PollerConfig, ResumablePollOperationState, - SendOperationFn + LongRunningOperation, + LroStatus } from "./models"; -import { getPollingURL } from "./requestUtils"; -import { createGetLROState, initializeState, LROState } from "./stateMachine"; +import { getPollingUrl } from "./requestUtils"; +import { createInitializeState, createPollForLROStatus } from "./stateMachine"; -export class GenericPollOperation - implements PollOperation, TResult> { - private getLROState?: ( +export class GenericPollOperation< + TResult, + TState extends PollOperationState +> implements PollOperation { + private getLROStatusFromResponse?: ( pollingURL: string, pollerConfig: PollerConfig - ) => Promise>; + ) => Promise>; private pollerConfig?: PollerConfig; constructor( - public state: PollOperationState, - private initialOperationArguments: OperationArguments, - private initialOperationSpec: OperationSpec, - private sendOperation: SendOperationFn, - private finalStateVia?: FinalStateVia + public state: TState & ResumablePollOperationState, + private lro: LongRunningOperation ) {} - public setPollerConfig(pollerConfig: PollerConfig) { + public setPollerConfig(pollerConfig: PollerConfig): void { this.pollerConfig = pollerConfig; } @@ -57,45 +55,36 @@ export class GenericPollOperation */ async update(options?: { abortSignal?: AbortSignalLike | undefined; - fireProgress?: ((state: PollOperationState) => void) | undefined; - }): Promise, TResult>> { - const state = this.state as ResumablePollOperationState; - const { onResponse, ...restOptions } = - this.initialOperationArguments.options || {}; + fireProgress?: ((state: TState) => void) | undefined; + }): Promise> { + const state = this.state; if (!state.isStarted) { - await this.sendOperation( - { - ...this.initialOperationArguments, - options: { - ...restOptions, - onResponse: initializeState( - state, - this.initialOperationSpec, - onResponse - ) - } - }, - this.initialOperationSpec + const initializeState = createInitializeState( + state, + this.lro.requestPath, + this.lro.requestMethod ); + await this.lro.sendInitialRequest(initializeState); } if (!state.isCompleted) { - if (this.getLROState === undefined) { + if (this.getLROStatusFromResponse === undefined) { if (state.config === undefined) { - throw new Error("Bad state: LRO mode is undefined"); + throw new Error( + "Bad state: LRO mode is undefined. Please check if the serialized state is well-formed." + ); } - this.getLROState = createGetLROState( - this.sendOperation, - this.initialOperationArguments, - this.initialOperationSpec, - state.config, - this.finalStateVia + this.getLROStatusFromResponse = createPollForLROStatus( + this.lro, + state.config ); } if (state.pollingURL === undefined) { - throw new Error("Bad state: polling URL is undefined"); + throw new Error( + "Bad state: polling URL is undefined. Please check if the serialized state is well-formed." + ); } - const currentState = await this.getLROState( + const currentState = await this.getLROStatusFromResponse( state.pollingURL, this.pollerConfig! ); @@ -103,20 +92,19 @@ export class GenericPollOperation state.result = currentState.flatResponse; state.isCompleted = true; } else { - this.getLROState = currentState.next ?? this.getLROState; - state.pollingURL = getPollingURL( + this.getLROStatusFromResponse = + currentState.next ?? this.getLROStatusFromResponse; + state.pollingURL = getPollingUrl( currentState.rawResponse, state.pollingURL ); } } - if (options?.fireProgress !== undefined) { - options.fireProgress(state); - } + options?.fireProgress?.(state); return this; } - async cancel(): Promise, TResult>> { + async cancel(): Promise> { this.state.isCancelled = true; return this; } diff --git a/test/smoke/generated/arm-package-resources-2019-08/src/lro/passthrough.ts b/test/smoke/generated/arm-package-resources-2019-08/src/lro/passthrough.ts index 64c10380c1..ae7f87d384 100644 --- a/test/smoke/generated/arm-package-resources-2019-08/src/lro/passthrough.ts +++ b/test/smoke/generated/arm-package-resources-2019-08/src/lro/passthrough.ts @@ -7,15 +7,14 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; export function processPassthroughOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/arm-package-resources-2019-08/src/lro/pollingMethod.ts b/test/smoke/generated/arm-package-resources-2019-08/src/lro/pollingMethod.ts deleted file mode 100644 index cb6482bbde..0000000000 --- a/test/smoke/generated/arm-package-resources-2019-08/src/lro/pollingMethod.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - OperationArguments, - OperationSpec, - OperationResponseMap -} from "@azure/core-client"; -import { LROMode, LROResult, SendOperationFn } from "./models"; - -export function createPollingMethod( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - mode?: LROMode -): (path?: string) => Promise> { - /** - * Polling calls will always return a status object i.e. {"status": "success"} - * these intermediate responses are not described in the swagger so we need to - * pass custom mappers at runtime. - * This function replaces all the existing mappers to be able to deserialize a status object - * @param responses Original set of responses defined in the operation - */ - function getCompositeMappers(responses: { - [responseCode: string]: OperationResponseMap; - }): { - [responseCode: string]: OperationResponseMap; - } { - return Object.keys(responses).reduce((acc, statusCode) => { - return { - ...acc, - [statusCode]: { - ...responses[statusCode], - bodyMapper: { - type: { - name: "Composite", - modelProperties: { - status: { - serializedName: "status", - type: { - name: "String" - } - } - } - } - } - } - }; - }, {} as { [responseCode: string]: OperationResponseMap }); - } - // Make sure we don't send any body to the get request - const { requestBody, responses, ...restSpec } = spec; - if (mode === "AzureAsync") { - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: getCompositeMappers(responses), - httpMethod: "GET", - ...(path && { path }) - }); - }; - } - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: responses, - httpMethod: "GET", - ...(path && { path }) - }); - }; -} - -export function createRetrieveAzureAsyncResource( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec -): (path?: string) => Promise> { - const updatedArgs = { ...args }; - if (updatedArgs.options) { - (updatedArgs.options as any).shouldDeserialize = true; - } - return createPollingMethod(sendOperationFn, updatedArgs, spec); -} diff --git a/test/smoke/generated/arm-package-resources-2019-08/src/lro/requestUtils.ts b/test/smoke/generated/arm-package-resources-2019-08/src/lro/requestUtils.ts index 9162f66339..40d993686f 100644 --- a/test/smoke/generated/arm-package-resources-2019-08/src/lro/requestUtils.ts +++ b/test/smoke/generated/arm-package-resources-2019-08/src/lro/requestUtils.ts @@ -7,119 +7,9 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse, OperationSpec } from "@azure/core-client"; -import { LROConfig } from "./models"; -import { terminalStates } from "./stateMachine"; - -/** - * We need to selectively deserialize our responses, only deserializing if we - * are in a final LRO response, not deserializing any polling non-terminal responses - */ -export function shouldDeserializeLRO(finalStateVia?: string) { - let initialOperationInfo: LROResponseInfo | undefined; - let isInitialRequest = true; - - return (response: FullOperationResponse) => { - if (response.status < 200 || response.status >= 300) { - return true; - } - - if (!initialOperationInfo) { - initialOperationInfo = getLROData(response); - } else { - isInitialRequest = false; - } - - if ( - initialOperationInfo.azureAsyncOperation || - initialOperationInfo.operationLocation - ) { - return ( - !isInitialRequest && - isAsyncOperationFinalResponse( - response, - initialOperationInfo, - finalStateVia - ) - ); - } - - if (initialOperationInfo.location) { - return isLocationFinalResponse(response); - } - - if (initialOperationInfo.requestMethod === "PUT") { - return isBodyPollingFinalResponse(response); - } - - return true; - }; -} - -function isAsyncOperationFinalResponse( - response: FullOperationResponse, - initialOperationInfo: LROResponseInfo, - finalStateVia?: string -): boolean { - const status: string = response.parsedBody?.status || "Succeeded"; - if (!terminalStates.includes(status.toLowerCase())) { - return false; - } - - if (initialOperationInfo.requestMethod === "DELETE") { - return true; - } - - if ( - initialOperationInfo.requestMethod === "PUT" && - finalStateVia && - finalStateVia.toLowerCase() === "azure-asyncoperation" - ) { - return true; - } - - if ( - initialOperationInfo.requestMethod !== "PUT" && - !initialOperationInfo.location - ) { - return true; - } - - return false; -} - -function isLocationFinalResponse(response: FullOperationResponse): boolean { - return response.status !== 202; -} - -function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { - const provisioningState: string = - response.parsedBody?.properties?.provisioningState || "Succeeded"; - - if (terminalStates.includes(provisioningState.toLowerCase())) { - return true; - } - - return false; -} - -interface LROResponseInfo { - requestMethod: string; - azureAsyncOperation?: string; - operationLocation?: string; - location?: string; -} - -function getLROData(result: FullOperationResponse): LROResponseInfo { - return { - azureAsyncOperation: result.headers.get("azure-asyncoperation"), - operationLocation: result.headers.get("operation-location"), - location: result.headers.get("location"), - requestMethod: result.request.method - }; -} +import { LroConfig, RawResponse } from "./models"; /** * Detects where the continuation token is and returns it. Notice that azure-asyncoperation @@ -127,45 +17,41 @@ function getLROData(result: FullOperationResponse): LROResponseInfo { * where both azure-asyncoperation and location could be present in the same response but * azure-asyncoperation should be the one to use for polling. */ -export function getPollingURL( - rawResponse: FullOperationResponse, +export function getPollingUrl( + rawResponse: RawResponse, defaultPath: string ): string { return ( - getAzureAsyncoperation(rawResponse) ?? + getAzureAsyncOperation(rawResponse) ?? getLocation(rawResponse) ?? getOperationLocation(rawResponse) ?? defaultPath ); } -function getLocation(rawResponse: FullOperationResponse): string | undefined { - return rawResponse.headers?.get("location"); +function getLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["location"]; } -function getOperationLocation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("operation-location"); +function getOperationLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["operation-location"]; } -function getAzureAsyncoperation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("azure-asyncoperation"); +function getAzureAsyncOperation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["azure-asyncoperation"]; } -export function inferLROMode( - spec: OperationSpec, - rawResponse: FullOperationResponse -): LROConfig { - const requestMethod = spec.httpMethod; - if (getAzureAsyncoperation(rawResponse) !== undefined) { +export function inferLroMode( + requestPath: string, + requestMethod: string, + rawResponse: RawResponse +): LroConfig { + if (getAzureAsyncOperation(rawResponse) !== undefined) { return { mode: "AzureAsync", resourceLocation: requestMethod === "PUT" - ? spec.path + ? requestPath : requestMethod === "POST" ? getLocation(rawResponse) : undefined @@ -185,10 +71,35 @@ export function inferLROMode( return {}; } -export function getSpecPath(spec: OperationSpec): string { - if (spec.path) { - return spec.path; - } else { - throw Error("Bad spec: request path is not found!"); +export class RestError extends Error { + public statusCode?: number; + constructor(message: string, statusCode: number) { + super(message); + this.name = "RestError"; + this.statusCode = statusCode; + + Object.setPrototypeOf(this, RestError.prototype); + } +} + +export function isUnexpectedInitialResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![203, 204, 202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} in the initial response. This may indicate a server issue.`, + code + ); } + return false; +} + +export function isUnexpectedPollingResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} while polling. This may indicate a server issue.`, + code + ); + } + return false; } diff --git a/test/smoke/generated/arm-package-resources-2019-08/src/lro/stateMachine.ts b/test/smoke/generated/arm-package-resources-2019-08/src/lro/stateMachine.ts index b2a69b5546..19a8f67470 100644 --- a/test/smoke/generated/arm-package-resources-2019-08/src/lro/stateMachine.ts +++ b/test/smoke/generated/arm-package-resources-2019-08/src/lro/stateMachine.ts @@ -7,14 +7,8 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec, - RawResponseCallback -} from "@azure/core-client"; import { processAzureAsyncOperationResult } from "./azureAsyncPolling"; import { isBodyPollingDone, @@ -22,73 +16,36 @@ import { } from "./bodyPolling"; import { processLocationPollingOperationResult } from "./locationPolling"; import { - FinalStateVia, - LROConfig, - LROResult, + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroStatus, PollerConfig, - ResumablePollOperationState, - SendOperationFn + RawResponse, + ResumablePollOperationState } from "./models"; import { processPassthroughOperationResult } from "./passthrough"; import { - createPollingMethod, - createRetrieveAzureAsyncResource -} from "./pollingMethod"; -import { getPollingURL, getSpecPath, inferLROMode } from "./requestUtils"; - -export const successStates = ["succeeded"]; -export const failureStates = ["failed", "canceled", "cancelled"]; -export const terminalStates = successStates.concat(failureStates); - -/** - * The type of a terminal state of an LRO. - */ -interface LROTerminalState extends LROResult { - /** - * Whether the operation has finished. - */ - done: true; -} - -/** - * The type of an in-progress state of an LRO. - */ -interface LROInProgressState extends LROResult { - /** - * Whether the operation has finished. - */ - done: false; - /** - * The request to be sent next if it is different from the standard polling one. - * Notice that it will disregard any polling URLs provided to it. - */ - next?: () => Promise>; -} - -/** - * The type of an LRO state which is a tagged union of terminal and in-progress states. - */ -export type LROState = LROTerminalState | LROInProgressState; + getPollingUrl, + inferLroMode, + isUnexpectedInitialResponse +} from "./requestUtils"; /** * creates a stepping function that maps an LRO state to another. */ -function createTransition( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { +export function createGetLroStatusFromResponse( + lroPrimitives: LongRunningOperation, + config: LroConfig, + lroResourceLocationConfig?: LroResourceLocationConfig +): GetLroStatusFromResponse { switch (config.mode) { case "AzureAsync": { return processAzureAsyncOperationResult( - createRetrieveAzureAsyncResource(sendOperationFn, args, spec), + lroPrimitives, config.resourceLocation, - finalStateVia + lroResourceLocationConfig ); } case "Location": { @@ -106,52 +63,20 @@ function createTransition( /** * Creates a polling operation that returns a LRO state. */ -export function createGetLROState( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia +export function createPollForLROStatus( + lroPrimitives: LongRunningOperation, + config: LroConfig ): ( pollingURL: string, pollerConfig: PollerConfig -) => Promise> { - const step = createTransition( - sendOperationFn, - args, - spec, - config, - finalStateVia - ); - const customerCallback = args?.options?.onResponse; - let response: LROState | undefined = undefined; - let retryAfter: string | undefined = undefined; - const poll = createPollingMethod( - sendOperationFn, - { - ...args, - options: { - ...args.options, - onResponse: ( - rawResponse: FullOperationResponse, - flatResponse: unknown - ): void => { - response = step(rawResponse, flatResponse as TResult); - retryAfter = rawResponse.headers.get("Retry-After"); - if (response.done) { - customerCallback?.(rawResponse, flatResponse); - } - } - } - }, - spec, - config.mode - ); +) => Promise> { return async ( path: string, pollerConfig: PollerConfig - ): Promise> => { - await poll(path); + ): Promise> => { + const response = await lroPrimitives.sendPollRequest(config, path); + const retryAfter: string | undefined = + response.rawResponse.headers["retry-after"]; if (retryAfter !== undefined) { const retryAfterInMs = parseInt(retryAfter); pollerConfig.intervalInMs = isNaN(retryAfterInMs) @@ -161,7 +86,7 @@ export function createGetLROState( ) : retryAfterInMs; } - return response!; + return response; }; } @@ -179,24 +104,26 @@ function calculatePollingIntervalFromDate( /** * Creates a callback to be used to initialize the polling operation state. - * @param state of the polling operation - * @param operationSpec of the LRO - * @param callback callback to be called when the operation is done + * @param state - of the polling operation + * @param operationSpec - of the LRO + * @param callback - callback to be called when the operation is done * @returns callback that initializes the state of the polling operation */ -export function initializeState( +export function createInitializeState( state: ResumablePollOperationState, - operationSpec: OperationSpec, - callback?: RawResponseCallback -): (rawResponse: FullOperationResponse, flatResponse: unknown) => void { - return (rawResponse: FullOperationResponse, flatResponse: unknown) => { + requestPath: string, + requestMethod: string +): (rawResponse: RawResponse, flatResponse: unknown) => boolean { + return (rawResponse: RawResponse, flatResponse: unknown) => { + if (isUnexpectedInitialResponse(rawResponse)) return true; state.initialRawResponse = rawResponse; state.isStarted = true; - state.pollingURL = getPollingURL( - state.initialRawResponse, - getSpecPath(operationSpec) + state.pollingURL = getPollingUrl(state.initialRawResponse, requestPath); + state.config = inferLroMode( + requestPath, + requestMethod, + state.initialRawResponse ); - state.config = inferLROMode(operationSpec, state.initialRawResponse); /** short circuit polling if body polling is done in the initial request */ if ( state.config.mode === undefined || @@ -205,12 +132,7 @@ export function initializeState( ) { state.result = flatResponse as TResult; state.isCompleted = true; - /** - * We need to check if the LRO operation is finished inside the - * call back so that we can call the customer-provided callback - * on that result. - */ - callback?.(rawResponse, flatResponse); } + return Boolean(state.isCompleted); }; } diff --git a/test/smoke/generated/arm-package-resources-2019-08/src/operations/deployments.ts b/test/smoke/generated/arm-package-resources-2019-08/src/operations/deployments.ts index 0e85095e14..4b666e2cfa 100644 --- a/test/smoke/generated/arm-package-resources-2019-08/src/operations/deployments.ts +++ b/test/smoke/generated/arm-package-resources-2019-08/src/operations/deployments.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ResourceManagementClientContext } from "../resourceManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { DeploymentExtended, DeploymentsListAtScopeNextOptionalParams, @@ -402,15 +403,22 @@ export class DeploymentsImpl implements Deployments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { scope, deploymentName, options }, - deleteAtScopeOperationSpec, - sendOperation + deleteAtScopeOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -502,15 +510,22 @@ export class DeploymentsImpl implements Deployments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { scope, deploymentName, parameters, options }, - createOrUpdateAtScopeOperationSpec, - sendOperation + createOrUpdateAtScopeOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -667,15 +682,22 @@ export class DeploymentsImpl implements Deployments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { deploymentName, options }, - deleteAtTenantScopeOperationSpec, - sendOperation + deleteAtTenantScopeOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -757,15 +779,22 @@ export class DeploymentsImpl implements Deployments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { deploymentName, parameters, options }, - createOrUpdateAtTenantScopeOperationSpec, - sendOperation + createOrUpdateAtTenantScopeOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -911,15 +940,22 @@ export class DeploymentsImpl implements Deployments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { groupId, deploymentName, options }, - deleteAtManagementGroupScopeOperationSpec, - sendOperation + deleteAtManagementGroupScopeOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1013,15 +1049,22 @@ export class DeploymentsImpl implements Deployments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { groupId, deploymentName, parameters, options }, - createOrUpdateAtManagementGroupScopeOperationSpec, - sendOperation + createOrUpdateAtManagementGroupScopeOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1178,15 +1221,22 @@ export class DeploymentsImpl implements Deployments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { deploymentName, options }, - deleteAtSubscriptionScopeOperationSpec, - sendOperation + deleteAtSubscriptionScopeOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1271,15 +1321,22 @@ export class DeploymentsImpl implements Deployments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { deploymentName, parameters, options }, - createOrUpdateAtSubscriptionScopeOperationSpec, - sendOperation + createOrUpdateAtSubscriptionScopeOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1396,16 +1453,23 @@ export class DeploymentsImpl implements Deployments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { deploymentName, parameters, options }, whatIfAtSubscriptionScopeOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1503,15 +1567,22 @@ export class DeploymentsImpl implements Deployments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, deploymentName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1607,15 +1678,22 @@ export class DeploymentsImpl implements Deployments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, deploymentName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1746,16 +1824,23 @@ export class DeploymentsImpl implements Deployments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, deploymentName, parameters, options }, whatIfOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/arm-package-resources-2019-08/src/operations/resourceGroups.ts b/test/smoke/generated/arm-package-resources-2019-08/src/operations/resourceGroups.ts index e9157bdad9..1832cf8066 100644 --- a/test/smoke/generated/arm-package-resources-2019-08/src/operations/resourceGroups.ts +++ b/test/smoke/generated/arm-package-resources-2019-08/src/operations/resourceGroups.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ResourceManagementClientContext } from "../resourceManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ResourceGroup, ResourceGroupsListNextOptionalParams, @@ -163,15 +164,22 @@ export class ResourceGroupsImpl implements ResourceGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -267,16 +275,23 @@ export class ResourceGroupsImpl implements ResourceGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, parameters, options }, exportTemplateOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/arm-package-resources-2019-08/src/operations/resources.ts b/test/smoke/generated/arm-package-resources-2019-08/src/operations/resources.ts index b4d68da494..24eaf2bad2 100644 --- a/test/smoke/generated/arm-package-resources-2019-08/src/operations/resources.ts +++ b/test/smoke/generated/arm-package-resources-2019-08/src/operations/resources.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ResourceManagementClientContext } from "../resourceManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { GenericResourceExpanded, ResourcesListByResourceGroupNextOptionalParams, @@ -213,15 +214,22 @@ export class ResourcesImpl implements Resources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { sourceResourceGroupName, parameters, options }, - moveResourcesOperationSpec, - sendOperation + moveResourcesOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -291,15 +299,22 @@ export class ResourcesImpl implements Resources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { sourceResourceGroupName, parameters, options }, - validateMoveResourcesOperationSpec, - sendOperation + validateMoveResourcesOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -419,11 +434,18 @@ export class ResourcesImpl implements Resources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, resourceProviderNamespace, @@ -433,9 +455,9 @@ export class ResourcesImpl implements Resources { apiVersion, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -526,11 +548,18 @@ export class ResourcesImpl implements Resources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, resourceProviderNamespace, @@ -541,9 +570,9 @@ export class ResourcesImpl implements Resources { parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -637,11 +666,18 @@ export class ResourcesImpl implements Resources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, resourceProviderNamespace, @@ -652,9 +688,9 @@ export class ResourcesImpl implements Resources { parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -787,15 +823,22 @@ export class ResourcesImpl implements Resources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceId, apiVersion, options }, - deleteByIdOperationSpec, - sendOperation + deleteByIdOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -864,15 +907,22 @@ export class ResourcesImpl implements Resources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceId, apiVersion, parameters, options }, - createOrUpdateByIdOperationSpec, - sendOperation + createOrUpdateByIdOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -948,15 +998,22 @@ export class ResourcesImpl implements Resources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceId, apiVersion, parameters, options }, - updateByIdOperationSpec, - sendOperation + updateByIdOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/coreClientLro.ts b/test/smoke/generated/compute-resource-manager/src/coreClientLro.ts new file mode 100644 index 0000000000..d793a24458 --- /dev/null +++ b/test/smoke/generated/compute-resource-manager/src/coreClientLro.ts @@ -0,0 +1,323 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + OperationArguments, + OperationSpec, + OperationResponseMap, + FullOperationResponse +} from "@azure/core-client"; +import { + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + createGetLroStatusFromResponse, + RawResponse +} from "./lro"; + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +export const terminalStates = successStates.concat(failureStates); + +export type SendOperationFn = ( + args: OperationArguments, + spec: OperationSpec +) => Promise>; + +export function createPollingMethod( + sendOperationFn: SendOperationFn, + GetLroStatusFromResponse: GetLroStatusFromResponse, + args: OperationArguments, + spec: OperationSpec, + mode?: LroMode +): (path?: string) => Promise> { + /** + * Polling calls will always return a status object i.e. {"status": "success"} + * these intermediate responses are not described in the swagger so we need to + * pass custom mappers at runtime. + * This function replaces all the existing mappers to be able to deserialize a status object + * @param responses Original set of responses defined in the operation + */ + function getCompositeMappers(responses: { + [responseCode: string]: OperationResponseMap; + }): { + [responseCode: string]: OperationResponseMap; + } { + return Object.keys(responses).reduce((acc, statusCode) => { + return { + ...acc, + [statusCode]: { + ...responses[statusCode], + bodyMapper: { + type: { + name: "Composite", + modelProperties: { + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } + } + } + }; + }, {} as { [responseCode: string]: OperationResponseMap }); + } + let response: LroStatus | undefined = undefined; + const customerCallback = args?.options?.onResponse; + const updatedArgs = { + ...args, + options: { + ...args.options, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ): void => { + response = GetLroStatusFromResponse( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse as TResult + ); + if (response.done) { + customerCallback?.(rawResponse, flatResponse); + } + } + } + }; + // Make sure we don't send any body to the get request + const { requestBody, responses, ...restSpec } = spec; + if (mode === "AzureAsync") { + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: getCompositeMappers(responses), + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; + } + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: responses, + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; +} + +/** + * We need to selectively deserialize our responses, only deserializing if we + * are in a final Lro response, not deserializing any polling non-terminal responses + */ +export function shouldDeserializeLro(lroResourceLocationConfig?: string) { + let initialOperationInfo: LroResponseInfo | undefined; + let isInitialRequest = true; + + return (response: FullOperationResponse) => { + if (response.status < 200 || response.status >= 300) { + return true; + } + + if (!initialOperationInfo) { + initialOperationInfo = getLroData(response); + } else { + isInitialRequest = false; + } + + if ( + initialOperationInfo.azureAsyncOperation || + initialOperationInfo.operationLocation + ) { + return ( + !isInitialRequest && + isAsyncOperationFinalResponse( + response, + initialOperationInfo, + lroResourceLocationConfig + ) + ); + } + + if (initialOperationInfo.location) { + return isLocationFinalResponse(response); + } + + if (initialOperationInfo.requestMethod === "PUT") { + return isBodyPollingFinalResponse(response); + } + + return true; + }; +} + +function isAsyncOperationFinalResponse( + response: FullOperationResponse, + initialOperationInfo: LroResponseInfo, + lroResourceLocationConfig?: string +): boolean { + const status: string = response.parsedBody?.status || "Succeeded"; + if (!terminalStates.includes(status.toLowerCase())) { + return false; + } + + if (initialOperationInfo.requestMethod === "DELETE") { + return true; + } + + if ( + initialOperationInfo.requestMethod === "PUT" && + lroResourceLocationConfig && + lroResourceLocationConfig.toLowerCase() === "azure-asyncoperation" + ) { + return true; + } + + if ( + initialOperationInfo.requestMethod !== "PUT" && + !initialOperationInfo.location + ) { + return true; + } + + return false; +} + +function isLocationFinalResponse(response: FullOperationResponse): boolean { + return response.status !== 202; +} + +function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { + const provisioningState: string = + response.parsedBody?.properties?.provisioningState || "Succeeded"; + + if (terminalStates.includes(provisioningState.toLowerCase())) { + return true; + } + + return false; +} + +interface LroResponseInfo { + requestMethod: string; + azureAsyncOperation?: string; + operationLocation?: string; + location?: string; +} + +function getLroData(result: FullOperationResponse): LroResponseInfo { + return { + azureAsyncOperation: result.headers.get("azure-asyncoperation"), + operationLocation: result.headers.get("operation-location"), + location: result.headers.get("location"), + requestMethod: result.request.method + }; +} + +export function getSpecPath(spec: OperationSpec): string { + if (spec.path) { + return spec.path; + } else { + throw Error("Bad spec: request path is not found!"); + } +} + +export class CoreClientLro implements LongRunningOperation { + constructor( + private sendOperationFn: SendOperationFn, + private args: OperationArguments, + private spec: OperationSpec, + private lroResourceLocationConfig?: LroResourceLocationConfig, + public requestPath: string = spec.path!, + public requestMethod: string = spec.httpMethod + ) {} + public async sendInitialRequest( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ): Promise> { + const { onResponse, ...restOptions } = this.args.options || {}; + return this.sendOperationFn( + { + ...this.args, + options: { + ...restOptions, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ) => { + const isCompleted = initializeState( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse + ); + if (isCompleted) { + onResponse?.(rawResponse, flatResponse); + } + } + } + }, + this.spec + ); + } + + public async sendPollRequest( + config: LroConfig, + path: string + ): Promise> { + const getLroStatusFromResponse = createGetLroStatusFromResponse( + this, + config, + this.lroResourceLocationConfig + ); + return createPollingMethod( + this.sendOperationFn, + getLroStatusFromResponse, + this.args, + this.spec, + config.mode + )(path); + } + + public async retrieveAzureAsyncResource( + path?: string + ): Promise> { + const updatedArgs = { ...this.args }; + if (updatedArgs.options) { + (updatedArgs.options as any).shouldDeserialize = true; + } + return createPollingMethod( + this.sendOperationFn, + (rawResponse, flatResponse) => ({ + rawResponse, + flatResponse, + done: true + }), + updatedArgs, + this.spec + )(path); + } +} diff --git a/test/smoke/generated/compute-resource-manager/src/lro/azureAsyncPolling.ts b/test/smoke/generated/compute-resource-manager/src/lro/azureAsyncPolling.ts index 0d63c54f60..725578a692 100644 --- a/test/smoke/generated/compute-resource-manager/src/lro/azureAsyncPolling.ts +++ b/test/smoke/generated/compute-resource-manager/src/lro/azureAsyncPolling.ts @@ -7,39 +7,61 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { FinalStateVia, LROResult } from "./models"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroResourceLocationConfig, + LongRunningOperation, + LroBody, + LroResponse, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getResponseStatus(rawResponse: FullOperationResponse): string { - const { status } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getResponseStatus(rawResponse: RawResponse): string { + const { status } = (rawResponse.body as LroBody) ?? {}; return status?.toLowerCase() ?? "succeeded"; } -function isAzureAsyncPollingDone(rawResponse: FullOperationResponse) { +function isAzureAsyncPollingDone(rawResponse: RawResponse): boolean { const state = getResponseStatus(rawResponse); - if (failureStates.includes(state)) { + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { throw new Error(`Operation status: ${state}`); } return successStates.includes(state); } +async function sendFinalRequest( + lro: LongRunningOperation, + lroResourceLocationConfig?: LroResourceLocationConfig, + resourceLocation?: string +): Promise | undefined> { + switch (lroResourceLocationConfig) { + case "original-uri": + return lro.retrieveAzureAsyncResource(); + case "azure-async-operation": + return Promise.resolve(undefined); + case "location": + default: + return lro.retrieveAzureAsyncResource(resourceLocation); + } +} + export function processAzureAsyncOperationResult( - restrieveResource: (path?: string) => Promise>, + lro: LongRunningOperation, resourceLocation?: string, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { + lroResourceLocationConfig?: LroResourceLocationConfig +): (rawResponse: RawResponse, flatResponse: TResult) => LroStatus { return ( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult - ): LROState => { + ): LroStatus => { if (isAzureAsyncPollingDone(rawResponse)) { if (resourceLocation === undefined) { return { rawResponse, flatResponse, done: true }; @@ -49,20 +71,11 @@ export function processAzureAsyncOperationResult( flatResponse, done: false, next: async () => { - async function sendFinalRequest(): Promise< - LROResult | undefined - > { - switch (finalStateVia) { - case "original-uri": - return restrieveResource(); - case "azure-async-operation": - return Promise.resolve(undefined); - case "location": - default: - return restrieveResource(resourceLocation); - } - } - const finalResponse = await sendFinalRequest(); + const finalResponse = await sendFinalRequest( + lro, + lroResourceLocationConfig, + resourceLocation + ); return { ...(finalResponse ?? { rawResponse, diff --git a/test/smoke/generated/compute-resource-manager/src/lro/bodyPolling.ts b/test/smoke/generated/compute-resource-manager/src/lro/bodyPolling.ts index 269d8e6799..b1c87f8bc8 100644 --- a/test/smoke/generated/compute-resource-manager/src/lro/bodyPolling.ts +++ b/test/smoke/generated/compute-resource-manager/src/lro/bodyPolling.ts @@ -7,24 +7,33 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroBody, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getProvisioningState(rawResponse: FullOperationResponse): string { - const { properties, provisioningState } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getProvisioningState(rawResponse: RawResponse): string { + const { properties, provisioningState } = (rawResponse.body as LroBody) ?? {}; const state: string | undefined = properties?.provisioningState ?? provisioningState; return state?.toLowerCase() ?? "succeeded"; } -export function isBodyPollingDone(rawResponse: FullOperationResponse) { +export function isBodyPollingDone(rawResponse: RawResponse): boolean { const state = getProvisioningState(rawResponse); - if (failureStates.includes(state)) { - throw new Error(`Provisioning state: ${state}`); + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { + throw new Error( + `The long running operation has failed. The provisioning state: ${state}.` + ); } return successStates.includes(state); } @@ -34,9 +43,9 @@ export function isBodyPollingDone(rawResponse: FullOperationResponse) { * from the result to determine the current operation state */ export function processBodyPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/compute-resource-manager/src/lro/index.ts b/test/smoke/generated/compute-resource-manager/src/lro/index.ts index 85c2187669..20df608fc8 100644 --- a/test/smoke/generated/compute-resource-manager/src/lro/index.ts +++ b/test/smoke/generated/compute-resource-manager/src/lro/index.ts @@ -6,5 +6,21 @@ * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ -export { shouldDeserializeLRO } from "./requestUtils"; -export { LROPoller } from "./lroPoller"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { LroEngine } from "./lroEngine"; +export { createGetLroStatusFromResponse } from "./stateMachine"; +export { + LroResourceLocationConfig, + GetLroStatusFromResponse, + RawResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + LroTerminalState, + LroInProgressState, + LroEngineOptions +} from "./models"; diff --git a/test/smoke/generated/compute-resource-manager/src/lro/locationPolling.ts b/test/smoke/generated/compute-resource-manager/src/lro/locationPolling.ts index 6fef619384..9d1aadfbde 100644 --- a/test/smoke/generated/compute-resource-manager/src/lro/locationPolling.ts +++ b/test/smoke/generated/compute-resource-manager/src/lro/locationPolling.ts @@ -7,23 +7,21 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function isLocationPollingDone(rawResponse: FullOperationResponse) { - const code = rawResponse.status; - if (![202, 200].includes(code)) { - throw new Error(`Operation failed`); - } - return code !== 202; +function isLocationPollingDone(rawResponse: RawResponse): boolean { + return ( + !isUnexpectedPollingResponse(rawResponse) && rawResponse.statusCode !== 202 + ); } export function processLocationPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/compute-resource-manager/src/lro/lroEngine.ts b/test/smoke/generated/compute-resource-manager/src/lro/lroEngine.ts new file mode 100644 index 0000000000..85cc15e609 --- /dev/null +++ b/test/smoke/generated/compute-resource-manager/src/lro/lroEngine.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Poller, PollOperationState } from "@azure/core-lro"; +import { + LongRunningOperation, + LroEngineOptions, + ResumablePollOperationState +} from "./models"; +import { GenericPollOperation } from "./operation"; + +/** + * The LRO Engine, a class that performs polling. + */ +export class LroEngine< + TResult, + TState extends PollOperationState +> extends Poller { + private intervalInMs: number; + + constructor(lro: LongRunningOperation, options?: LroEngineOptions) { + const { intervalInMs = 2000, resumeFrom } = options || {}; + function deserializeState( + resumeFrom: string + ): TState & ResumablePollOperationState { + try { + return JSON.parse(resumeFrom).state; + } catch (e) { + throw new Error( + `LroEngine: Unable to deserialize state: ${resumeFrom}` + ); + } + } + const state: TState & ResumablePollOperationState = resumeFrom + ? deserializeState(resumeFrom) + : ({} as any); + + const operation = new GenericPollOperation(state, lro); + super(operation); + + this.intervalInMs = intervalInMs; + operation.setPollerConfig(this as any); + } + + /** + * The method used by the poller to wait before attempting to update its operation. + */ + delay(): Promise { + return new Promise((resolve) => + setTimeout(() => resolve(), this.intervalInMs) + ); + } +} diff --git a/test/smoke/generated/compute-resource-manager/src/lro/lroPoller.ts b/test/smoke/generated/compute-resource-manager/src/lro/lroPoller.ts deleted file mode 100644 index cd1cd64fe8..0000000000 --- a/test/smoke/generated/compute-resource-manager/src/lro/lroPoller.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { Poller, PollOperationState } from "@azure/core-lro"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { FinalStateVia, SendOperationFn } from "./models"; -import { GenericPollOperation } from "./operation"; - -export interface LROPollerOptions { - /** - * Defines how much time the poller is going to wait before making a new request to the service. - */ - intervalInMs?: number; - /** - * A serialized poller which can be used to resume an existing paused Long-Running-Operation. - */ - resumeFrom?: string; -} - -export class LROPoller extends Poller< - PollOperationState, - TResult -> { - private intervalInMs: number; - - constructor( - { intervalInMs = 2000, resumeFrom }: LROPollerOptions, - initialOperationArguments: OperationArguments, - initialOperationSpec: OperationSpec, - sendOperation: SendOperationFn, - finalStateVia?: FinalStateVia - ) { - const state: PollOperationState = resumeFrom - ? JSON.parse(resumeFrom).state - : {}; - - const operation = new GenericPollOperation( - state, - initialOperationArguments, - initialOperationSpec, - sendOperation, - finalStateVia - ); - super(operation); - - this.intervalInMs = intervalInMs; - operation.setPollerConfig(this as any); - } - - /** - * The method used by the poller to wait before attempting to update its operation. - */ - delay(): Promise { - return new Promise((resolve) => - setTimeout(() => resolve(), this.intervalInMs) - ); - } -} diff --git a/test/smoke/generated/compute-resource-manager/src/lro/models.ts b/test/smoke/generated/compute-resource-manager/src/lro/models.ts index a4a5a5abd6..93c3437c8e 100644 --- a/test/smoke/generated/compute-resource-manager/src/lro/models.ts +++ b/test/smoke/generated/compute-resource-manager/src/lro/models.ts @@ -7,46 +7,167 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec -} from "@azure/core-client"; import { PollOperationState } from "@azure/core-lro"; -export type FinalStateVia = +/** + * Options for the LRO poller. + */ +export interface LroEngineOptions { + /** + * Defines how much time the poller is going to wait before making a new request to the service. + */ + intervalInMs?: number; + /** + * A serialized poller which can be used to resume an existing paused Long-Running-Operation. + */ + resumeFrom?: string; +} + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +/** + * The LRO states that signal that the LRO has completed. + */ +export const terminalStates = successStates.concat(failureStates); + +/** + * The potential location of the result of the LRO if specified by the LRO extension in the swagger. + */ +export type LroResourceLocationConfig = | "azure-async-operation" | "location" | "original-uri"; -export interface LROResult { +/** + * The type of a LRO response body. This is just a convenience type for checking the status of the operation. + */ + +export interface LroBody extends Record { + /** The status of the operation. */ + status?: string; + /** The state of the provisioning process */ + provisioningState?: string; + /** The properties of the provisioning process */ + properties?: { provisioningState?: string } & Record; +} + +/** + * Simple type of the raw response. + */ +export interface RawResponse { + /** The HTTP status code */ + statusCode: number; + /** A HttpHeaders collection in the response represented as a simple JSON object where all header names have been normalized to be lower-case. */ + headers: { + [headerName: string]: string; + }; + /** The parsed response body */ + body?: unknown; +} + +/** + * The type of the response of a LRO. + */ +export interface LroResponse { + /** The flattened response */ flatResponse: T; - rawResponse: FullOperationResponse; + /** The raw response */ + rawResponse: RawResponse; } -export type LROMode = "AzureAsync" | "Location" | "Body"; +/** The type of which LRO implementation being followed by a specific API. */ +export type LroMode = "AzureAsync" | "Location" | "Body"; -export interface LROConfig { - mode?: LROMode; +/** + * The configuration of a LRO to determine how to perform polling and checking whether the operation has completed. + */ +export interface LroConfig { + /** The LRO mode */ + mode?: LroMode; + /** The path of a provisioned resource */ resourceLocation?: string; } -export type SendOperationFn = ( - args: OperationArguments, - spec: OperationSpec -) => Promise>; - /** * Type of a polling operation state that can actually be resumed. */ export type ResumablePollOperationState = PollOperationState & { - initialRawResponse?: FullOperationResponse; - config?: LROConfig; + initialRawResponse?: RawResponse; + config?: LroConfig; pollingURL?: string; }; export interface PollerConfig { intervalInMs: number; } + +/** + * The type of a terminal state of an LRO. + */ +export interface LroTerminalState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: true; +} + +/** + * The type of an in-progress state of an LRO. + */ +export interface LroInProgressState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: false; + /** + * The request to be sent next if it is different from the standard polling one. + * Notice that it will disregard any polling URLs provided to it. + */ + next?: () => Promise>; +} + +/** + * The type of an LRO state which is a tagged union of terminal and in-progress states. + */ +export type LroStatus = LroTerminalState | LroInProgressState; + +/** + * The type of the getLROStatusFromResponse method. It takes the response as input and returns along the response whether the operation has finished. + */ +export type GetLroStatusFromResponse = ( + rawResponse: RawResponse, + flatResponse: T +) => LroStatus; + +/** + * Description of a long running operation. + */ +export interface LongRunningOperation { + /** + * The request path. + */ + requestPath: string; + /** + * The HTTP request method. + */ + requestMethod: string; + /** + * A function that can be used to send initial request to the service. + */ + sendInitialRequest: ( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ) => Promise>; + /** + * A function that can be used to poll for the current status of a long running operation. + */ + sendPollRequest: (config: LroConfig, path: string) => Promise>; + /** + * A function that can be used to retrieve the provisioned azure resource. + */ + retrieveAzureAsyncResource: (path?: string) => Promise>; +} diff --git a/test/smoke/generated/compute-resource-manager/src/lro/operation.ts b/test/smoke/generated/compute-resource-manager/src/lro/operation.ts index 801d03e720..3ea7b76d89 100644 --- a/test/smoke/generated/compute-resource-manager/src/lro/operation.ts +++ b/test/smoke/generated/compute-resource-manager/src/lro/operation.ts @@ -7,36 +7,34 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. import { AbortSignalLike } from "@azure/abort-controller"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { PollOperation, PollOperationState } from "@azure/core-lro"; +import { PollOperationState, PollOperation } from "@azure/core-lro"; import { - FinalStateVia, PollerConfig, ResumablePollOperationState, - SendOperationFn + LongRunningOperation, + LroStatus } from "./models"; -import { getPollingURL } from "./requestUtils"; -import { createGetLROState, initializeState, LROState } from "./stateMachine"; +import { getPollingUrl } from "./requestUtils"; +import { createInitializeState, createPollForLROStatus } from "./stateMachine"; -export class GenericPollOperation - implements PollOperation, TResult> { - private getLROState?: ( +export class GenericPollOperation< + TResult, + TState extends PollOperationState +> implements PollOperation { + private getLROStatusFromResponse?: ( pollingURL: string, pollerConfig: PollerConfig - ) => Promise>; + ) => Promise>; private pollerConfig?: PollerConfig; constructor( - public state: PollOperationState, - private initialOperationArguments: OperationArguments, - private initialOperationSpec: OperationSpec, - private sendOperation: SendOperationFn, - private finalStateVia?: FinalStateVia + public state: TState & ResumablePollOperationState, + private lro: LongRunningOperation ) {} - public setPollerConfig(pollerConfig: PollerConfig) { + public setPollerConfig(pollerConfig: PollerConfig): void { this.pollerConfig = pollerConfig; } @@ -57,45 +55,36 @@ export class GenericPollOperation */ async update(options?: { abortSignal?: AbortSignalLike | undefined; - fireProgress?: ((state: PollOperationState) => void) | undefined; - }): Promise, TResult>> { - const state = this.state as ResumablePollOperationState; - const { onResponse, ...restOptions } = - this.initialOperationArguments.options || {}; + fireProgress?: ((state: TState) => void) | undefined; + }): Promise> { + const state = this.state; if (!state.isStarted) { - await this.sendOperation( - { - ...this.initialOperationArguments, - options: { - ...restOptions, - onResponse: initializeState( - state, - this.initialOperationSpec, - onResponse - ) - } - }, - this.initialOperationSpec + const initializeState = createInitializeState( + state, + this.lro.requestPath, + this.lro.requestMethod ); + await this.lro.sendInitialRequest(initializeState); } if (!state.isCompleted) { - if (this.getLROState === undefined) { + if (this.getLROStatusFromResponse === undefined) { if (state.config === undefined) { - throw new Error("Bad state: LRO mode is undefined"); + throw new Error( + "Bad state: LRO mode is undefined. Please check if the serialized state is well-formed." + ); } - this.getLROState = createGetLROState( - this.sendOperation, - this.initialOperationArguments, - this.initialOperationSpec, - state.config, - this.finalStateVia + this.getLROStatusFromResponse = createPollForLROStatus( + this.lro, + state.config ); } if (state.pollingURL === undefined) { - throw new Error("Bad state: polling URL is undefined"); + throw new Error( + "Bad state: polling URL is undefined. Please check if the serialized state is well-formed." + ); } - const currentState = await this.getLROState( + const currentState = await this.getLROStatusFromResponse( state.pollingURL, this.pollerConfig! ); @@ -103,20 +92,19 @@ export class GenericPollOperation state.result = currentState.flatResponse; state.isCompleted = true; } else { - this.getLROState = currentState.next ?? this.getLROState; - state.pollingURL = getPollingURL( + this.getLROStatusFromResponse = + currentState.next ?? this.getLROStatusFromResponse; + state.pollingURL = getPollingUrl( currentState.rawResponse, state.pollingURL ); } } - if (options?.fireProgress !== undefined) { - options.fireProgress(state); - } + options?.fireProgress?.(state); return this; } - async cancel(): Promise, TResult>> { + async cancel(): Promise> { this.state.isCancelled = true; return this; } diff --git a/test/smoke/generated/compute-resource-manager/src/lro/passthrough.ts b/test/smoke/generated/compute-resource-manager/src/lro/passthrough.ts index 64c10380c1..ae7f87d384 100644 --- a/test/smoke/generated/compute-resource-manager/src/lro/passthrough.ts +++ b/test/smoke/generated/compute-resource-manager/src/lro/passthrough.ts @@ -7,15 +7,14 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; export function processPassthroughOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/compute-resource-manager/src/lro/pollingMethod.ts b/test/smoke/generated/compute-resource-manager/src/lro/pollingMethod.ts deleted file mode 100644 index cb6482bbde..0000000000 --- a/test/smoke/generated/compute-resource-manager/src/lro/pollingMethod.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - OperationArguments, - OperationSpec, - OperationResponseMap -} from "@azure/core-client"; -import { LROMode, LROResult, SendOperationFn } from "./models"; - -export function createPollingMethod( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - mode?: LROMode -): (path?: string) => Promise> { - /** - * Polling calls will always return a status object i.e. {"status": "success"} - * these intermediate responses are not described in the swagger so we need to - * pass custom mappers at runtime. - * This function replaces all the existing mappers to be able to deserialize a status object - * @param responses Original set of responses defined in the operation - */ - function getCompositeMappers(responses: { - [responseCode: string]: OperationResponseMap; - }): { - [responseCode: string]: OperationResponseMap; - } { - return Object.keys(responses).reduce((acc, statusCode) => { - return { - ...acc, - [statusCode]: { - ...responses[statusCode], - bodyMapper: { - type: { - name: "Composite", - modelProperties: { - status: { - serializedName: "status", - type: { - name: "String" - } - } - } - } - } - } - }; - }, {} as { [responseCode: string]: OperationResponseMap }); - } - // Make sure we don't send any body to the get request - const { requestBody, responses, ...restSpec } = spec; - if (mode === "AzureAsync") { - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: getCompositeMappers(responses), - httpMethod: "GET", - ...(path && { path }) - }); - }; - } - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: responses, - httpMethod: "GET", - ...(path && { path }) - }); - }; -} - -export function createRetrieveAzureAsyncResource( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec -): (path?: string) => Promise> { - const updatedArgs = { ...args }; - if (updatedArgs.options) { - (updatedArgs.options as any).shouldDeserialize = true; - } - return createPollingMethod(sendOperationFn, updatedArgs, spec); -} diff --git a/test/smoke/generated/compute-resource-manager/src/lro/requestUtils.ts b/test/smoke/generated/compute-resource-manager/src/lro/requestUtils.ts index 9162f66339..40d993686f 100644 --- a/test/smoke/generated/compute-resource-manager/src/lro/requestUtils.ts +++ b/test/smoke/generated/compute-resource-manager/src/lro/requestUtils.ts @@ -7,119 +7,9 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse, OperationSpec } from "@azure/core-client"; -import { LROConfig } from "./models"; -import { terminalStates } from "./stateMachine"; - -/** - * We need to selectively deserialize our responses, only deserializing if we - * are in a final LRO response, not deserializing any polling non-terminal responses - */ -export function shouldDeserializeLRO(finalStateVia?: string) { - let initialOperationInfo: LROResponseInfo | undefined; - let isInitialRequest = true; - - return (response: FullOperationResponse) => { - if (response.status < 200 || response.status >= 300) { - return true; - } - - if (!initialOperationInfo) { - initialOperationInfo = getLROData(response); - } else { - isInitialRequest = false; - } - - if ( - initialOperationInfo.azureAsyncOperation || - initialOperationInfo.operationLocation - ) { - return ( - !isInitialRequest && - isAsyncOperationFinalResponse( - response, - initialOperationInfo, - finalStateVia - ) - ); - } - - if (initialOperationInfo.location) { - return isLocationFinalResponse(response); - } - - if (initialOperationInfo.requestMethod === "PUT") { - return isBodyPollingFinalResponse(response); - } - - return true; - }; -} - -function isAsyncOperationFinalResponse( - response: FullOperationResponse, - initialOperationInfo: LROResponseInfo, - finalStateVia?: string -): boolean { - const status: string = response.parsedBody?.status || "Succeeded"; - if (!terminalStates.includes(status.toLowerCase())) { - return false; - } - - if (initialOperationInfo.requestMethod === "DELETE") { - return true; - } - - if ( - initialOperationInfo.requestMethod === "PUT" && - finalStateVia && - finalStateVia.toLowerCase() === "azure-asyncoperation" - ) { - return true; - } - - if ( - initialOperationInfo.requestMethod !== "PUT" && - !initialOperationInfo.location - ) { - return true; - } - - return false; -} - -function isLocationFinalResponse(response: FullOperationResponse): boolean { - return response.status !== 202; -} - -function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { - const provisioningState: string = - response.parsedBody?.properties?.provisioningState || "Succeeded"; - - if (terminalStates.includes(provisioningState.toLowerCase())) { - return true; - } - - return false; -} - -interface LROResponseInfo { - requestMethod: string; - azureAsyncOperation?: string; - operationLocation?: string; - location?: string; -} - -function getLROData(result: FullOperationResponse): LROResponseInfo { - return { - azureAsyncOperation: result.headers.get("azure-asyncoperation"), - operationLocation: result.headers.get("operation-location"), - location: result.headers.get("location"), - requestMethod: result.request.method - }; -} +import { LroConfig, RawResponse } from "./models"; /** * Detects where the continuation token is and returns it. Notice that azure-asyncoperation @@ -127,45 +17,41 @@ function getLROData(result: FullOperationResponse): LROResponseInfo { * where both azure-asyncoperation and location could be present in the same response but * azure-asyncoperation should be the one to use for polling. */ -export function getPollingURL( - rawResponse: FullOperationResponse, +export function getPollingUrl( + rawResponse: RawResponse, defaultPath: string ): string { return ( - getAzureAsyncoperation(rawResponse) ?? + getAzureAsyncOperation(rawResponse) ?? getLocation(rawResponse) ?? getOperationLocation(rawResponse) ?? defaultPath ); } -function getLocation(rawResponse: FullOperationResponse): string | undefined { - return rawResponse.headers?.get("location"); +function getLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["location"]; } -function getOperationLocation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("operation-location"); +function getOperationLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["operation-location"]; } -function getAzureAsyncoperation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("azure-asyncoperation"); +function getAzureAsyncOperation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["azure-asyncoperation"]; } -export function inferLROMode( - spec: OperationSpec, - rawResponse: FullOperationResponse -): LROConfig { - const requestMethod = spec.httpMethod; - if (getAzureAsyncoperation(rawResponse) !== undefined) { +export function inferLroMode( + requestPath: string, + requestMethod: string, + rawResponse: RawResponse +): LroConfig { + if (getAzureAsyncOperation(rawResponse) !== undefined) { return { mode: "AzureAsync", resourceLocation: requestMethod === "PUT" - ? spec.path + ? requestPath : requestMethod === "POST" ? getLocation(rawResponse) : undefined @@ -185,10 +71,35 @@ export function inferLROMode( return {}; } -export function getSpecPath(spec: OperationSpec): string { - if (spec.path) { - return spec.path; - } else { - throw Error("Bad spec: request path is not found!"); +export class RestError extends Error { + public statusCode?: number; + constructor(message: string, statusCode: number) { + super(message); + this.name = "RestError"; + this.statusCode = statusCode; + + Object.setPrototypeOf(this, RestError.prototype); + } +} + +export function isUnexpectedInitialResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![203, 204, 202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} in the initial response. This may indicate a server issue.`, + code + ); } + return false; +} + +export function isUnexpectedPollingResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} while polling. This may indicate a server issue.`, + code + ); + } + return false; } diff --git a/test/smoke/generated/compute-resource-manager/src/lro/stateMachine.ts b/test/smoke/generated/compute-resource-manager/src/lro/stateMachine.ts index b2a69b5546..19a8f67470 100644 --- a/test/smoke/generated/compute-resource-manager/src/lro/stateMachine.ts +++ b/test/smoke/generated/compute-resource-manager/src/lro/stateMachine.ts @@ -7,14 +7,8 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec, - RawResponseCallback -} from "@azure/core-client"; import { processAzureAsyncOperationResult } from "./azureAsyncPolling"; import { isBodyPollingDone, @@ -22,73 +16,36 @@ import { } from "./bodyPolling"; import { processLocationPollingOperationResult } from "./locationPolling"; import { - FinalStateVia, - LROConfig, - LROResult, + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroStatus, PollerConfig, - ResumablePollOperationState, - SendOperationFn + RawResponse, + ResumablePollOperationState } from "./models"; import { processPassthroughOperationResult } from "./passthrough"; import { - createPollingMethod, - createRetrieveAzureAsyncResource -} from "./pollingMethod"; -import { getPollingURL, getSpecPath, inferLROMode } from "./requestUtils"; - -export const successStates = ["succeeded"]; -export const failureStates = ["failed", "canceled", "cancelled"]; -export const terminalStates = successStates.concat(failureStates); - -/** - * The type of a terminal state of an LRO. - */ -interface LROTerminalState extends LROResult { - /** - * Whether the operation has finished. - */ - done: true; -} - -/** - * The type of an in-progress state of an LRO. - */ -interface LROInProgressState extends LROResult { - /** - * Whether the operation has finished. - */ - done: false; - /** - * The request to be sent next if it is different from the standard polling one. - * Notice that it will disregard any polling URLs provided to it. - */ - next?: () => Promise>; -} - -/** - * The type of an LRO state which is a tagged union of terminal and in-progress states. - */ -export type LROState = LROTerminalState | LROInProgressState; + getPollingUrl, + inferLroMode, + isUnexpectedInitialResponse +} from "./requestUtils"; /** * creates a stepping function that maps an LRO state to another. */ -function createTransition( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { +export function createGetLroStatusFromResponse( + lroPrimitives: LongRunningOperation, + config: LroConfig, + lroResourceLocationConfig?: LroResourceLocationConfig +): GetLroStatusFromResponse { switch (config.mode) { case "AzureAsync": { return processAzureAsyncOperationResult( - createRetrieveAzureAsyncResource(sendOperationFn, args, spec), + lroPrimitives, config.resourceLocation, - finalStateVia + lroResourceLocationConfig ); } case "Location": { @@ -106,52 +63,20 @@ function createTransition( /** * Creates a polling operation that returns a LRO state. */ -export function createGetLROState( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia +export function createPollForLROStatus( + lroPrimitives: LongRunningOperation, + config: LroConfig ): ( pollingURL: string, pollerConfig: PollerConfig -) => Promise> { - const step = createTransition( - sendOperationFn, - args, - spec, - config, - finalStateVia - ); - const customerCallback = args?.options?.onResponse; - let response: LROState | undefined = undefined; - let retryAfter: string | undefined = undefined; - const poll = createPollingMethod( - sendOperationFn, - { - ...args, - options: { - ...args.options, - onResponse: ( - rawResponse: FullOperationResponse, - flatResponse: unknown - ): void => { - response = step(rawResponse, flatResponse as TResult); - retryAfter = rawResponse.headers.get("Retry-After"); - if (response.done) { - customerCallback?.(rawResponse, flatResponse); - } - } - } - }, - spec, - config.mode - ); +) => Promise> { return async ( path: string, pollerConfig: PollerConfig - ): Promise> => { - await poll(path); + ): Promise> => { + const response = await lroPrimitives.sendPollRequest(config, path); + const retryAfter: string | undefined = + response.rawResponse.headers["retry-after"]; if (retryAfter !== undefined) { const retryAfterInMs = parseInt(retryAfter); pollerConfig.intervalInMs = isNaN(retryAfterInMs) @@ -161,7 +86,7 @@ export function createGetLROState( ) : retryAfterInMs; } - return response!; + return response; }; } @@ -179,24 +104,26 @@ function calculatePollingIntervalFromDate( /** * Creates a callback to be used to initialize the polling operation state. - * @param state of the polling operation - * @param operationSpec of the LRO - * @param callback callback to be called when the operation is done + * @param state - of the polling operation + * @param operationSpec - of the LRO + * @param callback - callback to be called when the operation is done * @returns callback that initializes the state of the polling operation */ -export function initializeState( +export function createInitializeState( state: ResumablePollOperationState, - operationSpec: OperationSpec, - callback?: RawResponseCallback -): (rawResponse: FullOperationResponse, flatResponse: unknown) => void { - return (rawResponse: FullOperationResponse, flatResponse: unknown) => { + requestPath: string, + requestMethod: string +): (rawResponse: RawResponse, flatResponse: unknown) => boolean { + return (rawResponse: RawResponse, flatResponse: unknown) => { + if (isUnexpectedInitialResponse(rawResponse)) return true; state.initialRawResponse = rawResponse; state.isStarted = true; - state.pollingURL = getPollingURL( - state.initialRawResponse, - getSpecPath(operationSpec) + state.pollingURL = getPollingUrl(state.initialRawResponse, requestPath); + state.config = inferLroMode( + requestPath, + requestMethod, + state.initialRawResponse ); - state.config = inferLROMode(operationSpec, state.initialRawResponse); /** short circuit polling if body polling is done in the initial request */ if ( state.config.mode === undefined || @@ -205,12 +132,7 @@ export function initializeState( ) { state.result = flatResponse as TResult; state.isCompleted = true; - /** - * We need to check if the LRO operation is finished inside the - * call back so that we can call the customer-provided callback - * on that result. - */ - callback?.(rawResponse, flatResponse); } + return Boolean(state.isCompleted); }; } diff --git a/test/smoke/generated/compute-resource-manager/src/operations/containerServices.ts b/test/smoke/generated/compute-resource-manager/src/operations/containerServices.ts index 8befa63786..fec8d77ed2 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/containerServices.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/containerServices.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ContainerService, ContainerServicesListNextOptionalParams, @@ -205,15 +206,22 @@ export class ContainerServicesImpl implements ContainerServices { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, containerServiceName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -304,15 +312,22 @@ export class ContainerServicesImpl implements ContainerServices { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, containerServiceName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/dedicatedHosts.ts b/test/smoke/generated/compute-resource-manager/src/operations/dedicatedHosts.ts index a4a9eb076c..740ebb1dfb 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/dedicatedHosts.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/dedicatedHosts.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { DedicatedHost, DedicatedHostsListByHostGroupNextOptionalParams, @@ -165,15 +166,22 @@ export class DedicatedHostsImpl implements DedicatedHosts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, hostGroupName, hostName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -250,15 +258,22 @@ export class DedicatedHostsImpl implements DedicatedHosts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, hostGroupName, hostName, parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -328,15 +343,22 @@ export class DedicatedHostsImpl implements DedicatedHosts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, hostGroupName, hostName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/diskEncryptionSets.ts b/test/smoke/generated/compute-resource-manager/src/operations/diskEncryptionSets.ts index 2001f71439..0ee6f230e7 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/diskEncryptionSets.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/diskEncryptionSets.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { DiskEncryptionSet, DiskEncryptionSetsListByResourceGroupNextOptionalParams, @@ -193,15 +194,22 @@ export class DiskEncryptionSetsImpl implements DiskEncryptionSets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, diskEncryptionSetName, diskEncryptionSet, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -279,15 +287,22 @@ export class DiskEncryptionSetsImpl implements DiskEncryptionSets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, diskEncryptionSetName, diskEncryptionSet, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -376,15 +391,22 @@ export class DiskEncryptionSetsImpl implements DiskEncryptionSets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, diskEncryptionSetName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/disks.ts b/test/smoke/generated/compute-resource-manager/src/operations/disks.ts index e73b77b5fb..80552b63a0 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/disks.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/disks.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { Disk, DisksListByResourceGroupNextOptionalParams, @@ -196,15 +197,22 @@ export class DisksImpl implements Disks { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, diskName, disk, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -277,15 +285,22 @@ export class DisksImpl implements Disks { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, diskName, disk, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -373,15 +388,22 @@ export class DisksImpl implements Disks { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, diskName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -473,16 +495,23 @@ export class DisksImpl implements Disks { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, diskName, grantAccessData, options }, grantAccessOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -551,16 +580,23 @@ export class DisksImpl implements Disks { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, diskName, options }, revokeAccessOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/galleries.ts b/test/smoke/generated/compute-resource-manager/src/operations/galleries.ts index caa7fff145..e83e3809fe 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/galleries.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/galleries.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { Gallery, GalleriesListByResourceGroupNextOptionalParams, @@ -191,15 +192,22 @@ export class GalleriesImpl implements Galleries { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, galleryName, gallery, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -273,15 +281,22 @@ export class GalleriesImpl implements Galleries { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, galleryName, gallery, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -364,15 +379,22 @@ export class GalleriesImpl implements Galleries { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, galleryName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/galleryApplicationVersions.ts b/test/smoke/generated/compute-resource-manager/src/operations/galleryApplicationVersions.ts index 1b2fb1d814..fd142f88c8 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/galleryApplicationVersions.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/galleryApplicationVersions.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { GalleryApplicationVersion, GalleryApplicationVersionsListByGalleryApplicationNextOptionalParams, @@ -183,11 +184,18 @@ export class GalleryApplicationVersionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, galleryName, @@ -196,9 +204,9 @@ export class GalleryApplicationVersionsImpl galleryApplicationVersion, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -290,11 +298,18 @@ export class GalleryApplicationVersionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, galleryName, @@ -303,9 +318,9 @@ export class GalleryApplicationVersionsImpl galleryApplicationVersion, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -416,11 +431,18 @@ export class GalleryApplicationVersionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, galleryName, @@ -428,9 +450,9 @@ export class GalleryApplicationVersionsImpl galleryApplicationVersionName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/galleryApplications.ts b/test/smoke/generated/compute-resource-manager/src/operations/galleryApplications.ts index e09296cab0..ad3c5bdcd6 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/galleryApplications.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/galleryApplications.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { GalleryApplication, GalleryApplicationsListByGalleryNextOptionalParams, @@ -168,11 +169,18 @@ export class GalleryApplicationsImpl implements GalleryApplications { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, galleryName, @@ -180,9 +188,9 @@ export class GalleryApplicationsImpl implements GalleryApplications { galleryApplication, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -265,11 +273,18 @@ export class GalleryApplicationsImpl implements GalleryApplications { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, galleryName, @@ -277,9 +292,9 @@ export class GalleryApplicationsImpl implements GalleryApplications { galleryApplication, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -373,15 +388,22 @@ export class GalleryApplicationsImpl implements GalleryApplications { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, galleryName, galleryApplicationName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/galleryImageVersions.ts b/test/smoke/generated/compute-resource-manager/src/operations/galleryImageVersions.ts index efbd0fe99a..08e1fadc75 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/galleryImageVersions.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/galleryImageVersions.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { GalleryImageVersion, GalleryImageVersionsListByGalleryImageNextOptionalParams, @@ -180,11 +181,18 @@ export class GalleryImageVersionsImpl implements GalleryImageVersions { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, galleryName, @@ -193,9 +201,9 @@ export class GalleryImageVersionsImpl implements GalleryImageVersions { galleryImageVersion, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -284,11 +292,18 @@ export class GalleryImageVersionsImpl implements GalleryImageVersions { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, galleryName, @@ -297,9 +312,9 @@ export class GalleryImageVersionsImpl implements GalleryImageVersions { galleryImageVersion, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -404,11 +419,18 @@ export class GalleryImageVersionsImpl implements GalleryImageVersions { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, galleryName, @@ -416,9 +438,9 @@ export class GalleryImageVersionsImpl implements GalleryImageVersions { galleryImageVersionName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/galleryImages.ts b/test/smoke/generated/compute-resource-manager/src/operations/galleryImages.ts index 9fc6ae134d..e7c25759a4 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/galleryImages.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/galleryImages.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { GalleryImage, GalleryImagesListByGalleryNextOptionalParams, @@ -168,11 +169,18 @@ export class GalleryImagesImpl implements GalleryImages { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, galleryName, @@ -180,9 +188,9 @@ export class GalleryImagesImpl implements GalleryImages { galleryImage, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -265,11 +273,18 @@ export class GalleryImagesImpl implements GalleryImages { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, galleryName, @@ -277,9 +292,9 @@ export class GalleryImagesImpl implements GalleryImages { galleryImage, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -373,15 +388,22 @@ export class GalleryImagesImpl implements GalleryImages { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, galleryName, galleryImageName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/images.ts b/test/smoke/generated/compute-resource-manager/src/operations/images.ts index ed3fa0f74d..87225a4981 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/images.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/images.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { Image, ImagesListByResourceGroupNextOptionalParams, @@ -191,15 +192,22 @@ export class ImagesImpl implements Images { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, imageName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -268,15 +276,22 @@ export class ImagesImpl implements Images { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, imageName, parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -341,15 +356,22 @@ export class ImagesImpl implements Images { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, imageName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/logAnalytics.ts b/test/smoke/generated/compute-resource-manager/src/operations/logAnalytics.ts index 22cb6ac653..f8c0ca5966 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/logAnalytics.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/logAnalytics.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { RequestRateByIntervalInput, LogAnalyticsExportRequestRateByIntervalOptionalParams, @@ -80,16 +81,23 @@ export class LogAnalyticsImpl implements LogAnalytics { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { location, parameters, options }, exportRequestRateByIntervalOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -157,16 +165,23 @@ export class LogAnalyticsImpl implements LogAnalytics { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { location, parameters, options }, exportThrottledRequestsOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/snapshots.ts b/test/smoke/generated/compute-resource-manager/src/operations/snapshots.ts index 70a0f3e6bb..bacff33c99 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/snapshots.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/snapshots.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { Snapshot, SnapshotsListByResourceGroupNextOptionalParams, @@ -196,15 +197,22 @@ export class SnapshotsImpl implements Snapshots { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, snapshotName, snapshot, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -280,15 +288,22 @@ export class SnapshotsImpl implements Snapshots { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, snapshotName, snapshot, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -376,15 +391,22 @@ export class SnapshotsImpl implements Snapshots { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, snapshotName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -482,16 +504,23 @@ export class SnapshotsImpl implements Snapshots { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, snapshotName, grantAccessData, options }, grantAccessOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -560,16 +589,23 @@ export class SnapshotsImpl implements Snapshots { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, snapshotName, options }, revokeAccessOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineExtensions.ts b/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineExtensions.ts index d75804bad2..b0ffd6ada5 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineExtensions.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineExtensions.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualMachineExtension, VirtualMachineExtensionsCreateOrUpdateOptionalParams, @@ -88,11 +89,18 @@ export class VirtualMachineExtensionsImpl implements VirtualMachineExtensions { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmName, @@ -100,9 +108,9 @@ export class VirtualMachineExtensionsImpl implements VirtualMachineExtensions { extensionParameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -179,11 +187,18 @@ export class VirtualMachineExtensionsImpl implements VirtualMachineExtensions { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmName, @@ -191,9 +206,9 @@ export class VirtualMachineExtensionsImpl implements VirtualMachineExtensions { extensionParameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -263,15 +278,22 @@ export class VirtualMachineExtensionsImpl implements VirtualMachineExtensions { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmName, vmExtensionName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSetExtensions.ts b/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSetExtensions.ts index f3371d9827..4300c31631 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSetExtensions.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSetExtensions.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualMachineScaleSetExtension, VirtualMachineScaleSetExtensionsListNextOptionalParams, @@ -155,11 +156,18 @@ export class VirtualMachineScaleSetExtensionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, @@ -167,9 +175,9 @@ export class VirtualMachineScaleSetExtensionsImpl extensionParameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -246,11 +254,18 @@ export class VirtualMachineScaleSetExtensionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, @@ -258,9 +273,9 @@ export class VirtualMachineScaleSetExtensionsImpl extensionParameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -330,15 +345,22 @@ export class VirtualMachineScaleSetExtensionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, vmssExtensionName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSetRollingUpgrades.ts b/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSetRollingUpgrades.ts index 9d922f607d..22a04d7a6a 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSetRollingUpgrades.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSetRollingUpgrades.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualMachineScaleSetRollingUpgradesCancelOptionalParams, VirtualMachineScaleSetRollingUpgradesStartOSUpgradeOptionalParams, @@ -74,15 +75,22 @@ export class VirtualMachineScaleSetRollingUpgradesImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, options }, - cancelOperationSpec, - sendOperation + cancelOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -146,15 +154,22 @@ export class VirtualMachineScaleSetRollingUpgradesImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, options }, - startOSUpgradeOperationSpec, - sendOperation + startOSUpgradeOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -220,15 +235,22 @@ export class VirtualMachineScaleSetRollingUpgradesImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, options }, - startExtensionUpgradeOperationSpec, - sendOperation + startExtensionUpgradeOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSetVMExtensions.ts b/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSetVMExtensions.ts index b7aa09f83b..46c5ef2323 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSetVMExtensions.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSetVMExtensions.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualMachineExtension, VirtualMachineScaleSetVMExtensionsCreateOrUpdateOptionalParams, @@ -93,11 +94,18 @@ export class VirtualMachineScaleSetVMExtensionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, @@ -106,9 +114,9 @@ export class VirtualMachineScaleSetVMExtensionsImpl extensionParameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -190,11 +198,18 @@ export class VirtualMachineScaleSetVMExtensionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, @@ -203,9 +218,9 @@ export class VirtualMachineScaleSetVMExtensionsImpl extensionParameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -280,11 +295,18 @@ export class VirtualMachineScaleSetVMExtensionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, @@ -292,9 +314,9 @@ export class VirtualMachineScaleSetVMExtensionsImpl vmExtensionName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSetVMs.ts b/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSetVMs.ts index cb230b6a03..5648181c78 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSetVMs.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSetVMs.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualMachineScaleSetVM, VirtualMachineScaleSetVMsListNextOptionalParams, @@ -169,15 +170,22 @@ export class VirtualMachineScaleSetVMsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, instanceId, options }, - reimageOperationSpec, - sendOperation + reimageOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -245,15 +253,22 @@ export class VirtualMachineScaleSetVMsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, instanceId, options }, - reimageAllOperationSpec, - sendOperation + reimageAllOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -323,15 +338,22 @@ export class VirtualMachineScaleSetVMsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, instanceId, options }, - deallocateOperationSpec, - sendOperation + deallocateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -407,15 +429,22 @@ export class VirtualMachineScaleSetVMsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, instanceId, parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -485,15 +514,22 @@ export class VirtualMachineScaleSetVMsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, instanceId, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -617,15 +653,22 @@ export class VirtualMachineScaleSetVMsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, instanceId, options }, - powerOffOperationSpec, - sendOperation + powerOffOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -694,15 +737,22 @@ export class VirtualMachineScaleSetVMsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, instanceId, options }, - restartOperationSpec, - sendOperation + restartOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -769,15 +819,22 @@ export class VirtualMachineScaleSetVMsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, instanceId, options }, - startOperationSpec, - sendOperation + startOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -845,15 +902,22 @@ export class VirtualMachineScaleSetVMsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, instanceId, options }, - redeployOperationSpec, - sendOperation + redeployOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -921,15 +985,22 @@ export class VirtualMachineScaleSetVMsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, instanceId, options }, - performMaintenanceOperationSpec, - sendOperation + performMaintenanceOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1023,16 +1094,23 @@ export class VirtualMachineScaleSetVMsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, instanceId, parameters, options }, runCommandOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSets.ts b/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSets.ts index 493b42c8a7..fe00dd4340 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSets.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/virtualMachineScaleSets.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualMachineScaleSet, VirtualMachineScaleSetsListNextOptionalParams, @@ -361,15 +362,22 @@ export class VirtualMachineScaleSetsImpl implements VirtualMachineScaleSets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -441,15 +449,22 @@ export class VirtualMachineScaleSetsImpl implements VirtualMachineScaleSets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -514,15 +529,22 @@ export class VirtualMachineScaleSetsImpl implements VirtualMachineScaleSets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -603,15 +625,22 @@ export class VirtualMachineScaleSetsImpl implements VirtualMachineScaleSets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, options }, - deallocateOperationSpec, - sendOperation + deallocateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -677,15 +706,22 @@ export class VirtualMachineScaleSetsImpl implements VirtualMachineScaleSets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, vmInstanceIDs, options }, - deleteInstancesOperationSpec, - sendOperation + deleteInstancesOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -831,15 +867,22 @@ export class VirtualMachineScaleSetsImpl implements VirtualMachineScaleSets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, options }, - powerOffOperationSpec, - sendOperation + powerOffOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -903,15 +946,22 @@ export class VirtualMachineScaleSetsImpl implements VirtualMachineScaleSets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, options }, - restartOperationSpec, - sendOperation + restartOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -973,15 +1023,22 @@ export class VirtualMachineScaleSetsImpl implements VirtualMachineScaleSets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, options }, - startOperationSpec, - sendOperation + startOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1044,15 +1101,22 @@ export class VirtualMachineScaleSetsImpl implements VirtualMachineScaleSets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, options }, - redeployOperationSpec, - sendOperation + redeployOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1118,15 +1182,22 @@ export class VirtualMachineScaleSetsImpl implements VirtualMachineScaleSets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, options }, - performMaintenanceOperationSpec, - sendOperation + performMaintenanceOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1193,15 +1264,22 @@ export class VirtualMachineScaleSetsImpl implements VirtualMachineScaleSets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, vmInstanceIDs, options }, - updateInstancesOperationSpec, - sendOperation + updateInstancesOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1268,15 +1346,22 @@ export class VirtualMachineScaleSetsImpl implements VirtualMachineScaleSets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, options }, - reimageOperationSpec, - sendOperation + reimageOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1341,15 +1426,22 @@ export class VirtualMachineScaleSetsImpl implements VirtualMachineScaleSets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, options }, - reimageAllOperationSpec, - sendOperation + reimageAllOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1455,15 +1547,22 @@ export class VirtualMachineScaleSetsImpl implements VirtualMachineScaleSets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmScaleSetName, parameters, options }, - setOrchestrationServiceStateOperationSpec, - sendOperation + setOrchestrationServiceStateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/compute-resource-manager/src/operations/virtualMachines.ts b/test/smoke/generated/compute-resource-manager/src/operations/virtualMachines.ts index 62dea29b52..f15c911045 100644 --- a/test/smoke/generated/compute-resource-manager/src/operations/virtualMachines.ts +++ b/test/smoke/generated/compute-resource-manager/src/operations/virtualMachines.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { ComputeManagementClientContext } from "../computeManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualMachine, VirtualMachinesListByLocationNextOptionalParams, @@ -341,16 +342,23 @@ export class VirtualMachinesImpl implements VirtualMachines { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmName, parameters, options }, captureOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -424,15 +432,22 @@ export class VirtualMachinesImpl implements VirtualMachines { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -505,15 +520,22 @@ export class VirtualMachinesImpl implements VirtualMachines { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmName, parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -578,15 +600,22 @@ export class VirtualMachinesImpl implements VirtualMachines { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -679,15 +708,22 @@ export class VirtualMachinesImpl implements VirtualMachines { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmName, options }, - convertToManagedDisksOperationSpec, - sendOperation + convertToManagedDisksOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -751,15 +787,22 @@ export class VirtualMachinesImpl implements VirtualMachines { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmName, options }, - deallocateOperationSpec, - sendOperation + deallocateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -889,15 +932,22 @@ export class VirtualMachinesImpl implements VirtualMachines { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmName, options }, - powerOffOperationSpec, - sendOperation + powerOffOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -956,15 +1006,22 @@ export class VirtualMachinesImpl implements VirtualMachines { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmName, options }, - reapplyOperationSpec, - sendOperation + reapplyOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1022,15 +1079,22 @@ export class VirtualMachinesImpl implements VirtualMachines { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmName, options }, - restartOperationSpec, - sendOperation + restartOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1088,15 +1152,22 @@ export class VirtualMachinesImpl implements VirtualMachines { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmName, options }, - startOperationSpec, - sendOperation + startOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1154,15 +1225,22 @@ export class VirtualMachinesImpl implements VirtualMachines { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmName, options }, - redeployOperationSpec, - sendOperation + redeployOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1220,15 +1298,22 @@ export class VirtualMachinesImpl implements VirtualMachines { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmName, options }, - reimageOperationSpec, - sendOperation + reimageOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1286,15 +1371,22 @@ export class VirtualMachinesImpl implements VirtualMachines { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmName, options }, - performMaintenanceOperationSpec, - sendOperation + performMaintenanceOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1381,16 +1473,23 @@ export class VirtualMachinesImpl implements VirtualMachines { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vmName, parameters, options }, runCommandOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/coreClientLro.ts b/test/smoke/generated/cosmos-db-resource-manager/src/coreClientLro.ts new file mode 100644 index 0000000000..d793a24458 --- /dev/null +++ b/test/smoke/generated/cosmos-db-resource-manager/src/coreClientLro.ts @@ -0,0 +1,323 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + OperationArguments, + OperationSpec, + OperationResponseMap, + FullOperationResponse +} from "@azure/core-client"; +import { + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + createGetLroStatusFromResponse, + RawResponse +} from "./lro"; + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +export const terminalStates = successStates.concat(failureStates); + +export type SendOperationFn = ( + args: OperationArguments, + spec: OperationSpec +) => Promise>; + +export function createPollingMethod( + sendOperationFn: SendOperationFn, + GetLroStatusFromResponse: GetLroStatusFromResponse, + args: OperationArguments, + spec: OperationSpec, + mode?: LroMode +): (path?: string) => Promise> { + /** + * Polling calls will always return a status object i.e. {"status": "success"} + * these intermediate responses are not described in the swagger so we need to + * pass custom mappers at runtime. + * This function replaces all the existing mappers to be able to deserialize a status object + * @param responses Original set of responses defined in the operation + */ + function getCompositeMappers(responses: { + [responseCode: string]: OperationResponseMap; + }): { + [responseCode: string]: OperationResponseMap; + } { + return Object.keys(responses).reduce((acc, statusCode) => { + return { + ...acc, + [statusCode]: { + ...responses[statusCode], + bodyMapper: { + type: { + name: "Composite", + modelProperties: { + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } + } + } + }; + }, {} as { [responseCode: string]: OperationResponseMap }); + } + let response: LroStatus | undefined = undefined; + const customerCallback = args?.options?.onResponse; + const updatedArgs = { + ...args, + options: { + ...args.options, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ): void => { + response = GetLroStatusFromResponse( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse as TResult + ); + if (response.done) { + customerCallback?.(rawResponse, flatResponse); + } + } + } + }; + // Make sure we don't send any body to the get request + const { requestBody, responses, ...restSpec } = spec; + if (mode === "AzureAsync") { + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: getCompositeMappers(responses), + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; + } + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: responses, + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; +} + +/** + * We need to selectively deserialize our responses, only deserializing if we + * are in a final Lro response, not deserializing any polling non-terminal responses + */ +export function shouldDeserializeLro(lroResourceLocationConfig?: string) { + let initialOperationInfo: LroResponseInfo | undefined; + let isInitialRequest = true; + + return (response: FullOperationResponse) => { + if (response.status < 200 || response.status >= 300) { + return true; + } + + if (!initialOperationInfo) { + initialOperationInfo = getLroData(response); + } else { + isInitialRequest = false; + } + + if ( + initialOperationInfo.azureAsyncOperation || + initialOperationInfo.operationLocation + ) { + return ( + !isInitialRequest && + isAsyncOperationFinalResponse( + response, + initialOperationInfo, + lroResourceLocationConfig + ) + ); + } + + if (initialOperationInfo.location) { + return isLocationFinalResponse(response); + } + + if (initialOperationInfo.requestMethod === "PUT") { + return isBodyPollingFinalResponse(response); + } + + return true; + }; +} + +function isAsyncOperationFinalResponse( + response: FullOperationResponse, + initialOperationInfo: LroResponseInfo, + lroResourceLocationConfig?: string +): boolean { + const status: string = response.parsedBody?.status || "Succeeded"; + if (!terminalStates.includes(status.toLowerCase())) { + return false; + } + + if (initialOperationInfo.requestMethod === "DELETE") { + return true; + } + + if ( + initialOperationInfo.requestMethod === "PUT" && + lroResourceLocationConfig && + lroResourceLocationConfig.toLowerCase() === "azure-asyncoperation" + ) { + return true; + } + + if ( + initialOperationInfo.requestMethod !== "PUT" && + !initialOperationInfo.location + ) { + return true; + } + + return false; +} + +function isLocationFinalResponse(response: FullOperationResponse): boolean { + return response.status !== 202; +} + +function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { + const provisioningState: string = + response.parsedBody?.properties?.provisioningState || "Succeeded"; + + if (terminalStates.includes(provisioningState.toLowerCase())) { + return true; + } + + return false; +} + +interface LroResponseInfo { + requestMethod: string; + azureAsyncOperation?: string; + operationLocation?: string; + location?: string; +} + +function getLroData(result: FullOperationResponse): LroResponseInfo { + return { + azureAsyncOperation: result.headers.get("azure-asyncoperation"), + operationLocation: result.headers.get("operation-location"), + location: result.headers.get("location"), + requestMethod: result.request.method + }; +} + +export function getSpecPath(spec: OperationSpec): string { + if (spec.path) { + return spec.path; + } else { + throw Error("Bad spec: request path is not found!"); + } +} + +export class CoreClientLro implements LongRunningOperation { + constructor( + private sendOperationFn: SendOperationFn, + private args: OperationArguments, + private spec: OperationSpec, + private lroResourceLocationConfig?: LroResourceLocationConfig, + public requestPath: string = spec.path!, + public requestMethod: string = spec.httpMethod + ) {} + public async sendInitialRequest( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ): Promise> { + const { onResponse, ...restOptions } = this.args.options || {}; + return this.sendOperationFn( + { + ...this.args, + options: { + ...restOptions, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ) => { + const isCompleted = initializeState( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse + ); + if (isCompleted) { + onResponse?.(rawResponse, flatResponse); + } + } + } + }, + this.spec + ); + } + + public async sendPollRequest( + config: LroConfig, + path: string + ): Promise> { + const getLroStatusFromResponse = createGetLroStatusFromResponse( + this, + config, + this.lroResourceLocationConfig + ); + return createPollingMethod( + this.sendOperationFn, + getLroStatusFromResponse, + this.args, + this.spec, + config.mode + )(path); + } + + public async retrieveAzureAsyncResource( + path?: string + ): Promise> { + const updatedArgs = { ...this.args }; + if (updatedArgs.options) { + (updatedArgs.options as any).shouldDeserialize = true; + } + return createPollingMethod( + this.sendOperationFn, + (rawResponse, flatResponse) => ({ + rawResponse, + flatResponse, + done: true + }), + updatedArgs, + this.spec + )(path); + } +} diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/lro/azureAsyncPolling.ts b/test/smoke/generated/cosmos-db-resource-manager/src/lro/azureAsyncPolling.ts index 0d63c54f60..725578a692 100644 --- a/test/smoke/generated/cosmos-db-resource-manager/src/lro/azureAsyncPolling.ts +++ b/test/smoke/generated/cosmos-db-resource-manager/src/lro/azureAsyncPolling.ts @@ -7,39 +7,61 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { FinalStateVia, LROResult } from "./models"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroResourceLocationConfig, + LongRunningOperation, + LroBody, + LroResponse, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getResponseStatus(rawResponse: FullOperationResponse): string { - const { status } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getResponseStatus(rawResponse: RawResponse): string { + const { status } = (rawResponse.body as LroBody) ?? {}; return status?.toLowerCase() ?? "succeeded"; } -function isAzureAsyncPollingDone(rawResponse: FullOperationResponse) { +function isAzureAsyncPollingDone(rawResponse: RawResponse): boolean { const state = getResponseStatus(rawResponse); - if (failureStates.includes(state)) { + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { throw new Error(`Operation status: ${state}`); } return successStates.includes(state); } +async function sendFinalRequest( + lro: LongRunningOperation, + lroResourceLocationConfig?: LroResourceLocationConfig, + resourceLocation?: string +): Promise | undefined> { + switch (lroResourceLocationConfig) { + case "original-uri": + return lro.retrieveAzureAsyncResource(); + case "azure-async-operation": + return Promise.resolve(undefined); + case "location": + default: + return lro.retrieveAzureAsyncResource(resourceLocation); + } +} + export function processAzureAsyncOperationResult( - restrieveResource: (path?: string) => Promise>, + lro: LongRunningOperation, resourceLocation?: string, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { + lroResourceLocationConfig?: LroResourceLocationConfig +): (rawResponse: RawResponse, flatResponse: TResult) => LroStatus { return ( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult - ): LROState => { + ): LroStatus => { if (isAzureAsyncPollingDone(rawResponse)) { if (resourceLocation === undefined) { return { rawResponse, flatResponse, done: true }; @@ -49,20 +71,11 @@ export function processAzureAsyncOperationResult( flatResponse, done: false, next: async () => { - async function sendFinalRequest(): Promise< - LROResult | undefined - > { - switch (finalStateVia) { - case "original-uri": - return restrieveResource(); - case "azure-async-operation": - return Promise.resolve(undefined); - case "location": - default: - return restrieveResource(resourceLocation); - } - } - const finalResponse = await sendFinalRequest(); + const finalResponse = await sendFinalRequest( + lro, + lroResourceLocationConfig, + resourceLocation + ); return { ...(finalResponse ?? { rawResponse, diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/lro/bodyPolling.ts b/test/smoke/generated/cosmos-db-resource-manager/src/lro/bodyPolling.ts index 269d8e6799..b1c87f8bc8 100644 --- a/test/smoke/generated/cosmos-db-resource-manager/src/lro/bodyPolling.ts +++ b/test/smoke/generated/cosmos-db-resource-manager/src/lro/bodyPolling.ts @@ -7,24 +7,33 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroBody, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getProvisioningState(rawResponse: FullOperationResponse): string { - const { properties, provisioningState } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getProvisioningState(rawResponse: RawResponse): string { + const { properties, provisioningState } = (rawResponse.body as LroBody) ?? {}; const state: string | undefined = properties?.provisioningState ?? provisioningState; return state?.toLowerCase() ?? "succeeded"; } -export function isBodyPollingDone(rawResponse: FullOperationResponse) { +export function isBodyPollingDone(rawResponse: RawResponse): boolean { const state = getProvisioningState(rawResponse); - if (failureStates.includes(state)) { - throw new Error(`Provisioning state: ${state}`); + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { + throw new Error( + `The long running operation has failed. The provisioning state: ${state}.` + ); } return successStates.includes(state); } @@ -34,9 +43,9 @@ export function isBodyPollingDone(rawResponse: FullOperationResponse) { * from the result to determine the current operation state */ export function processBodyPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/lro/index.ts b/test/smoke/generated/cosmos-db-resource-manager/src/lro/index.ts index 85c2187669..20df608fc8 100644 --- a/test/smoke/generated/cosmos-db-resource-manager/src/lro/index.ts +++ b/test/smoke/generated/cosmos-db-resource-manager/src/lro/index.ts @@ -6,5 +6,21 @@ * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ -export { shouldDeserializeLRO } from "./requestUtils"; -export { LROPoller } from "./lroPoller"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { LroEngine } from "./lroEngine"; +export { createGetLroStatusFromResponse } from "./stateMachine"; +export { + LroResourceLocationConfig, + GetLroStatusFromResponse, + RawResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + LroTerminalState, + LroInProgressState, + LroEngineOptions +} from "./models"; diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/lro/locationPolling.ts b/test/smoke/generated/cosmos-db-resource-manager/src/lro/locationPolling.ts index 6fef619384..9d1aadfbde 100644 --- a/test/smoke/generated/cosmos-db-resource-manager/src/lro/locationPolling.ts +++ b/test/smoke/generated/cosmos-db-resource-manager/src/lro/locationPolling.ts @@ -7,23 +7,21 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function isLocationPollingDone(rawResponse: FullOperationResponse) { - const code = rawResponse.status; - if (![202, 200].includes(code)) { - throw new Error(`Operation failed`); - } - return code !== 202; +function isLocationPollingDone(rawResponse: RawResponse): boolean { + return ( + !isUnexpectedPollingResponse(rawResponse) && rawResponse.statusCode !== 202 + ); } export function processLocationPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/lro/lroEngine.ts b/test/smoke/generated/cosmos-db-resource-manager/src/lro/lroEngine.ts new file mode 100644 index 0000000000..85cc15e609 --- /dev/null +++ b/test/smoke/generated/cosmos-db-resource-manager/src/lro/lroEngine.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Poller, PollOperationState } from "@azure/core-lro"; +import { + LongRunningOperation, + LroEngineOptions, + ResumablePollOperationState +} from "./models"; +import { GenericPollOperation } from "./operation"; + +/** + * The LRO Engine, a class that performs polling. + */ +export class LroEngine< + TResult, + TState extends PollOperationState +> extends Poller { + private intervalInMs: number; + + constructor(lro: LongRunningOperation, options?: LroEngineOptions) { + const { intervalInMs = 2000, resumeFrom } = options || {}; + function deserializeState( + resumeFrom: string + ): TState & ResumablePollOperationState { + try { + return JSON.parse(resumeFrom).state; + } catch (e) { + throw new Error( + `LroEngine: Unable to deserialize state: ${resumeFrom}` + ); + } + } + const state: TState & ResumablePollOperationState = resumeFrom + ? deserializeState(resumeFrom) + : ({} as any); + + const operation = new GenericPollOperation(state, lro); + super(operation); + + this.intervalInMs = intervalInMs; + operation.setPollerConfig(this as any); + } + + /** + * The method used by the poller to wait before attempting to update its operation. + */ + delay(): Promise { + return new Promise((resolve) => + setTimeout(() => resolve(), this.intervalInMs) + ); + } +} diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/lro/lroPoller.ts b/test/smoke/generated/cosmos-db-resource-manager/src/lro/lroPoller.ts deleted file mode 100644 index cd1cd64fe8..0000000000 --- a/test/smoke/generated/cosmos-db-resource-manager/src/lro/lroPoller.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { Poller, PollOperationState } from "@azure/core-lro"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { FinalStateVia, SendOperationFn } from "./models"; -import { GenericPollOperation } from "./operation"; - -export interface LROPollerOptions { - /** - * Defines how much time the poller is going to wait before making a new request to the service. - */ - intervalInMs?: number; - /** - * A serialized poller which can be used to resume an existing paused Long-Running-Operation. - */ - resumeFrom?: string; -} - -export class LROPoller extends Poller< - PollOperationState, - TResult -> { - private intervalInMs: number; - - constructor( - { intervalInMs = 2000, resumeFrom }: LROPollerOptions, - initialOperationArguments: OperationArguments, - initialOperationSpec: OperationSpec, - sendOperation: SendOperationFn, - finalStateVia?: FinalStateVia - ) { - const state: PollOperationState = resumeFrom - ? JSON.parse(resumeFrom).state - : {}; - - const operation = new GenericPollOperation( - state, - initialOperationArguments, - initialOperationSpec, - sendOperation, - finalStateVia - ); - super(operation); - - this.intervalInMs = intervalInMs; - operation.setPollerConfig(this as any); - } - - /** - * The method used by the poller to wait before attempting to update its operation. - */ - delay(): Promise { - return new Promise((resolve) => - setTimeout(() => resolve(), this.intervalInMs) - ); - } -} diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/lro/models.ts b/test/smoke/generated/cosmos-db-resource-manager/src/lro/models.ts index a4a5a5abd6..93c3437c8e 100644 --- a/test/smoke/generated/cosmos-db-resource-manager/src/lro/models.ts +++ b/test/smoke/generated/cosmos-db-resource-manager/src/lro/models.ts @@ -7,46 +7,167 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec -} from "@azure/core-client"; import { PollOperationState } from "@azure/core-lro"; -export type FinalStateVia = +/** + * Options for the LRO poller. + */ +export interface LroEngineOptions { + /** + * Defines how much time the poller is going to wait before making a new request to the service. + */ + intervalInMs?: number; + /** + * A serialized poller which can be used to resume an existing paused Long-Running-Operation. + */ + resumeFrom?: string; +} + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +/** + * The LRO states that signal that the LRO has completed. + */ +export const terminalStates = successStates.concat(failureStates); + +/** + * The potential location of the result of the LRO if specified by the LRO extension in the swagger. + */ +export type LroResourceLocationConfig = | "azure-async-operation" | "location" | "original-uri"; -export interface LROResult { +/** + * The type of a LRO response body. This is just a convenience type for checking the status of the operation. + */ + +export interface LroBody extends Record { + /** The status of the operation. */ + status?: string; + /** The state of the provisioning process */ + provisioningState?: string; + /** The properties of the provisioning process */ + properties?: { provisioningState?: string } & Record; +} + +/** + * Simple type of the raw response. + */ +export interface RawResponse { + /** The HTTP status code */ + statusCode: number; + /** A HttpHeaders collection in the response represented as a simple JSON object where all header names have been normalized to be lower-case. */ + headers: { + [headerName: string]: string; + }; + /** The parsed response body */ + body?: unknown; +} + +/** + * The type of the response of a LRO. + */ +export interface LroResponse { + /** The flattened response */ flatResponse: T; - rawResponse: FullOperationResponse; + /** The raw response */ + rawResponse: RawResponse; } -export type LROMode = "AzureAsync" | "Location" | "Body"; +/** The type of which LRO implementation being followed by a specific API. */ +export type LroMode = "AzureAsync" | "Location" | "Body"; -export interface LROConfig { - mode?: LROMode; +/** + * The configuration of a LRO to determine how to perform polling and checking whether the operation has completed. + */ +export interface LroConfig { + /** The LRO mode */ + mode?: LroMode; + /** The path of a provisioned resource */ resourceLocation?: string; } -export type SendOperationFn = ( - args: OperationArguments, - spec: OperationSpec -) => Promise>; - /** * Type of a polling operation state that can actually be resumed. */ export type ResumablePollOperationState = PollOperationState & { - initialRawResponse?: FullOperationResponse; - config?: LROConfig; + initialRawResponse?: RawResponse; + config?: LroConfig; pollingURL?: string; }; export interface PollerConfig { intervalInMs: number; } + +/** + * The type of a terminal state of an LRO. + */ +export interface LroTerminalState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: true; +} + +/** + * The type of an in-progress state of an LRO. + */ +export interface LroInProgressState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: false; + /** + * The request to be sent next if it is different from the standard polling one. + * Notice that it will disregard any polling URLs provided to it. + */ + next?: () => Promise>; +} + +/** + * The type of an LRO state which is a tagged union of terminal and in-progress states. + */ +export type LroStatus = LroTerminalState | LroInProgressState; + +/** + * The type of the getLROStatusFromResponse method. It takes the response as input and returns along the response whether the operation has finished. + */ +export type GetLroStatusFromResponse = ( + rawResponse: RawResponse, + flatResponse: T +) => LroStatus; + +/** + * Description of a long running operation. + */ +export interface LongRunningOperation { + /** + * The request path. + */ + requestPath: string; + /** + * The HTTP request method. + */ + requestMethod: string; + /** + * A function that can be used to send initial request to the service. + */ + sendInitialRequest: ( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ) => Promise>; + /** + * A function that can be used to poll for the current status of a long running operation. + */ + sendPollRequest: (config: LroConfig, path: string) => Promise>; + /** + * A function that can be used to retrieve the provisioned azure resource. + */ + retrieveAzureAsyncResource: (path?: string) => Promise>; +} diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/lro/operation.ts b/test/smoke/generated/cosmos-db-resource-manager/src/lro/operation.ts index 801d03e720..3ea7b76d89 100644 --- a/test/smoke/generated/cosmos-db-resource-manager/src/lro/operation.ts +++ b/test/smoke/generated/cosmos-db-resource-manager/src/lro/operation.ts @@ -7,36 +7,34 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. import { AbortSignalLike } from "@azure/abort-controller"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { PollOperation, PollOperationState } from "@azure/core-lro"; +import { PollOperationState, PollOperation } from "@azure/core-lro"; import { - FinalStateVia, PollerConfig, ResumablePollOperationState, - SendOperationFn + LongRunningOperation, + LroStatus } from "./models"; -import { getPollingURL } from "./requestUtils"; -import { createGetLROState, initializeState, LROState } from "./stateMachine"; +import { getPollingUrl } from "./requestUtils"; +import { createInitializeState, createPollForLROStatus } from "./stateMachine"; -export class GenericPollOperation - implements PollOperation, TResult> { - private getLROState?: ( +export class GenericPollOperation< + TResult, + TState extends PollOperationState +> implements PollOperation { + private getLROStatusFromResponse?: ( pollingURL: string, pollerConfig: PollerConfig - ) => Promise>; + ) => Promise>; private pollerConfig?: PollerConfig; constructor( - public state: PollOperationState, - private initialOperationArguments: OperationArguments, - private initialOperationSpec: OperationSpec, - private sendOperation: SendOperationFn, - private finalStateVia?: FinalStateVia + public state: TState & ResumablePollOperationState, + private lro: LongRunningOperation ) {} - public setPollerConfig(pollerConfig: PollerConfig) { + public setPollerConfig(pollerConfig: PollerConfig): void { this.pollerConfig = pollerConfig; } @@ -57,45 +55,36 @@ export class GenericPollOperation */ async update(options?: { abortSignal?: AbortSignalLike | undefined; - fireProgress?: ((state: PollOperationState) => void) | undefined; - }): Promise, TResult>> { - const state = this.state as ResumablePollOperationState; - const { onResponse, ...restOptions } = - this.initialOperationArguments.options || {}; + fireProgress?: ((state: TState) => void) | undefined; + }): Promise> { + const state = this.state; if (!state.isStarted) { - await this.sendOperation( - { - ...this.initialOperationArguments, - options: { - ...restOptions, - onResponse: initializeState( - state, - this.initialOperationSpec, - onResponse - ) - } - }, - this.initialOperationSpec + const initializeState = createInitializeState( + state, + this.lro.requestPath, + this.lro.requestMethod ); + await this.lro.sendInitialRequest(initializeState); } if (!state.isCompleted) { - if (this.getLROState === undefined) { + if (this.getLROStatusFromResponse === undefined) { if (state.config === undefined) { - throw new Error("Bad state: LRO mode is undefined"); + throw new Error( + "Bad state: LRO mode is undefined. Please check if the serialized state is well-formed." + ); } - this.getLROState = createGetLROState( - this.sendOperation, - this.initialOperationArguments, - this.initialOperationSpec, - state.config, - this.finalStateVia + this.getLROStatusFromResponse = createPollForLROStatus( + this.lro, + state.config ); } if (state.pollingURL === undefined) { - throw new Error("Bad state: polling URL is undefined"); + throw new Error( + "Bad state: polling URL is undefined. Please check if the serialized state is well-formed." + ); } - const currentState = await this.getLROState( + const currentState = await this.getLROStatusFromResponse( state.pollingURL, this.pollerConfig! ); @@ -103,20 +92,19 @@ export class GenericPollOperation state.result = currentState.flatResponse; state.isCompleted = true; } else { - this.getLROState = currentState.next ?? this.getLROState; - state.pollingURL = getPollingURL( + this.getLROStatusFromResponse = + currentState.next ?? this.getLROStatusFromResponse; + state.pollingURL = getPollingUrl( currentState.rawResponse, state.pollingURL ); } } - if (options?.fireProgress !== undefined) { - options.fireProgress(state); - } + options?.fireProgress?.(state); return this; } - async cancel(): Promise, TResult>> { + async cancel(): Promise> { this.state.isCancelled = true; return this; } diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/lro/passthrough.ts b/test/smoke/generated/cosmos-db-resource-manager/src/lro/passthrough.ts index 64c10380c1..ae7f87d384 100644 --- a/test/smoke/generated/cosmos-db-resource-manager/src/lro/passthrough.ts +++ b/test/smoke/generated/cosmos-db-resource-manager/src/lro/passthrough.ts @@ -7,15 +7,14 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; export function processPassthroughOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/lro/pollingMethod.ts b/test/smoke/generated/cosmos-db-resource-manager/src/lro/pollingMethod.ts deleted file mode 100644 index cb6482bbde..0000000000 --- a/test/smoke/generated/cosmos-db-resource-manager/src/lro/pollingMethod.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - OperationArguments, - OperationSpec, - OperationResponseMap -} from "@azure/core-client"; -import { LROMode, LROResult, SendOperationFn } from "./models"; - -export function createPollingMethod( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - mode?: LROMode -): (path?: string) => Promise> { - /** - * Polling calls will always return a status object i.e. {"status": "success"} - * these intermediate responses are not described in the swagger so we need to - * pass custom mappers at runtime. - * This function replaces all the existing mappers to be able to deserialize a status object - * @param responses Original set of responses defined in the operation - */ - function getCompositeMappers(responses: { - [responseCode: string]: OperationResponseMap; - }): { - [responseCode: string]: OperationResponseMap; - } { - return Object.keys(responses).reduce((acc, statusCode) => { - return { - ...acc, - [statusCode]: { - ...responses[statusCode], - bodyMapper: { - type: { - name: "Composite", - modelProperties: { - status: { - serializedName: "status", - type: { - name: "String" - } - } - } - } - } - } - }; - }, {} as { [responseCode: string]: OperationResponseMap }); - } - // Make sure we don't send any body to the get request - const { requestBody, responses, ...restSpec } = spec; - if (mode === "AzureAsync") { - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: getCompositeMappers(responses), - httpMethod: "GET", - ...(path && { path }) - }); - }; - } - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: responses, - httpMethod: "GET", - ...(path && { path }) - }); - }; -} - -export function createRetrieveAzureAsyncResource( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec -): (path?: string) => Promise> { - const updatedArgs = { ...args }; - if (updatedArgs.options) { - (updatedArgs.options as any).shouldDeserialize = true; - } - return createPollingMethod(sendOperationFn, updatedArgs, spec); -} diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/lro/requestUtils.ts b/test/smoke/generated/cosmos-db-resource-manager/src/lro/requestUtils.ts index 9162f66339..40d993686f 100644 --- a/test/smoke/generated/cosmos-db-resource-manager/src/lro/requestUtils.ts +++ b/test/smoke/generated/cosmos-db-resource-manager/src/lro/requestUtils.ts @@ -7,119 +7,9 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse, OperationSpec } from "@azure/core-client"; -import { LROConfig } from "./models"; -import { terminalStates } from "./stateMachine"; - -/** - * We need to selectively deserialize our responses, only deserializing if we - * are in a final LRO response, not deserializing any polling non-terminal responses - */ -export function shouldDeserializeLRO(finalStateVia?: string) { - let initialOperationInfo: LROResponseInfo | undefined; - let isInitialRequest = true; - - return (response: FullOperationResponse) => { - if (response.status < 200 || response.status >= 300) { - return true; - } - - if (!initialOperationInfo) { - initialOperationInfo = getLROData(response); - } else { - isInitialRequest = false; - } - - if ( - initialOperationInfo.azureAsyncOperation || - initialOperationInfo.operationLocation - ) { - return ( - !isInitialRequest && - isAsyncOperationFinalResponse( - response, - initialOperationInfo, - finalStateVia - ) - ); - } - - if (initialOperationInfo.location) { - return isLocationFinalResponse(response); - } - - if (initialOperationInfo.requestMethod === "PUT") { - return isBodyPollingFinalResponse(response); - } - - return true; - }; -} - -function isAsyncOperationFinalResponse( - response: FullOperationResponse, - initialOperationInfo: LROResponseInfo, - finalStateVia?: string -): boolean { - const status: string = response.parsedBody?.status || "Succeeded"; - if (!terminalStates.includes(status.toLowerCase())) { - return false; - } - - if (initialOperationInfo.requestMethod === "DELETE") { - return true; - } - - if ( - initialOperationInfo.requestMethod === "PUT" && - finalStateVia && - finalStateVia.toLowerCase() === "azure-asyncoperation" - ) { - return true; - } - - if ( - initialOperationInfo.requestMethod !== "PUT" && - !initialOperationInfo.location - ) { - return true; - } - - return false; -} - -function isLocationFinalResponse(response: FullOperationResponse): boolean { - return response.status !== 202; -} - -function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { - const provisioningState: string = - response.parsedBody?.properties?.provisioningState || "Succeeded"; - - if (terminalStates.includes(provisioningState.toLowerCase())) { - return true; - } - - return false; -} - -interface LROResponseInfo { - requestMethod: string; - azureAsyncOperation?: string; - operationLocation?: string; - location?: string; -} - -function getLROData(result: FullOperationResponse): LROResponseInfo { - return { - azureAsyncOperation: result.headers.get("azure-asyncoperation"), - operationLocation: result.headers.get("operation-location"), - location: result.headers.get("location"), - requestMethod: result.request.method - }; -} +import { LroConfig, RawResponse } from "./models"; /** * Detects where the continuation token is and returns it. Notice that azure-asyncoperation @@ -127,45 +17,41 @@ function getLROData(result: FullOperationResponse): LROResponseInfo { * where both azure-asyncoperation and location could be present in the same response but * azure-asyncoperation should be the one to use for polling. */ -export function getPollingURL( - rawResponse: FullOperationResponse, +export function getPollingUrl( + rawResponse: RawResponse, defaultPath: string ): string { return ( - getAzureAsyncoperation(rawResponse) ?? + getAzureAsyncOperation(rawResponse) ?? getLocation(rawResponse) ?? getOperationLocation(rawResponse) ?? defaultPath ); } -function getLocation(rawResponse: FullOperationResponse): string | undefined { - return rawResponse.headers?.get("location"); +function getLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["location"]; } -function getOperationLocation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("operation-location"); +function getOperationLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["operation-location"]; } -function getAzureAsyncoperation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("azure-asyncoperation"); +function getAzureAsyncOperation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["azure-asyncoperation"]; } -export function inferLROMode( - spec: OperationSpec, - rawResponse: FullOperationResponse -): LROConfig { - const requestMethod = spec.httpMethod; - if (getAzureAsyncoperation(rawResponse) !== undefined) { +export function inferLroMode( + requestPath: string, + requestMethod: string, + rawResponse: RawResponse +): LroConfig { + if (getAzureAsyncOperation(rawResponse) !== undefined) { return { mode: "AzureAsync", resourceLocation: requestMethod === "PUT" - ? spec.path + ? requestPath : requestMethod === "POST" ? getLocation(rawResponse) : undefined @@ -185,10 +71,35 @@ export function inferLROMode( return {}; } -export function getSpecPath(spec: OperationSpec): string { - if (spec.path) { - return spec.path; - } else { - throw Error("Bad spec: request path is not found!"); +export class RestError extends Error { + public statusCode?: number; + constructor(message: string, statusCode: number) { + super(message); + this.name = "RestError"; + this.statusCode = statusCode; + + Object.setPrototypeOf(this, RestError.prototype); + } +} + +export function isUnexpectedInitialResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![203, 204, 202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} in the initial response. This may indicate a server issue.`, + code + ); } + return false; +} + +export function isUnexpectedPollingResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} while polling. This may indicate a server issue.`, + code + ); + } + return false; } diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/lro/stateMachine.ts b/test/smoke/generated/cosmos-db-resource-manager/src/lro/stateMachine.ts index b2a69b5546..19a8f67470 100644 --- a/test/smoke/generated/cosmos-db-resource-manager/src/lro/stateMachine.ts +++ b/test/smoke/generated/cosmos-db-resource-manager/src/lro/stateMachine.ts @@ -7,14 +7,8 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec, - RawResponseCallback -} from "@azure/core-client"; import { processAzureAsyncOperationResult } from "./azureAsyncPolling"; import { isBodyPollingDone, @@ -22,73 +16,36 @@ import { } from "./bodyPolling"; import { processLocationPollingOperationResult } from "./locationPolling"; import { - FinalStateVia, - LROConfig, - LROResult, + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroStatus, PollerConfig, - ResumablePollOperationState, - SendOperationFn + RawResponse, + ResumablePollOperationState } from "./models"; import { processPassthroughOperationResult } from "./passthrough"; import { - createPollingMethod, - createRetrieveAzureAsyncResource -} from "./pollingMethod"; -import { getPollingURL, getSpecPath, inferLROMode } from "./requestUtils"; - -export const successStates = ["succeeded"]; -export const failureStates = ["failed", "canceled", "cancelled"]; -export const terminalStates = successStates.concat(failureStates); - -/** - * The type of a terminal state of an LRO. - */ -interface LROTerminalState extends LROResult { - /** - * Whether the operation has finished. - */ - done: true; -} - -/** - * The type of an in-progress state of an LRO. - */ -interface LROInProgressState extends LROResult { - /** - * Whether the operation has finished. - */ - done: false; - /** - * The request to be sent next if it is different from the standard polling one. - * Notice that it will disregard any polling URLs provided to it. - */ - next?: () => Promise>; -} - -/** - * The type of an LRO state which is a tagged union of terminal and in-progress states. - */ -export type LROState = LROTerminalState | LROInProgressState; + getPollingUrl, + inferLroMode, + isUnexpectedInitialResponse +} from "./requestUtils"; /** * creates a stepping function that maps an LRO state to another. */ -function createTransition( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { +export function createGetLroStatusFromResponse( + lroPrimitives: LongRunningOperation, + config: LroConfig, + lroResourceLocationConfig?: LroResourceLocationConfig +): GetLroStatusFromResponse { switch (config.mode) { case "AzureAsync": { return processAzureAsyncOperationResult( - createRetrieveAzureAsyncResource(sendOperationFn, args, spec), + lroPrimitives, config.resourceLocation, - finalStateVia + lroResourceLocationConfig ); } case "Location": { @@ -106,52 +63,20 @@ function createTransition( /** * Creates a polling operation that returns a LRO state. */ -export function createGetLROState( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia +export function createPollForLROStatus( + lroPrimitives: LongRunningOperation, + config: LroConfig ): ( pollingURL: string, pollerConfig: PollerConfig -) => Promise> { - const step = createTransition( - sendOperationFn, - args, - spec, - config, - finalStateVia - ); - const customerCallback = args?.options?.onResponse; - let response: LROState | undefined = undefined; - let retryAfter: string | undefined = undefined; - const poll = createPollingMethod( - sendOperationFn, - { - ...args, - options: { - ...args.options, - onResponse: ( - rawResponse: FullOperationResponse, - flatResponse: unknown - ): void => { - response = step(rawResponse, flatResponse as TResult); - retryAfter = rawResponse.headers.get("Retry-After"); - if (response.done) { - customerCallback?.(rawResponse, flatResponse); - } - } - } - }, - spec, - config.mode - ); +) => Promise> { return async ( path: string, pollerConfig: PollerConfig - ): Promise> => { - await poll(path); + ): Promise> => { + const response = await lroPrimitives.sendPollRequest(config, path); + const retryAfter: string | undefined = + response.rawResponse.headers["retry-after"]; if (retryAfter !== undefined) { const retryAfterInMs = parseInt(retryAfter); pollerConfig.intervalInMs = isNaN(retryAfterInMs) @@ -161,7 +86,7 @@ export function createGetLROState( ) : retryAfterInMs; } - return response!; + return response; }; } @@ -179,24 +104,26 @@ function calculatePollingIntervalFromDate( /** * Creates a callback to be used to initialize the polling operation state. - * @param state of the polling operation - * @param operationSpec of the LRO - * @param callback callback to be called when the operation is done + * @param state - of the polling operation + * @param operationSpec - of the LRO + * @param callback - callback to be called when the operation is done * @returns callback that initializes the state of the polling operation */ -export function initializeState( +export function createInitializeState( state: ResumablePollOperationState, - operationSpec: OperationSpec, - callback?: RawResponseCallback -): (rawResponse: FullOperationResponse, flatResponse: unknown) => void { - return (rawResponse: FullOperationResponse, flatResponse: unknown) => { + requestPath: string, + requestMethod: string +): (rawResponse: RawResponse, flatResponse: unknown) => boolean { + return (rawResponse: RawResponse, flatResponse: unknown) => { + if (isUnexpectedInitialResponse(rawResponse)) return true; state.initialRawResponse = rawResponse; state.isStarted = true; - state.pollingURL = getPollingURL( - state.initialRawResponse, - getSpecPath(operationSpec) + state.pollingURL = getPollingUrl(state.initialRawResponse, requestPath); + state.config = inferLroMode( + requestPath, + requestMethod, + state.initialRawResponse ); - state.config = inferLROMode(operationSpec, state.initialRawResponse); /** short circuit polling if body polling is done in the initial request */ if ( state.config.mode === undefined || @@ -205,12 +132,7 @@ export function initializeState( ) { state.result = flatResponse as TResult; state.isCompleted = true; - /** - * We need to check if the LRO operation is finished inside the - * call back so that we can call the customer-provided callback - * on that result. - */ - callback?.(rawResponse, flatResponse); } + return Boolean(state.isCompleted); }; } diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/operations/cassandraResources.ts b/test/smoke/generated/cosmos-db-resource-manager/src/operations/cassandraResources.ts index ce960d7bd6..6e4f01ef5e 100644 --- a/test/smoke/generated/cosmos-db-resource-manager/src/operations/cassandraResources.ts +++ b/test/smoke/generated/cosmos-db-resource-manager/src/operations/cassandraResources.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { CosmosDBManagementClientContext } from "../cosmosDBManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { CassandraKeyspaceGetResults, CassandraResourcesListCassandraKeyspacesOptionalParams, @@ -275,11 +276,18 @@ export class CassandraResourcesImpl implements CassandraResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -287,9 +295,9 @@ export class CassandraResourcesImpl implements CassandraResources { createUpdateCassandraKeyspaceParameters, options }, - createUpdateCassandraKeyspaceOperationSpec, - sendOperation + createUpdateCassandraKeyspaceOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -360,15 +368,22 @@ export class CassandraResourcesImpl implements CassandraResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, keyspaceName, options }, - deleteCassandraKeyspaceOperationSpec, - sendOperation + deleteCassandraKeyspaceOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -465,11 +480,18 @@ export class CassandraResourcesImpl implements CassandraResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -477,9 +499,9 @@ export class CassandraResourcesImpl implements CassandraResources { updateThroughputParameters, options }, - updateCassandraKeyspaceThroughputOperationSpec, - sendOperation + updateCassandraKeyspaceThroughputOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -600,11 +622,18 @@ export class CassandraResourcesImpl implements CassandraResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -613,9 +642,9 @@ export class CassandraResourcesImpl implements CassandraResources { createUpdateCassandraTableParameters, options }, - createUpdateCassandraTableOperationSpec, - sendOperation + createUpdateCassandraTableOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -691,15 +720,22 @@ export class CassandraResourcesImpl implements CassandraResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, keyspaceName, tableName, options }, - deleteCassandraTableOperationSpec, - sendOperation + deleteCassandraTableOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -803,11 +839,18 @@ export class CassandraResourcesImpl implements CassandraResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -816,9 +859,9 @@ export class CassandraResourcesImpl implements CassandraResources { updateThroughputParameters, options }, - updateCassandraTableThroughputOperationSpec, - sendOperation + updateCassandraTableThroughputOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/operations/databaseAccounts.ts b/test/smoke/generated/cosmos-db-resource-manager/src/operations/databaseAccounts.ts index 2606aff6fd..8d38d2c1ac 100644 --- a/test/smoke/generated/cosmos-db-resource-manager/src/operations/databaseAccounts.ts +++ b/test/smoke/generated/cosmos-db-resource-manager/src/operations/databaseAccounts.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { CosmosDBManagementClientContext } from "../cosmosDBManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { DatabaseAccountGetResults, DatabaseAccountsListOptionalParams, @@ -403,15 +404,22 @@ export class DatabaseAccountsImpl implements DatabaseAccounts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, updateParameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -484,15 +492,22 @@ export class DatabaseAccountsImpl implements DatabaseAccounts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, createUpdateParameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -558,15 +573,22 @@ export class DatabaseAccountsImpl implements DatabaseAccounts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -633,15 +655,22 @@ export class DatabaseAccountsImpl implements DatabaseAccounts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, failoverParameters, options }, - failoverPriorityChangeOperationSpec, - sendOperation + failoverPriorityChangeOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -770,15 +799,22 @@ export class DatabaseAccountsImpl implements DatabaseAccounts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, regionParameterForOffline, options }, - offlineRegionOperationSpec, - sendOperation + offlineRegionOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -845,15 +881,22 @@ export class DatabaseAccountsImpl implements DatabaseAccounts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, regionParameterForOnline, options }, - onlineRegionOperationSpec, - sendOperation + onlineRegionOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -954,15 +997,22 @@ export class DatabaseAccountsImpl implements DatabaseAccounts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, keyToRegenerate, options }, - regenerateKeyOperationSpec, - sendOperation + regenerateKeyOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/operations/gremlinResources.ts b/test/smoke/generated/cosmos-db-resource-manager/src/operations/gremlinResources.ts index e05b4408a2..403aab199b 100644 --- a/test/smoke/generated/cosmos-db-resource-manager/src/operations/gremlinResources.ts +++ b/test/smoke/generated/cosmos-db-resource-manager/src/operations/gremlinResources.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { CosmosDBManagementClientContext } from "../cosmosDBManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { GremlinDatabaseGetResults, GremlinResourcesListGremlinDatabasesOptionalParams, @@ -273,11 +274,18 @@ export class GremlinResourcesImpl implements GremlinResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -285,9 +293,9 @@ export class GremlinResourcesImpl implements GremlinResources { createUpdateGremlinDatabaseParameters, options }, - createUpdateGremlinDatabaseOperationSpec, - sendOperation + createUpdateGremlinDatabaseOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -358,15 +366,22 @@ export class GremlinResourcesImpl implements GremlinResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, databaseName, options }, - deleteGremlinDatabaseOperationSpec, - sendOperation + deleteGremlinDatabaseOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -463,11 +478,18 @@ export class GremlinResourcesImpl implements GremlinResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -475,9 +497,9 @@ export class GremlinResourcesImpl implements GremlinResources { updateThroughputParameters, options }, - updateGremlinDatabaseThroughputOperationSpec, - sendOperation + updateGremlinDatabaseThroughputOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -597,11 +619,18 @@ export class GremlinResourcesImpl implements GremlinResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -610,9 +639,9 @@ export class GremlinResourcesImpl implements GremlinResources { createUpdateGremlinGraphParameters, options }, - createUpdateGremlinGraphOperationSpec, - sendOperation + createUpdateGremlinGraphOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -687,15 +716,22 @@ export class GremlinResourcesImpl implements GremlinResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, databaseName, graphName, options }, - deleteGremlinGraphOperationSpec, - sendOperation + deleteGremlinGraphOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -797,11 +833,18 @@ export class GremlinResourcesImpl implements GremlinResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -810,9 +853,9 @@ export class GremlinResourcesImpl implements GremlinResources { updateThroughputParameters, options }, - updateGremlinGraphThroughputOperationSpec, - sendOperation + updateGremlinGraphThroughputOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/operations/mongoDBResources.ts b/test/smoke/generated/cosmos-db-resource-manager/src/operations/mongoDBResources.ts index e850a44282..a6a3858c2d 100644 --- a/test/smoke/generated/cosmos-db-resource-manager/src/operations/mongoDBResources.ts +++ b/test/smoke/generated/cosmos-db-resource-manager/src/operations/mongoDBResources.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { CosmosDBManagementClientContext } from "../cosmosDBManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { MongoDBDatabaseGetResults, MongoDBResourcesListMongoDBDatabasesOptionalParams, @@ -273,11 +274,18 @@ export class MongoDBResourcesImpl implements MongoDBResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -285,9 +293,9 @@ export class MongoDBResourcesImpl implements MongoDBResources { createUpdateMongoDBDatabaseParameters, options }, - createUpdateMongoDBDatabaseOperationSpec, - sendOperation + createUpdateMongoDBDatabaseOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -358,15 +366,22 @@ export class MongoDBResourcesImpl implements MongoDBResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, databaseName, options }, - deleteMongoDBDatabaseOperationSpec, - sendOperation + deleteMongoDBDatabaseOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -463,11 +478,18 @@ export class MongoDBResourcesImpl implements MongoDBResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -475,9 +497,9 @@ export class MongoDBResourcesImpl implements MongoDBResources { updateThroughputParameters, options }, - updateMongoDBDatabaseThroughputOperationSpec, - sendOperation + updateMongoDBDatabaseThroughputOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -598,11 +620,18 @@ export class MongoDBResourcesImpl implements MongoDBResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -611,9 +640,9 @@ export class MongoDBResourcesImpl implements MongoDBResources { createUpdateMongoDBCollectionParameters, options }, - createUpdateMongoDBCollectionOperationSpec, - sendOperation + createUpdateMongoDBCollectionOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -689,15 +718,22 @@ export class MongoDBResourcesImpl implements MongoDBResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, databaseName, collectionName, options }, - deleteMongoDBCollectionOperationSpec, - sendOperation + deleteMongoDBCollectionOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -801,11 +837,18 @@ export class MongoDBResourcesImpl implements MongoDBResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -814,9 +857,9 @@ export class MongoDBResourcesImpl implements MongoDBResources { updateThroughputParameters, options }, - updateMongoDBCollectionThroughputOperationSpec, - sendOperation + updateMongoDBCollectionThroughputOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/operations/notebookWorkspaces.ts b/test/smoke/generated/cosmos-db-resource-manager/src/operations/notebookWorkspaces.ts index 2a4da522d8..4c64e82ea1 100644 --- a/test/smoke/generated/cosmos-db-resource-manager/src/operations/notebookWorkspaces.ts +++ b/test/smoke/generated/cosmos-db-resource-manager/src/operations/notebookWorkspaces.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { CosmosDBManagementClientContext } from "../cosmosDBManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { NotebookWorkspace, NotebookWorkspacesListByDatabaseAccountOptionalParams, @@ -191,11 +192,18 @@ export class NotebookWorkspacesImpl implements NotebookWorkspaces { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -203,9 +211,9 @@ export class NotebookWorkspacesImpl implements NotebookWorkspaces { notebookCreateUpdateParameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -276,15 +284,22 @@ export class NotebookWorkspacesImpl implements NotebookWorkspaces { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, notebookWorkspaceName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -370,15 +385,22 @@ export class NotebookWorkspacesImpl implements NotebookWorkspaces { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, notebookWorkspaceName, options }, - regenerateAuthTokenOperationSpec, - sendOperation + regenerateAuthTokenOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -445,15 +467,22 @@ export class NotebookWorkspacesImpl implements NotebookWorkspaces { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, notebookWorkspaceName, options }, - startOperationSpec, - sendOperation + startOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/operations/privateEndpointConnections.ts b/test/smoke/generated/cosmos-db-resource-manager/src/operations/privateEndpointConnections.ts index 79b46f20a8..c7858abfb7 100644 --- a/test/smoke/generated/cosmos-db-resource-manager/src/operations/privateEndpointConnections.ts +++ b/test/smoke/generated/cosmos-db-resource-manager/src/operations/privateEndpointConnections.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { CosmosDBManagementClientContext } from "../cosmosDBManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { PrivateEndpointConnectionAutoGenerated, PrivateEndpointConnectionsListByDatabaseAccountOptionalParams, @@ -190,11 +191,18 @@ export class PrivateEndpointConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -202,9 +210,9 @@ export class PrivateEndpointConnectionsImpl parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -274,20 +282,27 @@ export class PrivateEndpointConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, privateEndpointConnectionName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/operations/sqlResources.ts b/test/smoke/generated/cosmos-db-resource-manager/src/operations/sqlResources.ts index 74563d6f61..c5a9d657a6 100644 --- a/test/smoke/generated/cosmos-db-resource-manager/src/operations/sqlResources.ts +++ b/test/smoke/generated/cosmos-db-resource-manager/src/operations/sqlResources.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { CosmosDBManagementClientContext } from "../cosmosDBManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { SqlDatabaseGetResults, SqlResourcesListSqlDatabasesOptionalParams, @@ -526,11 +527,18 @@ export class SqlResourcesImpl implements SqlResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -538,9 +546,9 @@ export class SqlResourcesImpl implements SqlResources { createUpdateSqlDatabaseParameters, options }, - createUpdateSqlDatabaseOperationSpec, - sendOperation + createUpdateSqlDatabaseOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -610,15 +618,22 @@ export class SqlResourcesImpl implements SqlResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, databaseName, options }, - deleteSqlDatabaseOperationSpec, - sendOperation + deleteSqlDatabaseOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -713,11 +728,18 @@ export class SqlResourcesImpl implements SqlResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -725,9 +747,9 @@ export class SqlResourcesImpl implements SqlResources { updateThroughputParameters, options }, - updateSqlDatabaseThroughputOperationSpec, - sendOperation + updateSqlDatabaseThroughputOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -847,11 +869,18 @@ export class SqlResourcesImpl implements SqlResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -860,9 +889,9 @@ export class SqlResourcesImpl implements SqlResources { createUpdateSqlContainerParameters, options }, - createUpdateSqlContainerOperationSpec, - sendOperation + createUpdateSqlContainerOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -937,15 +966,22 @@ export class SqlResourcesImpl implements SqlResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, databaseName, containerName, options }, - deleteSqlContainerOperationSpec, - sendOperation + deleteSqlContainerOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1046,11 +1082,18 @@ export class SqlResourcesImpl implements SqlResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -1059,9 +1102,9 @@ export class SqlResourcesImpl implements SqlResources { updateThroughputParameters, options }, - updateSqlContainerThroughputOperationSpec, - sendOperation + updateSqlContainerThroughputOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1198,11 +1241,18 @@ export class SqlResourcesImpl implements SqlResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -1212,9 +1262,9 @@ export class SqlResourcesImpl implements SqlResources { createUpdateSqlStoredProcedureParameters, options }, - createUpdateSqlStoredProcedureOperationSpec, - sendOperation + createUpdateSqlStoredProcedureOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1295,11 +1345,18 @@ export class SqlResourcesImpl implements SqlResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -1308,9 +1365,9 @@ export class SqlResourcesImpl implements SqlResources { storedProcedureName, options }, - deleteSqlStoredProcedureOperationSpec, - sendOperation + deleteSqlStoredProcedureOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1448,11 +1505,18 @@ export class SqlResourcesImpl implements SqlResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -1462,9 +1526,9 @@ export class SqlResourcesImpl implements SqlResources { createUpdateSqlUserDefinedFunctionParameters, options }, - createUpdateSqlUserDefinedFunctionOperationSpec, - sendOperation + createUpdateSqlUserDefinedFunctionOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1545,11 +1609,18 @@ export class SqlResourcesImpl implements SqlResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -1558,9 +1629,9 @@ export class SqlResourcesImpl implements SqlResources { userDefinedFunctionName, options }, - deleteSqlUserDefinedFunctionOperationSpec, - sendOperation + deleteSqlUserDefinedFunctionOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1695,11 +1766,18 @@ export class SqlResourcesImpl implements SqlResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -1709,9 +1787,9 @@ export class SqlResourcesImpl implements SqlResources { createUpdateSqlTriggerParameters, options }, - createUpdateSqlTriggerOperationSpec, - sendOperation + createUpdateSqlTriggerOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1791,11 +1869,18 @@ export class SqlResourcesImpl implements SqlResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -1804,9 +1889,9 @@ export class SqlResourcesImpl implements SqlResources { triggerName, options }, - deleteSqlTriggerOperationSpec, - sendOperation + deleteSqlTriggerOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/cosmos-db-resource-manager/src/operations/tableResources.ts b/test/smoke/generated/cosmos-db-resource-manager/src/operations/tableResources.ts index 631e50141b..3a683d9975 100644 --- a/test/smoke/generated/cosmos-db-resource-manager/src/operations/tableResources.ts +++ b/test/smoke/generated/cosmos-db-resource-manager/src/operations/tableResources.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { CosmosDBManagementClientContext } from "../cosmosDBManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { TableGetResults, TableResourcesListTablesOptionalParams, @@ -190,11 +191,18 @@ export class TableResourcesImpl implements TableResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -202,9 +210,9 @@ export class TableResourcesImpl implements TableResources { createUpdateTableParameters, options }, - createUpdateTableOperationSpec, - sendOperation + createUpdateTableOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -274,15 +282,22 @@ export class TableResourcesImpl implements TableResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, tableName, options }, - deleteTableOperationSpec, - sendOperation + deleteTableOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -377,11 +392,18 @@ export class TableResourcesImpl implements TableResources { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, @@ -389,9 +411,9 @@ export class TableResourcesImpl implements TableResources { updateThroughputParameters, options }, - updateTableThroughputOperationSpec, - sendOperation + updateTableThroughputOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/keyvault-resource-manager/src/coreClientLro.ts b/test/smoke/generated/keyvault-resource-manager/src/coreClientLro.ts new file mode 100644 index 0000000000..d793a24458 --- /dev/null +++ b/test/smoke/generated/keyvault-resource-manager/src/coreClientLro.ts @@ -0,0 +1,323 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + OperationArguments, + OperationSpec, + OperationResponseMap, + FullOperationResponse +} from "@azure/core-client"; +import { + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + createGetLroStatusFromResponse, + RawResponse +} from "./lro"; + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +export const terminalStates = successStates.concat(failureStates); + +export type SendOperationFn = ( + args: OperationArguments, + spec: OperationSpec +) => Promise>; + +export function createPollingMethod( + sendOperationFn: SendOperationFn, + GetLroStatusFromResponse: GetLroStatusFromResponse, + args: OperationArguments, + spec: OperationSpec, + mode?: LroMode +): (path?: string) => Promise> { + /** + * Polling calls will always return a status object i.e. {"status": "success"} + * these intermediate responses are not described in the swagger so we need to + * pass custom mappers at runtime. + * This function replaces all the existing mappers to be able to deserialize a status object + * @param responses Original set of responses defined in the operation + */ + function getCompositeMappers(responses: { + [responseCode: string]: OperationResponseMap; + }): { + [responseCode: string]: OperationResponseMap; + } { + return Object.keys(responses).reduce((acc, statusCode) => { + return { + ...acc, + [statusCode]: { + ...responses[statusCode], + bodyMapper: { + type: { + name: "Composite", + modelProperties: { + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } + } + } + }; + }, {} as { [responseCode: string]: OperationResponseMap }); + } + let response: LroStatus | undefined = undefined; + const customerCallback = args?.options?.onResponse; + const updatedArgs = { + ...args, + options: { + ...args.options, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ): void => { + response = GetLroStatusFromResponse( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse as TResult + ); + if (response.done) { + customerCallback?.(rawResponse, flatResponse); + } + } + } + }; + // Make sure we don't send any body to the get request + const { requestBody, responses, ...restSpec } = spec; + if (mode === "AzureAsync") { + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: getCompositeMappers(responses), + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; + } + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: responses, + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; +} + +/** + * We need to selectively deserialize our responses, only deserializing if we + * are in a final Lro response, not deserializing any polling non-terminal responses + */ +export function shouldDeserializeLro(lroResourceLocationConfig?: string) { + let initialOperationInfo: LroResponseInfo | undefined; + let isInitialRequest = true; + + return (response: FullOperationResponse) => { + if (response.status < 200 || response.status >= 300) { + return true; + } + + if (!initialOperationInfo) { + initialOperationInfo = getLroData(response); + } else { + isInitialRequest = false; + } + + if ( + initialOperationInfo.azureAsyncOperation || + initialOperationInfo.operationLocation + ) { + return ( + !isInitialRequest && + isAsyncOperationFinalResponse( + response, + initialOperationInfo, + lroResourceLocationConfig + ) + ); + } + + if (initialOperationInfo.location) { + return isLocationFinalResponse(response); + } + + if (initialOperationInfo.requestMethod === "PUT") { + return isBodyPollingFinalResponse(response); + } + + return true; + }; +} + +function isAsyncOperationFinalResponse( + response: FullOperationResponse, + initialOperationInfo: LroResponseInfo, + lroResourceLocationConfig?: string +): boolean { + const status: string = response.parsedBody?.status || "Succeeded"; + if (!terminalStates.includes(status.toLowerCase())) { + return false; + } + + if (initialOperationInfo.requestMethod === "DELETE") { + return true; + } + + if ( + initialOperationInfo.requestMethod === "PUT" && + lroResourceLocationConfig && + lroResourceLocationConfig.toLowerCase() === "azure-asyncoperation" + ) { + return true; + } + + if ( + initialOperationInfo.requestMethod !== "PUT" && + !initialOperationInfo.location + ) { + return true; + } + + return false; +} + +function isLocationFinalResponse(response: FullOperationResponse): boolean { + return response.status !== 202; +} + +function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { + const provisioningState: string = + response.parsedBody?.properties?.provisioningState || "Succeeded"; + + if (terminalStates.includes(provisioningState.toLowerCase())) { + return true; + } + + return false; +} + +interface LroResponseInfo { + requestMethod: string; + azureAsyncOperation?: string; + operationLocation?: string; + location?: string; +} + +function getLroData(result: FullOperationResponse): LroResponseInfo { + return { + azureAsyncOperation: result.headers.get("azure-asyncoperation"), + operationLocation: result.headers.get("operation-location"), + location: result.headers.get("location"), + requestMethod: result.request.method + }; +} + +export function getSpecPath(spec: OperationSpec): string { + if (spec.path) { + return spec.path; + } else { + throw Error("Bad spec: request path is not found!"); + } +} + +export class CoreClientLro implements LongRunningOperation { + constructor( + private sendOperationFn: SendOperationFn, + private args: OperationArguments, + private spec: OperationSpec, + private lroResourceLocationConfig?: LroResourceLocationConfig, + public requestPath: string = spec.path!, + public requestMethod: string = spec.httpMethod + ) {} + public async sendInitialRequest( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ): Promise> { + const { onResponse, ...restOptions } = this.args.options || {}; + return this.sendOperationFn( + { + ...this.args, + options: { + ...restOptions, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ) => { + const isCompleted = initializeState( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse + ); + if (isCompleted) { + onResponse?.(rawResponse, flatResponse); + } + } + } + }, + this.spec + ); + } + + public async sendPollRequest( + config: LroConfig, + path: string + ): Promise> { + const getLroStatusFromResponse = createGetLroStatusFromResponse( + this, + config, + this.lroResourceLocationConfig + ); + return createPollingMethod( + this.sendOperationFn, + getLroStatusFromResponse, + this.args, + this.spec, + config.mode + )(path); + } + + public async retrieveAzureAsyncResource( + path?: string + ): Promise> { + const updatedArgs = { ...this.args }; + if (updatedArgs.options) { + (updatedArgs.options as any).shouldDeserialize = true; + } + return createPollingMethod( + this.sendOperationFn, + (rawResponse, flatResponse) => ({ + rawResponse, + flatResponse, + done: true + }), + updatedArgs, + this.spec + )(path); + } +} diff --git a/test/smoke/generated/keyvault-resource-manager/src/lro/azureAsyncPolling.ts b/test/smoke/generated/keyvault-resource-manager/src/lro/azureAsyncPolling.ts index 0d63c54f60..725578a692 100644 --- a/test/smoke/generated/keyvault-resource-manager/src/lro/azureAsyncPolling.ts +++ b/test/smoke/generated/keyvault-resource-manager/src/lro/azureAsyncPolling.ts @@ -7,39 +7,61 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { FinalStateVia, LROResult } from "./models"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroResourceLocationConfig, + LongRunningOperation, + LroBody, + LroResponse, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getResponseStatus(rawResponse: FullOperationResponse): string { - const { status } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getResponseStatus(rawResponse: RawResponse): string { + const { status } = (rawResponse.body as LroBody) ?? {}; return status?.toLowerCase() ?? "succeeded"; } -function isAzureAsyncPollingDone(rawResponse: FullOperationResponse) { +function isAzureAsyncPollingDone(rawResponse: RawResponse): boolean { const state = getResponseStatus(rawResponse); - if (failureStates.includes(state)) { + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { throw new Error(`Operation status: ${state}`); } return successStates.includes(state); } +async function sendFinalRequest( + lro: LongRunningOperation, + lroResourceLocationConfig?: LroResourceLocationConfig, + resourceLocation?: string +): Promise | undefined> { + switch (lroResourceLocationConfig) { + case "original-uri": + return lro.retrieveAzureAsyncResource(); + case "azure-async-operation": + return Promise.resolve(undefined); + case "location": + default: + return lro.retrieveAzureAsyncResource(resourceLocation); + } +} + export function processAzureAsyncOperationResult( - restrieveResource: (path?: string) => Promise>, + lro: LongRunningOperation, resourceLocation?: string, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { + lroResourceLocationConfig?: LroResourceLocationConfig +): (rawResponse: RawResponse, flatResponse: TResult) => LroStatus { return ( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult - ): LROState => { + ): LroStatus => { if (isAzureAsyncPollingDone(rawResponse)) { if (resourceLocation === undefined) { return { rawResponse, flatResponse, done: true }; @@ -49,20 +71,11 @@ export function processAzureAsyncOperationResult( flatResponse, done: false, next: async () => { - async function sendFinalRequest(): Promise< - LROResult | undefined - > { - switch (finalStateVia) { - case "original-uri": - return restrieveResource(); - case "azure-async-operation": - return Promise.resolve(undefined); - case "location": - default: - return restrieveResource(resourceLocation); - } - } - const finalResponse = await sendFinalRequest(); + const finalResponse = await sendFinalRequest( + lro, + lroResourceLocationConfig, + resourceLocation + ); return { ...(finalResponse ?? { rawResponse, diff --git a/test/smoke/generated/keyvault-resource-manager/src/lro/bodyPolling.ts b/test/smoke/generated/keyvault-resource-manager/src/lro/bodyPolling.ts index 269d8e6799..b1c87f8bc8 100644 --- a/test/smoke/generated/keyvault-resource-manager/src/lro/bodyPolling.ts +++ b/test/smoke/generated/keyvault-resource-manager/src/lro/bodyPolling.ts @@ -7,24 +7,33 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroBody, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getProvisioningState(rawResponse: FullOperationResponse): string { - const { properties, provisioningState } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getProvisioningState(rawResponse: RawResponse): string { + const { properties, provisioningState } = (rawResponse.body as LroBody) ?? {}; const state: string | undefined = properties?.provisioningState ?? provisioningState; return state?.toLowerCase() ?? "succeeded"; } -export function isBodyPollingDone(rawResponse: FullOperationResponse) { +export function isBodyPollingDone(rawResponse: RawResponse): boolean { const state = getProvisioningState(rawResponse); - if (failureStates.includes(state)) { - throw new Error(`Provisioning state: ${state}`); + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { + throw new Error( + `The long running operation has failed. The provisioning state: ${state}.` + ); } return successStates.includes(state); } @@ -34,9 +43,9 @@ export function isBodyPollingDone(rawResponse: FullOperationResponse) { * from the result to determine the current operation state */ export function processBodyPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/keyvault-resource-manager/src/lro/index.ts b/test/smoke/generated/keyvault-resource-manager/src/lro/index.ts index 85c2187669..20df608fc8 100644 --- a/test/smoke/generated/keyvault-resource-manager/src/lro/index.ts +++ b/test/smoke/generated/keyvault-resource-manager/src/lro/index.ts @@ -6,5 +6,21 @@ * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ -export { shouldDeserializeLRO } from "./requestUtils"; -export { LROPoller } from "./lroPoller"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { LroEngine } from "./lroEngine"; +export { createGetLroStatusFromResponse } from "./stateMachine"; +export { + LroResourceLocationConfig, + GetLroStatusFromResponse, + RawResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + LroTerminalState, + LroInProgressState, + LroEngineOptions +} from "./models"; diff --git a/test/smoke/generated/keyvault-resource-manager/src/lro/locationPolling.ts b/test/smoke/generated/keyvault-resource-manager/src/lro/locationPolling.ts index 6fef619384..9d1aadfbde 100644 --- a/test/smoke/generated/keyvault-resource-manager/src/lro/locationPolling.ts +++ b/test/smoke/generated/keyvault-resource-manager/src/lro/locationPolling.ts @@ -7,23 +7,21 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function isLocationPollingDone(rawResponse: FullOperationResponse) { - const code = rawResponse.status; - if (![202, 200].includes(code)) { - throw new Error(`Operation failed`); - } - return code !== 202; +function isLocationPollingDone(rawResponse: RawResponse): boolean { + return ( + !isUnexpectedPollingResponse(rawResponse) && rawResponse.statusCode !== 202 + ); } export function processLocationPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/keyvault-resource-manager/src/lro/lroEngine.ts b/test/smoke/generated/keyvault-resource-manager/src/lro/lroEngine.ts new file mode 100644 index 0000000000..85cc15e609 --- /dev/null +++ b/test/smoke/generated/keyvault-resource-manager/src/lro/lroEngine.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Poller, PollOperationState } from "@azure/core-lro"; +import { + LongRunningOperation, + LroEngineOptions, + ResumablePollOperationState +} from "./models"; +import { GenericPollOperation } from "./operation"; + +/** + * The LRO Engine, a class that performs polling. + */ +export class LroEngine< + TResult, + TState extends PollOperationState +> extends Poller { + private intervalInMs: number; + + constructor(lro: LongRunningOperation, options?: LroEngineOptions) { + const { intervalInMs = 2000, resumeFrom } = options || {}; + function deserializeState( + resumeFrom: string + ): TState & ResumablePollOperationState { + try { + return JSON.parse(resumeFrom).state; + } catch (e) { + throw new Error( + `LroEngine: Unable to deserialize state: ${resumeFrom}` + ); + } + } + const state: TState & ResumablePollOperationState = resumeFrom + ? deserializeState(resumeFrom) + : ({} as any); + + const operation = new GenericPollOperation(state, lro); + super(operation); + + this.intervalInMs = intervalInMs; + operation.setPollerConfig(this as any); + } + + /** + * The method used by the poller to wait before attempting to update its operation. + */ + delay(): Promise { + return new Promise((resolve) => + setTimeout(() => resolve(), this.intervalInMs) + ); + } +} diff --git a/test/smoke/generated/keyvault-resource-manager/src/lro/lroPoller.ts b/test/smoke/generated/keyvault-resource-manager/src/lro/lroPoller.ts deleted file mode 100644 index cd1cd64fe8..0000000000 --- a/test/smoke/generated/keyvault-resource-manager/src/lro/lroPoller.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { Poller, PollOperationState } from "@azure/core-lro"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { FinalStateVia, SendOperationFn } from "./models"; -import { GenericPollOperation } from "./operation"; - -export interface LROPollerOptions { - /** - * Defines how much time the poller is going to wait before making a new request to the service. - */ - intervalInMs?: number; - /** - * A serialized poller which can be used to resume an existing paused Long-Running-Operation. - */ - resumeFrom?: string; -} - -export class LROPoller extends Poller< - PollOperationState, - TResult -> { - private intervalInMs: number; - - constructor( - { intervalInMs = 2000, resumeFrom }: LROPollerOptions, - initialOperationArguments: OperationArguments, - initialOperationSpec: OperationSpec, - sendOperation: SendOperationFn, - finalStateVia?: FinalStateVia - ) { - const state: PollOperationState = resumeFrom - ? JSON.parse(resumeFrom).state - : {}; - - const operation = new GenericPollOperation( - state, - initialOperationArguments, - initialOperationSpec, - sendOperation, - finalStateVia - ); - super(operation); - - this.intervalInMs = intervalInMs; - operation.setPollerConfig(this as any); - } - - /** - * The method used by the poller to wait before attempting to update its operation. - */ - delay(): Promise { - return new Promise((resolve) => - setTimeout(() => resolve(), this.intervalInMs) - ); - } -} diff --git a/test/smoke/generated/keyvault-resource-manager/src/lro/models.ts b/test/smoke/generated/keyvault-resource-manager/src/lro/models.ts index a4a5a5abd6..93c3437c8e 100644 --- a/test/smoke/generated/keyvault-resource-manager/src/lro/models.ts +++ b/test/smoke/generated/keyvault-resource-manager/src/lro/models.ts @@ -7,46 +7,167 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec -} from "@azure/core-client"; import { PollOperationState } from "@azure/core-lro"; -export type FinalStateVia = +/** + * Options for the LRO poller. + */ +export interface LroEngineOptions { + /** + * Defines how much time the poller is going to wait before making a new request to the service. + */ + intervalInMs?: number; + /** + * A serialized poller which can be used to resume an existing paused Long-Running-Operation. + */ + resumeFrom?: string; +} + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +/** + * The LRO states that signal that the LRO has completed. + */ +export const terminalStates = successStates.concat(failureStates); + +/** + * The potential location of the result of the LRO if specified by the LRO extension in the swagger. + */ +export type LroResourceLocationConfig = | "azure-async-operation" | "location" | "original-uri"; -export interface LROResult { +/** + * The type of a LRO response body. This is just a convenience type for checking the status of the operation. + */ + +export interface LroBody extends Record { + /** The status of the operation. */ + status?: string; + /** The state of the provisioning process */ + provisioningState?: string; + /** The properties of the provisioning process */ + properties?: { provisioningState?: string } & Record; +} + +/** + * Simple type of the raw response. + */ +export interface RawResponse { + /** The HTTP status code */ + statusCode: number; + /** A HttpHeaders collection in the response represented as a simple JSON object where all header names have been normalized to be lower-case. */ + headers: { + [headerName: string]: string; + }; + /** The parsed response body */ + body?: unknown; +} + +/** + * The type of the response of a LRO. + */ +export interface LroResponse { + /** The flattened response */ flatResponse: T; - rawResponse: FullOperationResponse; + /** The raw response */ + rawResponse: RawResponse; } -export type LROMode = "AzureAsync" | "Location" | "Body"; +/** The type of which LRO implementation being followed by a specific API. */ +export type LroMode = "AzureAsync" | "Location" | "Body"; -export interface LROConfig { - mode?: LROMode; +/** + * The configuration of a LRO to determine how to perform polling and checking whether the operation has completed. + */ +export interface LroConfig { + /** The LRO mode */ + mode?: LroMode; + /** The path of a provisioned resource */ resourceLocation?: string; } -export type SendOperationFn = ( - args: OperationArguments, - spec: OperationSpec -) => Promise>; - /** * Type of a polling operation state that can actually be resumed. */ export type ResumablePollOperationState = PollOperationState & { - initialRawResponse?: FullOperationResponse; - config?: LROConfig; + initialRawResponse?: RawResponse; + config?: LroConfig; pollingURL?: string; }; export interface PollerConfig { intervalInMs: number; } + +/** + * The type of a terminal state of an LRO. + */ +export interface LroTerminalState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: true; +} + +/** + * The type of an in-progress state of an LRO. + */ +export interface LroInProgressState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: false; + /** + * The request to be sent next if it is different from the standard polling one. + * Notice that it will disregard any polling URLs provided to it. + */ + next?: () => Promise>; +} + +/** + * The type of an LRO state which is a tagged union of terminal and in-progress states. + */ +export type LroStatus = LroTerminalState | LroInProgressState; + +/** + * The type of the getLROStatusFromResponse method. It takes the response as input and returns along the response whether the operation has finished. + */ +export type GetLroStatusFromResponse = ( + rawResponse: RawResponse, + flatResponse: T +) => LroStatus; + +/** + * Description of a long running operation. + */ +export interface LongRunningOperation { + /** + * The request path. + */ + requestPath: string; + /** + * The HTTP request method. + */ + requestMethod: string; + /** + * A function that can be used to send initial request to the service. + */ + sendInitialRequest: ( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ) => Promise>; + /** + * A function that can be used to poll for the current status of a long running operation. + */ + sendPollRequest: (config: LroConfig, path: string) => Promise>; + /** + * A function that can be used to retrieve the provisioned azure resource. + */ + retrieveAzureAsyncResource: (path?: string) => Promise>; +} diff --git a/test/smoke/generated/keyvault-resource-manager/src/lro/operation.ts b/test/smoke/generated/keyvault-resource-manager/src/lro/operation.ts index 801d03e720..3ea7b76d89 100644 --- a/test/smoke/generated/keyvault-resource-manager/src/lro/operation.ts +++ b/test/smoke/generated/keyvault-resource-manager/src/lro/operation.ts @@ -7,36 +7,34 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. import { AbortSignalLike } from "@azure/abort-controller"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { PollOperation, PollOperationState } from "@azure/core-lro"; +import { PollOperationState, PollOperation } from "@azure/core-lro"; import { - FinalStateVia, PollerConfig, ResumablePollOperationState, - SendOperationFn + LongRunningOperation, + LroStatus } from "./models"; -import { getPollingURL } from "./requestUtils"; -import { createGetLROState, initializeState, LROState } from "./stateMachine"; +import { getPollingUrl } from "./requestUtils"; +import { createInitializeState, createPollForLROStatus } from "./stateMachine"; -export class GenericPollOperation - implements PollOperation, TResult> { - private getLROState?: ( +export class GenericPollOperation< + TResult, + TState extends PollOperationState +> implements PollOperation { + private getLROStatusFromResponse?: ( pollingURL: string, pollerConfig: PollerConfig - ) => Promise>; + ) => Promise>; private pollerConfig?: PollerConfig; constructor( - public state: PollOperationState, - private initialOperationArguments: OperationArguments, - private initialOperationSpec: OperationSpec, - private sendOperation: SendOperationFn, - private finalStateVia?: FinalStateVia + public state: TState & ResumablePollOperationState, + private lro: LongRunningOperation ) {} - public setPollerConfig(pollerConfig: PollerConfig) { + public setPollerConfig(pollerConfig: PollerConfig): void { this.pollerConfig = pollerConfig; } @@ -57,45 +55,36 @@ export class GenericPollOperation */ async update(options?: { abortSignal?: AbortSignalLike | undefined; - fireProgress?: ((state: PollOperationState) => void) | undefined; - }): Promise, TResult>> { - const state = this.state as ResumablePollOperationState; - const { onResponse, ...restOptions } = - this.initialOperationArguments.options || {}; + fireProgress?: ((state: TState) => void) | undefined; + }): Promise> { + const state = this.state; if (!state.isStarted) { - await this.sendOperation( - { - ...this.initialOperationArguments, - options: { - ...restOptions, - onResponse: initializeState( - state, - this.initialOperationSpec, - onResponse - ) - } - }, - this.initialOperationSpec + const initializeState = createInitializeState( + state, + this.lro.requestPath, + this.lro.requestMethod ); + await this.lro.sendInitialRequest(initializeState); } if (!state.isCompleted) { - if (this.getLROState === undefined) { + if (this.getLROStatusFromResponse === undefined) { if (state.config === undefined) { - throw new Error("Bad state: LRO mode is undefined"); + throw new Error( + "Bad state: LRO mode is undefined. Please check if the serialized state is well-formed." + ); } - this.getLROState = createGetLROState( - this.sendOperation, - this.initialOperationArguments, - this.initialOperationSpec, - state.config, - this.finalStateVia + this.getLROStatusFromResponse = createPollForLROStatus( + this.lro, + state.config ); } if (state.pollingURL === undefined) { - throw new Error("Bad state: polling URL is undefined"); + throw new Error( + "Bad state: polling URL is undefined. Please check if the serialized state is well-formed." + ); } - const currentState = await this.getLROState( + const currentState = await this.getLROStatusFromResponse( state.pollingURL, this.pollerConfig! ); @@ -103,20 +92,19 @@ export class GenericPollOperation state.result = currentState.flatResponse; state.isCompleted = true; } else { - this.getLROState = currentState.next ?? this.getLROState; - state.pollingURL = getPollingURL( + this.getLROStatusFromResponse = + currentState.next ?? this.getLROStatusFromResponse; + state.pollingURL = getPollingUrl( currentState.rawResponse, state.pollingURL ); } } - if (options?.fireProgress !== undefined) { - options.fireProgress(state); - } + options?.fireProgress?.(state); return this; } - async cancel(): Promise, TResult>> { + async cancel(): Promise> { this.state.isCancelled = true; return this; } diff --git a/test/smoke/generated/keyvault-resource-manager/src/lro/passthrough.ts b/test/smoke/generated/keyvault-resource-manager/src/lro/passthrough.ts index 64c10380c1..ae7f87d384 100644 --- a/test/smoke/generated/keyvault-resource-manager/src/lro/passthrough.ts +++ b/test/smoke/generated/keyvault-resource-manager/src/lro/passthrough.ts @@ -7,15 +7,14 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; export function processPassthroughOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/keyvault-resource-manager/src/lro/pollingMethod.ts b/test/smoke/generated/keyvault-resource-manager/src/lro/pollingMethod.ts deleted file mode 100644 index cb6482bbde..0000000000 --- a/test/smoke/generated/keyvault-resource-manager/src/lro/pollingMethod.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - OperationArguments, - OperationSpec, - OperationResponseMap -} from "@azure/core-client"; -import { LROMode, LROResult, SendOperationFn } from "./models"; - -export function createPollingMethod( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - mode?: LROMode -): (path?: string) => Promise> { - /** - * Polling calls will always return a status object i.e. {"status": "success"} - * these intermediate responses are not described in the swagger so we need to - * pass custom mappers at runtime. - * This function replaces all the existing mappers to be able to deserialize a status object - * @param responses Original set of responses defined in the operation - */ - function getCompositeMappers(responses: { - [responseCode: string]: OperationResponseMap; - }): { - [responseCode: string]: OperationResponseMap; - } { - return Object.keys(responses).reduce((acc, statusCode) => { - return { - ...acc, - [statusCode]: { - ...responses[statusCode], - bodyMapper: { - type: { - name: "Composite", - modelProperties: { - status: { - serializedName: "status", - type: { - name: "String" - } - } - } - } - } - } - }; - }, {} as { [responseCode: string]: OperationResponseMap }); - } - // Make sure we don't send any body to the get request - const { requestBody, responses, ...restSpec } = spec; - if (mode === "AzureAsync") { - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: getCompositeMappers(responses), - httpMethod: "GET", - ...(path && { path }) - }); - }; - } - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: responses, - httpMethod: "GET", - ...(path && { path }) - }); - }; -} - -export function createRetrieveAzureAsyncResource( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec -): (path?: string) => Promise> { - const updatedArgs = { ...args }; - if (updatedArgs.options) { - (updatedArgs.options as any).shouldDeserialize = true; - } - return createPollingMethod(sendOperationFn, updatedArgs, spec); -} diff --git a/test/smoke/generated/keyvault-resource-manager/src/lro/requestUtils.ts b/test/smoke/generated/keyvault-resource-manager/src/lro/requestUtils.ts index 9162f66339..40d993686f 100644 --- a/test/smoke/generated/keyvault-resource-manager/src/lro/requestUtils.ts +++ b/test/smoke/generated/keyvault-resource-manager/src/lro/requestUtils.ts @@ -7,119 +7,9 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse, OperationSpec } from "@azure/core-client"; -import { LROConfig } from "./models"; -import { terminalStates } from "./stateMachine"; - -/** - * We need to selectively deserialize our responses, only deserializing if we - * are in a final LRO response, not deserializing any polling non-terminal responses - */ -export function shouldDeserializeLRO(finalStateVia?: string) { - let initialOperationInfo: LROResponseInfo | undefined; - let isInitialRequest = true; - - return (response: FullOperationResponse) => { - if (response.status < 200 || response.status >= 300) { - return true; - } - - if (!initialOperationInfo) { - initialOperationInfo = getLROData(response); - } else { - isInitialRequest = false; - } - - if ( - initialOperationInfo.azureAsyncOperation || - initialOperationInfo.operationLocation - ) { - return ( - !isInitialRequest && - isAsyncOperationFinalResponse( - response, - initialOperationInfo, - finalStateVia - ) - ); - } - - if (initialOperationInfo.location) { - return isLocationFinalResponse(response); - } - - if (initialOperationInfo.requestMethod === "PUT") { - return isBodyPollingFinalResponse(response); - } - - return true; - }; -} - -function isAsyncOperationFinalResponse( - response: FullOperationResponse, - initialOperationInfo: LROResponseInfo, - finalStateVia?: string -): boolean { - const status: string = response.parsedBody?.status || "Succeeded"; - if (!terminalStates.includes(status.toLowerCase())) { - return false; - } - - if (initialOperationInfo.requestMethod === "DELETE") { - return true; - } - - if ( - initialOperationInfo.requestMethod === "PUT" && - finalStateVia && - finalStateVia.toLowerCase() === "azure-asyncoperation" - ) { - return true; - } - - if ( - initialOperationInfo.requestMethod !== "PUT" && - !initialOperationInfo.location - ) { - return true; - } - - return false; -} - -function isLocationFinalResponse(response: FullOperationResponse): boolean { - return response.status !== 202; -} - -function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { - const provisioningState: string = - response.parsedBody?.properties?.provisioningState || "Succeeded"; - - if (terminalStates.includes(provisioningState.toLowerCase())) { - return true; - } - - return false; -} - -interface LROResponseInfo { - requestMethod: string; - azureAsyncOperation?: string; - operationLocation?: string; - location?: string; -} - -function getLROData(result: FullOperationResponse): LROResponseInfo { - return { - azureAsyncOperation: result.headers.get("azure-asyncoperation"), - operationLocation: result.headers.get("operation-location"), - location: result.headers.get("location"), - requestMethod: result.request.method - }; -} +import { LroConfig, RawResponse } from "./models"; /** * Detects where the continuation token is and returns it. Notice that azure-asyncoperation @@ -127,45 +17,41 @@ function getLROData(result: FullOperationResponse): LROResponseInfo { * where both azure-asyncoperation and location could be present in the same response but * azure-asyncoperation should be the one to use for polling. */ -export function getPollingURL( - rawResponse: FullOperationResponse, +export function getPollingUrl( + rawResponse: RawResponse, defaultPath: string ): string { return ( - getAzureAsyncoperation(rawResponse) ?? + getAzureAsyncOperation(rawResponse) ?? getLocation(rawResponse) ?? getOperationLocation(rawResponse) ?? defaultPath ); } -function getLocation(rawResponse: FullOperationResponse): string | undefined { - return rawResponse.headers?.get("location"); +function getLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["location"]; } -function getOperationLocation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("operation-location"); +function getOperationLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["operation-location"]; } -function getAzureAsyncoperation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("azure-asyncoperation"); +function getAzureAsyncOperation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["azure-asyncoperation"]; } -export function inferLROMode( - spec: OperationSpec, - rawResponse: FullOperationResponse -): LROConfig { - const requestMethod = spec.httpMethod; - if (getAzureAsyncoperation(rawResponse) !== undefined) { +export function inferLroMode( + requestPath: string, + requestMethod: string, + rawResponse: RawResponse +): LroConfig { + if (getAzureAsyncOperation(rawResponse) !== undefined) { return { mode: "AzureAsync", resourceLocation: requestMethod === "PUT" - ? spec.path + ? requestPath : requestMethod === "POST" ? getLocation(rawResponse) : undefined @@ -185,10 +71,35 @@ export function inferLROMode( return {}; } -export function getSpecPath(spec: OperationSpec): string { - if (spec.path) { - return spec.path; - } else { - throw Error("Bad spec: request path is not found!"); +export class RestError extends Error { + public statusCode?: number; + constructor(message: string, statusCode: number) { + super(message); + this.name = "RestError"; + this.statusCode = statusCode; + + Object.setPrototypeOf(this, RestError.prototype); + } +} + +export function isUnexpectedInitialResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![203, 204, 202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} in the initial response. This may indicate a server issue.`, + code + ); } + return false; +} + +export function isUnexpectedPollingResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} while polling. This may indicate a server issue.`, + code + ); + } + return false; } diff --git a/test/smoke/generated/keyvault-resource-manager/src/lro/stateMachine.ts b/test/smoke/generated/keyvault-resource-manager/src/lro/stateMachine.ts index b2a69b5546..19a8f67470 100644 --- a/test/smoke/generated/keyvault-resource-manager/src/lro/stateMachine.ts +++ b/test/smoke/generated/keyvault-resource-manager/src/lro/stateMachine.ts @@ -7,14 +7,8 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec, - RawResponseCallback -} from "@azure/core-client"; import { processAzureAsyncOperationResult } from "./azureAsyncPolling"; import { isBodyPollingDone, @@ -22,73 +16,36 @@ import { } from "./bodyPolling"; import { processLocationPollingOperationResult } from "./locationPolling"; import { - FinalStateVia, - LROConfig, - LROResult, + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroStatus, PollerConfig, - ResumablePollOperationState, - SendOperationFn + RawResponse, + ResumablePollOperationState } from "./models"; import { processPassthroughOperationResult } from "./passthrough"; import { - createPollingMethod, - createRetrieveAzureAsyncResource -} from "./pollingMethod"; -import { getPollingURL, getSpecPath, inferLROMode } from "./requestUtils"; - -export const successStates = ["succeeded"]; -export const failureStates = ["failed", "canceled", "cancelled"]; -export const terminalStates = successStates.concat(failureStates); - -/** - * The type of a terminal state of an LRO. - */ -interface LROTerminalState extends LROResult { - /** - * Whether the operation has finished. - */ - done: true; -} - -/** - * The type of an in-progress state of an LRO. - */ -interface LROInProgressState extends LROResult { - /** - * Whether the operation has finished. - */ - done: false; - /** - * The request to be sent next if it is different from the standard polling one. - * Notice that it will disregard any polling URLs provided to it. - */ - next?: () => Promise>; -} - -/** - * The type of an LRO state which is a tagged union of terminal and in-progress states. - */ -export type LROState = LROTerminalState | LROInProgressState; + getPollingUrl, + inferLroMode, + isUnexpectedInitialResponse +} from "./requestUtils"; /** * creates a stepping function that maps an LRO state to another. */ -function createTransition( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { +export function createGetLroStatusFromResponse( + lroPrimitives: LongRunningOperation, + config: LroConfig, + lroResourceLocationConfig?: LroResourceLocationConfig +): GetLroStatusFromResponse { switch (config.mode) { case "AzureAsync": { return processAzureAsyncOperationResult( - createRetrieveAzureAsyncResource(sendOperationFn, args, spec), + lroPrimitives, config.resourceLocation, - finalStateVia + lroResourceLocationConfig ); } case "Location": { @@ -106,52 +63,20 @@ function createTransition( /** * Creates a polling operation that returns a LRO state. */ -export function createGetLROState( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia +export function createPollForLROStatus( + lroPrimitives: LongRunningOperation, + config: LroConfig ): ( pollingURL: string, pollerConfig: PollerConfig -) => Promise> { - const step = createTransition( - sendOperationFn, - args, - spec, - config, - finalStateVia - ); - const customerCallback = args?.options?.onResponse; - let response: LROState | undefined = undefined; - let retryAfter: string | undefined = undefined; - const poll = createPollingMethod( - sendOperationFn, - { - ...args, - options: { - ...args.options, - onResponse: ( - rawResponse: FullOperationResponse, - flatResponse: unknown - ): void => { - response = step(rawResponse, flatResponse as TResult); - retryAfter = rawResponse.headers.get("Retry-After"); - if (response.done) { - customerCallback?.(rawResponse, flatResponse); - } - } - } - }, - spec, - config.mode - ); +) => Promise> { return async ( path: string, pollerConfig: PollerConfig - ): Promise> => { - await poll(path); + ): Promise> => { + const response = await lroPrimitives.sendPollRequest(config, path); + const retryAfter: string | undefined = + response.rawResponse.headers["retry-after"]; if (retryAfter !== undefined) { const retryAfterInMs = parseInt(retryAfter); pollerConfig.intervalInMs = isNaN(retryAfterInMs) @@ -161,7 +86,7 @@ export function createGetLROState( ) : retryAfterInMs; } - return response!; + return response; }; } @@ -179,24 +104,26 @@ function calculatePollingIntervalFromDate( /** * Creates a callback to be used to initialize the polling operation state. - * @param state of the polling operation - * @param operationSpec of the LRO - * @param callback callback to be called when the operation is done + * @param state - of the polling operation + * @param operationSpec - of the LRO + * @param callback - callback to be called when the operation is done * @returns callback that initializes the state of the polling operation */ -export function initializeState( +export function createInitializeState( state: ResumablePollOperationState, - operationSpec: OperationSpec, - callback?: RawResponseCallback -): (rawResponse: FullOperationResponse, flatResponse: unknown) => void { - return (rawResponse: FullOperationResponse, flatResponse: unknown) => { + requestPath: string, + requestMethod: string +): (rawResponse: RawResponse, flatResponse: unknown) => boolean { + return (rawResponse: RawResponse, flatResponse: unknown) => { + if (isUnexpectedInitialResponse(rawResponse)) return true; state.initialRawResponse = rawResponse; state.isStarted = true; - state.pollingURL = getPollingURL( - state.initialRawResponse, - getSpecPath(operationSpec) + state.pollingURL = getPollingUrl(state.initialRawResponse, requestPath); + state.config = inferLroMode( + requestPath, + requestMethod, + state.initialRawResponse ); - state.config = inferLROMode(operationSpec, state.initialRawResponse); /** short circuit polling if body polling is done in the initial request */ if ( state.config.mode === undefined || @@ -205,12 +132,7 @@ export function initializeState( ) { state.result = flatResponse as TResult; state.isCompleted = true; - /** - * We need to check if the LRO operation is finished inside the - * call back so that we can call the customer-provided callback - * on that result. - */ - callback?.(rawResponse, flatResponse); } + return Boolean(state.isCompleted); }; } diff --git a/test/smoke/generated/keyvault-resource-manager/src/operations/privateEndpointConnections.ts b/test/smoke/generated/keyvault-resource-manager/src/operations/privateEndpointConnections.ts index 4e2469ba93..74969f065f 100644 --- a/test/smoke/generated/keyvault-resource-manager/src/operations/privateEndpointConnections.ts +++ b/test/smoke/generated/keyvault-resource-manager/src/operations/privateEndpointConnections.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { KeyVaultManagementClientContext } from "../keyVaultManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { PrivateEndpointConnectionsGetOptionalParams, PrivateEndpointConnectionsGetResponse, @@ -132,15 +133,22 @@ export class PrivateEndpointConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vaultName, privateEndpointConnectionName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/keyvault-resource-manager/src/operations/vaults.ts b/test/smoke/generated/keyvault-resource-manager/src/operations/vaults.ts index 5e21dd87ab..4485f62778 100644 --- a/test/smoke/generated/keyvault-resource-manager/src/operations/vaults.ts +++ b/test/smoke/generated/keyvault-resource-manager/src/operations/vaults.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { KeyVaultManagementClientContext } from "../keyVaultManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { Vault, VaultsListByResourceGroupNextOptionalParams, @@ -296,15 +297,22 @@ export class VaultsImpl implements Vaults { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vaultName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -502,15 +510,22 @@ export class VaultsImpl implements Vaults { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { vaultName, location, options }, - purgeDeletedOperationSpec, - sendOperation + purgeDeletedOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/msi-resource-manager/review/msi-resource-manager.api.md b/test/smoke/generated/msi-resource-manager/review/msi-resource-manager.api.md index ef61a1bcbc..3ac4d46409 100644 --- a/test/smoke/generated/msi-resource-manager/review/msi-resource-manager.api.md +++ b/test/smoke/generated/msi-resource-manager/review/msi-resource-manager.api.md @@ -1,224 +1,224 @@ -## API Report File for "msi-resource-manager" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as coreAuth from '@azure/core-auth'; -import * as coreClient from '@azure/core-client'; -import { PagedAsyncIterableIterator } from '@azure/core-paging'; - -// @public -export interface CloudError { - error?: CloudErrorBody; -} - -// @public -export interface CloudErrorBody { - code?: string; - details?: CloudErrorBody[]; - message?: string; - target?: string; -} - -// @public -export type Identity = TrackedResource & { - readonly tenantId?: string; - readonly principalId?: string; - readonly clientId?: string; -}; - -// @public -export type IdentityUpdate = Resource & { - location?: string; - tags?: { - [propertyName: string]: string; - }; - readonly tenantId?: string; - readonly principalId?: string; - readonly clientId?: string; -}; - -// @public (undocumented) -export class ManagedServiceIdentityClient extends ManagedServiceIdentityClientContext { - constructor(credentials: coreAuth.TokenCredential, subscriptionId: string, options?: ManagedServiceIdentityClientOptionalParams); - // (undocumented) - operations: Operations; - // (undocumented) - systemAssignedIdentities: SystemAssignedIdentities; - // (undocumented) - userAssignedIdentities: UserAssignedIdentities; -} - -// @public (undocumented) -export class ManagedServiceIdentityClientContext extends coreClient.ServiceClient { - // (undocumented) - $host: string; - constructor(credentials: coreAuth.TokenCredential, subscriptionId: string, options?: ManagedServiceIdentityClientOptionalParams); - // (undocumented) - apiVersion: string; - // (undocumented) - subscriptionId: string; -} - -// @public -export interface ManagedServiceIdentityClientOptionalParams extends coreClient.ServiceClientOptions { - $host?: string; - apiVersion?: string; - endpoint?: string; -} - -// @public -export interface Operation { - display?: OperationDisplay; - name?: string; -} - -// @public -export interface OperationDisplay { - description?: string; - operation?: string; - provider?: string; - resource?: string; -} - -// @public -export interface OperationListResult { - nextLink?: string; - value?: Operation[]; -} - -// @public -export interface Operations { - list(options?: OperationsListOptionalParams): PagedAsyncIterableIterator; -} - -// @public -export interface OperationsListNextOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type OperationsListNextResponse = OperationListResult; - -// @public -export interface OperationsListOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type OperationsListResponse = OperationListResult; - -// @public -export type ProxyResource = Resource & {}; - -// @public (undocumented) -export interface Resource { - readonly id?: string; - readonly name?: string; - readonly type?: string; -} - -// @public -export interface SystemAssignedIdentities { - getByScope(scope: string, options?: SystemAssignedIdentitiesGetByScopeOptionalParams): Promise; -} - -// @public -export interface SystemAssignedIdentitiesGetByScopeOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type SystemAssignedIdentitiesGetByScopeResponse = SystemAssignedIdentity; - -// @public -export type SystemAssignedIdentity = ProxyResource & { - location: string; - tags?: { - [propertyName: string]: string; - }; - readonly tenantId?: string; - readonly principalId?: string; - readonly clientId?: string; - readonly clientSecretUrl?: string; -}; - -// @public -export type TrackedResource = Resource & { - tags?: { - [propertyName: string]: string; - }; - location: string; -}; - -// @public -export interface UserAssignedIdentities { - createOrUpdate(resourceGroupName: string, resourceName: string, parameters: Identity, options?: UserAssignedIdentitiesCreateOrUpdateOptionalParams): Promise; - delete(resourceGroupName: string, resourceName: string, options?: UserAssignedIdentitiesDeleteOptionalParams): Promise; - get(resourceGroupName: string, resourceName: string, options?: UserAssignedIdentitiesGetOptionalParams): Promise; - listByResourceGroup(resourceGroupName: string, options?: UserAssignedIdentitiesListByResourceGroupOptionalParams): PagedAsyncIterableIterator; - listBySubscription(options?: UserAssignedIdentitiesListBySubscriptionOptionalParams): PagedAsyncIterableIterator; - update(resourceGroupName: string, resourceName: string, parameters: IdentityUpdate, options?: UserAssignedIdentitiesUpdateOptionalParams): Promise; -} - -// @public -export interface UserAssignedIdentitiesCreateOrUpdateOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type UserAssignedIdentitiesCreateOrUpdateResponse = Identity; - -// @public -export interface UserAssignedIdentitiesDeleteOptionalParams extends coreClient.OperationOptions { -} - -// @public -export interface UserAssignedIdentitiesGetOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type UserAssignedIdentitiesGetResponse = Identity; - -// @public -export interface UserAssignedIdentitiesListByResourceGroupNextOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type UserAssignedIdentitiesListByResourceGroupNextResponse = UserAssignedIdentitiesListResult; - -// @public -export interface UserAssignedIdentitiesListByResourceGroupOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type UserAssignedIdentitiesListByResourceGroupResponse = UserAssignedIdentitiesListResult; - -// @public -export interface UserAssignedIdentitiesListBySubscriptionNextOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type UserAssignedIdentitiesListBySubscriptionNextResponse = UserAssignedIdentitiesListResult; - -// @public -export interface UserAssignedIdentitiesListBySubscriptionOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type UserAssignedIdentitiesListBySubscriptionResponse = UserAssignedIdentitiesListResult; - -// @public -export interface UserAssignedIdentitiesListResult { - nextLink?: string; - value?: Identity[]; -} - -// @public -export interface UserAssignedIdentitiesUpdateOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type UserAssignedIdentitiesUpdateResponse = Identity; - - -// (No @packageDocumentation comment for this package) - -``` +## API Report File for "msi-resource-manager" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import * as coreAuth from '@azure/core-auth'; +import * as coreClient from '@azure/core-client'; +import { PagedAsyncIterableIterator } from '@azure/core-paging'; + +// @public +export interface CloudError { + error?: CloudErrorBody; +} + +// @public +export interface CloudErrorBody { + code?: string; + details?: CloudErrorBody[]; + message?: string; + target?: string; +} + +// @public +export type Identity = TrackedResource & { + readonly tenantId?: string; + readonly principalId?: string; + readonly clientId?: string; +}; + +// @public +export type IdentityUpdate = Resource & { + location?: string; + tags?: { + [propertyName: string]: string; + }; + readonly tenantId?: string; + readonly principalId?: string; + readonly clientId?: string; +}; + +// @public (undocumented) +export class ManagedServiceIdentityClient extends ManagedServiceIdentityClientContext { + constructor(credentials: coreAuth.TokenCredential, subscriptionId: string, options?: ManagedServiceIdentityClientOptionalParams); + // (undocumented) + operations: Operations; + // (undocumented) + systemAssignedIdentities: SystemAssignedIdentities; + // (undocumented) + userAssignedIdentities: UserAssignedIdentities; +} + +// @public (undocumented) +export class ManagedServiceIdentityClientContext extends coreClient.ServiceClient { + // (undocumented) + $host: string; + constructor(credentials: coreAuth.TokenCredential, subscriptionId: string, options?: ManagedServiceIdentityClientOptionalParams); + // (undocumented) + apiVersion: string; + // (undocumented) + subscriptionId: string; +} + +// @public +export interface ManagedServiceIdentityClientOptionalParams extends coreClient.ServiceClientOptions { + $host?: string; + apiVersion?: string; + endpoint?: string; +} + +// @public +export interface Operation { + display?: OperationDisplay; + name?: string; +} + +// @public +export interface OperationDisplay { + description?: string; + operation?: string; + provider?: string; + resource?: string; +} + +// @public +export interface OperationListResult { + nextLink?: string; + value?: Operation[]; +} + +// @public +export interface Operations { + list(options?: OperationsListOptionalParams): PagedAsyncIterableIterator; +} + +// @public +export interface OperationsListNextOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type OperationsListNextResponse = OperationListResult; + +// @public +export interface OperationsListOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type OperationsListResponse = OperationListResult; + +// @public +export type ProxyResource = Resource & {}; + +// @public (undocumented) +export interface Resource { + readonly id?: string; + readonly name?: string; + readonly type?: string; +} + +// @public +export interface SystemAssignedIdentities { + getByScope(scope: string, options?: SystemAssignedIdentitiesGetByScopeOptionalParams): Promise; +} + +// @public +export interface SystemAssignedIdentitiesGetByScopeOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type SystemAssignedIdentitiesGetByScopeResponse = SystemAssignedIdentity; + +// @public +export type SystemAssignedIdentity = ProxyResource & { + location: string; + tags?: { + [propertyName: string]: string; + }; + readonly tenantId?: string; + readonly principalId?: string; + readonly clientId?: string; + readonly clientSecretUrl?: string; +}; + +// @public +export type TrackedResource = Resource & { + tags?: { + [propertyName: string]: string; + }; + location: string; +}; + +// @public +export interface UserAssignedIdentities { + createOrUpdate(resourceGroupName: string, resourceName: string, parameters: Identity, options?: UserAssignedIdentitiesCreateOrUpdateOptionalParams): Promise; + delete(resourceGroupName: string, resourceName: string, options?: UserAssignedIdentitiesDeleteOptionalParams): Promise; + get(resourceGroupName: string, resourceName: string, options?: UserAssignedIdentitiesGetOptionalParams): Promise; + listByResourceGroup(resourceGroupName: string, options?: UserAssignedIdentitiesListByResourceGroupOptionalParams): PagedAsyncIterableIterator; + listBySubscription(options?: UserAssignedIdentitiesListBySubscriptionOptionalParams): PagedAsyncIterableIterator; + update(resourceGroupName: string, resourceName: string, parameters: IdentityUpdate, options?: UserAssignedIdentitiesUpdateOptionalParams): Promise; +} + +// @public +export interface UserAssignedIdentitiesCreateOrUpdateOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type UserAssignedIdentitiesCreateOrUpdateResponse = Identity; + +// @public +export interface UserAssignedIdentitiesDeleteOptionalParams extends coreClient.OperationOptions { +} + +// @public +export interface UserAssignedIdentitiesGetOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type UserAssignedIdentitiesGetResponse = Identity; + +// @public +export interface UserAssignedIdentitiesListByResourceGroupNextOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type UserAssignedIdentitiesListByResourceGroupNextResponse = UserAssignedIdentitiesListResult; + +// @public +export interface UserAssignedIdentitiesListByResourceGroupOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type UserAssignedIdentitiesListByResourceGroupResponse = UserAssignedIdentitiesListResult; + +// @public +export interface UserAssignedIdentitiesListBySubscriptionNextOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type UserAssignedIdentitiesListBySubscriptionNextResponse = UserAssignedIdentitiesListResult; + +// @public +export interface UserAssignedIdentitiesListBySubscriptionOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type UserAssignedIdentitiesListBySubscriptionResponse = UserAssignedIdentitiesListResult; + +// @public +export interface UserAssignedIdentitiesListResult { + nextLink?: string; + value?: Identity[]; +} + +// @public +export interface UserAssignedIdentitiesUpdateOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type UserAssignedIdentitiesUpdateResponse = Identity; + + +// (No @packageDocumentation comment for this package) + +``` diff --git a/test/smoke/generated/msi-resource-manager/temp/msi-resource-manager.api.json b/test/smoke/generated/msi-resource-manager/temp/msi-resource-manager.api.json index 3823e38e70..5cb0616286 100644 --- a/test/smoke/generated/msi-resource-manager/temp/msi-resource-manager.api.json +++ b/test/smoke/generated/msi-resource-manager/temp/msi-resource-manager.api.json @@ -1,2520 +1,2520 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "7.9.10", - "schemaVersion": 1003, - "oldestForwardsCompatibleVersion": 1001 - }, - "kind": "Package", - "canonicalReference": "msi-resource-manager!", - "docComment": "", - "name": "msi-resource-manager", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "msi-resource-manager!", - "name": "", - "members": [ - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!CloudError:interface", - "docComment": "/**\n * An error response from the ManagedServiceIdentity service.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface CloudError " - } - ], - "releaseTag": "Public", - "name": "CloudError", - "members": [ - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!CloudError#error:member", - "docComment": "/**\n * A list of additional details about the error.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "error?: " - }, - { - "kind": "Reference", - "text": "CloudErrorBody", - "canonicalReference": "msi-resource-manager!CloudErrorBody:interface" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "error", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "extendsTokenRanges": [] - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!CloudErrorBody:interface", - "docComment": "/**\n * An error response from the ManagedServiceIdentity service.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface CloudErrorBody " - } - ], - "releaseTag": "Public", - "name": "CloudErrorBody", - "members": [ - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!CloudErrorBody#code:member", - "docComment": "/**\n * An identifier for the error.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "code?: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "code", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!CloudErrorBody#details:member", - "docComment": "/**\n * A list of additional details about the error.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "details?: " - }, - { - "kind": "Reference", - "text": "CloudErrorBody", - "canonicalReference": "msi-resource-manager!CloudErrorBody:interface" - }, - { - "kind": "Content", - "text": "[]" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "details", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 3 - } - }, - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!CloudErrorBody#message:member", - "docComment": "/**\n * A message describing the error, intended to be suitable for display in a user interface.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "message?: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "message", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!CloudErrorBody#target:member", - "docComment": "/**\n * The target of the particular error. For example, the name of the property in error.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "target?: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "target", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "extendsTokenRanges": [] - }, - { - "kind": "TypeAlias", - "canonicalReference": "msi-resource-manager!Identity:type", - "docComment": "/**\n * Describes an identity resource.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare type Identity = " - }, - { - "kind": "Reference", - "text": "TrackedResource", - "canonicalReference": "msi-resource-manager!TrackedResource:type" - }, - { - "kind": "Content", - "text": " & {\n readonly tenantId?: string;\n readonly principalId?: string;\n readonly clientId?: string;\n}" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "Identity", - "typeTokenRange": { - "startIndex": 1, - "endIndex": 3 - } - }, - { - "kind": "TypeAlias", - "canonicalReference": "msi-resource-manager!IdentityUpdate:type", - "docComment": "/**\n * Describes an identity resource.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare type IdentityUpdate = " - }, - { - "kind": "Reference", - "text": "Resource", - "canonicalReference": "msi-resource-manager!Resource:interface" - }, - { - "kind": "Content", - "text": " & {\n location?: string;\n tags?: {\n [propertyName: string]: string;\n };\n readonly tenantId?: string;\n readonly principalId?: string;\n readonly clientId?: string;\n}" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "IdentityUpdate", - "typeTokenRange": { - "startIndex": 1, - "endIndex": 3 - } - }, - { - "kind": "Class", - "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClient:class", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class ManagedServiceIdentityClient extends " - }, - { - "kind": "Reference", - "text": "ManagedServiceIdentityClientContext", - "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientContext:class" - }, - { - "kind": "Content", - "text": " " - } - ], - "releaseTag": "Public", - "name": "ManagedServiceIdentityClient", - "members": [ - { - "kind": "Constructor", - "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClient:constructor(1)", - "docComment": "/**\n * Initializes a new instance of the ManagedServiceIdentityClient class.\n *\n * @param credentials - Subscription credentials which uniquely identify client subscription.\n *\n * @param subscriptionId - The Id of the Subscription to which the identity belongs.\n *\n * @param options - The parameter options\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "constructor(credentials: " - }, - { - "kind": "Content", - "text": "coreAuth." - }, - { - "kind": "Reference", - "text": "TokenCredential", - "canonicalReference": "@azure/core-auth!TokenCredential:interface" - }, - { - "kind": "Content", - "text": ", subscriptionId: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ", options?: " - }, - { - "kind": "Reference", - "text": "ManagedServiceIdentityClientOptionalParams", - "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientOptionalParams:interface" - }, - { - "kind": "Content", - "text": ");" - } - ], - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "credentials", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 3 - } - }, - { - "parameterName": "subscriptionId", - "parameterTypeTokenRange": { - "startIndex": 4, - "endIndex": 5 - } - }, - { - "parameterName": "options", - "parameterTypeTokenRange": { - "startIndex": 6, - "endIndex": 7 - } - } - ] - }, - { - "kind": "Property", - "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClient#operations:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "operations: " - }, - { - "kind": "Reference", - "text": "Operations", - "canonicalReference": "msi-resource-manager!Operations:interface" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "operations", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "isStatic": false - }, - { - "kind": "Property", - "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClient#systemAssignedIdentities:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "systemAssignedIdentities: " - }, - { - "kind": "Reference", - "text": "SystemAssignedIdentities", - "canonicalReference": "msi-resource-manager!SystemAssignedIdentities:interface" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "systemAssignedIdentities", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "isStatic": false - }, - { - "kind": "Property", - "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClient#userAssignedIdentities:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "userAssignedIdentities: " - }, - { - "kind": "Reference", - "text": "UserAssignedIdentities", - "canonicalReference": "msi-resource-manager!UserAssignedIdentities:interface" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "userAssignedIdentities", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "isStatic": false - } - ], - "extendsTokenRange": { - "startIndex": 1, - "endIndex": 3 - }, - "implementsTokenRanges": [] - }, - { - "kind": "Class", - "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientContext:class", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare class ManagedServiceIdentityClientContext extends " - }, - { - "kind": "Content", - "text": "coreClient." - }, - { - "kind": "Reference", - "text": "ServiceClient", - "canonicalReference": "@azure/core-client!ServiceClient:class" - }, - { - "kind": "Content", - "text": " " - } - ], - "releaseTag": "Public", - "name": "ManagedServiceIdentityClientContext", - "members": [ - { - "kind": "Constructor", - "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientContext:constructor(1)", - "docComment": "/**\n * Initializes a new instance of the ManagedServiceIdentityClientContext class.\n *\n * @param credentials - Subscription credentials which uniquely identify client subscription.\n *\n * @param subscriptionId - The Id of the Subscription to which the identity belongs.\n *\n * @param options - The parameter options\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "constructor(credentials: " - }, - { - "kind": "Content", - "text": "coreAuth." - }, - { - "kind": "Reference", - "text": "TokenCredential", - "canonicalReference": "@azure/core-auth!TokenCredential:interface" - }, - { - "kind": "Content", - "text": ", subscriptionId: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ", options?: " - }, - { - "kind": "Reference", - "text": "ManagedServiceIdentityClientOptionalParams", - "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientOptionalParams:interface" - }, - { - "kind": "Content", - "text": ");" - } - ], - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "credentials", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 3 - } - }, - { - "parameterName": "subscriptionId", - "parameterTypeTokenRange": { - "startIndex": 4, - "endIndex": 5 - } - }, - { - "parameterName": "options", - "parameterTypeTokenRange": { - "startIndex": 6, - "endIndex": 7 - } - } - ] - }, - { - "kind": "Property", - "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientContext#$host:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "$host: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "$host", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "isStatic": false - }, - { - "kind": "Property", - "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientContext#apiVersion:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "apiVersion: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "apiVersion", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "isStatic": false - }, - { - "kind": "Property", - "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientContext#subscriptionId:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "subscriptionId: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "subscriptionId", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "isStatic": false - } - ], - "extendsTokenRange": { - "startIndex": 1, - "endIndex": 4 - }, - "implementsTokenRanges": [] - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientOptionalParams:interface", - "docComment": "/**\n * Optional parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface ManagedServiceIdentityClientOptionalParams extends " - }, - { - "kind": "Content", - "text": "coreClient." - }, - { - "kind": "Reference", - "text": "ServiceClientOptions", - "canonicalReference": "@azure/core-client!ServiceClientOptions:interface" - }, - { - "kind": "Content", - "text": " " - } - ], - "releaseTag": "Public", - "name": "ManagedServiceIdentityClientOptionalParams", - "members": [ - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientOptionalParams#$host:member", - "docComment": "/**\n * server parameter\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "$host?: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "$host", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientOptionalParams#apiVersion:member", - "docComment": "/**\n * Api Version\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "apiVersion?: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "apiVersion", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientOptionalParams#endpoint:member", - "docComment": "/**\n * Overrides client endpoint.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "endpoint?: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "endpoint", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "extendsTokenRanges": [ - { - "startIndex": 1, - "endIndex": 4 - } - ] - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!Operation:interface", - "docComment": "/**\n * Operation supported by the Microsoft.ManagedIdentity REST API.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface Operation " - } - ], - "releaseTag": "Public", - "name": "Operation", - "members": [ - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!Operation#display:member", - "docComment": "/**\n * The object that describes the operation.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "display?: " - }, - { - "kind": "Reference", - "text": "OperationDisplay", - "canonicalReference": "msi-resource-manager!OperationDisplay:interface" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "display", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!Operation#name:member", - "docComment": "/**\n * The name of the REST Operation. This is of the format {provider}/{resource}/{operation}.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "name?: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "name", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "extendsTokenRanges": [] - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!OperationDisplay:interface", - "docComment": "/**\n * The object that describes the operation.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface OperationDisplay " - } - ], - "releaseTag": "Public", - "name": "OperationDisplay", - "members": [ - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!OperationDisplay#description:member", - "docComment": "/**\n * A description of the operation.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "description?: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "description", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!OperationDisplay#operation:member", - "docComment": "/**\n * The type of operation. For example: read, write, delete.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "operation?: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "operation", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!OperationDisplay#provider:member", - "docComment": "/**\n * Friendly name of the resource provider.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "provider?: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "provider", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!OperationDisplay#resource:member", - "docComment": "/**\n * The resource type on which the operation is performed.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "resource?: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "resource", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "extendsTokenRanges": [] - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!OperationListResult:interface", - "docComment": "/**\n * A list of operations supported by Microsoft.ManagedIdentity Resource Provider.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface OperationListResult " - } - ], - "releaseTag": "Public", - "name": "OperationListResult", - "members": [ - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!OperationListResult#nextLink:member", - "docComment": "/**\n * The url to get the next page of results, if any.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "nextLink?: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "nextLink", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!OperationListResult#value:member", - "docComment": "/**\n * A list of operations supported by Microsoft.ManagedIdentity Resource Provider.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "value?: " - }, - { - "kind": "Reference", - "text": "Operation", - "canonicalReference": "msi-resource-manager!Operation:interface" - }, - { - "kind": "Content", - "text": "[]" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "value", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 3 - } - } - ], - "extendsTokenRanges": [] - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!Operations:interface", - "docComment": "/**\n * Interface representing a Operations.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface Operations " - } - ], - "releaseTag": "Public", - "name": "Operations", - "members": [ - { - "kind": "MethodSignature", - "canonicalReference": "msi-resource-manager!Operations#list:member(1)", - "docComment": "/**\n * Lists available operations for the Microsoft.ManagedIdentity provider\n *\n * @param options - The options parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "list(options?: " - }, - { - "kind": "Reference", - "text": "OperationsListOptionalParams", - "canonicalReference": "msi-resource-manager!OperationsListOptionalParams:interface" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Reference", - "text": "PagedAsyncIterableIterator", - "canonicalReference": "@azure/core-paging!PagedAsyncIterableIterator:interface" - }, - { - "kind": "Content", - "text": "<" - }, - { - "kind": "Reference", - "text": "Operation", - "canonicalReference": "msi-resource-manager!Operation:interface" - }, - { - "kind": "Content", - "text": ">" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 3, - "endIndex": 7 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "options", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "name": "list" - } - ], - "extendsTokenRanges": [] - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!OperationsListNextOptionalParams:interface", - "docComment": "/**\n * Optional parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface OperationsListNextOptionalParams extends " - }, - { - "kind": "Content", - "text": "coreClient." - }, - { - "kind": "Reference", - "text": "OperationOptions", - "canonicalReference": "@azure/core-client!OperationOptions:interface" - }, - { - "kind": "Content", - "text": " " - } - ], - "releaseTag": "Public", - "name": "OperationsListNextOptionalParams", - "members": [], - "extendsTokenRanges": [ - { - "startIndex": 1, - "endIndex": 4 - } - ] - }, - { - "kind": "TypeAlias", - "canonicalReference": "msi-resource-manager!OperationsListNextResponse:type", - "docComment": "/**\n * Contains response data for the listNext operation.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare type OperationsListNextResponse = " - }, - { - "kind": "Reference", - "text": "OperationListResult", - "canonicalReference": "msi-resource-manager!OperationListResult:interface" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "OperationsListNextResponse", - "typeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!OperationsListOptionalParams:interface", - "docComment": "/**\n * Optional parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface OperationsListOptionalParams extends " - }, - { - "kind": "Content", - "text": "coreClient." - }, - { - "kind": "Reference", - "text": "OperationOptions", - "canonicalReference": "@azure/core-client!OperationOptions:interface" - }, - { - "kind": "Content", - "text": " " - } - ], - "releaseTag": "Public", - "name": "OperationsListOptionalParams", - "members": [], - "extendsTokenRanges": [ - { - "startIndex": 1, - "endIndex": 4 - } - ] - }, - { - "kind": "TypeAlias", - "canonicalReference": "msi-resource-manager!OperationsListResponse:type", - "docComment": "/**\n * Contains response data for the list operation.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare type OperationsListResponse = " - }, - { - "kind": "Reference", - "text": "OperationListResult", - "canonicalReference": "msi-resource-manager!OperationListResult:interface" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "OperationsListResponse", - "typeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "TypeAlias", - "canonicalReference": "msi-resource-manager!ProxyResource:type", - "docComment": "/**\n * The resource model definition for a ARM proxy resource. It will have everything other than required location and tags\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare type ProxyResource = " - }, - { - "kind": "Reference", - "text": "Resource", - "canonicalReference": "msi-resource-manager!Resource:interface" - }, - { - "kind": "Content", - "text": " & {}" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "ProxyResource", - "typeTokenRange": { - "startIndex": 1, - "endIndex": 3 - } - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!Resource:interface", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface Resource " - } - ], - "releaseTag": "Public", - "name": "Resource", - "members": [ - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!Resource#id:member", - "docComment": "/**\n * Fully qualified resource Id for the resource. Ex - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} NOTE: This property will not be serialized. It can only be populated by the server.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "readonly id?: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "id", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!Resource#name:member", - "docComment": "/**\n * The name of the resource NOTE: This property will not be serialized. It can only be populated by the server.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "readonly name?: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "name", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!Resource#type:member", - "docComment": "/**\n * The type of the resource. Ex- Microsoft.Compute/virtualMachines or Microsoft.Storage/storageAccounts. NOTE: This property will not be serialized. It can only be populated by the server.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "readonly type?: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "type", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "extendsTokenRanges": [] - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!SystemAssignedIdentities:interface", - "docComment": "/**\n * Interface representing a SystemAssignedIdentities.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface SystemAssignedIdentities " - } - ], - "releaseTag": "Public", - "name": "SystemAssignedIdentities", - "members": [ - { - "kind": "MethodSignature", - "canonicalReference": "msi-resource-manager!SystemAssignedIdentities#getByScope:member(1)", - "docComment": "/**\n * Gets the systemAssignedIdentity available under the specified RP scope.\n *\n * @param scope - The resource provider scope of the resource. Parent resource being extended by Managed Identities.\n *\n * @param options - The options parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "getByScope(scope: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ", options?: " - }, - { - "kind": "Reference", - "text": "SystemAssignedIdentitiesGetByScopeOptionalParams", - "canonicalReference": "msi-resource-manager!SystemAssignedIdentitiesGetByScopeOptionalParams:interface" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Reference", - "text": "Promise", - "canonicalReference": "!Promise:interface" - }, - { - "kind": "Content", - "text": "<" - }, - { - "kind": "Reference", - "text": "SystemAssignedIdentitiesGetByScopeResponse", - "canonicalReference": "msi-resource-manager!SystemAssignedIdentitiesGetByScopeResponse:type" - }, - { - "kind": "Content", - "text": ">" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 5, - "endIndex": 9 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "scope", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "parameterName": "options", - "parameterTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - } - } - ], - "name": "getByScope" - } - ], - "extendsTokenRanges": [] - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!SystemAssignedIdentitiesGetByScopeOptionalParams:interface", - "docComment": "/**\n * Optional parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface SystemAssignedIdentitiesGetByScopeOptionalParams extends " - }, - { - "kind": "Content", - "text": "coreClient." - }, - { - "kind": "Reference", - "text": "OperationOptions", - "canonicalReference": "@azure/core-client!OperationOptions:interface" - }, - { - "kind": "Content", - "text": " " - } - ], - "releaseTag": "Public", - "name": "SystemAssignedIdentitiesGetByScopeOptionalParams", - "members": [], - "extendsTokenRanges": [ - { - "startIndex": 1, - "endIndex": 4 - } - ] - }, - { - "kind": "TypeAlias", - "canonicalReference": "msi-resource-manager!SystemAssignedIdentitiesGetByScopeResponse:type", - "docComment": "/**\n * Contains response data for the getByScope operation.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare type SystemAssignedIdentitiesGetByScopeResponse = " - }, - { - "kind": "Reference", - "text": "SystemAssignedIdentity", - "canonicalReference": "msi-resource-manager!SystemAssignedIdentity:type" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "SystemAssignedIdentitiesGetByScopeResponse", - "typeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "TypeAlias", - "canonicalReference": "msi-resource-manager!SystemAssignedIdentity:type", - "docComment": "/**\n * Describes a system assigned identity resource.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare type SystemAssignedIdentity = " - }, - { - "kind": "Reference", - "text": "ProxyResource", - "canonicalReference": "msi-resource-manager!ProxyResource:type" - }, - { - "kind": "Content", - "text": " & {\n location: string;\n tags?: {\n [propertyName: string]: string;\n };\n readonly tenantId?: string;\n readonly principalId?: string;\n readonly clientId?: string;\n readonly clientSecretUrl?: string;\n}" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "SystemAssignedIdentity", - "typeTokenRange": { - "startIndex": 1, - "endIndex": 3 - } - }, - { - "kind": "TypeAlias", - "canonicalReference": "msi-resource-manager!TrackedResource:type", - "docComment": "/**\n * The resource model definition for a ARM tracked top level resource\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare type TrackedResource = " - }, - { - "kind": "Reference", - "text": "Resource", - "canonicalReference": "msi-resource-manager!Resource:interface" - }, - { - "kind": "Content", - "text": " & {\n tags?: {\n [propertyName: string]: string;\n };\n location: string;\n}" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "TrackedResource", - "typeTokenRange": { - "startIndex": 1, - "endIndex": 3 - } - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!UserAssignedIdentities:interface", - "docComment": "/**\n * Interface representing a UserAssignedIdentities.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface UserAssignedIdentities " - } - ], - "releaseTag": "Public", - "name": "UserAssignedIdentities", - "members": [ - { - "kind": "MethodSignature", - "canonicalReference": "msi-resource-manager!UserAssignedIdentities#createOrUpdate:member(1)", - "docComment": "/**\n * Create or update an identity in the specified subscription and resource group.\n *\n * @param resourceGroupName - The name of the Resource Group to which the identity belongs.\n *\n * @param resourceName - The name of the identity resource.\n *\n * @param parameters - Parameters to create or update the identity\n *\n * @param options - The options parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "createOrUpdate(resourceGroupName: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ", resourceName: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ", parameters: " - }, - { - "kind": "Reference", - "text": "Identity", - "canonicalReference": "msi-resource-manager!Identity:type" - }, - { - "kind": "Content", - "text": ", options?: " - }, - { - "kind": "Reference", - "text": "UserAssignedIdentitiesCreateOrUpdateOptionalParams", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesCreateOrUpdateOptionalParams:interface" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Reference", - "text": "Promise", - "canonicalReference": "!Promise:interface" - }, - { - "kind": "Content", - "text": "<" - }, - { - "kind": "Reference", - "text": "UserAssignedIdentitiesCreateOrUpdateResponse", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesCreateOrUpdateResponse:type" - }, - { - "kind": "Content", - "text": ">" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 9, - "endIndex": 13 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "resourceGroupName", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "parameterName": "resourceName", - "parameterTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - } - }, - { - "parameterName": "parameters", - "parameterTypeTokenRange": { - "startIndex": 5, - "endIndex": 6 - } - }, - { - "parameterName": "options", - "parameterTypeTokenRange": { - "startIndex": 7, - "endIndex": 8 - } - } - ], - "name": "createOrUpdate" - }, - { - "kind": "MethodSignature", - "canonicalReference": "msi-resource-manager!UserAssignedIdentities#delete:member(1)", - "docComment": "/**\n * Deletes the identity.\n *\n * @param resourceGroupName - The name of the Resource Group to which the identity belongs.\n *\n * @param resourceName - The name of the identity resource.\n *\n * @param options - The options parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "delete(resourceGroupName: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ", resourceName: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ", options?: " - }, - { - "kind": "Reference", - "text": "UserAssignedIdentitiesDeleteOptionalParams", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesDeleteOptionalParams:interface" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Reference", - "text": "Promise", - "canonicalReference": "!Promise:interface" - }, - { - "kind": "Content", - "text": "" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 7, - "endIndex": 9 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "resourceGroupName", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "parameterName": "resourceName", - "parameterTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - } - }, - { - "parameterName": "options", - "parameterTypeTokenRange": { - "startIndex": 5, - "endIndex": 6 - } - } - ], - "name": "delete" - }, - { - "kind": "MethodSignature", - "canonicalReference": "msi-resource-manager!UserAssignedIdentities#get:member(1)", - "docComment": "/**\n * Gets the identity.\n *\n * @param resourceGroupName - The name of the Resource Group to which the identity belongs.\n *\n * @param resourceName - The name of the identity resource.\n *\n * @param options - The options parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "get(resourceGroupName: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ", resourceName: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ", options?: " - }, - { - "kind": "Reference", - "text": "UserAssignedIdentitiesGetOptionalParams", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesGetOptionalParams:interface" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Reference", - "text": "Promise", - "canonicalReference": "!Promise:interface" - }, - { - "kind": "Content", - "text": "<" - }, - { - "kind": "Reference", - "text": "UserAssignedIdentitiesGetResponse", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesGetResponse:type" - }, - { - "kind": "Content", - "text": ">" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 7, - "endIndex": 11 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "resourceGroupName", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "parameterName": "resourceName", - "parameterTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - } - }, - { - "parameterName": "options", - "parameterTypeTokenRange": { - "startIndex": 5, - "endIndex": 6 - } - } - ], - "name": "get" - }, - { - "kind": "MethodSignature", - "canonicalReference": "msi-resource-manager!UserAssignedIdentities#listByResourceGroup:member(1)", - "docComment": "/**\n * Lists all the userAssignedIdentities available under the specified ResourceGroup.\n *\n * @param resourceGroupName - The name of the Resource Group to which the identity belongs.\n *\n * @param options - The options parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "listByResourceGroup(resourceGroupName: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ", options?: " - }, - { - "kind": "Reference", - "text": "UserAssignedIdentitiesListByResourceGroupOptionalParams", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListByResourceGroupOptionalParams:interface" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Reference", - "text": "PagedAsyncIterableIterator", - "canonicalReference": "@azure/core-paging!PagedAsyncIterableIterator:interface" - }, - { - "kind": "Content", - "text": "<" - }, - { - "kind": "Reference", - "text": "Identity", - "canonicalReference": "msi-resource-manager!Identity:type" - }, - { - "kind": "Content", - "text": ">" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 5, - "endIndex": 9 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "resourceGroupName", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "parameterName": "options", - "parameterTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - } - } - ], - "name": "listByResourceGroup" - }, - { - "kind": "MethodSignature", - "canonicalReference": "msi-resource-manager!UserAssignedIdentities#listBySubscription:member(1)", - "docComment": "/**\n * Lists all the userAssignedIdentities available under the specified subscription.\n *\n * @param options - The options parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "listBySubscription(options?: " - }, - { - "kind": "Reference", - "text": "UserAssignedIdentitiesListBySubscriptionOptionalParams", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListBySubscriptionOptionalParams:interface" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Reference", - "text": "PagedAsyncIterableIterator", - "canonicalReference": "@azure/core-paging!PagedAsyncIterableIterator:interface" - }, - { - "kind": "Content", - "text": "<" - }, - { - "kind": "Reference", - "text": "Identity", - "canonicalReference": "msi-resource-manager!Identity:type" - }, - { - "kind": "Content", - "text": ">" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 3, - "endIndex": 7 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "options", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ], - "name": "listBySubscription" - }, - { - "kind": "MethodSignature", - "canonicalReference": "msi-resource-manager!UserAssignedIdentities#update:member(1)", - "docComment": "/**\n * Update an identity in the specified subscription and resource group.\n *\n * @param resourceGroupName - The name of the Resource Group to which the identity belongs.\n *\n * @param resourceName - The name of the identity resource.\n *\n * @param parameters - Parameters to update the identity\n *\n * @param options - The options parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "update(resourceGroupName: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ", resourceName: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ", parameters: " - }, - { - "kind": "Reference", - "text": "IdentityUpdate", - "canonicalReference": "msi-resource-manager!IdentityUpdate:type" - }, - { - "kind": "Content", - "text": ", options?: " - }, - { - "kind": "Reference", - "text": "UserAssignedIdentitiesUpdateOptionalParams", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesUpdateOptionalParams:interface" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Reference", - "text": "Promise", - "canonicalReference": "!Promise:interface" - }, - { - "kind": "Content", - "text": "<" - }, - { - "kind": "Reference", - "text": "UserAssignedIdentitiesUpdateResponse", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesUpdateResponse:type" - }, - { - "kind": "Content", - "text": ">" - }, - { - "kind": "Content", - "text": ";" - } - ], - "returnTypeTokenRange": { - "startIndex": 9, - "endIndex": 13 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "resourceGroupName", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "parameterName": "resourceName", - "parameterTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - } - }, - { - "parameterName": "parameters", - "parameterTypeTokenRange": { - "startIndex": 5, - "endIndex": 6 - } - }, - { - "parameterName": "options", - "parameterTypeTokenRange": { - "startIndex": 7, - "endIndex": 8 - } - } - ], - "name": "update" - } - ], - "extendsTokenRanges": [] - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesCreateOrUpdateOptionalParams:interface", - "docComment": "/**\n * Optional parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface UserAssignedIdentitiesCreateOrUpdateOptionalParams extends " - }, - { - "kind": "Content", - "text": "coreClient." - }, - { - "kind": "Reference", - "text": "OperationOptions", - "canonicalReference": "@azure/core-client!OperationOptions:interface" - }, - { - "kind": "Content", - "text": " " - } - ], - "releaseTag": "Public", - "name": "UserAssignedIdentitiesCreateOrUpdateOptionalParams", - "members": [], - "extendsTokenRanges": [ - { - "startIndex": 1, - "endIndex": 4 - } - ] - }, - { - "kind": "TypeAlias", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesCreateOrUpdateResponse:type", - "docComment": "/**\n * Contains response data for the createOrUpdate operation.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare type UserAssignedIdentitiesCreateOrUpdateResponse = " - }, - { - "kind": "Reference", - "text": "Identity", - "canonicalReference": "msi-resource-manager!Identity:type" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "UserAssignedIdentitiesCreateOrUpdateResponse", - "typeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesDeleteOptionalParams:interface", - "docComment": "/**\n * Optional parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface UserAssignedIdentitiesDeleteOptionalParams extends " - }, - { - "kind": "Content", - "text": "coreClient." - }, - { - "kind": "Reference", - "text": "OperationOptions", - "canonicalReference": "@azure/core-client!OperationOptions:interface" - }, - { - "kind": "Content", - "text": " " - } - ], - "releaseTag": "Public", - "name": "UserAssignedIdentitiesDeleteOptionalParams", - "members": [], - "extendsTokenRanges": [ - { - "startIndex": 1, - "endIndex": 4 - } - ] - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesGetOptionalParams:interface", - "docComment": "/**\n * Optional parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface UserAssignedIdentitiesGetOptionalParams extends " - }, - { - "kind": "Content", - "text": "coreClient." - }, - { - "kind": "Reference", - "text": "OperationOptions", - "canonicalReference": "@azure/core-client!OperationOptions:interface" - }, - { - "kind": "Content", - "text": " " - } - ], - "releaseTag": "Public", - "name": "UserAssignedIdentitiesGetOptionalParams", - "members": [], - "extendsTokenRanges": [ - { - "startIndex": 1, - "endIndex": 4 - } - ] - }, - { - "kind": "TypeAlias", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesGetResponse:type", - "docComment": "/**\n * Contains response data for the get operation.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare type UserAssignedIdentitiesGetResponse = " - }, - { - "kind": "Reference", - "text": "Identity", - "canonicalReference": "msi-resource-manager!Identity:type" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "UserAssignedIdentitiesGetResponse", - "typeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListByResourceGroupNextOptionalParams:interface", - "docComment": "/**\n * Optional parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface UserAssignedIdentitiesListByResourceGroupNextOptionalParams extends " - }, - { - "kind": "Content", - "text": "coreClient." - }, - { - "kind": "Reference", - "text": "OperationOptions", - "canonicalReference": "@azure/core-client!OperationOptions:interface" - }, - { - "kind": "Content", - "text": " " - } - ], - "releaseTag": "Public", - "name": "UserAssignedIdentitiesListByResourceGroupNextOptionalParams", - "members": [], - "extendsTokenRanges": [ - { - "startIndex": 1, - "endIndex": 4 - } - ] - }, - { - "kind": "TypeAlias", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListByResourceGroupNextResponse:type", - "docComment": "/**\n * Contains response data for the listByResourceGroupNext operation.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare type UserAssignedIdentitiesListByResourceGroupNextResponse = " - }, - { - "kind": "Reference", - "text": "UserAssignedIdentitiesListResult", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListResult:interface" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "UserAssignedIdentitiesListByResourceGroupNextResponse", - "typeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListByResourceGroupOptionalParams:interface", - "docComment": "/**\n * Optional parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface UserAssignedIdentitiesListByResourceGroupOptionalParams extends " - }, - { - "kind": "Content", - "text": "coreClient." - }, - { - "kind": "Reference", - "text": "OperationOptions", - "canonicalReference": "@azure/core-client!OperationOptions:interface" - }, - { - "kind": "Content", - "text": " " - } - ], - "releaseTag": "Public", - "name": "UserAssignedIdentitiesListByResourceGroupOptionalParams", - "members": [], - "extendsTokenRanges": [ - { - "startIndex": 1, - "endIndex": 4 - } - ] - }, - { - "kind": "TypeAlias", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListByResourceGroupResponse:type", - "docComment": "/**\n * Contains response data for the listByResourceGroup operation.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare type UserAssignedIdentitiesListByResourceGroupResponse = " - }, - { - "kind": "Reference", - "text": "UserAssignedIdentitiesListResult", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListResult:interface" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "UserAssignedIdentitiesListByResourceGroupResponse", - "typeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListBySubscriptionNextOptionalParams:interface", - "docComment": "/**\n * Optional parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface UserAssignedIdentitiesListBySubscriptionNextOptionalParams extends " - }, - { - "kind": "Content", - "text": "coreClient." - }, - { - "kind": "Reference", - "text": "OperationOptions", - "canonicalReference": "@azure/core-client!OperationOptions:interface" - }, - { - "kind": "Content", - "text": " " - } - ], - "releaseTag": "Public", - "name": "UserAssignedIdentitiesListBySubscriptionNextOptionalParams", - "members": [], - "extendsTokenRanges": [ - { - "startIndex": 1, - "endIndex": 4 - } - ] - }, - { - "kind": "TypeAlias", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListBySubscriptionNextResponse:type", - "docComment": "/**\n * Contains response data for the listBySubscriptionNext operation.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare type UserAssignedIdentitiesListBySubscriptionNextResponse = " - }, - { - "kind": "Reference", - "text": "UserAssignedIdentitiesListResult", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListResult:interface" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "UserAssignedIdentitiesListBySubscriptionNextResponse", - "typeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListBySubscriptionOptionalParams:interface", - "docComment": "/**\n * Optional parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface UserAssignedIdentitiesListBySubscriptionOptionalParams extends " - }, - { - "kind": "Content", - "text": "coreClient." - }, - { - "kind": "Reference", - "text": "OperationOptions", - "canonicalReference": "@azure/core-client!OperationOptions:interface" - }, - { - "kind": "Content", - "text": " " - } - ], - "releaseTag": "Public", - "name": "UserAssignedIdentitiesListBySubscriptionOptionalParams", - "members": [], - "extendsTokenRanges": [ - { - "startIndex": 1, - "endIndex": 4 - } - ] - }, - { - "kind": "TypeAlias", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListBySubscriptionResponse:type", - "docComment": "/**\n * Contains response data for the listBySubscription operation.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare type UserAssignedIdentitiesListBySubscriptionResponse = " - }, - { - "kind": "Reference", - "text": "UserAssignedIdentitiesListResult", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListResult:interface" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "UserAssignedIdentitiesListBySubscriptionResponse", - "typeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListResult:interface", - "docComment": "/**\n * Values returned by the List operation.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface UserAssignedIdentitiesListResult " - } - ], - "releaseTag": "Public", - "name": "UserAssignedIdentitiesListResult", - "members": [ - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListResult#nextLink:member", - "docComment": "/**\n * The url to get the next page of results, if any.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "nextLink?: " - }, - { - "kind": "Content", - "text": "string" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "nextLink", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "PropertySignature", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListResult#value:member", - "docComment": "/**\n * The collection of userAssignedIdentities returned by the listing operation.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "value?: " - }, - { - "kind": "Reference", - "text": "Identity", - "canonicalReference": "msi-resource-manager!Identity:type" - }, - { - "kind": "Content", - "text": "[]" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "value", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 3 - } - } - ], - "extendsTokenRanges": [] - }, - { - "kind": "Interface", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesUpdateOptionalParams:interface", - "docComment": "/**\n * Optional parameters.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export interface UserAssignedIdentitiesUpdateOptionalParams extends " - }, - { - "kind": "Content", - "text": "coreClient." - }, - { - "kind": "Reference", - "text": "OperationOptions", - "canonicalReference": "@azure/core-client!OperationOptions:interface" - }, - { - "kind": "Content", - "text": " " - } - ], - "releaseTag": "Public", - "name": "UserAssignedIdentitiesUpdateOptionalParams", - "members": [], - "extendsTokenRanges": [ - { - "startIndex": 1, - "endIndex": 4 - } - ] - }, - { - "kind": "TypeAlias", - "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesUpdateResponse:type", - "docComment": "/**\n * Contains response data for the update operation.\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export declare type UserAssignedIdentitiesUpdateResponse = " - }, - { - "kind": "Reference", - "text": "Identity", - "canonicalReference": "msi-resource-manager!Identity:type" - }, - { - "kind": "Content", - "text": ";" - } - ], - "releaseTag": "Public", - "name": "UserAssignedIdentitiesUpdateResponse", - "typeTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - } - ] - } - ] -} +{ + "metadata": { + "toolPackage": "@microsoft/api-extractor", + "toolVersion": "7.9.10", + "schemaVersion": 1003, + "oldestForwardsCompatibleVersion": 1001 + }, + "kind": "Package", + "canonicalReference": "msi-resource-manager!", + "docComment": "", + "name": "msi-resource-manager", + "members": [ + { + "kind": "EntryPoint", + "canonicalReference": "msi-resource-manager!", + "name": "", + "members": [ + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!CloudError:interface", + "docComment": "/**\n * An error response from the ManagedServiceIdentity service.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface CloudError " + } + ], + "releaseTag": "Public", + "name": "CloudError", + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!CloudError#error:member", + "docComment": "/**\n * A list of additional details about the error.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "error?: " + }, + { + "kind": "Reference", + "text": "CloudErrorBody", + "canonicalReference": "msi-resource-manager!CloudErrorBody:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "error", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!CloudErrorBody:interface", + "docComment": "/**\n * An error response from the ManagedServiceIdentity service.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface CloudErrorBody " + } + ], + "releaseTag": "Public", + "name": "CloudErrorBody", + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!CloudErrorBody#code:member", + "docComment": "/**\n * An identifier for the error.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "code?: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "code", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!CloudErrorBody#details:member", + "docComment": "/**\n * A list of additional details about the error.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "details?: " + }, + { + "kind": "Reference", + "text": "CloudErrorBody", + "canonicalReference": "msi-resource-manager!CloudErrorBody:interface" + }, + { + "kind": "Content", + "text": "[]" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "details", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!CloudErrorBody#message:member", + "docComment": "/**\n * A message describing the error, intended to be suitable for display in a user interface.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "message?: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "message", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!CloudErrorBody#target:member", + "docComment": "/**\n * The target of the particular error. For example, the name of the property in error.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "target?: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "target", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "TypeAlias", + "canonicalReference": "msi-resource-manager!Identity:type", + "docComment": "/**\n * Describes an identity resource.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type Identity = " + }, + { + "kind": "Reference", + "text": "TrackedResource", + "canonicalReference": "msi-resource-manager!TrackedResource:type" + }, + { + "kind": "Content", + "text": " & {\n readonly tenantId?: string;\n readonly principalId?: string;\n readonly clientId?: string;\n}" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "Identity", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 3 + } + }, + { + "kind": "TypeAlias", + "canonicalReference": "msi-resource-manager!IdentityUpdate:type", + "docComment": "/**\n * Describes an identity resource.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type IdentityUpdate = " + }, + { + "kind": "Reference", + "text": "Resource", + "canonicalReference": "msi-resource-manager!Resource:interface" + }, + { + "kind": "Content", + "text": " & {\n location?: string;\n tags?: {\n [propertyName: string]: string;\n };\n readonly tenantId?: string;\n readonly principalId?: string;\n readonly clientId?: string;\n}" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "IdentityUpdate", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 3 + } + }, + { + "kind": "Class", + "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClient:class", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class ManagedServiceIdentityClient extends " + }, + { + "kind": "Reference", + "text": "ManagedServiceIdentityClientContext", + "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientContext:class" + }, + { + "kind": "Content", + "text": " " + } + ], + "releaseTag": "Public", + "name": "ManagedServiceIdentityClient", + "members": [ + { + "kind": "Constructor", + "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClient:constructor(1)", + "docComment": "/**\n * Initializes a new instance of the ManagedServiceIdentityClient class.\n *\n * @param credentials - Subscription credentials which uniquely identify client subscription.\n *\n * @param subscriptionId - The Id of the Subscription to which the identity belongs.\n *\n * @param options - The parameter options\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "constructor(credentials: " + }, + { + "kind": "Content", + "text": "coreAuth." + }, + { + "kind": "Reference", + "text": "TokenCredential", + "canonicalReference": "@azure/core-auth!TokenCredential:interface" + }, + { + "kind": "Content", + "text": ", subscriptionId: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ", options?: " + }, + { + "kind": "Reference", + "text": "ManagedServiceIdentityClientOptionalParams", + "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientOptionalParams:interface" + }, + { + "kind": "Content", + "text": ");" + } + ], + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "credentials", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + } + }, + { + "parameterName": "subscriptionId", + "parameterTypeTokenRange": { + "startIndex": 4, + "endIndex": 5 + } + }, + { + "parameterName": "options", + "parameterTypeTokenRange": { + "startIndex": 6, + "endIndex": 7 + } + } + ] + }, + { + "kind": "Property", + "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClient#operations:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "operations: " + }, + { + "kind": "Reference", + "text": "Operations", + "canonicalReference": "msi-resource-manager!Operations:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "operations", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false + }, + { + "kind": "Property", + "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClient#systemAssignedIdentities:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "systemAssignedIdentities: " + }, + { + "kind": "Reference", + "text": "SystemAssignedIdentities", + "canonicalReference": "msi-resource-manager!SystemAssignedIdentities:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "systemAssignedIdentities", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false + }, + { + "kind": "Property", + "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClient#userAssignedIdentities:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "userAssignedIdentities: " + }, + { + "kind": "Reference", + "text": "UserAssignedIdentities", + "canonicalReference": "msi-resource-manager!UserAssignedIdentities:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "userAssignedIdentities", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false + } + ], + "extendsTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "implementsTokenRanges": [] + }, + { + "kind": "Class", + "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientContext:class", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class ManagedServiceIdentityClientContext extends " + }, + { + "kind": "Content", + "text": "coreClient." + }, + { + "kind": "Reference", + "text": "ServiceClient", + "canonicalReference": "@azure/core-client!ServiceClient:class" + }, + { + "kind": "Content", + "text": " " + } + ], + "releaseTag": "Public", + "name": "ManagedServiceIdentityClientContext", + "members": [ + { + "kind": "Constructor", + "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientContext:constructor(1)", + "docComment": "/**\n * Initializes a new instance of the ManagedServiceIdentityClientContext class.\n *\n * @param credentials - Subscription credentials which uniquely identify client subscription.\n *\n * @param subscriptionId - The Id of the Subscription to which the identity belongs.\n *\n * @param options - The parameter options\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "constructor(credentials: " + }, + { + "kind": "Content", + "text": "coreAuth." + }, + { + "kind": "Reference", + "text": "TokenCredential", + "canonicalReference": "@azure/core-auth!TokenCredential:interface" + }, + { + "kind": "Content", + "text": ", subscriptionId: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ", options?: " + }, + { + "kind": "Reference", + "text": "ManagedServiceIdentityClientOptionalParams", + "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientOptionalParams:interface" + }, + { + "kind": "Content", + "text": ");" + } + ], + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "credentials", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + } + }, + { + "parameterName": "subscriptionId", + "parameterTypeTokenRange": { + "startIndex": 4, + "endIndex": 5 + } + }, + { + "parameterName": "options", + "parameterTypeTokenRange": { + "startIndex": 6, + "endIndex": 7 + } + } + ] + }, + { + "kind": "Property", + "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientContext#$host:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "$host: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "$host", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false + }, + { + "kind": "Property", + "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientContext#apiVersion:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "apiVersion: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "apiVersion", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false + }, + { + "kind": "Property", + "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientContext#subscriptionId:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "subscriptionId: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "subscriptionId", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false + } + ], + "extendsTokenRange": { + "startIndex": 1, + "endIndex": 4 + }, + "implementsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientOptionalParams:interface", + "docComment": "/**\n * Optional parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface ManagedServiceIdentityClientOptionalParams extends " + }, + { + "kind": "Content", + "text": "coreClient." + }, + { + "kind": "Reference", + "text": "ServiceClientOptions", + "canonicalReference": "@azure/core-client!ServiceClientOptions:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "releaseTag": "Public", + "name": "ManagedServiceIdentityClientOptionalParams", + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientOptionalParams#$host:member", + "docComment": "/**\n * server parameter\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "$host?: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "$host", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientOptionalParams#apiVersion:member", + "docComment": "/**\n * Api Version\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "apiVersion?: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "apiVersion", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!ManagedServiceIdentityClientOptionalParams#endpoint:member", + "docComment": "/**\n * Overrides client endpoint.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "endpoint?: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "endpoint", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 4 + } + ] + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!Operation:interface", + "docComment": "/**\n * Operation supported by the Microsoft.ManagedIdentity REST API.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface Operation " + } + ], + "releaseTag": "Public", + "name": "Operation", + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!Operation#display:member", + "docComment": "/**\n * The object that describes the operation.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "display?: " + }, + { + "kind": "Reference", + "text": "OperationDisplay", + "canonicalReference": "msi-resource-manager!OperationDisplay:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "display", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!Operation#name:member", + "docComment": "/**\n * The name of the REST Operation. This is of the format {provider}/{resource}/{operation}.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "name?: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "name", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!OperationDisplay:interface", + "docComment": "/**\n * The object that describes the operation.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface OperationDisplay " + } + ], + "releaseTag": "Public", + "name": "OperationDisplay", + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!OperationDisplay#description:member", + "docComment": "/**\n * A description of the operation.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "description?: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "description", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!OperationDisplay#operation:member", + "docComment": "/**\n * The type of operation. For example: read, write, delete.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "operation?: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "operation", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!OperationDisplay#provider:member", + "docComment": "/**\n * Friendly name of the resource provider.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "provider?: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "provider", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!OperationDisplay#resource:member", + "docComment": "/**\n * The resource type on which the operation is performed.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "resource?: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "resource", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!OperationListResult:interface", + "docComment": "/**\n * A list of operations supported by Microsoft.ManagedIdentity Resource Provider.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface OperationListResult " + } + ], + "releaseTag": "Public", + "name": "OperationListResult", + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!OperationListResult#nextLink:member", + "docComment": "/**\n * The url to get the next page of results, if any.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "nextLink?: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "nextLink", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!OperationListResult#value:member", + "docComment": "/**\n * A list of operations supported by Microsoft.ManagedIdentity Resource Provider.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "value?: " + }, + { + "kind": "Reference", + "text": "Operation", + "canonicalReference": "msi-resource-manager!Operation:interface" + }, + { + "kind": "Content", + "text": "[]" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "value", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!Operations:interface", + "docComment": "/**\n * Interface representing a Operations.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface Operations " + } + ], + "releaseTag": "Public", + "name": "Operations", + "members": [ + { + "kind": "MethodSignature", + "canonicalReference": "msi-resource-manager!Operations#list:member(1)", + "docComment": "/**\n * Lists available operations for the Microsoft.ManagedIdentity provider\n *\n * @param options - The options parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "list(options?: " + }, + { + "kind": "Reference", + "text": "OperationsListOptionalParams", + "canonicalReference": "msi-resource-manager!OperationsListOptionalParams:interface" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Reference", + "text": "PagedAsyncIterableIterator", + "canonicalReference": "@azure/core-paging!PagedAsyncIterableIterator:interface" + }, + { + "kind": "Content", + "text": "<" + }, + { + "kind": "Reference", + "text": "Operation", + "canonicalReference": "msi-resource-manager!Operation:interface" + }, + { + "kind": "Content", + "text": ">" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 7 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "options", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "name": "list" + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!OperationsListNextOptionalParams:interface", + "docComment": "/**\n * Optional parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface OperationsListNextOptionalParams extends " + }, + { + "kind": "Content", + "text": "coreClient." + }, + { + "kind": "Reference", + "text": "OperationOptions", + "canonicalReference": "@azure/core-client!OperationOptions:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "releaseTag": "Public", + "name": "OperationsListNextOptionalParams", + "members": [], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 4 + } + ] + }, + { + "kind": "TypeAlias", + "canonicalReference": "msi-resource-manager!OperationsListNextResponse:type", + "docComment": "/**\n * Contains response data for the listNext operation.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type OperationsListNextResponse = " + }, + { + "kind": "Reference", + "text": "OperationListResult", + "canonicalReference": "msi-resource-manager!OperationListResult:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "OperationsListNextResponse", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!OperationsListOptionalParams:interface", + "docComment": "/**\n * Optional parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface OperationsListOptionalParams extends " + }, + { + "kind": "Content", + "text": "coreClient." + }, + { + "kind": "Reference", + "text": "OperationOptions", + "canonicalReference": "@azure/core-client!OperationOptions:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "releaseTag": "Public", + "name": "OperationsListOptionalParams", + "members": [], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 4 + } + ] + }, + { + "kind": "TypeAlias", + "canonicalReference": "msi-resource-manager!OperationsListResponse:type", + "docComment": "/**\n * Contains response data for the list operation.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type OperationsListResponse = " + }, + { + "kind": "Reference", + "text": "OperationListResult", + "canonicalReference": "msi-resource-manager!OperationListResult:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "OperationsListResponse", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "TypeAlias", + "canonicalReference": "msi-resource-manager!ProxyResource:type", + "docComment": "/**\n * The resource model definition for a ARM proxy resource. It will have everything other than required location and tags\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type ProxyResource = " + }, + { + "kind": "Reference", + "text": "Resource", + "canonicalReference": "msi-resource-manager!Resource:interface" + }, + { + "kind": "Content", + "text": " & {}" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "ProxyResource", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 3 + } + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!Resource:interface", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface Resource " + } + ], + "releaseTag": "Public", + "name": "Resource", + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!Resource#id:member", + "docComment": "/**\n * Fully qualified resource Id for the resource. Ex - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} NOTE: This property will not be serialized. It can only be populated by the server.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "readonly id?: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "id", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!Resource#name:member", + "docComment": "/**\n * The name of the resource NOTE: This property will not be serialized. It can only be populated by the server.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "readonly name?: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "name", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!Resource#type:member", + "docComment": "/**\n * The type of the resource. Ex- Microsoft.Compute/virtualMachines or Microsoft.Storage/storageAccounts. NOTE: This property will not be serialized. It can only be populated by the server.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "readonly type?: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "type", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!SystemAssignedIdentities:interface", + "docComment": "/**\n * Interface representing a SystemAssignedIdentities.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface SystemAssignedIdentities " + } + ], + "releaseTag": "Public", + "name": "SystemAssignedIdentities", + "members": [ + { + "kind": "MethodSignature", + "canonicalReference": "msi-resource-manager!SystemAssignedIdentities#getByScope:member(1)", + "docComment": "/**\n * Gets the systemAssignedIdentity available under the specified RP scope.\n *\n * @param scope - The resource provider scope of the resource. Parent resource being extended by Managed Identities.\n *\n * @param options - The options parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "getByScope(scope: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ", options?: " + }, + { + "kind": "Reference", + "text": "SystemAssignedIdentitiesGetByScopeOptionalParams", + "canonicalReference": "msi-resource-manager!SystemAssignedIdentitiesGetByScopeOptionalParams:interface" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Reference", + "text": "Promise", + "canonicalReference": "!Promise:interface" + }, + { + "kind": "Content", + "text": "<" + }, + { + "kind": "Reference", + "text": "SystemAssignedIdentitiesGetByScopeResponse", + "canonicalReference": "msi-resource-manager!SystemAssignedIdentitiesGetByScopeResponse:type" + }, + { + "kind": "Content", + "text": ">" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 9 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "scope", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "parameterName": "options", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + } + } + ], + "name": "getByScope" + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!SystemAssignedIdentitiesGetByScopeOptionalParams:interface", + "docComment": "/**\n * Optional parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface SystemAssignedIdentitiesGetByScopeOptionalParams extends " + }, + { + "kind": "Content", + "text": "coreClient." + }, + { + "kind": "Reference", + "text": "OperationOptions", + "canonicalReference": "@azure/core-client!OperationOptions:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "releaseTag": "Public", + "name": "SystemAssignedIdentitiesGetByScopeOptionalParams", + "members": [], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 4 + } + ] + }, + { + "kind": "TypeAlias", + "canonicalReference": "msi-resource-manager!SystemAssignedIdentitiesGetByScopeResponse:type", + "docComment": "/**\n * Contains response data for the getByScope operation.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type SystemAssignedIdentitiesGetByScopeResponse = " + }, + { + "kind": "Reference", + "text": "SystemAssignedIdentity", + "canonicalReference": "msi-resource-manager!SystemAssignedIdentity:type" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "SystemAssignedIdentitiesGetByScopeResponse", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "TypeAlias", + "canonicalReference": "msi-resource-manager!SystemAssignedIdentity:type", + "docComment": "/**\n * Describes a system assigned identity resource.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type SystemAssignedIdentity = " + }, + { + "kind": "Reference", + "text": "ProxyResource", + "canonicalReference": "msi-resource-manager!ProxyResource:type" + }, + { + "kind": "Content", + "text": " & {\n location: string;\n tags?: {\n [propertyName: string]: string;\n };\n readonly tenantId?: string;\n readonly principalId?: string;\n readonly clientId?: string;\n readonly clientSecretUrl?: string;\n}" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "SystemAssignedIdentity", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 3 + } + }, + { + "kind": "TypeAlias", + "canonicalReference": "msi-resource-manager!TrackedResource:type", + "docComment": "/**\n * The resource model definition for a ARM tracked top level resource\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type TrackedResource = " + }, + { + "kind": "Reference", + "text": "Resource", + "canonicalReference": "msi-resource-manager!Resource:interface" + }, + { + "kind": "Content", + "text": " & {\n tags?: {\n [propertyName: string]: string;\n };\n location: string;\n}" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "TrackedResource", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 3 + } + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!UserAssignedIdentities:interface", + "docComment": "/**\n * Interface representing a UserAssignedIdentities.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface UserAssignedIdentities " + } + ], + "releaseTag": "Public", + "name": "UserAssignedIdentities", + "members": [ + { + "kind": "MethodSignature", + "canonicalReference": "msi-resource-manager!UserAssignedIdentities#createOrUpdate:member(1)", + "docComment": "/**\n * Create or update an identity in the specified subscription and resource group.\n *\n * @param resourceGroupName - The name of the Resource Group to which the identity belongs.\n *\n * @param resourceName - The name of the identity resource.\n *\n * @param parameters - Parameters to create or update the identity\n *\n * @param options - The options parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "createOrUpdate(resourceGroupName: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ", resourceName: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ", parameters: " + }, + { + "kind": "Reference", + "text": "Identity", + "canonicalReference": "msi-resource-manager!Identity:type" + }, + { + "kind": "Content", + "text": ", options?: " + }, + { + "kind": "Reference", + "text": "UserAssignedIdentitiesCreateOrUpdateOptionalParams", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesCreateOrUpdateOptionalParams:interface" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Reference", + "text": "Promise", + "canonicalReference": "!Promise:interface" + }, + { + "kind": "Content", + "text": "<" + }, + { + "kind": "Reference", + "text": "UserAssignedIdentitiesCreateOrUpdateResponse", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesCreateOrUpdateResponse:type" + }, + { + "kind": "Content", + "text": ">" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 9, + "endIndex": 13 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "resourceGroupName", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "parameterName": "resourceName", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + } + }, + { + "parameterName": "parameters", + "parameterTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + } + }, + { + "parameterName": "options", + "parameterTypeTokenRange": { + "startIndex": 7, + "endIndex": 8 + } + } + ], + "name": "createOrUpdate" + }, + { + "kind": "MethodSignature", + "canonicalReference": "msi-resource-manager!UserAssignedIdentities#delete:member(1)", + "docComment": "/**\n * Deletes the identity.\n *\n * @param resourceGroupName - The name of the Resource Group to which the identity belongs.\n *\n * @param resourceName - The name of the identity resource.\n *\n * @param options - The options parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "delete(resourceGroupName: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ", resourceName: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ", options?: " + }, + { + "kind": "Reference", + "text": "UserAssignedIdentitiesDeleteOptionalParams", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesDeleteOptionalParams:interface" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Reference", + "text": "Promise", + "canonicalReference": "!Promise:interface" + }, + { + "kind": "Content", + "text": "" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 7, + "endIndex": 9 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "resourceGroupName", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "parameterName": "resourceName", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + } + }, + { + "parameterName": "options", + "parameterTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + } + } + ], + "name": "delete" + }, + { + "kind": "MethodSignature", + "canonicalReference": "msi-resource-manager!UserAssignedIdentities#get:member(1)", + "docComment": "/**\n * Gets the identity.\n *\n * @param resourceGroupName - The name of the Resource Group to which the identity belongs.\n *\n * @param resourceName - The name of the identity resource.\n *\n * @param options - The options parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "get(resourceGroupName: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ", resourceName: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ", options?: " + }, + { + "kind": "Reference", + "text": "UserAssignedIdentitiesGetOptionalParams", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesGetOptionalParams:interface" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Reference", + "text": "Promise", + "canonicalReference": "!Promise:interface" + }, + { + "kind": "Content", + "text": "<" + }, + { + "kind": "Reference", + "text": "UserAssignedIdentitiesGetResponse", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesGetResponse:type" + }, + { + "kind": "Content", + "text": ">" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 7, + "endIndex": 11 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "resourceGroupName", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "parameterName": "resourceName", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + } + }, + { + "parameterName": "options", + "parameterTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + } + } + ], + "name": "get" + }, + { + "kind": "MethodSignature", + "canonicalReference": "msi-resource-manager!UserAssignedIdentities#listByResourceGroup:member(1)", + "docComment": "/**\n * Lists all the userAssignedIdentities available under the specified ResourceGroup.\n *\n * @param resourceGroupName - The name of the Resource Group to which the identity belongs.\n *\n * @param options - The options parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "listByResourceGroup(resourceGroupName: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ", options?: " + }, + { + "kind": "Reference", + "text": "UserAssignedIdentitiesListByResourceGroupOptionalParams", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListByResourceGroupOptionalParams:interface" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Reference", + "text": "PagedAsyncIterableIterator", + "canonicalReference": "@azure/core-paging!PagedAsyncIterableIterator:interface" + }, + { + "kind": "Content", + "text": "<" + }, + { + "kind": "Reference", + "text": "Identity", + "canonicalReference": "msi-resource-manager!Identity:type" + }, + { + "kind": "Content", + "text": ">" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 9 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "resourceGroupName", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "parameterName": "options", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + } + } + ], + "name": "listByResourceGroup" + }, + { + "kind": "MethodSignature", + "canonicalReference": "msi-resource-manager!UserAssignedIdentities#listBySubscription:member(1)", + "docComment": "/**\n * Lists all the userAssignedIdentities available under the specified subscription.\n *\n * @param options - The options parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "listBySubscription(options?: " + }, + { + "kind": "Reference", + "text": "UserAssignedIdentitiesListBySubscriptionOptionalParams", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListBySubscriptionOptionalParams:interface" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Reference", + "text": "PagedAsyncIterableIterator", + "canonicalReference": "@azure/core-paging!PagedAsyncIterableIterator:interface" + }, + { + "kind": "Content", + "text": "<" + }, + { + "kind": "Reference", + "text": "Identity", + "canonicalReference": "msi-resource-manager!Identity:type" + }, + { + "kind": "Content", + "text": ">" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 7 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "options", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "name": "listBySubscription" + }, + { + "kind": "MethodSignature", + "canonicalReference": "msi-resource-manager!UserAssignedIdentities#update:member(1)", + "docComment": "/**\n * Update an identity in the specified subscription and resource group.\n *\n * @param resourceGroupName - The name of the Resource Group to which the identity belongs.\n *\n * @param resourceName - The name of the identity resource.\n *\n * @param parameters - Parameters to update the identity\n *\n * @param options - The options parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "update(resourceGroupName: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ", resourceName: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ", parameters: " + }, + { + "kind": "Reference", + "text": "IdentityUpdate", + "canonicalReference": "msi-resource-manager!IdentityUpdate:type" + }, + { + "kind": "Content", + "text": ", options?: " + }, + { + "kind": "Reference", + "text": "UserAssignedIdentitiesUpdateOptionalParams", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesUpdateOptionalParams:interface" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Reference", + "text": "Promise", + "canonicalReference": "!Promise:interface" + }, + { + "kind": "Content", + "text": "<" + }, + { + "kind": "Reference", + "text": "UserAssignedIdentitiesUpdateResponse", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesUpdateResponse:type" + }, + { + "kind": "Content", + "text": ">" + }, + { + "kind": "Content", + "text": ";" + } + ], + "returnTypeTokenRange": { + "startIndex": 9, + "endIndex": 13 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "resourceGroupName", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "parameterName": "resourceName", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + } + }, + { + "parameterName": "parameters", + "parameterTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + } + }, + { + "parameterName": "options", + "parameterTypeTokenRange": { + "startIndex": 7, + "endIndex": 8 + } + } + ], + "name": "update" + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesCreateOrUpdateOptionalParams:interface", + "docComment": "/**\n * Optional parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface UserAssignedIdentitiesCreateOrUpdateOptionalParams extends " + }, + { + "kind": "Content", + "text": "coreClient." + }, + { + "kind": "Reference", + "text": "OperationOptions", + "canonicalReference": "@azure/core-client!OperationOptions:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "releaseTag": "Public", + "name": "UserAssignedIdentitiesCreateOrUpdateOptionalParams", + "members": [], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 4 + } + ] + }, + { + "kind": "TypeAlias", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesCreateOrUpdateResponse:type", + "docComment": "/**\n * Contains response data for the createOrUpdate operation.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type UserAssignedIdentitiesCreateOrUpdateResponse = " + }, + { + "kind": "Reference", + "text": "Identity", + "canonicalReference": "msi-resource-manager!Identity:type" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "UserAssignedIdentitiesCreateOrUpdateResponse", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesDeleteOptionalParams:interface", + "docComment": "/**\n * Optional parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface UserAssignedIdentitiesDeleteOptionalParams extends " + }, + { + "kind": "Content", + "text": "coreClient." + }, + { + "kind": "Reference", + "text": "OperationOptions", + "canonicalReference": "@azure/core-client!OperationOptions:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "releaseTag": "Public", + "name": "UserAssignedIdentitiesDeleteOptionalParams", + "members": [], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 4 + } + ] + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesGetOptionalParams:interface", + "docComment": "/**\n * Optional parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface UserAssignedIdentitiesGetOptionalParams extends " + }, + { + "kind": "Content", + "text": "coreClient." + }, + { + "kind": "Reference", + "text": "OperationOptions", + "canonicalReference": "@azure/core-client!OperationOptions:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "releaseTag": "Public", + "name": "UserAssignedIdentitiesGetOptionalParams", + "members": [], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 4 + } + ] + }, + { + "kind": "TypeAlias", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesGetResponse:type", + "docComment": "/**\n * Contains response data for the get operation.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type UserAssignedIdentitiesGetResponse = " + }, + { + "kind": "Reference", + "text": "Identity", + "canonicalReference": "msi-resource-manager!Identity:type" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "UserAssignedIdentitiesGetResponse", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListByResourceGroupNextOptionalParams:interface", + "docComment": "/**\n * Optional parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface UserAssignedIdentitiesListByResourceGroupNextOptionalParams extends " + }, + { + "kind": "Content", + "text": "coreClient." + }, + { + "kind": "Reference", + "text": "OperationOptions", + "canonicalReference": "@azure/core-client!OperationOptions:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "releaseTag": "Public", + "name": "UserAssignedIdentitiesListByResourceGroupNextOptionalParams", + "members": [], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 4 + } + ] + }, + { + "kind": "TypeAlias", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListByResourceGroupNextResponse:type", + "docComment": "/**\n * Contains response data for the listByResourceGroupNext operation.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type UserAssignedIdentitiesListByResourceGroupNextResponse = " + }, + { + "kind": "Reference", + "text": "UserAssignedIdentitiesListResult", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListResult:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "UserAssignedIdentitiesListByResourceGroupNextResponse", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListByResourceGroupOptionalParams:interface", + "docComment": "/**\n * Optional parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface UserAssignedIdentitiesListByResourceGroupOptionalParams extends " + }, + { + "kind": "Content", + "text": "coreClient." + }, + { + "kind": "Reference", + "text": "OperationOptions", + "canonicalReference": "@azure/core-client!OperationOptions:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "releaseTag": "Public", + "name": "UserAssignedIdentitiesListByResourceGroupOptionalParams", + "members": [], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 4 + } + ] + }, + { + "kind": "TypeAlias", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListByResourceGroupResponse:type", + "docComment": "/**\n * Contains response data for the listByResourceGroup operation.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type UserAssignedIdentitiesListByResourceGroupResponse = " + }, + { + "kind": "Reference", + "text": "UserAssignedIdentitiesListResult", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListResult:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "UserAssignedIdentitiesListByResourceGroupResponse", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListBySubscriptionNextOptionalParams:interface", + "docComment": "/**\n * Optional parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface UserAssignedIdentitiesListBySubscriptionNextOptionalParams extends " + }, + { + "kind": "Content", + "text": "coreClient." + }, + { + "kind": "Reference", + "text": "OperationOptions", + "canonicalReference": "@azure/core-client!OperationOptions:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "releaseTag": "Public", + "name": "UserAssignedIdentitiesListBySubscriptionNextOptionalParams", + "members": [], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 4 + } + ] + }, + { + "kind": "TypeAlias", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListBySubscriptionNextResponse:type", + "docComment": "/**\n * Contains response data for the listBySubscriptionNext operation.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type UserAssignedIdentitiesListBySubscriptionNextResponse = " + }, + { + "kind": "Reference", + "text": "UserAssignedIdentitiesListResult", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListResult:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "UserAssignedIdentitiesListBySubscriptionNextResponse", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListBySubscriptionOptionalParams:interface", + "docComment": "/**\n * Optional parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface UserAssignedIdentitiesListBySubscriptionOptionalParams extends " + }, + { + "kind": "Content", + "text": "coreClient." + }, + { + "kind": "Reference", + "text": "OperationOptions", + "canonicalReference": "@azure/core-client!OperationOptions:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "releaseTag": "Public", + "name": "UserAssignedIdentitiesListBySubscriptionOptionalParams", + "members": [], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 4 + } + ] + }, + { + "kind": "TypeAlias", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListBySubscriptionResponse:type", + "docComment": "/**\n * Contains response data for the listBySubscription operation.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type UserAssignedIdentitiesListBySubscriptionResponse = " + }, + { + "kind": "Reference", + "text": "UserAssignedIdentitiesListResult", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListResult:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "UserAssignedIdentitiesListBySubscriptionResponse", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListResult:interface", + "docComment": "/**\n * Values returned by the List operation.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface UserAssignedIdentitiesListResult " + } + ], + "releaseTag": "Public", + "name": "UserAssignedIdentitiesListResult", + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListResult#nextLink:member", + "docComment": "/**\n * The url to get the next page of results, if any.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "nextLink?: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "nextLink", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesListResult#value:member", + "docComment": "/**\n * The collection of userAssignedIdentities returned by the listing operation.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "value?: " + }, + { + "kind": "Reference", + "text": "Identity", + "canonicalReference": "msi-resource-manager!Identity:type" + }, + { + "kind": "Content", + "text": "[]" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "value", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesUpdateOptionalParams:interface", + "docComment": "/**\n * Optional parameters.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface UserAssignedIdentitiesUpdateOptionalParams extends " + }, + { + "kind": "Content", + "text": "coreClient." + }, + { + "kind": "Reference", + "text": "OperationOptions", + "canonicalReference": "@azure/core-client!OperationOptions:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "releaseTag": "Public", + "name": "UserAssignedIdentitiesUpdateOptionalParams", + "members": [], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 4 + } + ] + }, + { + "kind": "TypeAlias", + "canonicalReference": "msi-resource-manager!UserAssignedIdentitiesUpdateResponse:type", + "docComment": "/**\n * Contains response data for the update operation.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type UserAssignedIdentitiesUpdateResponse = " + }, + { + "kind": "Reference", + "text": "Identity", + "canonicalReference": "msi-resource-manager!Identity:type" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "UserAssignedIdentitiesUpdateResponse", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ] + } + ] +} diff --git a/test/smoke/generated/msi-resource-manager/temp/msi-resource-manager.api.md b/test/smoke/generated/msi-resource-manager/temp/msi-resource-manager.api.md index ef61a1bcbc..3ac4d46409 100644 --- a/test/smoke/generated/msi-resource-manager/temp/msi-resource-manager.api.md +++ b/test/smoke/generated/msi-resource-manager/temp/msi-resource-manager.api.md @@ -1,224 +1,224 @@ -## API Report File for "msi-resource-manager" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import * as coreAuth from '@azure/core-auth'; -import * as coreClient from '@azure/core-client'; -import { PagedAsyncIterableIterator } from '@azure/core-paging'; - -// @public -export interface CloudError { - error?: CloudErrorBody; -} - -// @public -export interface CloudErrorBody { - code?: string; - details?: CloudErrorBody[]; - message?: string; - target?: string; -} - -// @public -export type Identity = TrackedResource & { - readonly tenantId?: string; - readonly principalId?: string; - readonly clientId?: string; -}; - -// @public -export type IdentityUpdate = Resource & { - location?: string; - tags?: { - [propertyName: string]: string; - }; - readonly tenantId?: string; - readonly principalId?: string; - readonly clientId?: string; -}; - -// @public (undocumented) -export class ManagedServiceIdentityClient extends ManagedServiceIdentityClientContext { - constructor(credentials: coreAuth.TokenCredential, subscriptionId: string, options?: ManagedServiceIdentityClientOptionalParams); - // (undocumented) - operations: Operations; - // (undocumented) - systemAssignedIdentities: SystemAssignedIdentities; - // (undocumented) - userAssignedIdentities: UserAssignedIdentities; -} - -// @public (undocumented) -export class ManagedServiceIdentityClientContext extends coreClient.ServiceClient { - // (undocumented) - $host: string; - constructor(credentials: coreAuth.TokenCredential, subscriptionId: string, options?: ManagedServiceIdentityClientOptionalParams); - // (undocumented) - apiVersion: string; - // (undocumented) - subscriptionId: string; -} - -// @public -export interface ManagedServiceIdentityClientOptionalParams extends coreClient.ServiceClientOptions { - $host?: string; - apiVersion?: string; - endpoint?: string; -} - -// @public -export interface Operation { - display?: OperationDisplay; - name?: string; -} - -// @public -export interface OperationDisplay { - description?: string; - operation?: string; - provider?: string; - resource?: string; -} - -// @public -export interface OperationListResult { - nextLink?: string; - value?: Operation[]; -} - -// @public -export interface Operations { - list(options?: OperationsListOptionalParams): PagedAsyncIterableIterator; -} - -// @public -export interface OperationsListNextOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type OperationsListNextResponse = OperationListResult; - -// @public -export interface OperationsListOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type OperationsListResponse = OperationListResult; - -// @public -export type ProxyResource = Resource & {}; - -// @public (undocumented) -export interface Resource { - readonly id?: string; - readonly name?: string; - readonly type?: string; -} - -// @public -export interface SystemAssignedIdentities { - getByScope(scope: string, options?: SystemAssignedIdentitiesGetByScopeOptionalParams): Promise; -} - -// @public -export interface SystemAssignedIdentitiesGetByScopeOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type SystemAssignedIdentitiesGetByScopeResponse = SystemAssignedIdentity; - -// @public -export type SystemAssignedIdentity = ProxyResource & { - location: string; - tags?: { - [propertyName: string]: string; - }; - readonly tenantId?: string; - readonly principalId?: string; - readonly clientId?: string; - readonly clientSecretUrl?: string; -}; - -// @public -export type TrackedResource = Resource & { - tags?: { - [propertyName: string]: string; - }; - location: string; -}; - -// @public -export interface UserAssignedIdentities { - createOrUpdate(resourceGroupName: string, resourceName: string, parameters: Identity, options?: UserAssignedIdentitiesCreateOrUpdateOptionalParams): Promise; - delete(resourceGroupName: string, resourceName: string, options?: UserAssignedIdentitiesDeleteOptionalParams): Promise; - get(resourceGroupName: string, resourceName: string, options?: UserAssignedIdentitiesGetOptionalParams): Promise; - listByResourceGroup(resourceGroupName: string, options?: UserAssignedIdentitiesListByResourceGroupOptionalParams): PagedAsyncIterableIterator; - listBySubscription(options?: UserAssignedIdentitiesListBySubscriptionOptionalParams): PagedAsyncIterableIterator; - update(resourceGroupName: string, resourceName: string, parameters: IdentityUpdate, options?: UserAssignedIdentitiesUpdateOptionalParams): Promise; -} - -// @public -export interface UserAssignedIdentitiesCreateOrUpdateOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type UserAssignedIdentitiesCreateOrUpdateResponse = Identity; - -// @public -export interface UserAssignedIdentitiesDeleteOptionalParams extends coreClient.OperationOptions { -} - -// @public -export interface UserAssignedIdentitiesGetOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type UserAssignedIdentitiesGetResponse = Identity; - -// @public -export interface UserAssignedIdentitiesListByResourceGroupNextOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type UserAssignedIdentitiesListByResourceGroupNextResponse = UserAssignedIdentitiesListResult; - -// @public -export interface UserAssignedIdentitiesListByResourceGroupOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type UserAssignedIdentitiesListByResourceGroupResponse = UserAssignedIdentitiesListResult; - -// @public -export interface UserAssignedIdentitiesListBySubscriptionNextOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type UserAssignedIdentitiesListBySubscriptionNextResponse = UserAssignedIdentitiesListResult; - -// @public -export interface UserAssignedIdentitiesListBySubscriptionOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type UserAssignedIdentitiesListBySubscriptionResponse = UserAssignedIdentitiesListResult; - -// @public -export interface UserAssignedIdentitiesListResult { - nextLink?: string; - value?: Identity[]; -} - -// @public -export interface UserAssignedIdentitiesUpdateOptionalParams extends coreClient.OperationOptions { -} - -// @public -export type UserAssignedIdentitiesUpdateResponse = Identity; - - -// (No @packageDocumentation comment for this package) - -``` +## API Report File for "msi-resource-manager" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import * as coreAuth from '@azure/core-auth'; +import * as coreClient from '@azure/core-client'; +import { PagedAsyncIterableIterator } from '@azure/core-paging'; + +// @public +export interface CloudError { + error?: CloudErrorBody; +} + +// @public +export interface CloudErrorBody { + code?: string; + details?: CloudErrorBody[]; + message?: string; + target?: string; +} + +// @public +export type Identity = TrackedResource & { + readonly tenantId?: string; + readonly principalId?: string; + readonly clientId?: string; +}; + +// @public +export type IdentityUpdate = Resource & { + location?: string; + tags?: { + [propertyName: string]: string; + }; + readonly tenantId?: string; + readonly principalId?: string; + readonly clientId?: string; +}; + +// @public (undocumented) +export class ManagedServiceIdentityClient extends ManagedServiceIdentityClientContext { + constructor(credentials: coreAuth.TokenCredential, subscriptionId: string, options?: ManagedServiceIdentityClientOptionalParams); + // (undocumented) + operations: Operations; + // (undocumented) + systemAssignedIdentities: SystemAssignedIdentities; + // (undocumented) + userAssignedIdentities: UserAssignedIdentities; +} + +// @public (undocumented) +export class ManagedServiceIdentityClientContext extends coreClient.ServiceClient { + // (undocumented) + $host: string; + constructor(credentials: coreAuth.TokenCredential, subscriptionId: string, options?: ManagedServiceIdentityClientOptionalParams); + // (undocumented) + apiVersion: string; + // (undocumented) + subscriptionId: string; +} + +// @public +export interface ManagedServiceIdentityClientOptionalParams extends coreClient.ServiceClientOptions { + $host?: string; + apiVersion?: string; + endpoint?: string; +} + +// @public +export interface Operation { + display?: OperationDisplay; + name?: string; +} + +// @public +export interface OperationDisplay { + description?: string; + operation?: string; + provider?: string; + resource?: string; +} + +// @public +export interface OperationListResult { + nextLink?: string; + value?: Operation[]; +} + +// @public +export interface Operations { + list(options?: OperationsListOptionalParams): PagedAsyncIterableIterator; +} + +// @public +export interface OperationsListNextOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type OperationsListNextResponse = OperationListResult; + +// @public +export interface OperationsListOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type OperationsListResponse = OperationListResult; + +// @public +export type ProxyResource = Resource & {}; + +// @public (undocumented) +export interface Resource { + readonly id?: string; + readonly name?: string; + readonly type?: string; +} + +// @public +export interface SystemAssignedIdentities { + getByScope(scope: string, options?: SystemAssignedIdentitiesGetByScopeOptionalParams): Promise; +} + +// @public +export interface SystemAssignedIdentitiesGetByScopeOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type SystemAssignedIdentitiesGetByScopeResponse = SystemAssignedIdentity; + +// @public +export type SystemAssignedIdentity = ProxyResource & { + location: string; + tags?: { + [propertyName: string]: string; + }; + readonly tenantId?: string; + readonly principalId?: string; + readonly clientId?: string; + readonly clientSecretUrl?: string; +}; + +// @public +export type TrackedResource = Resource & { + tags?: { + [propertyName: string]: string; + }; + location: string; +}; + +// @public +export interface UserAssignedIdentities { + createOrUpdate(resourceGroupName: string, resourceName: string, parameters: Identity, options?: UserAssignedIdentitiesCreateOrUpdateOptionalParams): Promise; + delete(resourceGroupName: string, resourceName: string, options?: UserAssignedIdentitiesDeleteOptionalParams): Promise; + get(resourceGroupName: string, resourceName: string, options?: UserAssignedIdentitiesGetOptionalParams): Promise; + listByResourceGroup(resourceGroupName: string, options?: UserAssignedIdentitiesListByResourceGroupOptionalParams): PagedAsyncIterableIterator; + listBySubscription(options?: UserAssignedIdentitiesListBySubscriptionOptionalParams): PagedAsyncIterableIterator; + update(resourceGroupName: string, resourceName: string, parameters: IdentityUpdate, options?: UserAssignedIdentitiesUpdateOptionalParams): Promise; +} + +// @public +export interface UserAssignedIdentitiesCreateOrUpdateOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type UserAssignedIdentitiesCreateOrUpdateResponse = Identity; + +// @public +export interface UserAssignedIdentitiesDeleteOptionalParams extends coreClient.OperationOptions { +} + +// @public +export interface UserAssignedIdentitiesGetOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type UserAssignedIdentitiesGetResponse = Identity; + +// @public +export interface UserAssignedIdentitiesListByResourceGroupNextOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type UserAssignedIdentitiesListByResourceGroupNextResponse = UserAssignedIdentitiesListResult; + +// @public +export interface UserAssignedIdentitiesListByResourceGroupOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type UserAssignedIdentitiesListByResourceGroupResponse = UserAssignedIdentitiesListResult; + +// @public +export interface UserAssignedIdentitiesListBySubscriptionNextOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type UserAssignedIdentitiesListBySubscriptionNextResponse = UserAssignedIdentitiesListResult; + +// @public +export interface UserAssignedIdentitiesListBySubscriptionOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type UserAssignedIdentitiesListBySubscriptionResponse = UserAssignedIdentitiesListResult; + +// @public +export interface UserAssignedIdentitiesListResult { + nextLink?: string; + value?: Identity[]; +} + +// @public +export interface UserAssignedIdentitiesUpdateOptionalParams extends coreClient.OperationOptions { +} + +// @public +export type UserAssignedIdentitiesUpdateResponse = Identity; + + +// (No @packageDocumentation comment for this package) + +``` diff --git a/test/smoke/generated/network-resource-manager/src/coreClientLro.ts b/test/smoke/generated/network-resource-manager/src/coreClientLro.ts new file mode 100644 index 0000000000..d793a24458 --- /dev/null +++ b/test/smoke/generated/network-resource-manager/src/coreClientLro.ts @@ -0,0 +1,323 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + OperationArguments, + OperationSpec, + OperationResponseMap, + FullOperationResponse +} from "@azure/core-client"; +import { + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + createGetLroStatusFromResponse, + RawResponse +} from "./lro"; + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +export const terminalStates = successStates.concat(failureStates); + +export type SendOperationFn = ( + args: OperationArguments, + spec: OperationSpec +) => Promise>; + +export function createPollingMethod( + sendOperationFn: SendOperationFn, + GetLroStatusFromResponse: GetLroStatusFromResponse, + args: OperationArguments, + spec: OperationSpec, + mode?: LroMode +): (path?: string) => Promise> { + /** + * Polling calls will always return a status object i.e. {"status": "success"} + * these intermediate responses are not described in the swagger so we need to + * pass custom mappers at runtime. + * This function replaces all the existing mappers to be able to deserialize a status object + * @param responses Original set of responses defined in the operation + */ + function getCompositeMappers(responses: { + [responseCode: string]: OperationResponseMap; + }): { + [responseCode: string]: OperationResponseMap; + } { + return Object.keys(responses).reduce((acc, statusCode) => { + return { + ...acc, + [statusCode]: { + ...responses[statusCode], + bodyMapper: { + type: { + name: "Composite", + modelProperties: { + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } + } + } + }; + }, {} as { [responseCode: string]: OperationResponseMap }); + } + let response: LroStatus | undefined = undefined; + const customerCallback = args?.options?.onResponse; + const updatedArgs = { + ...args, + options: { + ...args.options, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ): void => { + response = GetLroStatusFromResponse( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse as TResult + ); + if (response.done) { + customerCallback?.(rawResponse, flatResponse); + } + } + } + }; + // Make sure we don't send any body to the get request + const { requestBody, responses, ...restSpec } = spec; + if (mode === "AzureAsync") { + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: getCompositeMappers(responses), + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; + } + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: responses, + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; +} + +/** + * We need to selectively deserialize our responses, only deserializing if we + * are in a final Lro response, not deserializing any polling non-terminal responses + */ +export function shouldDeserializeLro(lroResourceLocationConfig?: string) { + let initialOperationInfo: LroResponseInfo | undefined; + let isInitialRequest = true; + + return (response: FullOperationResponse) => { + if (response.status < 200 || response.status >= 300) { + return true; + } + + if (!initialOperationInfo) { + initialOperationInfo = getLroData(response); + } else { + isInitialRequest = false; + } + + if ( + initialOperationInfo.azureAsyncOperation || + initialOperationInfo.operationLocation + ) { + return ( + !isInitialRequest && + isAsyncOperationFinalResponse( + response, + initialOperationInfo, + lroResourceLocationConfig + ) + ); + } + + if (initialOperationInfo.location) { + return isLocationFinalResponse(response); + } + + if (initialOperationInfo.requestMethod === "PUT") { + return isBodyPollingFinalResponse(response); + } + + return true; + }; +} + +function isAsyncOperationFinalResponse( + response: FullOperationResponse, + initialOperationInfo: LroResponseInfo, + lroResourceLocationConfig?: string +): boolean { + const status: string = response.parsedBody?.status || "Succeeded"; + if (!terminalStates.includes(status.toLowerCase())) { + return false; + } + + if (initialOperationInfo.requestMethod === "DELETE") { + return true; + } + + if ( + initialOperationInfo.requestMethod === "PUT" && + lroResourceLocationConfig && + lroResourceLocationConfig.toLowerCase() === "azure-asyncoperation" + ) { + return true; + } + + if ( + initialOperationInfo.requestMethod !== "PUT" && + !initialOperationInfo.location + ) { + return true; + } + + return false; +} + +function isLocationFinalResponse(response: FullOperationResponse): boolean { + return response.status !== 202; +} + +function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { + const provisioningState: string = + response.parsedBody?.properties?.provisioningState || "Succeeded"; + + if (terminalStates.includes(provisioningState.toLowerCase())) { + return true; + } + + return false; +} + +interface LroResponseInfo { + requestMethod: string; + azureAsyncOperation?: string; + operationLocation?: string; + location?: string; +} + +function getLroData(result: FullOperationResponse): LroResponseInfo { + return { + azureAsyncOperation: result.headers.get("azure-asyncoperation"), + operationLocation: result.headers.get("operation-location"), + location: result.headers.get("location"), + requestMethod: result.request.method + }; +} + +export function getSpecPath(spec: OperationSpec): string { + if (spec.path) { + return spec.path; + } else { + throw Error("Bad spec: request path is not found!"); + } +} + +export class CoreClientLro implements LongRunningOperation { + constructor( + private sendOperationFn: SendOperationFn, + private args: OperationArguments, + private spec: OperationSpec, + private lroResourceLocationConfig?: LroResourceLocationConfig, + public requestPath: string = spec.path!, + public requestMethod: string = spec.httpMethod + ) {} + public async sendInitialRequest( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ): Promise> { + const { onResponse, ...restOptions } = this.args.options || {}; + return this.sendOperationFn( + { + ...this.args, + options: { + ...restOptions, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ) => { + const isCompleted = initializeState( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse + ); + if (isCompleted) { + onResponse?.(rawResponse, flatResponse); + } + } + } + }, + this.spec + ); + } + + public async sendPollRequest( + config: LroConfig, + path: string + ): Promise> { + const getLroStatusFromResponse = createGetLroStatusFromResponse( + this, + config, + this.lroResourceLocationConfig + ); + return createPollingMethod( + this.sendOperationFn, + getLroStatusFromResponse, + this.args, + this.spec, + config.mode + )(path); + } + + public async retrieveAzureAsyncResource( + path?: string + ): Promise> { + const updatedArgs = { ...this.args }; + if (updatedArgs.options) { + (updatedArgs.options as any).shouldDeserialize = true; + } + return createPollingMethod( + this.sendOperationFn, + (rawResponse, flatResponse) => ({ + rawResponse, + flatResponse, + done: true + }), + updatedArgs, + this.spec + )(path); + } +} diff --git a/test/smoke/generated/network-resource-manager/src/lro/azureAsyncPolling.ts b/test/smoke/generated/network-resource-manager/src/lro/azureAsyncPolling.ts index 0d63c54f60..725578a692 100644 --- a/test/smoke/generated/network-resource-manager/src/lro/azureAsyncPolling.ts +++ b/test/smoke/generated/network-resource-manager/src/lro/azureAsyncPolling.ts @@ -7,39 +7,61 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { FinalStateVia, LROResult } from "./models"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroResourceLocationConfig, + LongRunningOperation, + LroBody, + LroResponse, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getResponseStatus(rawResponse: FullOperationResponse): string { - const { status } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getResponseStatus(rawResponse: RawResponse): string { + const { status } = (rawResponse.body as LroBody) ?? {}; return status?.toLowerCase() ?? "succeeded"; } -function isAzureAsyncPollingDone(rawResponse: FullOperationResponse) { +function isAzureAsyncPollingDone(rawResponse: RawResponse): boolean { const state = getResponseStatus(rawResponse); - if (failureStates.includes(state)) { + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { throw new Error(`Operation status: ${state}`); } return successStates.includes(state); } +async function sendFinalRequest( + lro: LongRunningOperation, + lroResourceLocationConfig?: LroResourceLocationConfig, + resourceLocation?: string +): Promise | undefined> { + switch (lroResourceLocationConfig) { + case "original-uri": + return lro.retrieveAzureAsyncResource(); + case "azure-async-operation": + return Promise.resolve(undefined); + case "location": + default: + return lro.retrieveAzureAsyncResource(resourceLocation); + } +} + export function processAzureAsyncOperationResult( - restrieveResource: (path?: string) => Promise>, + lro: LongRunningOperation, resourceLocation?: string, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { + lroResourceLocationConfig?: LroResourceLocationConfig +): (rawResponse: RawResponse, flatResponse: TResult) => LroStatus { return ( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult - ): LROState => { + ): LroStatus => { if (isAzureAsyncPollingDone(rawResponse)) { if (resourceLocation === undefined) { return { rawResponse, flatResponse, done: true }; @@ -49,20 +71,11 @@ export function processAzureAsyncOperationResult( flatResponse, done: false, next: async () => { - async function sendFinalRequest(): Promise< - LROResult | undefined - > { - switch (finalStateVia) { - case "original-uri": - return restrieveResource(); - case "azure-async-operation": - return Promise.resolve(undefined); - case "location": - default: - return restrieveResource(resourceLocation); - } - } - const finalResponse = await sendFinalRequest(); + const finalResponse = await sendFinalRequest( + lro, + lroResourceLocationConfig, + resourceLocation + ); return { ...(finalResponse ?? { rawResponse, diff --git a/test/smoke/generated/network-resource-manager/src/lro/bodyPolling.ts b/test/smoke/generated/network-resource-manager/src/lro/bodyPolling.ts index 269d8e6799..b1c87f8bc8 100644 --- a/test/smoke/generated/network-resource-manager/src/lro/bodyPolling.ts +++ b/test/smoke/generated/network-resource-manager/src/lro/bodyPolling.ts @@ -7,24 +7,33 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroBody, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getProvisioningState(rawResponse: FullOperationResponse): string { - const { properties, provisioningState } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getProvisioningState(rawResponse: RawResponse): string { + const { properties, provisioningState } = (rawResponse.body as LroBody) ?? {}; const state: string | undefined = properties?.provisioningState ?? provisioningState; return state?.toLowerCase() ?? "succeeded"; } -export function isBodyPollingDone(rawResponse: FullOperationResponse) { +export function isBodyPollingDone(rawResponse: RawResponse): boolean { const state = getProvisioningState(rawResponse); - if (failureStates.includes(state)) { - throw new Error(`Provisioning state: ${state}`); + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { + throw new Error( + `The long running operation has failed. The provisioning state: ${state}.` + ); } return successStates.includes(state); } @@ -34,9 +43,9 @@ export function isBodyPollingDone(rawResponse: FullOperationResponse) { * from the result to determine the current operation state */ export function processBodyPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/network-resource-manager/src/lro/index.ts b/test/smoke/generated/network-resource-manager/src/lro/index.ts index 85c2187669..20df608fc8 100644 --- a/test/smoke/generated/network-resource-manager/src/lro/index.ts +++ b/test/smoke/generated/network-resource-manager/src/lro/index.ts @@ -6,5 +6,21 @@ * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ -export { shouldDeserializeLRO } from "./requestUtils"; -export { LROPoller } from "./lroPoller"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { LroEngine } from "./lroEngine"; +export { createGetLroStatusFromResponse } from "./stateMachine"; +export { + LroResourceLocationConfig, + GetLroStatusFromResponse, + RawResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + LroTerminalState, + LroInProgressState, + LroEngineOptions +} from "./models"; diff --git a/test/smoke/generated/network-resource-manager/src/lro/locationPolling.ts b/test/smoke/generated/network-resource-manager/src/lro/locationPolling.ts index 6fef619384..9d1aadfbde 100644 --- a/test/smoke/generated/network-resource-manager/src/lro/locationPolling.ts +++ b/test/smoke/generated/network-resource-manager/src/lro/locationPolling.ts @@ -7,23 +7,21 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function isLocationPollingDone(rawResponse: FullOperationResponse) { - const code = rawResponse.status; - if (![202, 200].includes(code)) { - throw new Error(`Operation failed`); - } - return code !== 202; +function isLocationPollingDone(rawResponse: RawResponse): boolean { + return ( + !isUnexpectedPollingResponse(rawResponse) && rawResponse.statusCode !== 202 + ); } export function processLocationPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/network-resource-manager/src/lro/lroEngine.ts b/test/smoke/generated/network-resource-manager/src/lro/lroEngine.ts new file mode 100644 index 0000000000..85cc15e609 --- /dev/null +++ b/test/smoke/generated/network-resource-manager/src/lro/lroEngine.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Poller, PollOperationState } from "@azure/core-lro"; +import { + LongRunningOperation, + LroEngineOptions, + ResumablePollOperationState +} from "./models"; +import { GenericPollOperation } from "./operation"; + +/** + * The LRO Engine, a class that performs polling. + */ +export class LroEngine< + TResult, + TState extends PollOperationState +> extends Poller { + private intervalInMs: number; + + constructor(lro: LongRunningOperation, options?: LroEngineOptions) { + const { intervalInMs = 2000, resumeFrom } = options || {}; + function deserializeState( + resumeFrom: string + ): TState & ResumablePollOperationState { + try { + return JSON.parse(resumeFrom).state; + } catch (e) { + throw new Error( + `LroEngine: Unable to deserialize state: ${resumeFrom}` + ); + } + } + const state: TState & ResumablePollOperationState = resumeFrom + ? deserializeState(resumeFrom) + : ({} as any); + + const operation = new GenericPollOperation(state, lro); + super(operation); + + this.intervalInMs = intervalInMs; + operation.setPollerConfig(this as any); + } + + /** + * The method used by the poller to wait before attempting to update its operation. + */ + delay(): Promise { + return new Promise((resolve) => + setTimeout(() => resolve(), this.intervalInMs) + ); + } +} diff --git a/test/smoke/generated/network-resource-manager/src/lro/lroPoller.ts b/test/smoke/generated/network-resource-manager/src/lro/lroPoller.ts deleted file mode 100644 index cd1cd64fe8..0000000000 --- a/test/smoke/generated/network-resource-manager/src/lro/lroPoller.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { Poller, PollOperationState } from "@azure/core-lro"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { FinalStateVia, SendOperationFn } from "./models"; -import { GenericPollOperation } from "./operation"; - -export interface LROPollerOptions { - /** - * Defines how much time the poller is going to wait before making a new request to the service. - */ - intervalInMs?: number; - /** - * A serialized poller which can be used to resume an existing paused Long-Running-Operation. - */ - resumeFrom?: string; -} - -export class LROPoller extends Poller< - PollOperationState, - TResult -> { - private intervalInMs: number; - - constructor( - { intervalInMs = 2000, resumeFrom }: LROPollerOptions, - initialOperationArguments: OperationArguments, - initialOperationSpec: OperationSpec, - sendOperation: SendOperationFn, - finalStateVia?: FinalStateVia - ) { - const state: PollOperationState = resumeFrom - ? JSON.parse(resumeFrom).state - : {}; - - const operation = new GenericPollOperation( - state, - initialOperationArguments, - initialOperationSpec, - sendOperation, - finalStateVia - ); - super(operation); - - this.intervalInMs = intervalInMs; - operation.setPollerConfig(this as any); - } - - /** - * The method used by the poller to wait before attempting to update its operation. - */ - delay(): Promise { - return new Promise((resolve) => - setTimeout(() => resolve(), this.intervalInMs) - ); - } -} diff --git a/test/smoke/generated/network-resource-manager/src/lro/models.ts b/test/smoke/generated/network-resource-manager/src/lro/models.ts index a4a5a5abd6..93c3437c8e 100644 --- a/test/smoke/generated/network-resource-manager/src/lro/models.ts +++ b/test/smoke/generated/network-resource-manager/src/lro/models.ts @@ -7,46 +7,167 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec -} from "@azure/core-client"; import { PollOperationState } from "@azure/core-lro"; -export type FinalStateVia = +/** + * Options for the LRO poller. + */ +export interface LroEngineOptions { + /** + * Defines how much time the poller is going to wait before making a new request to the service. + */ + intervalInMs?: number; + /** + * A serialized poller which can be used to resume an existing paused Long-Running-Operation. + */ + resumeFrom?: string; +} + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +/** + * The LRO states that signal that the LRO has completed. + */ +export const terminalStates = successStates.concat(failureStates); + +/** + * The potential location of the result of the LRO if specified by the LRO extension in the swagger. + */ +export type LroResourceLocationConfig = | "azure-async-operation" | "location" | "original-uri"; -export interface LROResult { +/** + * The type of a LRO response body. This is just a convenience type for checking the status of the operation. + */ + +export interface LroBody extends Record { + /** The status of the operation. */ + status?: string; + /** The state of the provisioning process */ + provisioningState?: string; + /** The properties of the provisioning process */ + properties?: { provisioningState?: string } & Record; +} + +/** + * Simple type of the raw response. + */ +export interface RawResponse { + /** The HTTP status code */ + statusCode: number; + /** A HttpHeaders collection in the response represented as a simple JSON object where all header names have been normalized to be lower-case. */ + headers: { + [headerName: string]: string; + }; + /** The parsed response body */ + body?: unknown; +} + +/** + * The type of the response of a LRO. + */ +export interface LroResponse { + /** The flattened response */ flatResponse: T; - rawResponse: FullOperationResponse; + /** The raw response */ + rawResponse: RawResponse; } -export type LROMode = "AzureAsync" | "Location" | "Body"; +/** The type of which LRO implementation being followed by a specific API. */ +export type LroMode = "AzureAsync" | "Location" | "Body"; -export interface LROConfig { - mode?: LROMode; +/** + * The configuration of a LRO to determine how to perform polling and checking whether the operation has completed. + */ +export interface LroConfig { + /** The LRO mode */ + mode?: LroMode; + /** The path of a provisioned resource */ resourceLocation?: string; } -export type SendOperationFn = ( - args: OperationArguments, - spec: OperationSpec -) => Promise>; - /** * Type of a polling operation state that can actually be resumed. */ export type ResumablePollOperationState = PollOperationState & { - initialRawResponse?: FullOperationResponse; - config?: LROConfig; + initialRawResponse?: RawResponse; + config?: LroConfig; pollingURL?: string; }; export interface PollerConfig { intervalInMs: number; } + +/** + * The type of a terminal state of an LRO. + */ +export interface LroTerminalState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: true; +} + +/** + * The type of an in-progress state of an LRO. + */ +export interface LroInProgressState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: false; + /** + * The request to be sent next if it is different from the standard polling one. + * Notice that it will disregard any polling URLs provided to it. + */ + next?: () => Promise>; +} + +/** + * The type of an LRO state which is a tagged union of terminal and in-progress states. + */ +export type LroStatus = LroTerminalState | LroInProgressState; + +/** + * The type of the getLROStatusFromResponse method. It takes the response as input and returns along the response whether the operation has finished. + */ +export type GetLroStatusFromResponse = ( + rawResponse: RawResponse, + flatResponse: T +) => LroStatus; + +/** + * Description of a long running operation. + */ +export interface LongRunningOperation { + /** + * The request path. + */ + requestPath: string; + /** + * The HTTP request method. + */ + requestMethod: string; + /** + * A function that can be used to send initial request to the service. + */ + sendInitialRequest: ( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ) => Promise>; + /** + * A function that can be used to poll for the current status of a long running operation. + */ + sendPollRequest: (config: LroConfig, path: string) => Promise>; + /** + * A function that can be used to retrieve the provisioned azure resource. + */ + retrieveAzureAsyncResource: (path?: string) => Promise>; +} diff --git a/test/smoke/generated/network-resource-manager/src/lro/operation.ts b/test/smoke/generated/network-resource-manager/src/lro/operation.ts index 801d03e720..3ea7b76d89 100644 --- a/test/smoke/generated/network-resource-manager/src/lro/operation.ts +++ b/test/smoke/generated/network-resource-manager/src/lro/operation.ts @@ -7,36 +7,34 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. import { AbortSignalLike } from "@azure/abort-controller"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { PollOperation, PollOperationState } from "@azure/core-lro"; +import { PollOperationState, PollOperation } from "@azure/core-lro"; import { - FinalStateVia, PollerConfig, ResumablePollOperationState, - SendOperationFn + LongRunningOperation, + LroStatus } from "./models"; -import { getPollingURL } from "./requestUtils"; -import { createGetLROState, initializeState, LROState } from "./stateMachine"; +import { getPollingUrl } from "./requestUtils"; +import { createInitializeState, createPollForLROStatus } from "./stateMachine"; -export class GenericPollOperation - implements PollOperation, TResult> { - private getLROState?: ( +export class GenericPollOperation< + TResult, + TState extends PollOperationState +> implements PollOperation { + private getLROStatusFromResponse?: ( pollingURL: string, pollerConfig: PollerConfig - ) => Promise>; + ) => Promise>; private pollerConfig?: PollerConfig; constructor( - public state: PollOperationState, - private initialOperationArguments: OperationArguments, - private initialOperationSpec: OperationSpec, - private sendOperation: SendOperationFn, - private finalStateVia?: FinalStateVia + public state: TState & ResumablePollOperationState, + private lro: LongRunningOperation ) {} - public setPollerConfig(pollerConfig: PollerConfig) { + public setPollerConfig(pollerConfig: PollerConfig): void { this.pollerConfig = pollerConfig; } @@ -57,45 +55,36 @@ export class GenericPollOperation */ async update(options?: { abortSignal?: AbortSignalLike | undefined; - fireProgress?: ((state: PollOperationState) => void) | undefined; - }): Promise, TResult>> { - const state = this.state as ResumablePollOperationState; - const { onResponse, ...restOptions } = - this.initialOperationArguments.options || {}; + fireProgress?: ((state: TState) => void) | undefined; + }): Promise> { + const state = this.state; if (!state.isStarted) { - await this.sendOperation( - { - ...this.initialOperationArguments, - options: { - ...restOptions, - onResponse: initializeState( - state, - this.initialOperationSpec, - onResponse - ) - } - }, - this.initialOperationSpec + const initializeState = createInitializeState( + state, + this.lro.requestPath, + this.lro.requestMethod ); + await this.lro.sendInitialRequest(initializeState); } if (!state.isCompleted) { - if (this.getLROState === undefined) { + if (this.getLROStatusFromResponse === undefined) { if (state.config === undefined) { - throw new Error("Bad state: LRO mode is undefined"); + throw new Error( + "Bad state: LRO mode is undefined. Please check if the serialized state is well-formed." + ); } - this.getLROState = createGetLROState( - this.sendOperation, - this.initialOperationArguments, - this.initialOperationSpec, - state.config, - this.finalStateVia + this.getLROStatusFromResponse = createPollForLROStatus( + this.lro, + state.config ); } if (state.pollingURL === undefined) { - throw new Error("Bad state: polling URL is undefined"); + throw new Error( + "Bad state: polling URL is undefined. Please check if the serialized state is well-formed." + ); } - const currentState = await this.getLROState( + const currentState = await this.getLROStatusFromResponse( state.pollingURL, this.pollerConfig! ); @@ -103,20 +92,19 @@ export class GenericPollOperation state.result = currentState.flatResponse; state.isCompleted = true; } else { - this.getLROState = currentState.next ?? this.getLROState; - state.pollingURL = getPollingURL( + this.getLROStatusFromResponse = + currentState.next ?? this.getLROStatusFromResponse; + state.pollingURL = getPollingUrl( currentState.rawResponse, state.pollingURL ); } } - if (options?.fireProgress !== undefined) { - options.fireProgress(state); - } + options?.fireProgress?.(state); return this; } - async cancel(): Promise, TResult>> { + async cancel(): Promise> { this.state.isCancelled = true; return this; } diff --git a/test/smoke/generated/network-resource-manager/src/lro/passthrough.ts b/test/smoke/generated/network-resource-manager/src/lro/passthrough.ts index 64c10380c1..ae7f87d384 100644 --- a/test/smoke/generated/network-resource-manager/src/lro/passthrough.ts +++ b/test/smoke/generated/network-resource-manager/src/lro/passthrough.ts @@ -7,15 +7,14 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; export function processPassthroughOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/network-resource-manager/src/lro/pollingMethod.ts b/test/smoke/generated/network-resource-manager/src/lro/pollingMethod.ts deleted file mode 100644 index cb6482bbde..0000000000 --- a/test/smoke/generated/network-resource-manager/src/lro/pollingMethod.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - OperationArguments, - OperationSpec, - OperationResponseMap -} from "@azure/core-client"; -import { LROMode, LROResult, SendOperationFn } from "./models"; - -export function createPollingMethod( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - mode?: LROMode -): (path?: string) => Promise> { - /** - * Polling calls will always return a status object i.e. {"status": "success"} - * these intermediate responses are not described in the swagger so we need to - * pass custom mappers at runtime. - * This function replaces all the existing mappers to be able to deserialize a status object - * @param responses Original set of responses defined in the operation - */ - function getCompositeMappers(responses: { - [responseCode: string]: OperationResponseMap; - }): { - [responseCode: string]: OperationResponseMap; - } { - return Object.keys(responses).reduce((acc, statusCode) => { - return { - ...acc, - [statusCode]: { - ...responses[statusCode], - bodyMapper: { - type: { - name: "Composite", - modelProperties: { - status: { - serializedName: "status", - type: { - name: "String" - } - } - } - } - } - } - }; - }, {} as { [responseCode: string]: OperationResponseMap }); - } - // Make sure we don't send any body to the get request - const { requestBody, responses, ...restSpec } = spec; - if (mode === "AzureAsync") { - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: getCompositeMappers(responses), - httpMethod: "GET", - ...(path && { path }) - }); - }; - } - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: responses, - httpMethod: "GET", - ...(path && { path }) - }); - }; -} - -export function createRetrieveAzureAsyncResource( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec -): (path?: string) => Promise> { - const updatedArgs = { ...args }; - if (updatedArgs.options) { - (updatedArgs.options as any).shouldDeserialize = true; - } - return createPollingMethod(sendOperationFn, updatedArgs, spec); -} diff --git a/test/smoke/generated/network-resource-manager/src/lro/requestUtils.ts b/test/smoke/generated/network-resource-manager/src/lro/requestUtils.ts index 9162f66339..40d993686f 100644 --- a/test/smoke/generated/network-resource-manager/src/lro/requestUtils.ts +++ b/test/smoke/generated/network-resource-manager/src/lro/requestUtils.ts @@ -7,119 +7,9 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse, OperationSpec } from "@azure/core-client"; -import { LROConfig } from "./models"; -import { terminalStates } from "./stateMachine"; - -/** - * We need to selectively deserialize our responses, only deserializing if we - * are in a final LRO response, not deserializing any polling non-terminal responses - */ -export function shouldDeserializeLRO(finalStateVia?: string) { - let initialOperationInfo: LROResponseInfo | undefined; - let isInitialRequest = true; - - return (response: FullOperationResponse) => { - if (response.status < 200 || response.status >= 300) { - return true; - } - - if (!initialOperationInfo) { - initialOperationInfo = getLROData(response); - } else { - isInitialRequest = false; - } - - if ( - initialOperationInfo.azureAsyncOperation || - initialOperationInfo.operationLocation - ) { - return ( - !isInitialRequest && - isAsyncOperationFinalResponse( - response, - initialOperationInfo, - finalStateVia - ) - ); - } - - if (initialOperationInfo.location) { - return isLocationFinalResponse(response); - } - - if (initialOperationInfo.requestMethod === "PUT") { - return isBodyPollingFinalResponse(response); - } - - return true; - }; -} - -function isAsyncOperationFinalResponse( - response: FullOperationResponse, - initialOperationInfo: LROResponseInfo, - finalStateVia?: string -): boolean { - const status: string = response.parsedBody?.status || "Succeeded"; - if (!terminalStates.includes(status.toLowerCase())) { - return false; - } - - if (initialOperationInfo.requestMethod === "DELETE") { - return true; - } - - if ( - initialOperationInfo.requestMethod === "PUT" && - finalStateVia && - finalStateVia.toLowerCase() === "azure-asyncoperation" - ) { - return true; - } - - if ( - initialOperationInfo.requestMethod !== "PUT" && - !initialOperationInfo.location - ) { - return true; - } - - return false; -} - -function isLocationFinalResponse(response: FullOperationResponse): boolean { - return response.status !== 202; -} - -function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { - const provisioningState: string = - response.parsedBody?.properties?.provisioningState || "Succeeded"; - - if (terminalStates.includes(provisioningState.toLowerCase())) { - return true; - } - - return false; -} - -interface LROResponseInfo { - requestMethod: string; - azureAsyncOperation?: string; - operationLocation?: string; - location?: string; -} - -function getLROData(result: FullOperationResponse): LROResponseInfo { - return { - azureAsyncOperation: result.headers.get("azure-asyncoperation"), - operationLocation: result.headers.get("operation-location"), - location: result.headers.get("location"), - requestMethod: result.request.method - }; -} +import { LroConfig, RawResponse } from "./models"; /** * Detects where the continuation token is and returns it. Notice that azure-asyncoperation @@ -127,45 +17,41 @@ function getLROData(result: FullOperationResponse): LROResponseInfo { * where both azure-asyncoperation and location could be present in the same response but * azure-asyncoperation should be the one to use for polling. */ -export function getPollingURL( - rawResponse: FullOperationResponse, +export function getPollingUrl( + rawResponse: RawResponse, defaultPath: string ): string { return ( - getAzureAsyncoperation(rawResponse) ?? + getAzureAsyncOperation(rawResponse) ?? getLocation(rawResponse) ?? getOperationLocation(rawResponse) ?? defaultPath ); } -function getLocation(rawResponse: FullOperationResponse): string | undefined { - return rawResponse.headers?.get("location"); +function getLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["location"]; } -function getOperationLocation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("operation-location"); +function getOperationLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["operation-location"]; } -function getAzureAsyncoperation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("azure-asyncoperation"); +function getAzureAsyncOperation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["azure-asyncoperation"]; } -export function inferLROMode( - spec: OperationSpec, - rawResponse: FullOperationResponse -): LROConfig { - const requestMethod = spec.httpMethod; - if (getAzureAsyncoperation(rawResponse) !== undefined) { +export function inferLroMode( + requestPath: string, + requestMethod: string, + rawResponse: RawResponse +): LroConfig { + if (getAzureAsyncOperation(rawResponse) !== undefined) { return { mode: "AzureAsync", resourceLocation: requestMethod === "PUT" - ? spec.path + ? requestPath : requestMethod === "POST" ? getLocation(rawResponse) : undefined @@ -185,10 +71,35 @@ export function inferLROMode( return {}; } -export function getSpecPath(spec: OperationSpec): string { - if (spec.path) { - return spec.path; - } else { - throw Error("Bad spec: request path is not found!"); +export class RestError extends Error { + public statusCode?: number; + constructor(message: string, statusCode: number) { + super(message); + this.name = "RestError"; + this.statusCode = statusCode; + + Object.setPrototypeOf(this, RestError.prototype); + } +} + +export function isUnexpectedInitialResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![203, 204, 202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} in the initial response. This may indicate a server issue.`, + code + ); } + return false; +} + +export function isUnexpectedPollingResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} while polling. This may indicate a server issue.`, + code + ); + } + return false; } diff --git a/test/smoke/generated/network-resource-manager/src/lro/stateMachine.ts b/test/smoke/generated/network-resource-manager/src/lro/stateMachine.ts index b2a69b5546..19a8f67470 100644 --- a/test/smoke/generated/network-resource-manager/src/lro/stateMachine.ts +++ b/test/smoke/generated/network-resource-manager/src/lro/stateMachine.ts @@ -7,14 +7,8 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec, - RawResponseCallback -} from "@azure/core-client"; import { processAzureAsyncOperationResult } from "./azureAsyncPolling"; import { isBodyPollingDone, @@ -22,73 +16,36 @@ import { } from "./bodyPolling"; import { processLocationPollingOperationResult } from "./locationPolling"; import { - FinalStateVia, - LROConfig, - LROResult, + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroStatus, PollerConfig, - ResumablePollOperationState, - SendOperationFn + RawResponse, + ResumablePollOperationState } from "./models"; import { processPassthroughOperationResult } from "./passthrough"; import { - createPollingMethod, - createRetrieveAzureAsyncResource -} from "./pollingMethod"; -import { getPollingURL, getSpecPath, inferLROMode } from "./requestUtils"; - -export const successStates = ["succeeded"]; -export const failureStates = ["failed", "canceled", "cancelled"]; -export const terminalStates = successStates.concat(failureStates); - -/** - * The type of a terminal state of an LRO. - */ -interface LROTerminalState extends LROResult { - /** - * Whether the operation has finished. - */ - done: true; -} - -/** - * The type of an in-progress state of an LRO. - */ -interface LROInProgressState extends LROResult { - /** - * Whether the operation has finished. - */ - done: false; - /** - * The request to be sent next if it is different from the standard polling one. - * Notice that it will disregard any polling URLs provided to it. - */ - next?: () => Promise>; -} - -/** - * The type of an LRO state which is a tagged union of terminal and in-progress states. - */ -export type LROState = LROTerminalState | LROInProgressState; + getPollingUrl, + inferLroMode, + isUnexpectedInitialResponse +} from "./requestUtils"; /** * creates a stepping function that maps an LRO state to another. */ -function createTransition( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { +export function createGetLroStatusFromResponse( + lroPrimitives: LongRunningOperation, + config: LroConfig, + lroResourceLocationConfig?: LroResourceLocationConfig +): GetLroStatusFromResponse { switch (config.mode) { case "AzureAsync": { return processAzureAsyncOperationResult( - createRetrieveAzureAsyncResource(sendOperationFn, args, spec), + lroPrimitives, config.resourceLocation, - finalStateVia + lroResourceLocationConfig ); } case "Location": { @@ -106,52 +63,20 @@ function createTransition( /** * Creates a polling operation that returns a LRO state. */ -export function createGetLROState( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia +export function createPollForLROStatus( + lroPrimitives: LongRunningOperation, + config: LroConfig ): ( pollingURL: string, pollerConfig: PollerConfig -) => Promise> { - const step = createTransition( - sendOperationFn, - args, - spec, - config, - finalStateVia - ); - const customerCallback = args?.options?.onResponse; - let response: LROState | undefined = undefined; - let retryAfter: string | undefined = undefined; - const poll = createPollingMethod( - sendOperationFn, - { - ...args, - options: { - ...args.options, - onResponse: ( - rawResponse: FullOperationResponse, - flatResponse: unknown - ): void => { - response = step(rawResponse, flatResponse as TResult); - retryAfter = rawResponse.headers.get("Retry-After"); - if (response.done) { - customerCallback?.(rawResponse, flatResponse); - } - } - } - }, - spec, - config.mode - ); +) => Promise> { return async ( path: string, pollerConfig: PollerConfig - ): Promise> => { - await poll(path); + ): Promise> => { + const response = await lroPrimitives.sendPollRequest(config, path); + const retryAfter: string | undefined = + response.rawResponse.headers["retry-after"]; if (retryAfter !== undefined) { const retryAfterInMs = parseInt(retryAfter); pollerConfig.intervalInMs = isNaN(retryAfterInMs) @@ -161,7 +86,7 @@ export function createGetLROState( ) : retryAfterInMs; } - return response!; + return response; }; } @@ -179,24 +104,26 @@ function calculatePollingIntervalFromDate( /** * Creates a callback to be used to initialize the polling operation state. - * @param state of the polling operation - * @param operationSpec of the LRO - * @param callback callback to be called when the operation is done + * @param state - of the polling operation + * @param operationSpec - of the LRO + * @param callback - callback to be called when the operation is done * @returns callback that initializes the state of the polling operation */ -export function initializeState( +export function createInitializeState( state: ResumablePollOperationState, - operationSpec: OperationSpec, - callback?: RawResponseCallback -): (rawResponse: FullOperationResponse, flatResponse: unknown) => void { - return (rawResponse: FullOperationResponse, flatResponse: unknown) => { + requestPath: string, + requestMethod: string +): (rawResponse: RawResponse, flatResponse: unknown) => boolean { + return (rawResponse: RawResponse, flatResponse: unknown) => { + if (isUnexpectedInitialResponse(rawResponse)) return true; state.initialRawResponse = rawResponse; state.isStarted = true; - state.pollingURL = getPollingURL( - state.initialRawResponse, - getSpecPath(operationSpec) + state.pollingURL = getPollingUrl(state.initialRawResponse, requestPath); + state.config = inferLroMode( + requestPath, + requestMethod, + state.initialRawResponse ); - state.config = inferLROMode(operationSpec, state.initialRawResponse); /** short circuit polling if body polling is done in the initial request */ if ( state.config.mode === undefined || @@ -205,12 +132,7 @@ export function initializeState( ) { state.result = flatResponse as TResult; state.isCompleted = true; - /** - * We need to check if the LRO operation is finished inside the - * call back so that we can call the customer-provided callback - * on that result. - */ - callback?.(rawResponse, flatResponse); } + return Boolean(state.isCompleted); }; } diff --git a/test/smoke/generated/network-resource-manager/src/networkManagementClient.ts b/test/smoke/generated/network-resource-manager/src/networkManagementClient.ts index 9011e2bd35..fe30f8e4d6 100644 --- a/test/smoke/generated/network-resource-manager/src/networkManagementClient.ts +++ b/test/smoke/generated/network-resource-manager/src/networkManagementClient.ts @@ -10,8 +10,9 @@ import * as coreClient from "@azure/core-client"; import * as coreAuth from "@azure/core-auth"; import "@azure/core-paging"; import { PagedAsyncIterableIterator } from "@azure/core-paging"; -import { LROPoller, shouldDeserializeLRO } from "./lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "./lro"; +import { CoreClientLro, shouldDeserializeLro } from "./coreClientLro"; import { ApplicationGatewaysImpl, ApplicationSecurityGroupsImpl, @@ -755,16 +756,23 @@ export class NetworkManagementClient extends NetworkManagementClientContext { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, bastionHostName, bslRequest, options }, putBastionShareableLinkOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -809,16 +817,23 @@ export class NetworkManagementClient extends NetworkManagementClientContext { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, bastionHostName, bslRequest, options }, deleteBastionShareableLinkOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -907,16 +922,23 @@ export class NetworkManagementClient extends NetworkManagementClientContext { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, bastionHostName, options }, getActiveSessionsOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1024,16 +1046,23 @@ export class NetworkManagementClient extends NetworkManagementClientContext { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualWANName, vpnClientParams, options }, generatevirtualwanvpnserverconfigurationvpnprofileOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/applicationGateways.ts b/test/smoke/generated/network-resource-manager/src/operations/applicationGateways.ts index 309df91681..52626f04f5 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/applicationGateways.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/applicationGateways.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ApplicationGateway, ApplicationGatewaysListNextOptionalParams, @@ -251,16 +252,23 @@ export class ApplicationGatewaysImpl implements ApplicationGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, applicationGatewayName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -346,16 +354,23 @@ export class ApplicationGatewaysImpl implements ApplicationGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, applicationGatewayName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -464,16 +479,23 @@ export class ApplicationGatewaysImpl implements ApplicationGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, applicationGatewayName, options }, startOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -535,16 +557,23 @@ export class ApplicationGatewaysImpl implements ApplicationGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, applicationGatewayName, options }, stopOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -611,16 +640,23 @@ export class ApplicationGatewaysImpl implements ApplicationGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, applicationGatewayName, options }, backendHealthOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -690,16 +726,23 @@ export class ApplicationGatewaysImpl implements ApplicationGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, applicationGatewayName, probeRequest, options }, backendHealthOnDemandOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/applicationSecurityGroups.ts b/test/smoke/generated/network-resource-manager/src/operations/applicationSecurityGroups.ts index 3dab923bd2..0f439911e9 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/applicationSecurityGroups.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/applicationSecurityGroups.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ApplicationSecurityGroup, ApplicationSecurityGroupsListAllNextOptionalParams, @@ -181,16 +182,23 @@ export class ApplicationSecurityGroupsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, applicationSecurityGroupName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -276,16 +284,23 @@ export class ApplicationSecurityGroupsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, applicationSecurityGroupName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/azureFirewalls.ts b/test/smoke/generated/network-resource-manager/src/operations/azureFirewalls.ts index 1eab9e5334..50ec01a5f5 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/azureFirewalls.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/azureFirewalls.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { AzureFirewall, AzureFirewallsListNextOptionalParams, @@ -180,16 +181,23 @@ export class AzureFirewallsImpl implements AzureFirewalls { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, azureFirewallName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -275,16 +283,23 @@ export class AzureFirewallsImpl implements AzureFirewalls { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, azureFirewallName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -356,16 +371,23 @@ export class AzureFirewallsImpl implements AzureFirewalls { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, azureFirewallName, parameters, options }, updateTagsOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/bastionHosts.ts b/test/smoke/generated/network-resource-manager/src/operations/bastionHosts.ts index aff11d8a32..aac5e516a2 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/bastionHosts.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/bastionHosts.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { BastionHost, BastionHostsListNextOptionalParams, @@ -180,16 +181,23 @@ export class BastionHostsImpl implements BastionHosts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, bastionHostName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -275,16 +283,23 @@ export class BastionHostsImpl implements BastionHosts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, bastionHostName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/connectionMonitors.ts b/test/smoke/generated/network-resource-manager/src/operations/connectionMonitors.ts index d6b9feda55..532ed30851 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/connectionMonitors.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/connectionMonitors.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ConnectionMonitorResult, ConnectionMonitorsListOptionalParams, @@ -156,11 +157,18 @@ export class ConnectionMonitorsImpl implements ConnectionMonitors { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, @@ -169,9 +177,9 @@ export class ConnectionMonitorsImpl implements ConnectionMonitors { options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -260,16 +268,23 @@ export class ConnectionMonitorsImpl implements ConnectionMonitors { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, connectionMonitorName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -363,16 +378,23 @@ export class ConnectionMonitorsImpl implements ConnectionMonitors { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, connectionMonitorName, options }, stopOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -439,16 +461,23 @@ export class ConnectionMonitorsImpl implements ConnectionMonitors { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, connectionMonitorName, options }, startOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -520,16 +549,23 @@ export class ConnectionMonitorsImpl implements ConnectionMonitors { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, connectionMonitorName, options }, queryOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/ddosCustomPolicies.ts b/test/smoke/generated/network-resource-manager/src/operations/ddosCustomPolicies.ts index ac24912141..6e8bde4db3 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/ddosCustomPolicies.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/ddosCustomPolicies.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { DdosCustomPoliciesDeleteOptionalParams, DdosCustomPoliciesGetOptionalParams, @@ -77,16 +78,23 @@ export class DdosCustomPoliciesImpl implements DdosCustomPolicies { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, ddosCustomPolicyName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -172,16 +180,23 @@ export class DdosCustomPoliciesImpl implements DdosCustomPolicies { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, ddosCustomPolicyName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/ddosProtectionPlans.ts b/test/smoke/generated/network-resource-manager/src/operations/ddosProtectionPlans.ts index 3193d54486..52c6631ea1 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/ddosProtectionPlans.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/ddosProtectionPlans.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { DdosProtectionPlan, DdosProtectionPlansListNextOptionalParams, @@ -183,16 +184,23 @@ export class DdosProtectionPlansImpl implements DdosProtectionPlans { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, ddosProtectionPlanName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -278,16 +286,23 @@ export class DdosProtectionPlansImpl implements DdosProtectionPlans { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, ddosProtectionPlanName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/expressRouteCircuitAuthorizations.ts b/test/smoke/generated/network-resource-manager/src/operations/expressRouteCircuitAuthorizations.ts index 429b382c04..4c3d7ada89 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/expressRouteCircuitAuthorizations.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/expressRouteCircuitAuthorizations.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ExpressRouteCircuitAuthorization, ExpressRouteCircuitAuthorizationsListNextOptionalParams, @@ -143,16 +144,23 @@ export class ExpressRouteCircuitAuthorizationsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, circuitName, authorizationName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -248,11 +256,18 @@ export class ExpressRouteCircuitAuthorizationsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, circuitName, @@ -261,9 +276,9 @@ export class ExpressRouteCircuitAuthorizationsImpl options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/expressRouteCircuitConnections.ts b/test/smoke/generated/network-resource-manager/src/operations/expressRouteCircuitConnections.ts index f50e7ea0ee..8112461b68 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/expressRouteCircuitConnections.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/expressRouteCircuitConnections.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ExpressRouteCircuitConnection, ExpressRouteCircuitConnectionsListNextOptionalParams, @@ -166,16 +167,23 @@ export class ExpressRouteCircuitConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, circuitName, peeringName, connectionName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -276,11 +284,18 @@ export class ExpressRouteCircuitConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, circuitName, @@ -290,9 +305,9 @@ export class ExpressRouteCircuitConnectionsImpl options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/expressRouteCircuitPeerings.ts b/test/smoke/generated/network-resource-manager/src/operations/expressRouteCircuitPeerings.ts index 5906aeaf4b..3a39e95f67 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/expressRouteCircuitPeerings.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/expressRouteCircuitPeerings.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ExpressRouteCircuitPeering, ExpressRouteCircuitPeeringsListNextOptionalParams, @@ -143,16 +144,23 @@ export class ExpressRouteCircuitPeeringsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, circuitName, peeringName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -246,11 +254,18 @@ export class ExpressRouteCircuitPeeringsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, circuitName, @@ -259,9 +274,9 @@ export class ExpressRouteCircuitPeeringsImpl options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/expressRouteCircuits.ts b/test/smoke/generated/network-resource-manager/src/operations/expressRouteCircuits.ts index 4a0d8d609b..ae78121dfd 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/expressRouteCircuits.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/expressRouteCircuits.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ExpressRouteCircuit, ExpressRouteCircuitsListNextOptionalParams, @@ -190,16 +191,23 @@ export class ExpressRouteCircuitsImpl implements ExpressRouteCircuits { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, circuitName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -285,16 +293,23 @@ export class ExpressRouteCircuitsImpl implements ExpressRouteCircuits { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, circuitName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -388,16 +403,23 @@ export class ExpressRouteCircuitsImpl implements ExpressRouteCircuits { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, circuitName, peeringName, devicePath, options }, listArpTableOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -476,16 +498,23 @@ export class ExpressRouteCircuitsImpl implements ExpressRouteCircuits { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, circuitName, peeringName, devicePath, options }, listRoutesTableOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -564,16 +593,23 @@ export class ExpressRouteCircuitsImpl implements ExpressRouteCircuits { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, circuitName, peeringName, devicePath, options }, listRoutesTableSummaryOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/expressRouteConnections.ts b/test/smoke/generated/network-resource-manager/src/operations/expressRouteConnections.ts index 445ce679a6..e4a73dbaa8 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/expressRouteConnections.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/expressRouteConnections.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ExpressRouteConnection, ExpressRouteConnectionsCreateOrUpdateOptionalParams, @@ -86,11 +87,18 @@ export class ExpressRouteConnectionsImpl implements ExpressRouteConnections { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, expressRouteGatewayName, @@ -99,9 +107,9 @@ export class ExpressRouteConnectionsImpl implements ExpressRouteConnections { options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -191,16 +199,23 @@ export class ExpressRouteConnectionsImpl implements ExpressRouteConnections { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, expressRouteGatewayName, connectionName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/expressRouteCrossConnectionPeerings.ts b/test/smoke/generated/network-resource-manager/src/operations/expressRouteCrossConnectionPeerings.ts index cdea95148a..5189540a2b 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/expressRouteCrossConnectionPeerings.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/expressRouteCrossConnectionPeerings.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ExpressRouteCrossConnectionPeering, ExpressRouteCrossConnectionPeeringsListNextOptionalParams, @@ -172,16 +173,23 @@ export class ExpressRouteCrossConnectionPeeringsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, crossConnectionName, peeringName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -277,11 +285,18 @@ export class ExpressRouteCrossConnectionPeeringsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, crossConnectionName, @@ -290,9 +305,9 @@ export class ExpressRouteCrossConnectionPeeringsImpl options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/expressRouteCrossConnections.ts b/test/smoke/generated/network-resource-manager/src/operations/expressRouteCrossConnections.ts index bb671e0341..780c22e561 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/expressRouteCrossConnections.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/expressRouteCrossConnections.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ExpressRouteCrossConnection, ExpressRouteCrossConnectionsListNextOptionalParams, @@ -238,16 +239,23 @@ export class ExpressRouteCrossConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, crossConnectionName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -346,11 +354,18 @@ export class ExpressRouteCrossConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, crossConnectionName, @@ -359,9 +374,9 @@ export class ExpressRouteCrossConnectionsImpl options }, listArpTableOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -441,11 +456,18 @@ export class ExpressRouteCrossConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, crossConnectionName, @@ -454,9 +476,9 @@ export class ExpressRouteCrossConnectionsImpl options }, listRoutesTableSummaryOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -534,11 +556,18 @@ export class ExpressRouteCrossConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, crossConnectionName, @@ -547,9 +576,9 @@ export class ExpressRouteCrossConnectionsImpl options }, listRoutesTableOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/expressRouteGateways.ts b/test/smoke/generated/network-resource-manager/src/operations/expressRouteGateways.ts index 4bd2db00bf..2d6aa02235 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/expressRouteGateways.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/expressRouteGateways.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ExpressRouteGatewaysListBySubscriptionOptionalParams, ExpressRouteGatewaysListBySubscriptionResponse, @@ -114,11 +115,18 @@ export class ExpressRouteGatewaysImpl implements ExpressRouteGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, expressRouteGatewayName, @@ -126,9 +134,9 @@ export class ExpressRouteGatewaysImpl implements ExpressRouteGateways { options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -212,16 +220,23 @@ export class ExpressRouteGatewaysImpl implements ExpressRouteGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, expressRouteGatewayName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/expressRoutePorts.ts b/test/smoke/generated/network-resource-manager/src/operations/expressRoutePorts.ts index 8814c52feb..bd3533baa5 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/expressRoutePorts.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/expressRoutePorts.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ExpressRoutePort, ExpressRoutePortsListByResourceGroupNextOptionalParams, @@ -183,16 +184,23 @@ export class ExpressRoutePortsImpl implements ExpressRoutePorts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, expressRoutePortName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -278,16 +286,23 @@ export class ExpressRoutePortsImpl implements ExpressRoutePorts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, expressRoutePortName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/firewallPolicies.ts b/test/smoke/generated/network-resource-manager/src/operations/firewallPolicies.ts index e2ed101520..d2a4ae9ecd 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/firewallPolicies.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/firewallPolicies.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { FirewallPolicy, FirewallPoliciesListNextOptionalParams, @@ -177,16 +178,23 @@ export class FirewallPoliciesImpl implements FirewallPolicies { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, firewallPolicyName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -272,16 +280,23 @@ export class FirewallPoliciesImpl implements FirewallPolicies { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, firewallPolicyName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/firewallPolicyRuleGroups.ts b/test/smoke/generated/network-resource-manager/src/operations/firewallPolicyRuleGroups.ts index 18c27d7f2c..f37243dfd1 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/firewallPolicyRuleGroups.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/firewallPolicyRuleGroups.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { FirewallPolicyRuleGroup, FirewallPolicyRuleGroupsListNextOptionalParams, @@ -154,16 +155,23 @@ export class FirewallPolicyRuleGroupsImpl implements FirewallPolicyRuleGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, firewallPolicyName, ruleGroupName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -256,11 +264,18 @@ export class FirewallPolicyRuleGroupsImpl implements FirewallPolicyRuleGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, firewallPolicyName, @@ -269,9 +284,9 @@ export class FirewallPolicyRuleGroupsImpl implements FirewallPolicyRuleGroups { options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/flowLogs.ts b/test/smoke/generated/network-resource-manager/src/operations/flowLogs.ts index 0fcbf46c63..69815e0b64 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/flowLogs.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/flowLogs.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { FlowLog, FlowLogsListNextOptionalParams, @@ -161,11 +162,18 @@ export class FlowLogsImpl implements FlowLogs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, @@ -174,9 +182,9 @@ export class FlowLogsImpl implements FlowLogs { options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -265,16 +273,23 @@ export class FlowLogsImpl implements FlowLogs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, flowLogName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/hubRouteTables.ts b/test/smoke/generated/network-resource-manager/src/operations/hubRouteTables.ts index 9bd4867c25..4cd6db685c 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/hubRouteTables.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/hubRouteTables.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { HubRouteTable, HubRouteTablesListNextOptionalParams, @@ -149,11 +150,18 @@ export class HubRouteTablesImpl implements HubRouteTables { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualHubName, @@ -162,9 +170,9 @@ export class HubRouteTablesImpl implements HubRouteTables { options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -253,16 +261,23 @@ export class HubRouteTablesImpl implements HubRouteTables { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualHubName, routeTableName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/inboundNatRules.ts b/test/smoke/generated/network-resource-manager/src/operations/inboundNatRules.ts index 2f46d73ead..4e13231343 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/inboundNatRules.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/inboundNatRules.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { InboundNatRule, InboundNatRulesListNextOptionalParams, @@ -167,16 +168,23 @@ export class InboundNatRulesImpl implements InboundNatRules { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, loadBalancerName, inboundNatRuleName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -270,11 +278,18 @@ export class InboundNatRulesImpl implements InboundNatRules { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, loadBalancerName, @@ -283,9 +298,9 @@ export class InboundNatRulesImpl implements InboundNatRules { options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/ipAllocations.ts b/test/smoke/generated/network-resource-manager/src/operations/ipAllocations.ts index 425b5a5f26..2267d329a5 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/ipAllocations.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/ipAllocations.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { IpAllocation, IpAllocationsListNextOptionalParams, @@ -183,16 +184,23 @@ export class IpAllocationsImpl implements IpAllocations { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, ipAllocationName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -278,16 +286,23 @@ export class IpAllocationsImpl implements IpAllocations { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, ipAllocationName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/ipGroups.ts b/test/smoke/generated/network-resource-manager/src/operations/ipGroups.ts index 91d00cd389..dc21ff0f90 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/ipGroups.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/ipGroups.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { IpGroup, IpGroupsListByResourceGroupNextOptionalParams, @@ -207,16 +208,23 @@ export class IpGroupsImpl implements IpGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, ipGroupsName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -300,16 +308,23 @@ export class IpGroupsImpl implements IpGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, ipGroupsName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/loadBalancerBackendAddressPools.ts b/test/smoke/generated/network-resource-manager/src/operations/loadBalancerBackendAddressPools.ts index 78fb62d75f..ad3ee2b850 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/loadBalancerBackendAddressPools.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/loadBalancerBackendAddressPools.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { BackendAddressPool, LoadBalancerBackendAddressPoolsListNextOptionalParams, @@ -195,11 +196,18 @@ export class LoadBalancerBackendAddressPoolsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, loadBalancerName, @@ -208,9 +216,9 @@ export class LoadBalancerBackendAddressPoolsImpl options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -281,16 +289,23 @@ export class LoadBalancerBackendAddressPoolsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, loadBalancerName, backendAddressPoolName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/loadBalancers.ts b/test/smoke/generated/network-resource-manager/src/operations/loadBalancers.ts index adaa28b9ca..95a564c54c 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/loadBalancers.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/loadBalancers.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { LoadBalancer, LoadBalancersListAllNextOptionalParams, @@ -180,16 +181,23 @@ export class LoadBalancersImpl implements LoadBalancers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, loadBalancerName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -275,16 +283,23 @@ export class LoadBalancersImpl implements LoadBalancers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, loadBalancerName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/localNetworkGateways.ts b/test/smoke/generated/network-resource-manager/src/operations/localNetworkGateways.ts index abad1c3afb..e76d875653 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/localNetworkGateways.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/localNetworkGateways.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { LocalNetworkGateway, LocalNetworkGatewaysListNextOptionalParams, @@ -141,16 +142,23 @@ export class LocalNetworkGatewaysImpl implements LocalNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, localNetworkGatewayName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -232,16 +240,23 @@ export class LocalNetworkGatewaysImpl implements LocalNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, localNetworkGatewayName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/natGateways.ts b/test/smoke/generated/network-resource-manager/src/operations/natGateways.ts index 63b056d34b..e104a09833 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/natGateways.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/natGateways.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { NatGateway, NatGatewaysListAllNextOptionalParams, @@ -180,16 +181,23 @@ export class NatGatewaysImpl implements NatGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, natGatewayName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -275,16 +283,23 @@ export class NatGatewaysImpl implements NatGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, natGatewayName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/networkInterfaceTapConfigurations.ts b/test/smoke/generated/network-resource-manager/src/operations/networkInterfaceTapConfigurations.ts index f557e4bef0..7793581439 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/networkInterfaceTapConfigurations.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/networkInterfaceTapConfigurations.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { NetworkInterfaceTapConfiguration, NetworkInterfaceTapConfigurationsListNextOptionalParams, @@ -155,11 +156,18 @@ export class NetworkInterfaceTapConfigurationsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkInterfaceName, @@ -167,9 +175,9 @@ export class NetworkInterfaceTapConfigurationsImpl options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -270,11 +278,18 @@ export class NetworkInterfaceTapConfigurationsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkInterfaceName, @@ -283,9 +298,9 @@ export class NetworkInterfaceTapConfigurationsImpl options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/networkInterfaces.ts b/test/smoke/generated/network-resource-manager/src/operations/networkInterfaces.ts index 05e1226128..61b6bb4172 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/networkInterfaces.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/networkInterfaces.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { NetworkInterface, NetworkInterfacesListAllNextOptionalParams, @@ -441,16 +442,23 @@ export class NetworkInterfacesImpl implements NetworkInterfaces { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkInterfaceName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -536,16 +544,23 @@ export class NetworkInterfacesImpl implements NetworkInterfaces { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkInterfaceName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -659,16 +674,23 @@ export class NetworkInterfacesImpl implements NetworkInterfaces { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkInterfaceName, options }, getEffectiveRouteTableOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -737,16 +759,23 @@ export class NetworkInterfacesImpl implements NetworkInterfaces { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkInterfaceName, options }, listEffectiveNetworkSecurityGroupsOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/networkProfiles.ts b/test/smoke/generated/network-resource-manager/src/operations/networkProfiles.ts index 30dde1e025..cad3ed7e37 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/networkProfiles.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/networkProfiles.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { NetworkProfile, NetworkProfilesListAllNextOptionalParams, @@ -180,16 +181,23 @@ export class NetworkProfilesImpl implements NetworkProfiles { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkProfileName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/networkSecurityGroups.ts b/test/smoke/generated/network-resource-manager/src/operations/networkSecurityGroups.ts index e6c3726cde..7c020a76cd 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/networkSecurityGroups.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/networkSecurityGroups.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { NetworkSecurityGroup, NetworkSecurityGroupsListAllNextOptionalParams, @@ -180,16 +181,23 @@ export class NetworkSecurityGroupsImpl implements NetworkSecurityGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkSecurityGroupName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -275,16 +283,23 @@ export class NetworkSecurityGroupsImpl implements NetworkSecurityGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkSecurityGroupName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/networkVirtualAppliances.ts b/test/smoke/generated/network-resource-manager/src/operations/networkVirtualAppliances.ts index a297583f0b..0de362ef5e 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/networkVirtualAppliances.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/networkVirtualAppliances.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { NetworkVirtualAppliance, NetworkVirtualAppliancesListByResourceGroupNextOptionalParams, @@ -183,16 +184,23 @@ export class NetworkVirtualAppliancesImpl implements NetworkVirtualAppliances { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkVirtualApplianceName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -297,16 +305,23 @@ export class NetworkVirtualAppliancesImpl implements NetworkVirtualAppliances { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkVirtualApplianceName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/networkWatchers.ts b/test/smoke/generated/network-resource-manager/src/operations/networkWatchers.ts index e3dfe74d14..afaa2bfc86 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/networkWatchers.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/networkWatchers.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { NetworkWatcher, NetworkWatchersListOptionalParams, @@ -232,16 +233,23 @@ export class NetworkWatchersImpl implements NetworkWatchers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -373,16 +381,23 @@ export class NetworkWatchersImpl implements NetworkWatchers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, parameters, options }, verifyIPFlowOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -454,16 +469,23 @@ export class NetworkWatchersImpl implements NetworkWatchers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, parameters, options }, getNextHopOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -535,16 +557,23 @@ export class NetworkWatchersImpl implements NetworkWatchers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, parameters, options }, getVMSecurityRulesOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -616,16 +645,23 @@ export class NetworkWatchersImpl implements NetworkWatchers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, parameters, options }, getTroubleshootingOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -697,16 +733,23 @@ export class NetworkWatchersImpl implements NetworkWatchers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, parameters, options }, getTroubleshootingResultOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -778,16 +821,23 @@ export class NetworkWatchersImpl implements NetworkWatchers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, parameters, options }, setFlowLogConfigurationOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -860,16 +910,23 @@ export class NetworkWatchersImpl implements NetworkWatchers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, parameters, options }, getFlowLogStatusOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -943,16 +1000,23 @@ export class NetworkWatchersImpl implements NetworkWatchers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, parameters, options }, checkConnectivityOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1026,16 +1090,23 @@ export class NetworkWatchersImpl implements NetworkWatchers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, parameters, options }, getAzureReachabilityReportOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1109,16 +1180,23 @@ export class NetworkWatchersImpl implements NetworkWatchers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, parameters, options }, listAvailableProvidersOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1197,16 +1275,23 @@ export class NetworkWatchersImpl implements NetworkWatchers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, parameters, options }, getNetworkConfigurationDiagnosticOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/p2SVpnGateways.ts b/test/smoke/generated/network-resource-manager/src/operations/p2SVpnGateways.ts index a0537e5f55..76d6153442 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/p2SVpnGateways.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/p2SVpnGateways.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { P2SVpnGateway, P2SVpnGatewaysListByResourceGroupNextOptionalParams, @@ -218,16 +219,23 @@ export class P2SVpnGatewaysImpl implements P2SVpnGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, gatewayName, p2SVpnGatewayParameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -312,16 +320,23 @@ export class P2SVpnGatewaysImpl implements P2SVpnGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, gatewayName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -415,16 +430,23 @@ export class P2SVpnGatewaysImpl implements P2SVpnGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, gatewayName, parameters, options }, generateVpnProfileOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -495,16 +517,23 @@ export class P2SVpnGatewaysImpl implements P2SVpnGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, gatewayName, options }, getP2SVpnConnectionHealthOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -577,16 +606,23 @@ export class P2SVpnGatewaysImpl implements P2SVpnGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, gatewayName, request, options }, getP2SVpnConnectionHealthDetailedOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -654,16 +690,23 @@ export class P2SVpnGatewaysImpl implements P2SVpnGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, p2SVpnGatewayName, request, options }, disconnectP2SVpnConnectionsOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/packetCaptures.ts b/test/smoke/generated/network-resource-manager/src/operations/packetCaptures.ts index 2154afafff..70b0727a3b 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/packetCaptures.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/packetCaptures.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { PacketCaptureResult, PacketCapturesListOptionalParams, @@ -152,11 +153,18 @@ export class PacketCapturesImpl implements PacketCaptures { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, @@ -165,9 +173,9 @@ export class PacketCapturesImpl implements PacketCaptures { options }, createOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -256,16 +264,23 @@ export class PacketCapturesImpl implements PacketCaptures { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, packetCaptureName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -332,16 +347,23 @@ export class PacketCapturesImpl implements PacketCaptures { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, packetCaptureName, options }, stopOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -413,16 +435,23 @@ export class PacketCapturesImpl implements PacketCaptures { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkWatcherName, packetCaptureName, options }, getStatusOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/privateDnsZoneGroups.ts b/test/smoke/generated/network-resource-manager/src/operations/privateDnsZoneGroups.ts index 67295399aa..0d8751c185 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/privateDnsZoneGroups.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/privateDnsZoneGroups.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { PrivateDnsZoneGroup, PrivateDnsZoneGroupsListNextOptionalParams, @@ -154,11 +155,18 @@ export class PrivateDnsZoneGroupsImpl implements PrivateDnsZoneGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, privateEndpointName, @@ -166,9 +174,9 @@ export class PrivateDnsZoneGroupsImpl implements PrivateDnsZoneGroups { options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -266,11 +274,18 @@ export class PrivateDnsZoneGroupsImpl implements PrivateDnsZoneGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, privateEndpointName, @@ -279,9 +294,9 @@ export class PrivateDnsZoneGroupsImpl implements PrivateDnsZoneGroups { options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/privateEndpoints.ts b/test/smoke/generated/network-resource-manager/src/operations/privateEndpoints.ts index 01581d61a4..1538e84a7c 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/privateEndpoints.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/privateEndpoints.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { PrivateEndpoint, PrivateEndpointsListNextOptionalParams, @@ -177,16 +178,23 @@ export class PrivateEndpointsImpl implements PrivateEndpoints { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, privateEndpointName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -272,16 +280,23 @@ export class PrivateEndpointsImpl implements PrivateEndpoints { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, privateEndpointName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/privateLinkServices.ts b/test/smoke/generated/network-resource-manager/src/operations/privateLinkServices.ts index 0a68abb58d..f7fb9ce19c 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/privateLinkServices.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/privateLinkServices.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { PrivateLinkService, PrivateLinkServicesListNextOptionalParams, @@ -407,16 +408,23 @@ export class PrivateLinkServicesImpl implements PrivateLinkServices { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serviceName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -502,16 +510,23 @@ export class PrivateLinkServicesImpl implements PrivateLinkServices { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serviceName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -647,16 +662,23 @@ export class PrivateLinkServicesImpl implements PrivateLinkServices { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serviceName, peConnectionName, options }, deletePrivateEndpointConnectionOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/publicIPAddresses.ts b/test/smoke/generated/network-resource-manager/src/operations/publicIPAddresses.ts index 8b3ce617ee..9254d67296 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/publicIPAddresses.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/publicIPAddresses.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { PublicIPAddress, PublicIPAddressesListAllNextOptionalParams, @@ -360,16 +361,23 @@ export class PublicIPAddressesImpl implements PublicIPAddresses { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, publicIpAddressName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -455,16 +463,23 @@ export class PublicIPAddressesImpl implements PublicIPAddresses { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, publicIpAddressName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/publicIPPrefixes.ts b/test/smoke/generated/network-resource-manager/src/operations/publicIPPrefixes.ts index 83f337de63..478f2f0f5a 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/publicIPPrefixes.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/publicIPPrefixes.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { PublicIPPrefix, PublicIPPrefixesListAllNextOptionalParams, @@ -180,16 +181,23 @@ export class PublicIPPrefixesImpl implements PublicIPPrefixes { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, publicIpPrefixName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -275,16 +283,23 @@ export class PublicIPPrefixesImpl implements PublicIPPrefixes { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, publicIpPrefixName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/routeFilterRules.ts b/test/smoke/generated/network-resource-manager/src/operations/routeFilterRules.ts index 8290afe494..1198252609 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/routeFilterRules.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/routeFilterRules.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { RouteFilterRule, RouteFilterRulesListByRouteFilterNextOptionalParams, @@ -154,16 +155,23 @@ export class RouteFilterRulesImpl implements RouteFilterRules { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, routeFilterName, ruleName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -257,11 +265,18 @@ export class RouteFilterRulesImpl implements RouteFilterRules { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, routeFilterName, @@ -270,9 +285,9 @@ export class RouteFilterRulesImpl implements RouteFilterRules { options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/routeFilters.ts b/test/smoke/generated/network-resource-manager/src/operations/routeFilters.ts index 2350bdab22..13e80e5305 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/routeFilters.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/routeFilters.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { RouteFilter, RouteFiltersListByResourceGroupNextOptionalParams, @@ -183,16 +184,23 @@ export class RouteFiltersImpl implements RouteFilters { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, routeFilterName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -278,16 +286,23 @@ export class RouteFiltersImpl implements RouteFilters { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, routeFilterName, routeFilterParameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/routeTables.ts b/test/smoke/generated/network-resource-manager/src/operations/routeTables.ts index c8b49f2423..bf39b4da15 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/routeTables.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/routeTables.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { RouteTable, RouteTablesListNextOptionalParams, @@ -180,16 +181,23 @@ export class RouteTablesImpl implements RouteTables { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, routeTableName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -275,16 +283,23 @@ export class RouteTablesImpl implements RouteTables { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, routeTableName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/routes.ts b/test/smoke/generated/network-resource-manager/src/operations/routes.ts index 76888e2ea5..be3d354f0b 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/routes.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/routes.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { Route, RoutesListNextOptionalParams, @@ -142,16 +143,23 @@ export class RoutesImpl implements Routes { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, routeTableName, routeName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -244,11 +252,18 @@ export class RoutesImpl implements Routes { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, routeTableName, @@ -257,9 +272,9 @@ export class RoutesImpl implements Routes { options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/securityPartnerProviders.ts b/test/smoke/generated/network-resource-manager/src/operations/securityPartnerProviders.ts index 1b0444d541..6786d61bd4 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/securityPartnerProviders.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/securityPartnerProviders.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { SecurityPartnerProvider, SecurityPartnerProvidersListByResourceGroupNextOptionalParams, @@ -183,16 +184,23 @@ export class SecurityPartnerProvidersImpl implements SecurityPartnerProviders { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, securityPartnerProviderName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -278,16 +286,23 @@ export class SecurityPartnerProvidersImpl implements SecurityPartnerProviders { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, securityPartnerProviderName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/securityRules.ts b/test/smoke/generated/network-resource-manager/src/operations/securityRules.ts index e3b384afc6..0c1f202519 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/securityRules.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/securityRules.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { SecurityRule, SecurityRulesListNextOptionalParams, @@ -154,11 +155,18 @@ export class SecurityRulesImpl implements SecurityRules { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkSecurityGroupName, @@ -166,9 +174,9 @@ export class SecurityRulesImpl implements SecurityRules { options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -267,11 +275,18 @@ export class SecurityRulesImpl implements SecurityRules { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, networkSecurityGroupName, @@ -280,9 +295,9 @@ export class SecurityRulesImpl implements SecurityRules { options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/serviceEndpointPolicies.ts b/test/smoke/generated/network-resource-manager/src/operations/serviceEndpointPolicies.ts index 789b6ef501..d1cf76b1de 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/serviceEndpointPolicies.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/serviceEndpointPolicies.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ServiceEndpointPolicy, ServiceEndpointPoliciesListNextOptionalParams, @@ -183,16 +184,23 @@ export class ServiceEndpointPoliciesImpl implements ServiceEndpointPolicies { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serviceEndpointPolicyName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -278,16 +286,23 @@ export class ServiceEndpointPoliciesImpl implements ServiceEndpointPolicies { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serviceEndpointPolicyName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/serviceEndpointPolicyDefinitions.ts b/test/smoke/generated/network-resource-manager/src/operations/serviceEndpointPolicyDefinitions.ts index b29288edf7..536a41b16f 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/serviceEndpointPolicyDefinitions.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/serviceEndpointPolicyDefinitions.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ServiceEndpointPolicyDefinition, ServiceEndpointPolicyDefinitionsListByResourceGroupNextOptionalParams, @@ -155,11 +156,18 @@ export class ServiceEndpointPolicyDefinitionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serviceEndpointPolicyName, @@ -167,9 +175,9 @@ export class ServiceEndpointPolicyDefinitionsImpl options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -270,11 +278,18 @@ export class ServiceEndpointPolicyDefinitionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serviceEndpointPolicyName, @@ -283,9 +298,9 @@ export class ServiceEndpointPolicyDefinitionsImpl options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/subnets.ts b/test/smoke/generated/network-resource-manager/src/operations/subnets.ts index 54eab99c34..5aba3839cb 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/subnets.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/subnets.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { Subnet, SubnetsListNextOptionalParams, @@ -158,16 +159,23 @@ export class SubnetsImpl implements Subnets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkName, subnetName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -260,11 +268,18 @@ export class SubnetsImpl implements Subnets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkName, @@ -273,9 +288,9 @@ export class SubnetsImpl implements Subnets { options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -348,11 +363,18 @@ export class SubnetsImpl implements Subnets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkName, @@ -361,9 +383,9 @@ export class SubnetsImpl implements Subnets { options }, prepareNetworkPoliciesOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -437,11 +459,18 @@ export class SubnetsImpl implements Subnets { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkName, @@ -450,9 +479,9 @@ export class SubnetsImpl implements Subnets { options }, unprepareNetworkPoliciesOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/virtualHubRouteTableV2S.ts b/test/smoke/generated/network-resource-manager/src/operations/virtualHubRouteTableV2S.ts index e846067fd8..1b783ed03a 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/virtualHubRouteTableV2S.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/virtualHubRouteTableV2S.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualHubRouteTableV2, VirtualHubRouteTableV2SListNextOptionalParams, @@ -170,11 +171,18 @@ export class VirtualHubRouteTableV2SImpl implements VirtualHubRouteTableV2S { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualHubName, @@ -183,9 +191,9 @@ export class VirtualHubRouteTableV2SImpl implements VirtualHubRouteTableV2S { options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -257,16 +265,23 @@ export class VirtualHubRouteTableV2SImpl implements VirtualHubRouteTableV2S { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualHubName, routeTableName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/virtualHubs.ts b/test/smoke/generated/network-resource-manager/src/operations/virtualHubs.ts index d0a1bd9e39..406fc7ea53 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/virtualHubs.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/virtualHubs.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualHub, VirtualHubsListByResourceGroupNextOptionalParams, @@ -207,16 +208,23 @@ export class VirtualHubsImpl implements VirtualHubs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualHubName, virtualHubParameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -300,16 +308,23 @@ export class VirtualHubsImpl implements VirtualHubs { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualHubName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/virtualNetworkGatewayConnections.ts b/test/smoke/generated/network-resource-manager/src/operations/virtualNetworkGatewayConnections.ts index d9464bd8b4..f6c5f20a82 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/virtualNetworkGatewayConnections.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/virtualNetworkGatewayConnections.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualNetworkGatewayConnection, VirtualNetworkGatewayConnectionsListNextOptionalParams, @@ -159,11 +160,18 @@ export class VirtualNetworkGatewayConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayConnectionName, @@ -171,9 +179,9 @@ export class VirtualNetworkGatewayConnectionsImpl options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -256,16 +264,23 @@ export class VirtualNetworkGatewayConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayConnectionName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -334,11 +349,18 @@ export class VirtualNetworkGatewayConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayConnectionName, @@ -346,9 +368,9 @@ export class VirtualNetworkGatewayConnectionsImpl options }, updateTagsOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -423,11 +445,18 @@ export class VirtualNetworkGatewayConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayConnectionName, @@ -435,9 +464,9 @@ export class VirtualNetworkGatewayConnectionsImpl options }, setSharedKeyOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -552,11 +581,18 @@ export class VirtualNetworkGatewayConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayConnectionName, @@ -564,9 +600,9 @@ export class VirtualNetworkGatewayConnectionsImpl options }, resetSharedKeyOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -642,16 +678,23 @@ export class VirtualNetworkGatewayConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayConnectionName, options }, startPacketCaptureOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -723,11 +766,18 @@ export class VirtualNetworkGatewayConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayConnectionName, @@ -735,9 +785,9 @@ export class VirtualNetworkGatewayConnectionsImpl options }, stopPacketCaptureOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/virtualNetworkGateways.ts b/test/smoke/generated/network-resource-manager/src/operations/virtualNetworkGateways.ts index cc659f08f6..2321f6d67c 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/virtualNetworkGateways.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/virtualNetworkGateways.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualNetworkGateway, VirtualNetworkGatewaysListNextOptionalParams, @@ -252,16 +253,23 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -343,16 +351,23 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -421,16 +436,23 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayName, parameters, options }, updateTagsOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -532,16 +554,23 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayName, options }, resetOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -603,16 +632,23 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayName, options }, resetVpnClientSharedKeyOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -685,16 +721,23 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayName, parameters, options }, generatevpnclientpackageOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -770,16 +813,23 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayName, parameters, options }, generateVpnProfileOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -852,16 +902,23 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayName, options }, getVpnProfilePackageUrlOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -929,16 +986,23 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayName, options }, getBgpPeerStatusOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1023,16 +1087,23 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayName, options }, getLearnedRoutesOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1103,16 +1174,23 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayName, peer, options }, getAdvertisedRoutesOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1189,11 +1267,18 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayName, @@ -1201,9 +1286,9 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { options }, setVpnclientIpsecParametersOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1279,16 +1364,23 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayName, options }, getVpnclientIpsecParametersOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1382,16 +1474,23 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayName, options }, startPacketCaptureOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1461,16 +1560,23 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayName, parameters, options }, stopPacketCaptureOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1544,16 +1650,23 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayName, options }, getVpnclientConnectionHealthOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1618,16 +1731,23 @@ export class VirtualNetworkGatewaysImpl implements VirtualNetworkGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkGatewayName, request, options }, disconnectVirtualNetworkGatewayVpnConnectionsOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/virtualNetworkPeerings.ts b/test/smoke/generated/network-resource-manager/src/operations/virtualNetworkPeerings.ts index 3e60f86dc7..c3257f344e 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/virtualNetworkPeerings.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/virtualNetworkPeerings.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualNetworkPeering, VirtualNetworkPeeringsListNextOptionalParams, @@ -154,11 +155,18 @@ export class VirtualNetworkPeeringsImpl implements VirtualNetworkPeerings { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkName, @@ -166,9 +174,9 @@ export class VirtualNetworkPeeringsImpl implements VirtualNetworkPeerings { options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -267,11 +275,18 @@ export class VirtualNetworkPeeringsImpl implements VirtualNetworkPeerings { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkName, @@ -280,9 +295,9 @@ export class VirtualNetworkPeeringsImpl implements VirtualNetworkPeerings { options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/virtualNetworkTaps.ts b/test/smoke/generated/network-resource-manager/src/operations/virtualNetworkTaps.ts index 62238e4a8f..790670856d 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/virtualNetworkTaps.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/virtualNetworkTaps.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualNetworkTap, VirtualNetworkTapsListAllNextOptionalParams, @@ -183,16 +184,23 @@ export class VirtualNetworkTapsImpl implements VirtualNetworkTaps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, tapName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -274,16 +282,23 @@ export class VirtualNetworkTapsImpl implements VirtualNetworkTaps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, tapName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/virtualNetworks.ts b/test/smoke/generated/network-resource-manager/src/operations/virtualNetworks.ts index 3bbdbc9e04..0bf273a57e 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/virtualNetworks.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/virtualNetworks.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualNetwork, VirtualNetworksListAllNextOptionalParams, @@ -258,16 +259,23 @@ export class VirtualNetworksImpl implements VirtualNetworks { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -353,16 +361,23 @@ export class VirtualNetworksImpl implements VirtualNetworks { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualNetworkName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/virtualRouterPeerings.ts b/test/smoke/generated/network-resource-manager/src/operations/virtualRouterPeerings.ts index c523e1aa39..3e00452caa 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/virtualRouterPeerings.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/virtualRouterPeerings.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualRouterPeering, VirtualRouterPeeringsListNextOptionalParams, @@ -154,16 +155,23 @@ export class VirtualRouterPeeringsImpl implements VirtualRouterPeerings { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualRouterName, peeringName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -256,11 +264,18 @@ export class VirtualRouterPeeringsImpl implements VirtualRouterPeerings { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualRouterName, @@ -269,9 +284,9 @@ export class VirtualRouterPeeringsImpl implements VirtualRouterPeerings { options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/virtualRouters.ts b/test/smoke/generated/network-resource-manager/src/operations/virtualRouters.ts index d362b8446d..3119655ba9 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/virtualRouters.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/virtualRouters.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualRouter, VirtualRoutersListByResourceGroupNextOptionalParams, @@ -180,16 +181,23 @@ export class VirtualRoutersImpl implements VirtualRouters { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualRouterName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -275,16 +283,23 @@ export class VirtualRoutersImpl implements VirtualRouters { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualRouterName, parameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/virtualWans.ts b/test/smoke/generated/network-resource-manager/src/operations/virtualWans.ts index 5f27b2d266..c6f06def36 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/virtualWans.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/virtualWans.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualWAN, VirtualWansListByResourceGroupNextOptionalParams, @@ -207,16 +208,23 @@ export class VirtualWansImpl implements VirtualWans { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualWANName, wANParameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -300,16 +308,23 @@ export class VirtualWansImpl implements VirtualWans { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualWANName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/vpnConnections.ts b/test/smoke/generated/network-resource-manager/src/operations/vpnConnections.ts index dec45be6f3..7e228e7b61 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/vpnConnections.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/vpnConnections.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VpnConnection, VpnConnectionsListByVpnGatewayNextOptionalParams, @@ -181,11 +182,18 @@ export class VpnConnectionsImpl implements VpnConnections { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, gatewayName, @@ -194,9 +202,9 @@ export class VpnConnectionsImpl implements VpnConnections { options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -267,16 +275,23 @@ export class VpnConnectionsImpl implements VpnConnections { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, gatewayName, connectionName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/vpnGateways.ts b/test/smoke/generated/network-resource-manager/src/operations/vpnGateways.ts index 770fcf133d..68f9db83ff 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/vpnGateways.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/vpnGateways.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VpnGateway, VpnGatewaysListByResourceGroupNextOptionalParams, @@ -209,16 +210,23 @@ export class VpnGatewaysImpl implements VpnGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, gatewayName, vpnGatewayParameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -302,16 +310,23 @@ export class VpnGatewaysImpl implements VpnGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, gatewayName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -378,16 +393,23 @@ export class VpnGatewaysImpl implements VpnGateways { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, gatewayName, options }, resetOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/vpnServerConfigurations.ts b/test/smoke/generated/network-resource-manager/src/operations/vpnServerConfigurations.ts index 8122b22749..a3b6fa5811 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/vpnServerConfigurations.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/vpnServerConfigurations.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VpnServerConfiguration, VpnServerConfigurationsListByResourceGroupNextOptionalParams, @@ -209,11 +210,18 @@ export class VpnServerConfigurationsImpl implements VpnServerConfigurations { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vpnServerConfigurationName, @@ -221,9 +229,9 @@ export class VpnServerConfigurationsImpl implements VpnServerConfigurations { options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -314,16 +322,23 @@ export class VpnServerConfigurationsImpl implements VpnServerConfigurations { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vpnServerConfigurationName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/vpnServerConfigurationsAssociatedWithVirtualWan.ts b/test/smoke/generated/network-resource-manager/src/operations/vpnServerConfigurationsAssociatedWithVirtualWan.ts index 8ce8714907..b3da8949d6 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/vpnServerConfigurationsAssociatedWithVirtualWan.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/vpnServerConfigurationsAssociatedWithVirtualWan.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VpnServerConfigurationsAssociatedWithVirtualWanListOptionalParams, VpnServerConfigurationsAssociatedWithVirtualWanListResponse @@ -78,16 +79,23 @@ export class VpnServerConfigurationsAssociatedWithVirtualWanImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualWANName, options }, listOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/vpnSites.ts b/test/smoke/generated/network-resource-manager/src/operations/vpnSites.ts index c3ac8e15ab..c2c56bbce8 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/vpnSites.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/vpnSites.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VpnSite, VpnSitesListByResourceGroupNextOptionalParams, @@ -207,16 +208,23 @@ export class VpnSitesImpl implements VpnSites { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vpnSiteName, vpnSiteParameters, options }, createOrUpdateOperationSpec, - sendOperation, "azure-async-operation" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -300,16 +308,23 @@ export class VpnSitesImpl implements VpnSites { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, vpnSiteName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/vpnSitesConfiguration.ts b/test/smoke/generated/network-resource-manager/src/operations/vpnSitesConfiguration.ts index 6e1566cc14..718e4cb290 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/vpnSitesConfiguration.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/vpnSitesConfiguration.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { GetVpnSitesConfigurationRequest, VpnSitesConfigurationDownloadOptionalParams @@ -72,16 +73,23 @@ export class VpnSitesConfigurationImpl implements VpnSitesConfiguration { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualWANName, request, options }, downloadOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/network-resource-manager/src/operations/webApplicationFirewallPolicies.ts b/test/smoke/generated/network-resource-manager/src/operations/webApplicationFirewallPolicies.ts index ac7f8df77e..9a064ef287 100644 --- a/test/smoke/generated/network-resource-manager/src/operations/webApplicationFirewallPolicies.ts +++ b/test/smoke/generated/network-resource-manager/src/operations/webApplicationFirewallPolicies.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { NetworkManagementClientContext } from "../networkManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { WebApplicationFirewallPolicy, WebApplicationFirewallPoliciesListNextOptionalParams, @@ -239,16 +240,23 @@ export class WebApplicationFirewallPoliciesImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, policyName, options }, deleteOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/coreClientLro.ts b/test/smoke/generated/sql-resource-manager/src/coreClientLro.ts new file mode 100644 index 0000000000..d793a24458 --- /dev/null +++ b/test/smoke/generated/sql-resource-manager/src/coreClientLro.ts @@ -0,0 +1,323 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + OperationArguments, + OperationSpec, + OperationResponseMap, + FullOperationResponse +} from "@azure/core-client"; +import { + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + createGetLroStatusFromResponse, + RawResponse +} from "./lro"; + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +export const terminalStates = successStates.concat(failureStates); + +export type SendOperationFn = ( + args: OperationArguments, + spec: OperationSpec +) => Promise>; + +export function createPollingMethod( + sendOperationFn: SendOperationFn, + GetLroStatusFromResponse: GetLroStatusFromResponse, + args: OperationArguments, + spec: OperationSpec, + mode?: LroMode +): (path?: string) => Promise> { + /** + * Polling calls will always return a status object i.e. {"status": "success"} + * these intermediate responses are not described in the swagger so we need to + * pass custom mappers at runtime. + * This function replaces all the existing mappers to be able to deserialize a status object + * @param responses Original set of responses defined in the operation + */ + function getCompositeMappers(responses: { + [responseCode: string]: OperationResponseMap; + }): { + [responseCode: string]: OperationResponseMap; + } { + return Object.keys(responses).reduce((acc, statusCode) => { + return { + ...acc, + [statusCode]: { + ...responses[statusCode], + bodyMapper: { + type: { + name: "Composite", + modelProperties: { + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } + } + } + }; + }, {} as { [responseCode: string]: OperationResponseMap }); + } + let response: LroStatus | undefined = undefined; + const customerCallback = args?.options?.onResponse; + const updatedArgs = { + ...args, + options: { + ...args.options, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ): void => { + response = GetLroStatusFromResponse( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse as TResult + ); + if (response.done) { + customerCallback?.(rawResponse, flatResponse); + } + } + } + }; + // Make sure we don't send any body to the get request + const { requestBody, responses, ...restSpec } = spec; + if (mode === "AzureAsync") { + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: getCompositeMappers(responses), + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; + } + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: responses, + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; +} + +/** + * We need to selectively deserialize our responses, only deserializing if we + * are in a final Lro response, not deserializing any polling non-terminal responses + */ +export function shouldDeserializeLro(lroResourceLocationConfig?: string) { + let initialOperationInfo: LroResponseInfo | undefined; + let isInitialRequest = true; + + return (response: FullOperationResponse) => { + if (response.status < 200 || response.status >= 300) { + return true; + } + + if (!initialOperationInfo) { + initialOperationInfo = getLroData(response); + } else { + isInitialRequest = false; + } + + if ( + initialOperationInfo.azureAsyncOperation || + initialOperationInfo.operationLocation + ) { + return ( + !isInitialRequest && + isAsyncOperationFinalResponse( + response, + initialOperationInfo, + lroResourceLocationConfig + ) + ); + } + + if (initialOperationInfo.location) { + return isLocationFinalResponse(response); + } + + if (initialOperationInfo.requestMethod === "PUT") { + return isBodyPollingFinalResponse(response); + } + + return true; + }; +} + +function isAsyncOperationFinalResponse( + response: FullOperationResponse, + initialOperationInfo: LroResponseInfo, + lroResourceLocationConfig?: string +): boolean { + const status: string = response.parsedBody?.status || "Succeeded"; + if (!terminalStates.includes(status.toLowerCase())) { + return false; + } + + if (initialOperationInfo.requestMethod === "DELETE") { + return true; + } + + if ( + initialOperationInfo.requestMethod === "PUT" && + lroResourceLocationConfig && + lroResourceLocationConfig.toLowerCase() === "azure-asyncoperation" + ) { + return true; + } + + if ( + initialOperationInfo.requestMethod !== "PUT" && + !initialOperationInfo.location + ) { + return true; + } + + return false; +} + +function isLocationFinalResponse(response: FullOperationResponse): boolean { + return response.status !== 202; +} + +function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { + const provisioningState: string = + response.parsedBody?.properties?.provisioningState || "Succeeded"; + + if (terminalStates.includes(provisioningState.toLowerCase())) { + return true; + } + + return false; +} + +interface LroResponseInfo { + requestMethod: string; + azureAsyncOperation?: string; + operationLocation?: string; + location?: string; +} + +function getLroData(result: FullOperationResponse): LroResponseInfo { + return { + azureAsyncOperation: result.headers.get("azure-asyncoperation"), + operationLocation: result.headers.get("operation-location"), + location: result.headers.get("location"), + requestMethod: result.request.method + }; +} + +export function getSpecPath(spec: OperationSpec): string { + if (spec.path) { + return spec.path; + } else { + throw Error("Bad spec: request path is not found!"); + } +} + +export class CoreClientLro implements LongRunningOperation { + constructor( + private sendOperationFn: SendOperationFn, + private args: OperationArguments, + private spec: OperationSpec, + private lroResourceLocationConfig?: LroResourceLocationConfig, + public requestPath: string = spec.path!, + public requestMethod: string = spec.httpMethod + ) {} + public async sendInitialRequest( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ): Promise> { + const { onResponse, ...restOptions } = this.args.options || {}; + return this.sendOperationFn( + { + ...this.args, + options: { + ...restOptions, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ) => { + const isCompleted = initializeState( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse + ); + if (isCompleted) { + onResponse?.(rawResponse, flatResponse); + } + } + } + }, + this.spec + ); + } + + public async sendPollRequest( + config: LroConfig, + path: string + ): Promise> { + const getLroStatusFromResponse = createGetLroStatusFromResponse( + this, + config, + this.lroResourceLocationConfig + ); + return createPollingMethod( + this.sendOperationFn, + getLroStatusFromResponse, + this.args, + this.spec, + config.mode + )(path); + } + + public async retrieveAzureAsyncResource( + path?: string + ): Promise> { + const updatedArgs = { ...this.args }; + if (updatedArgs.options) { + (updatedArgs.options as any).shouldDeserialize = true; + } + return createPollingMethod( + this.sendOperationFn, + (rawResponse, flatResponse) => ({ + rawResponse, + flatResponse, + done: true + }), + updatedArgs, + this.spec + )(path); + } +} diff --git a/test/smoke/generated/sql-resource-manager/src/lro/azureAsyncPolling.ts b/test/smoke/generated/sql-resource-manager/src/lro/azureAsyncPolling.ts index 0d63c54f60..725578a692 100644 --- a/test/smoke/generated/sql-resource-manager/src/lro/azureAsyncPolling.ts +++ b/test/smoke/generated/sql-resource-manager/src/lro/azureAsyncPolling.ts @@ -7,39 +7,61 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { FinalStateVia, LROResult } from "./models"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroResourceLocationConfig, + LongRunningOperation, + LroBody, + LroResponse, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getResponseStatus(rawResponse: FullOperationResponse): string { - const { status } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getResponseStatus(rawResponse: RawResponse): string { + const { status } = (rawResponse.body as LroBody) ?? {}; return status?.toLowerCase() ?? "succeeded"; } -function isAzureAsyncPollingDone(rawResponse: FullOperationResponse) { +function isAzureAsyncPollingDone(rawResponse: RawResponse): boolean { const state = getResponseStatus(rawResponse); - if (failureStates.includes(state)) { + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { throw new Error(`Operation status: ${state}`); } return successStates.includes(state); } +async function sendFinalRequest( + lro: LongRunningOperation, + lroResourceLocationConfig?: LroResourceLocationConfig, + resourceLocation?: string +): Promise | undefined> { + switch (lroResourceLocationConfig) { + case "original-uri": + return lro.retrieveAzureAsyncResource(); + case "azure-async-operation": + return Promise.resolve(undefined); + case "location": + default: + return lro.retrieveAzureAsyncResource(resourceLocation); + } +} + export function processAzureAsyncOperationResult( - restrieveResource: (path?: string) => Promise>, + lro: LongRunningOperation, resourceLocation?: string, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { + lroResourceLocationConfig?: LroResourceLocationConfig +): (rawResponse: RawResponse, flatResponse: TResult) => LroStatus { return ( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult - ): LROState => { + ): LroStatus => { if (isAzureAsyncPollingDone(rawResponse)) { if (resourceLocation === undefined) { return { rawResponse, flatResponse, done: true }; @@ -49,20 +71,11 @@ export function processAzureAsyncOperationResult( flatResponse, done: false, next: async () => { - async function sendFinalRequest(): Promise< - LROResult | undefined - > { - switch (finalStateVia) { - case "original-uri": - return restrieveResource(); - case "azure-async-operation": - return Promise.resolve(undefined); - case "location": - default: - return restrieveResource(resourceLocation); - } - } - const finalResponse = await sendFinalRequest(); + const finalResponse = await sendFinalRequest( + lro, + lroResourceLocationConfig, + resourceLocation + ); return { ...(finalResponse ?? { rawResponse, diff --git a/test/smoke/generated/sql-resource-manager/src/lro/bodyPolling.ts b/test/smoke/generated/sql-resource-manager/src/lro/bodyPolling.ts index 269d8e6799..b1c87f8bc8 100644 --- a/test/smoke/generated/sql-resource-manager/src/lro/bodyPolling.ts +++ b/test/smoke/generated/sql-resource-manager/src/lro/bodyPolling.ts @@ -7,24 +7,33 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroBody, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getProvisioningState(rawResponse: FullOperationResponse): string { - const { properties, provisioningState } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getProvisioningState(rawResponse: RawResponse): string { + const { properties, provisioningState } = (rawResponse.body as LroBody) ?? {}; const state: string | undefined = properties?.provisioningState ?? provisioningState; return state?.toLowerCase() ?? "succeeded"; } -export function isBodyPollingDone(rawResponse: FullOperationResponse) { +export function isBodyPollingDone(rawResponse: RawResponse): boolean { const state = getProvisioningState(rawResponse); - if (failureStates.includes(state)) { - throw new Error(`Provisioning state: ${state}`); + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { + throw new Error( + `The long running operation has failed. The provisioning state: ${state}.` + ); } return successStates.includes(state); } @@ -34,9 +43,9 @@ export function isBodyPollingDone(rawResponse: FullOperationResponse) { * from the result to determine the current operation state */ export function processBodyPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/sql-resource-manager/src/lro/index.ts b/test/smoke/generated/sql-resource-manager/src/lro/index.ts index 85c2187669..20df608fc8 100644 --- a/test/smoke/generated/sql-resource-manager/src/lro/index.ts +++ b/test/smoke/generated/sql-resource-manager/src/lro/index.ts @@ -6,5 +6,21 @@ * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ -export { shouldDeserializeLRO } from "./requestUtils"; -export { LROPoller } from "./lroPoller"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { LroEngine } from "./lroEngine"; +export { createGetLroStatusFromResponse } from "./stateMachine"; +export { + LroResourceLocationConfig, + GetLroStatusFromResponse, + RawResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + LroTerminalState, + LroInProgressState, + LroEngineOptions +} from "./models"; diff --git a/test/smoke/generated/sql-resource-manager/src/lro/locationPolling.ts b/test/smoke/generated/sql-resource-manager/src/lro/locationPolling.ts index 6fef619384..9d1aadfbde 100644 --- a/test/smoke/generated/sql-resource-manager/src/lro/locationPolling.ts +++ b/test/smoke/generated/sql-resource-manager/src/lro/locationPolling.ts @@ -7,23 +7,21 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function isLocationPollingDone(rawResponse: FullOperationResponse) { - const code = rawResponse.status; - if (![202, 200].includes(code)) { - throw new Error(`Operation failed`); - } - return code !== 202; +function isLocationPollingDone(rawResponse: RawResponse): boolean { + return ( + !isUnexpectedPollingResponse(rawResponse) && rawResponse.statusCode !== 202 + ); } export function processLocationPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/sql-resource-manager/src/lro/lroEngine.ts b/test/smoke/generated/sql-resource-manager/src/lro/lroEngine.ts new file mode 100644 index 0000000000..85cc15e609 --- /dev/null +++ b/test/smoke/generated/sql-resource-manager/src/lro/lroEngine.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Poller, PollOperationState } from "@azure/core-lro"; +import { + LongRunningOperation, + LroEngineOptions, + ResumablePollOperationState +} from "./models"; +import { GenericPollOperation } from "./operation"; + +/** + * The LRO Engine, a class that performs polling. + */ +export class LroEngine< + TResult, + TState extends PollOperationState +> extends Poller { + private intervalInMs: number; + + constructor(lro: LongRunningOperation, options?: LroEngineOptions) { + const { intervalInMs = 2000, resumeFrom } = options || {}; + function deserializeState( + resumeFrom: string + ): TState & ResumablePollOperationState { + try { + return JSON.parse(resumeFrom).state; + } catch (e) { + throw new Error( + `LroEngine: Unable to deserialize state: ${resumeFrom}` + ); + } + } + const state: TState & ResumablePollOperationState = resumeFrom + ? deserializeState(resumeFrom) + : ({} as any); + + const operation = new GenericPollOperation(state, lro); + super(operation); + + this.intervalInMs = intervalInMs; + operation.setPollerConfig(this as any); + } + + /** + * The method used by the poller to wait before attempting to update its operation. + */ + delay(): Promise { + return new Promise((resolve) => + setTimeout(() => resolve(), this.intervalInMs) + ); + } +} diff --git a/test/smoke/generated/sql-resource-manager/src/lro/lroPoller.ts b/test/smoke/generated/sql-resource-manager/src/lro/lroPoller.ts deleted file mode 100644 index cd1cd64fe8..0000000000 --- a/test/smoke/generated/sql-resource-manager/src/lro/lroPoller.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { Poller, PollOperationState } from "@azure/core-lro"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { FinalStateVia, SendOperationFn } from "./models"; -import { GenericPollOperation } from "./operation"; - -export interface LROPollerOptions { - /** - * Defines how much time the poller is going to wait before making a new request to the service. - */ - intervalInMs?: number; - /** - * A serialized poller which can be used to resume an existing paused Long-Running-Operation. - */ - resumeFrom?: string; -} - -export class LROPoller extends Poller< - PollOperationState, - TResult -> { - private intervalInMs: number; - - constructor( - { intervalInMs = 2000, resumeFrom }: LROPollerOptions, - initialOperationArguments: OperationArguments, - initialOperationSpec: OperationSpec, - sendOperation: SendOperationFn, - finalStateVia?: FinalStateVia - ) { - const state: PollOperationState = resumeFrom - ? JSON.parse(resumeFrom).state - : {}; - - const operation = new GenericPollOperation( - state, - initialOperationArguments, - initialOperationSpec, - sendOperation, - finalStateVia - ); - super(operation); - - this.intervalInMs = intervalInMs; - operation.setPollerConfig(this as any); - } - - /** - * The method used by the poller to wait before attempting to update its operation. - */ - delay(): Promise { - return new Promise((resolve) => - setTimeout(() => resolve(), this.intervalInMs) - ); - } -} diff --git a/test/smoke/generated/sql-resource-manager/src/lro/models.ts b/test/smoke/generated/sql-resource-manager/src/lro/models.ts index a4a5a5abd6..93c3437c8e 100644 --- a/test/smoke/generated/sql-resource-manager/src/lro/models.ts +++ b/test/smoke/generated/sql-resource-manager/src/lro/models.ts @@ -7,46 +7,167 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec -} from "@azure/core-client"; import { PollOperationState } from "@azure/core-lro"; -export type FinalStateVia = +/** + * Options for the LRO poller. + */ +export interface LroEngineOptions { + /** + * Defines how much time the poller is going to wait before making a new request to the service. + */ + intervalInMs?: number; + /** + * A serialized poller which can be used to resume an existing paused Long-Running-Operation. + */ + resumeFrom?: string; +} + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +/** + * The LRO states that signal that the LRO has completed. + */ +export const terminalStates = successStates.concat(failureStates); + +/** + * The potential location of the result of the LRO if specified by the LRO extension in the swagger. + */ +export type LroResourceLocationConfig = | "azure-async-operation" | "location" | "original-uri"; -export interface LROResult { +/** + * The type of a LRO response body. This is just a convenience type for checking the status of the operation. + */ + +export interface LroBody extends Record { + /** The status of the operation. */ + status?: string; + /** The state of the provisioning process */ + provisioningState?: string; + /** The properties of the provisioning process */ + properties?: { provisioningState?: string } & Record; +} + +/** + * Simple type of the raw response. + */ +export interface RawResponse { + /** The HTTP status code */ + statusCode: number; + /** A HttpHeaders collection in the response represented as a simple JSON object where all header names have been normalized to be lower-case. */ + headers: { + [headerName: string]: string; + }; + /** The parsed response body */ + body?: unknown; +} + +/** + * The type of the response of a LRO. + */ +export interface LroResponse { + /** The flattened response */ flatResponse: T; - rawResponse: FullOperationResponse; + /** The raw response */ + rawResponse: RawResponse; } -export type LROMode = "AzureAsync" | "Location" | "Body"; +/** The type of which LRO implementation being followed by a specific API. */ +export type LroMode = "AzureAsync" | "Location" | "Body"; -export interface LROConfig { - mode?: LROMode; +/** + * The configuration of a LRO to determine how to perform polling and checking whether the operation has completed. + */ +export interface LroConfig { + /** The LRO mode */ + mode?: LroMode; + /** The path of a provisioned resource */ resourceLocation?: string; } -export type SendOperationFn = ( - args: OperationArguments, - spec: OperationSpec -) => Promise>; - /** * Type of a polling operation state that can actually be resumed. */ export type ResumablePollOperationState = PollOperationState & { - initialRawResponse?: FullOperationResponse; - config?: LROConfig; + initialRawResponse?: RawResponse; + config?: LroConfig; pollingURL?: string; }; export interface PollerConfig { intervalInMs: number; } + +/** + * The type of a terminal state of an LRO. + */ +export interface LroTerminalState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: true; +} + +/** + * The type of an in-progress state of an LRO. + */ +export interface LroInProgressState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: false; + /** + * The request to be sent next if it is different from the standard polling one. + * Notice that it will disregard any polling URLs provided to it. + */ + next?: () => Promise>; +} + +/** + * The type of an LRO state which is a tagged union of terminal and in-progress states. + */ +export type LroStatus = LroTerminalState | LroInProgressState; + +/** + * The type of the getLROStatusFromResponse method. It takes the response as input and returns along the response whether the operation has finished. + */ +export type GetLroStatusFromResponse = ( + rawResponse: RawResponse, + flatResponse: T +) => LroStatus; + +/** + * Description of a long running operation. + */ +export interface LongRunningOperation { + /** + * The request path. + */ + requestPath: string; + /** + * The HTTP request method. + */ + requestMethod: string; + /** + * A function that can be used to send initial request to the service. + */ + sendInitialRequest: ( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ) => Promise>; + /** + * A function that can be used to poll for the current status of a long running operation. + */ + sendPollRequest: (config: LroConfig, path: string) => Promise>; + /** + * A function that can be used to retrieve the provisioned azure resource. + */ + retrieveAzureAsyncResource: (path?: string) => Promise>; +} diff --git a/test/smoke/generated/sql-resource-manager/src/lro/operation.ts b/test/smoke/generated/sql-resource-manager/src/lro/operation.ts index 801d03e720..3ea7b76d89 100644 --- a/test/smoke/generated/sql-resource-manager/src/lro/operation.ts +++ b/test/smoke/generated/sql-resource-manager/src/lro/operation.ts @@ -7,36 +7,34 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. import { AbortSignalLike } from "@azure/abort-controller"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { PollOperation, PollOperationState } from "@azure/core-lro"; +import { PollOperationState, PollOperation } from "@azure/core-lro"; import { - FinalStateVia, PollerConfig, ResumablePollOperationState, - SendOperationFn + LongRunningOperation, + LroStatus } from "./models"; -import { getPollingURL } from "./requestUtils"; -import { createGetLROState, initializeState, LROState } from "./stateMachine"; +import { getPollingUrl } from "./requestUtils"; +import { createInitializeState, createPollForLROStatus } from "./stateMachine"; -export class GenericPollOperation - implements PollOperation, TResult> { - private getLROState?: ( +export class GenericPollOperation< + TResult, + TState extends PollOperationState +> implements PollOperation { + private getLROStatusFromResponse?: ( pollingURL: string, pollerConfig: PollerConfig - ) => Promise>; + ) => Promise>; private pollerConfig?: PollerConfig; constructor( - public state: PollOperationState, - private initialOperationArguments: OperationArguments, - private initialOperationSpec: OperationSpec, - private sendOperation: SendOperationFn, - private finalStateVia?: FinalStateVia + public state: TState & ResumablePollOperationState, + private lro: LongRunningOperation ) {} - public setPollerConfig(pollerConfig: PollerConfig) { + public setPollerConfig(pollerConfig: PollerConfig): void { this.pollerConfig = pollerConfig; } @@ -57,45 +55,36 @@ export class GenericPollOperation */ async update(options?: { abortSignal?: AbortSignalLike | undefined; - fireProgress?: ((state: PollOperationState) => void) | undefined; - }): Promise, TResult>> { - const state = this.state as ResumablePollOperationState; - const { onResponse, ...restOptions } = - this.initialOperationArguments.options || {}; + fireProgress?: ((state: TState) => void) | undefined; + }): Promise> { + const state = this.state; if (!state.isStarted) { - await this.sendOperation( - { - ...this.initialOperationArguments, - options: { - ...restOptions, - onResponse: initializeState( - state, - this.initialOperationSpec, - onResponse - ) - } - }, - this.initialOperationSpec + const initializeState = createInitializeState( + state, + this.lro.requestPath, + this.lro.requestMethod ); + await this.lro.sendInitialRequest(initializeState); } if (!state.isCompleted) { - if (this.getLROState === undefined) { + if (this.getLROStatusFromResponse === undefined) { if (state.config === undefined) { - throw new Error("Bad state: LRO mode is undefined"); + throw new Error( + "Bad state: LRO mode is undefined. Please check if the serialized state is well-formed." + ); } - this.getLROState = createGetLROState( - this.sendOperation, - this.initialOperationArguments, - this.initialOperationSpec, - state.config, - this.finalStateVia + this.getLROStatusFromResponse = createPollForLROStatus( + this.lro, + state.config ); } if (state.pollingURL === undefined) { - throw new Error("Bad state: polling URL is undefined"); + throw new Error( + "Bad state: polling URL is undefined. Please check if the serialized state is well-formed." + ); } - const currentState = await this.getLROState( + const currentState = await this.getLROStatusFromResponse( state.pollingURL, this.pollerConfig! ); @@ -103,20 +92,19 @@ export class GenericPollOperation state.result = currentState.flatResponse; state.isCompleted = true; } else { - this.getLROState = currentState.next ?? this.getLROState; - state.pollingURL = getPollingURL( + this.getLROStatusFromResponse = + currentState.next ?? this.getLROStatusFromResponse; + state.pollingURL = getPollingUrl( currentState.rawResponse, state.pollingURL ); } } - if (options?.fireProgress !== undefined) { - options.fireProgress(state); - } + options?.fireProgress?.(state); return this; } - async cancel(): Promise, TResult>> { + async cancel(): Promise> { this.state.isCancelled = true; return this; } diff --git a/test/smoke/generated/sql-resource-manager/src/lro/passthrough.ts b/test/smoke/generated/sql-resource-manager/src/lro/passthrough.ts index 64c10380c1..ae7f87d384 100644 --- a/test/smoke/generated/sql-resource-manager/src/lro/passthrough.ts +++ b/test/smoke/generated/sql-resource-manager/src/lro/passthrough.ts @@ -7,15 +7,14 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; export function processPassthroughOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/sql-resource-manager/src/lro/pollingMethod.ts b/test/smoke/generated/sql-resource-manager/src/lro/pollingMethod.ts deleted file mode 100644 index cb6482bbde..0000000000 --- a/test/smoke/generated/sql-resource-manager/src/lro/pollingMethod.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - OperationArguments, - OperationSpec, - OperationResponseMap -} from "@azure/core-client"; -import { LROMode, LROResult, SendOperationFn } from "./models"; - -export function createPollingMethod( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - mode?: LROMode -): (path?: string) => Promise> { - /** - * Polling calls will always return a status object i.e. {"status": "success"} - * these intermediate responses are not described in the swagger so we need to - * pass custom mappers at runtime. - * This function replaces all the existing mappers to be able to deserialize a status object - * @param responses Original set of responses defined in the operation - */ - function getCompositeMappers(responses: { - [responseCode: string]: OperationResponseMap; - }): { - [responseCode: string]: OperationResponseMap; - } { - return Object.keys(responses).reduce((acc, statusCode) => { - return { - ...acc, - [statusCode]: { - ...responses[statusCode], - bodyMapper: { - type: { - name: "Composite", - modelProperties: { - status: { - serializedName: "status", - type: { - name: "String" - } - } - } - } - } - } - }; - }, {} as { [responseCode: string]: OperationResponseMap }); - } - // Make sure we don't send any body to the get request - const { requestBody, responses, ...restSpec } = spec; - if (mode === "AzureAsync") { - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: getCompositeMappers(responses), - httpMethod: "GET", - ...(path && { path }) - }); - }; - } - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: responses, - httpMethod: "GET", - ...(path && { path }) - }); - }; -} - -export function createRetrieveAzureAsyncResource( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec -): (path?: string) => Promise> { - const updatedArgs = { ...args }; - if (updatedArgs.options) { - (updatedArgs.options as any).shouldDeserialize = true; - } - return createPollingMethod(sendOperationFn, updatedArgs, spec); -} diff --git a/test/smoke/generated/sql-resource-manager/src/lro/requestUtils.ts b/test/smoke/generated/sql-resource-manager/src/lro/requestUtils.ts index 9162f66339..40d993686f 100644 --- a/test/smoke/generated/sql-resource-manager/src/lro/requestUtils.ts +++ b/test/smoke/generated/sql-resource-manager/src/lro/requestUtils.ts @@ -7,119 +7,9 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse, OperationSpec } from "@azure/core-client"; -import { LROConfig } from "./models"; -import { terminalStates } from "./stateMachine"; - -/** - * We need to selectively deserialize our responses, only deserializing if we - * are in a final LRO response, not deserializing any polling non-terminal responses - */ -export function shouldDeserializeLRO(finalStateVia?: string) { - let initialOperationInfo: LROResponseInfo | undefined; - let isInitialRequest = true; - - return (response: FullOperationResponse) => { - if (response.status < 200 || response.status >= 300) { - return true; - } - - if (!initialOperationInfo) { - initialOperationInfo = getLROData(response); - } else { - isInitialRequest = false; - } - - if ( - initialOperationInfo.azureAsyncOperation || - initialOperationInfo.operationLocation - ) { - return ( - !isInitialRequest && - isAsyncOperationFinalResponse( - response, - initialOperationInfo, - finalStateVia - ) - ); - } - - if (initialOperationInfo.location) { - return isLocationFinalResponse(response); - } - - if (initialOperationInfo.requestMethod === "PUT") { - return isBodyPollingFinalResponse(response); - } - - return true; - }; -} - -function isAsyncOperationFinalResponse( - response: FullOperationResponse, - initialOperationInfo: LROResponseInfo, - finalStateVia?: string -): boolean { - const status: string = response.parsedBody?.status || "Succeeded"; - if (!terminalStates.includes(status.toLowerCase())) { - return false; - } - - if (initialOperationInfo.requestMethod === "DELETE") { - return true; - } - - if ( - initialOperationInfo.requestMethod === "PUT" && - finalStateVia && - finalStateVia.toLowerCase() === "azure-asyncoperation" - ) { - return true; - } - - if ( - initialOperationInfo.requestMethod !== "PUT" && - !initialOperationInfo.location - ) { - return true; - } - - return false; -} - -function isLocationFinalResponse(response: FullOperationResponse): boolean { - return response.status !== 202; -} - -function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { - const provisioningState: string = - response.parsedBody?.properties?.provisioningState || "Succeeded"; - - if (terminalStates.includes(provisioningState.toLowerCase())) { - return true; - } - - return false; -} - -interface LROResponseInfo { - requestMethod: string; - azureAsyncOperation?: string; - operationLocation?: string; - location?: string; -} - -function getLROData(result: FullOperationResponse): LROResponseInfo { - return { - azureAsyncOperation: result.headers.get("azure-asyncoperation"), - operationLocation: result.headers.get("operation-location"), - location: result.headers.get("location"), - requestMethod: result.request.method - }; -} +import { LroConfig, RawResponse } from "./models"; /** * Detects where the continuation token is and returns it. Notice that azure-asyncoperation @@ -127,45 +17,41 @@ function getLROData(result: FullOperationResponse): LROResponseInfo { * where both azure-asyncoperation and location could be present in the same response but * azure-asyncoperation should be the one to use for polling. */ -export function getPollingURL( - rawResponse: FullOperationResponse, +export function getPollingUrl( + rawResponse: RawResponse, defaultPath: string ): string { return ( - getAzureAsyncoperation(rawResponse) ?? + getAzureAsyncOperation(rawResponse) ?? getLocation(rawResponse) ?? getOperationLocation(rawResponse) ?? defaultPath ); } -function getLocation(rawResponse: FullOperationResponse): string | undefined { - return rawResponse.headers?.get("location"); +function getLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["location"]; } -function getOperationLocation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("operation-location"); +function getOperationLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["operation-location"]; } -function getAzureAsyncoperation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("azure-asyncoperation"); +function getAzureAsyncOperation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["azure-asyncoperation"]; } -export function inferLROMode( - spec: OperationSpec, - rawResponse: FullOperationResponse -): LROConfig { - const requestMethod = spec.httpMethod; - if (getAzureAsyncoperation(rawResponse) !== undefined) { +export function inferLroMode( + requestPath: string, + requestMethod: string, + rawResponse: RawResponse +): LroConfig { + if (getAzureAsyncOperation(rawResponse) !== undefined) { return { mode: "AzureAsync", resourceLocation: requestMethod === "PUT" - ? spec.path + ? requestPath : requestMethod === "POST" ? getLocation(rawResponse) : undefined @@ -185,10 +71,35 @@ export function inferLROMode( return {}; } -export function getSpecPath(spec: OperationSpec): string { - if (spec.path) { - return spec.path; - } else { - throw Error("Bad spec: request path is not found!"); +export class RestError extends Error { + public statusCode?: number; + constructor(message: string, statusCode: number) { + super(message); + this.name = "RestError"; + this.statusCode = statusCode; + + Object.setPrototypeOf(this, RestError.prototype); + } +} + +export function isUnexpectedInitialResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![203, 204, 202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} in the initial response. This may indicate a server issue.`, + code + ); } + return false; +} + +export function isUnexpectedPollingResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} while polling. This may indicate a server issue.`, + code + ); + } + return false; } diff --git a/test/smoke/generated/sql-resource-manager/src/lro/stateMachine.ts b/test/smoke/generated/sql-resource-manager/src/lro/stateMachine.ts index b2a69b5546..19a8f67470 100644 --- a/test/smoke/generated/sql-resource-manager/src/lro/stateMachine.ts +++ b/test/smoke/generated/sql-resource-manager/src/lro/stateMachine.ts @@ -7,14 +7,8 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec, - RawResponseCallback -} from "@azure/core-client"; import { processAzureAsyncOperationResult } from "./azureAsyncPolling"; import { isBodyPollingDone, @@ -22,73 +16,36 @@ import { } from "./bodyPolling"; import { processLocationPollingOperationResult } from "./locationPolling"; import { - FinalStateVia, - LROConfig, - LROResult, + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroStatus, PollerConfig, - ResumablePollOperationState, - SendOperationFn + RawResponse, + ResumablePollOperationState } from "./models"; import { processPassthroughOperationResult } from "./passthrough"; import { - createPollingMethod, - createRetrieveAzureAsyncResource -} from "./pollingMethod"; -import { getPollingURL, getSpecPath, inferLROMode } from "./requestUtils"; - -export const successStates = ["succeeded"]; -export const failureStates = ["failed", "canceled", "cancelled"]; -export const terminalStates = successStates.concat(failureStates); - -/** - * The type of a terminal state of an LRO. - */ -interface LROTerminalState extends LROResult { - /** - * Whether the operation has finished. - */ - done: true; -} - -/** - * The type of an in-progress state of an LRO. - */ -interface LROInProgressState extends LROResult { - /** - * Whether the operation has finished. - */ - done: false; - /** - * The request to be sent next if it is different from the standard polling one. - * Notice that it will disregard any polling URLs provided to it. - */ - next?: () => Promise>; -} - -/** - * The type of an LRO state which is a tagged union of terminal and in-progress states. - */ -export type LROState = LROTerminalState | LROInProgressState; + getPollingUrl, + inferLroMode, + isUnexpectedInitialResponse +} from "./requestUtils"; /** * creates a stepping function that maps an LRO state to another. */ -function createTransition( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { +export function createGetLroStatusFromResponse( + lroPrimitives: LongRunningOperation, + config: LroConfig, + lroResourceLocationConfig?: LroResourceLocationConfig +): GetLroStatusFromResponse { switch (config.mode) { case "AzureAsync": { return processAzureAsyncOperationResult( - createRetrieveAzureAsyncResource(sendOperationFn, args, spec), + lroPrimitives, config.resourceLocation, - finalStateVia + lroResourceLocationConfig ); } case "Location": { @@ -106,52 +63,20 @@ function createTransition( /** * Creates a polling operation that returns a LRO state. */ -export function createGetLROState( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia +export function createPollForLROStatus( + lroPrimitives: LongRunningOperation, + config: LroConfig ): ( pollingURL: string, pollerConfig: PollerConfig -) => Promise> { - const step = createTransition( - sendOperationFn, - args, - spec, - config, - finalStateVia - ); - const customerCallback = args?.options?.onResponse; - let response: LROState | undefined = undefined; - let retryAfter: string | undefined = undefined; - const poll = createPollingMethod( - sendOperationFn, - { - ...args, - options: { - ...args.options, - onResponse: ( - rawResponse: FullOperationResponse, - flatResponse: unknown - ): void => { - response = step(rawResponse, flatResponse as TResult); - retryAfter = rawResponse.headers.get("Retry-After"); - if (response.done) { - customerCallback?.(rawResponse, flatResponse); - } - } - } - }, - spec, - config.mode - ); +) => Promise> { return async ( path: string, pollerConfig: PollerConfig - ): Promise> => { - await poll(path); + ): Promise> => { + const response = await lroPrimitives.sendPollRequest(config, path); + const retryAfter: string | undefined = + response.rawResponse.headers["retry-after"]; if (retryAfter !== undefined) { const retryAfterInMs = parseInt(retryAfter); pollerConfig.intervalInMs = isNaN(retryAfterInMs) @@ -161,7 +86,7 @@ export function createGetLROState( ) : retryAfterInMs; } - return response!; + return response; }; } @@ -179,24 +104,26 @@ function calculatePollingIntervalFromDate( /** * Creates a callback to be used to initialize the polling operation state. - * @param state of the polling operation - * @param operationSpec of the LRO - * @param callback callback to be called when the operation is done + * @param state - of the polling operation + * @param operationSpec - of the LRO + * @param callback - callback to be called when the operation is done * @returns callback that initializes the state of the polling operation */ -export function initializeState( +export function createInitializeState( state: ResumablePollOperationState, - operationSpec: OperationSpec, - callback?: RawResponseCallback -): (rawResponse: FullOperationResponse, flatResponse: unknown) => void { - return (rawResponse: FullOperationResponse, flatResponse: unknown) => { + requestPath: string, + requestMethod: string +): (rawResponse: RawResponse, flatResponse: unknown) => boolean { + return (rawResponse: RawResponse, flatResponse: unknown) => { + if (isUnexpectedInitialResponse(rawResponse)) return true; state.initialRawResponse = rawResponse; state.isStarted = true; - state.pollingURL = getPollingURL( - state.initialRawResponse, - getSpecPath(operationSpec) + state.pollingURL = getPollingUrl(state.initialRawResponse, requestPath); + state.config = inferLroMode( + requestPath, + requestMethod, + state.initialRawResponse ); - state.config = inferLROMode(operationSpec, state.initialRawResponse); /** short circuit polling if body polling is done in the initial request */ if ( state.config.mode === undefined || @@ -205,12 +132,7 @@ export function initializeState( ) { state.result = flatResponse as TResult; state.isCompleted = true; - /** - * We need to check if the LRO operation is finished inside the - * call back so that we can call the customer-provided callback - * on that result. - */ - callback?.(rawResponse, flatResponse); } + return Boolean(state.isCompleted); }; } diff --git a/test/smoke/generated/sql-resource-manager/src/operations/backupLongTermRetentionPolicies.ts b/test/smoke/generated/sql-resource-manager/src/operations/backupLongTermRetentionPolicies.ts index b75a439d76..1589977468 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/backupLongTermRetentionPolicies.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/backupLongTermRetentionPolicies.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { LongTermRetentionPolicyName, BackupLongTermRetentionPoliciesGetOptionalParams, @@ -111,11 +112,18 @@ export class BackupLongTermRetentionPoliciesImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -124,9 +132,9 @@ export class BackupLongTermRetentionPoliciesImpl parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/backupShortTermRetentionPolicies.ts b/test/smoke/generated/sql-resource-manager/src/operations/backupShortTermRetentionPolicies.ts index 43ef3cb717..2e0579bebb 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/backupShortTermRetentionPolicies.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/backupShortTermRetentionPolicies.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { BackupShortTermRetentionPolicy, BackupShortTermRetentionPoliciesListByDatabaseNextOptionalParams, @@ -201,11 +202,18 @@ export class BackupShortTermRetentionPoliciesImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -214,9 +222,9 @@ export class BackupShortTermRetentionPoliciesImpl parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -300,11 +308,18 @@ export class BackupShortTermRetentionPoliciesImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -313,9 +328,9 @@ export class BackupShortTermRetentionPoliciesImpl parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/databaseVulnerabilityAssessmentScans.ts b/test/smoke/generated/sql-resource-manager/src/operations/databaseVulnerabilityAssessmentScans.ts index 983779cdee..caa73e4932 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/databaseVulnerabilityAssessmentScans.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/databaseVulnerabilityAssessmentScans.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VulnerabilityAssessmentScanRecord, VulnerabilityAssessmentName, @@ -239,11 +240,18 @@ export class DatabaseVulnerabilityAssessmentScansImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -252,9 +260,9 @@ export class DatabaseVulnerabilityAssessmentScansImpl scanId, options }, - initiateScanOperationSpec, - sendOperation + initiateScanOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/databases.ts b/test/smoke/generated/sql-resource-manager/src/operations/databases.ts index a60dca19b2..c901319e70 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/databases.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/databases.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { Metric, DatabasesListMetricsOptionalParams, @@ -419,15 +420,22 @@ export class DatabasesImpl implements Databases { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, parameters, options }, - importOperationSpec, - sendOperation + importOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -506,11 +514,18 @@ export class DatabasesImpl implements Databases { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -519,9 +534,9 @@ export class DatabasesImpl implements Databases { parameters, options }, - createImportOperationOperationSpec, - sendOperation + createImportOperationOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -604,15 +619,22 @@ export class DatabasesImpl implements Databases { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, databaseName, parameters, options }, - exportOperationSpec, - sendOperation + exportOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -771,15 +793,22 @@ export class DatabasesImpl implements Databases { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, databaseName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -851,15 +880,22 @@ export class DatabasesImpl implements Databases { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, databaseName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -935,15 +971,22 @@ export class DatabasesImpl implements Databases { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, databaseName, parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1040,15 +1083,22 @@ export class DatabasesImpl implements Databases { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, databaseName, options }, - pauseOperationSpec, - sendOperation + pauseOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1122,15 +1172,22 @@ export class DatabasesImpl implements Databases { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, databaseName, options }, - resumeOperationSpec, - sendOperation + resumeOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1199,15 +1256,22 @@ export class DatabasesImpl implements Databases { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, databaseName, options }, - upgradeDataWarehouseOperationSpec, - sendOperation + upgradeDataWarehouseOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1298,15 +1362,22 @@ export class DatabasesImpl implements Databases { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, databaseName, options }, - failoverOperationSpec, - sendOperation + failoverOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/elasticPools.ts b/test/smoke/generated/sql-resource-manager/src/operations/elasticPools.ts index 3b9f22c2b7..e1566e95f4 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/elasticPools.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/elasticPools.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { Metric, ElasticPoolsListMetricsOptionalParams, @@ -399,15 +400,22 @@ export class ElasticPoolsImpl implements ElasticPools { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, elasticPoolName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -479,15 +487,22 @@ export class ElasticPoolsImpl implements ElasticPools { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, elasticPoolName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -563,15 +578,22 @@ export class ElasticPoolsImpl implements ElasticPools { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, elasticPoolName, parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -643,15 +665,22 @@ export class ElasticPoolsImpl implements ElasticPools { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, elasticPoolName, options }, - failoverOperationSpec, - sendOperation + failoverOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/encryptionProtectors.ts b/test/smoke/generated/sql-resource-manager/src/operations/encryptionProtectors.ts index da62dfc0f0..6b87c2a9c0 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/encryptionProtectors.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/encryptionProtectors.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { EncryptionProtector, EncryptionProtectorsListByServerNextOptionalParams, @@ -157,15 +158,22 @@ export class EncryptionProtectorsImpl implements EncryptionProtectors { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, encryptionProtectorName, options }, - revalidateOperationSpec, - sendOperation + revalidateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -279,11 +287,18 @@ export class EncryptionProtectorsImpl implements EncryptionProtectors { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -291,9 +306,9 @@ export class EncryptionProtectorsImpl implements EncryptionProtectors { parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/extendedServerBlobAuditingPolicies.ts b/test/smoke/generated/sql-resource-manager/src/operations/extendedServerBlobAuditingPolicies.ts index d8552c9a19..4e54df0358 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/extendedServerBlobAuditingPolicies.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/extendedServerBlobAuditingPolicies.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ExtendedServerBlobAuditingPolicy, ExtendedServerBlobAuditingPoliciesListByServerNextOptionalParams, @@ -181,15 +182,22 @@ export class ExtendedServerBlobAuditingPoliciesImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/failoverGroups.ts b/test/smoke/generated/sql-resource-manager/src/operations/failoverGroups.ts index d55ec4b53a..ca8964379d 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/failoverGroups.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/failoverGroups.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { FailoverGroup, FailoverGroupsListByServerNextOptionalParams, @@ -190,15 +191,22 @@ export class FailoverGroupsImpl implements FailoverGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, failoverGroupName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -270,15 +278,22 @@ export class FailoverGroupsImpl implements FailoverGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, failoverGroupName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -354,15 +369,22 @@ export class FailoverGroupsImpl implements FailoverGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, failoverGroupName, parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -457,15 +479,22 @@ export class FailoverGroupsImpl implements FailoverGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, failoverGroupName, options }, - failoverOperationSpec, - sendOperation + failoverOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -539,15 +568,22 @@ export class FailoverGroupsImpl implements FailoverGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, failoverGroupName, options }, - forceFailoverAllowDataLossOperationSpec, - sendOperation + forceFailoverAllowDataLossOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/instanceFailoverGroups.ts b/test/smoke/generated/sql-resource-manager/src/operations/instanceFailoverGroups.ts index 76f3b0a2ee..ef0f981914 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/instanceFailoverGroups.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/instanceFailoverGroups.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { InstanceFailoverGroup, InstanceFailoverGroupsListByLocationNextOptionalParams, @@ -187,11 +188,18 @@ export class InstanceFailoverGroupsImpl implements InstanceFailoverGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, locationName, @@ -199,9 +207,9 @@ export class InstanceFailoverGroupsImpl implements InstanceFailoverGroups { parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -273,15 +281,22 @@ export class InstanceFailoverGroupsImpl implements InstanceFailoverGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, locationName, failoverGroupName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -373,15 +388,22 @@ export class InstanceFailoverGroupsImpl implements InstanceFailoverGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, locationName, failoverGroupName, options }, - failoverOperationSpec, - sendOperation + failoverOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -458,15 +480,22 @@ export class InstanceFailoverGroupsImpl implements InstanceFailoverGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, locationName, failoverGroupName, options }, - forceFailoverAllowDataLossOperationSpec, - sendOperation + forceFailoverAllowDataLossOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/instancePools.ts b/test/smoke/generated/sql-resource-manager/src/operations/instancePools.ts index 72dd152584..1005a8b896 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/instancePools.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/instancePools.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { InstancePool, InstancePoolsListByResourceGroupNextOptionalParams, @@ -210,15 +211,22 @@ export class InstancePoolsImpl implements InstancePools { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, instancePoolName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -285,15 +293,22 @@ export class InstancePoolsImpl implements InstancePools { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, instancePoolName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -364,15 +379,22 @@ export class InstancePoolsImpl implements InstancePools { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, instancePoolName, parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/jobAgents.ts b/test/smoke/generated/sql-resource-manager/src/operations/jobAgents.ts index d3d7feb60e..202cee61d7 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/jobAgents.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/jobAgents.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { JobAgent, JobAgentsListByServerNextOptionalParams, @@ -204,15 +205,22 @@ export class JobAgentsImpl implements JobAgents { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, jobAgentName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -284,15 +292,22 @@ export class JobAgentsImpl implements JobAgents { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, jobAgentName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -368,15 +383,22 @@ export class JobAgentsImpl implements JobAgents { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, jobAgentName, parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/jobExecutions.ts b/test/smoke/generated/sql-resource-manager/src/operations/jobExecutions.ts index c0ba4f8895..1604f64979 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/jobExecutions.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/jobExecutions.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { JobExecution, JobExecutionsListByAgentNextOptionalParams, @@ -319,15 +320,22 @@ export class JobExecutionsImpl implements JobExecutions { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, jobAgentName, jobName, options }, - createOperationSpec, - sendOperation + createOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -461,11 +469,18 @@ export class JobExecutionsImpl implements JobExecutions { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -474,9 +489,9 @@ export class JobExecutionsImpl implements JobExecutions { jobExecutionId, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/longTermRetentionBackups.ts b/test/smoke/generated/sql-resource-manager/src/operations/longTermRetentionBackups.ts index d3379600f9..0368a0cd16 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/longTermRetentionBackups.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/longTermRetentionBackups.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { LongTermRetentionBackup, LongTermRetentionBackupsListByResourceGroupDatabaseNextOptionalParams, @@ -587,11 +588,18 @@ export class LongTermRetentionBackupsImpl implements LongTermRetentionBackups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, locationName, @@ -600,9 +608,9 @@ export class LongTermRetentionBackupsImpl implements LongTermRetentionBackups { backupName, options }, - deleteByResourceGroupOperationSpec, - sendOperation + deleteByResourceGroupOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -771,11 +779,18 @@ export class LongTermRetentionBackupsImpl implements LongTermRetentionBackups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { locationName, longTermRetentionServerName, @@ -783,9 +798,9 @@ export class LongTermRetentionBackupsImpl implements LongTermRetentionBackups { backupName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/longTermRetentionManagedInstanceBackups.ts b/test/smoke/generated/sql-resource-manager/src/operations/longTermRetentionManagedInstanceBackups.ts index 7620752df6..7fe78d072d 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/longTermRetentionManagedInstanceBackups.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/longTermRetentionManagedInstanceBackups.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ManagedInstanceLongTermRetentionBackup, LongTermRetentionManagedInstanceBackupsListByDatabaseNextOptionalParams, @@ -575,15 +576,22 @@ export class LongTermRetentionManagedInstanceBackupsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { locationName, managedInstanceName, databaseName, backupName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -742,11 +750,18 @@ export class LongTermRetentionManagedInstanceBackupsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, locationName, @@ -755,9 +770,9 @@ export class LongTermRetentionManagedInstanceBackupsImpl backupName, options }, - deleteByResourceGroupOperationSpec, - sendOperation + deleteByResourceGroupOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/managedBackupShortTermRetentionPolicies.ts b/test/smoke/generated/sql-resource-manager/src/operations/managedBackupShortTermRetentionPolicies.ts index b2cae19fde..b156b07033 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/managedBackupShortTermRetentionPolicies.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/managedBackupShortTermRetentionPolicies.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ManagedBackupShortTermRetentionPolicy, ManagedBackupShortTermRetentionPoliciesListByDatabaseNextOptionalParams, @@ -207,11 +208,18 @@ export class ManagedBackupShortTermRetentionPoliciesImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, @@ -220,9 +228,9 @@ export class ManagedBackupShortTermRetentionPoliciesImpl parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -306,11 +314,18 @@ export class ManagedBackupShortTermRetentionPoliciesImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, @@ -319,9 +334,9 @@ export class ManagedBackupShortTermRetentionPoliciesImpl parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/managedDatabaseVulnerabilityAssessmentScans.ts b/test/smoke/generated/sql-resource-manager/src/operations/managedDatabaseVulnerabilityAssessmentScans.ts index ca494e7c18..dfb1ec99c9 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/managedDatabaseVulnerabilityAssessmentScans.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/managedDatabaseVulnerabilityAssessmentScans.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VulnerabilityAssessmentScanRecord, VulnerabilityAssessmentName, @@ -241,11 +242,18 @@ export class ManagedDatabaseVulnerabilityAssessmentScansImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, @@ -254,9 +262,9 @@ export class ManagedDatabaseVulnerabilityAssessmentScansImpl scanId, options }, - initiateScanOperationSpec, - sendOperation + initiateScanOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/managedDatabases.ts b/test/smoke/generated/sql-resource-manager/src/operations/managedDatabases.ts index c8d067ae54..b7f3a96636 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/managedDatabases.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/managedDatabases.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ManagedDatabase, ManagedDatabasesListByInstanceNextOptionalParams, @@ -282,11 +283,18 @@ export class ManagedDatabasesImpl implements ManagedDatabases { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, @@ -294,9 +302,9 @@ export class ManagedDatabasesImpl implements ManagedDatabases { parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -368,15 +376,22 @@ export class ManagedDatabasesImpl implements ManagedDatabases { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, databaseName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -452,11 +467,18 @@ export class ManagedDatabasesImpl implements ManagedDatabases { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, @@ -464,9 +486,9 @@ export class ManagedDatabasesImpl implements ManagedDatabases { parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -558,11 +580,18 @@ export class ManagedDatabasesImpl implements ManagedDatabases { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, @@ -570,9 +599,9 @@ export class ManagedDatabasesImpl implements ManagedDatabases { parameters, options }, - completeRestoreOperationSpec, - sendOperation + completeRestoreOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceAdministrators.ts b/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceAdministrators.ts index ae0501fae4..056f01e1cb 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceAdministrators.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceAdministrators.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ManagedInstanceAdministrator, ManagedInstanceAdministratorsListByInstanceNextOptionalParams, @@ -198,15 +199,22 @@ export class ManagedInstanceAdministratorsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -273,15 +281,22 @@ export class ManagedInstanceAdministratorsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceEncryptionProtectors.ts b/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceEncryptionProtectors.ts index 90d010330a..6ad640792e 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceEncryptionProtectors.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceEncryptionProtectors.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ManagedInstanceEncryptionProtector, ManagedInstanceEncryptionProtectorsListByInstanceNextOptionalParams, @@ -158,20 +159,27 @@ export class ManagedInstanceEncryptionProtectorsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, encryptionProtectorName, options }, - revalidateOperationSpec, - sendOperation + revalidateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -292,11 +300,18 @@ export class ManagedInstanceEncryptionProtectorsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, @@ -304,9 +319,9 @@ export class ManagedInstanceEncryptionProtectorsImpl parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceKeys.ts b/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceKeys.ts index 7260ee71e3..71cb90da13 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceKeys.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceKeys.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ManagedInstanceKey, ManagedInstanceKeysListByInstanceNextOptionalParams, @@ -201,15 +202,22 @@ export class ManagedInstanceKeysImpl implements ManagedInstanceKeys { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, keyName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -281,15 +289,22 @@ export class ManagedInstanceKeysImpl implements ManagedInstanceKeys { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, keyName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceLongTermRetentionPolicies.ts b/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceLongTermRetentionPolicies.ts index cf9147d74d..5d667c8d1d 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceLongTermRetentionPolicies.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceLongTermRetentionPolicies.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ManagedInstanceLongTermRetentionPolicy, ManagedInstanceLongTermRetentionPoliciesListByDatabaseNextOptionalParams, @@ -205,11 +206,18 @@ export class ManagedInstanceLongTermRetentionPoliciesImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, @@ -218,9 +226,9 @@ export class ManagedInstanceLongTermRetentionPoliciesImpl parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceTdeCertificates.ts b/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceTdeCertificates.ts index 977277238d..0fe16c54ef 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceTdeCertificates.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/managedInstanceTdeCertificates.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { TdeCertificate, ManagedInstanceTdeCertificatesCreateOptionalParams @@ -74,15 +75,22 @@ export class ManagedInstanceTdeCertificatesImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, parameters, options }, - createOperationSpec, - sendOperation + createOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/managedInstances.ts b/test/smoke/generated/sql-resource-manager/src/operations/managedInstances.ts index 419cbad404..08fde182d8 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/managedInstances.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/managedInstances.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ManagedInstance, ManagedInstancesListByInstancePoolNextOptionalParams, @@ -320,15 +321,22 @@ export class ManagedInstancesImpl implements ManagedInstances { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -395,15 +403,22 @@ export class ManagedInstancesImpl implements ManagedInstances { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -474,15 +489,22 @@ export class ManagedInstancesImpl implements ManagedInstances { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/managedRestorableDroppedDatabaseBackupShortTermRetentionPolicies.ts b/test/smoke/generated/sql-resource-manager/src/operations/managedRestorableDroppedDatabaseBackupShortTermRetentionPolicies.ts index 5c15f64a24..dd640f70e8 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/managedRestorableDroppedDatabaseBackupShortTermRetentionPolicies.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/managedRestorableDroppedDatabaseBackupShortTermRetentionPolicies.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ManagedBackupShortTermRetentionPolicy, ManagedRestorableDroppedDatabaseBackupShortTermRetentionPoliciesListByRestorableDroppedDatabaseNextOptionalParams, @@ -209,11 +210,18 @@ export class ManagedRestorableDroppedDatabaseBackupShortTermRetentionPoliciesImp } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, @@ -222,9 +230,9 @@ export class ManagedRestorableDroppedDatabaseBackupShortTermRetentionPoliciesImp parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -312,11 +320,18 @@ export class ManagedRestorableDroppedDatabaseBackupShortTermRetentionPoliciesImp } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, @@ -325,9 +340,9 @@ export class ManagedRestorableDroppedDatabaseBackupShortTermRetentionPoliciesImp parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/managedServerSecurityAlertPolicies.ts b/test/smoke/generated/sql-resource-manager/src/operations/managedServerSecurityAlertPolicies.ts index 95ab5f8ce2..3f38823688 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/managedServerSecurityAlertPolicies.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/managedServerSecurityAlertPolicies.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ManagedServerSecurityAlertPolicy, ManagedServerSecurityAlertPoliciesListByInstanceNextOptionalParams, @@ -191,11 +192,18 @@ export class ManagedServerSecurityAlertPoliciesImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, managedInstanceName, @@ -203,9 +211,9 @@ export class ManagedServerSecurityAlertPoliciesImpl parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/privateEndpointConnections.ts b/test/smoke/generated/sql-resource-manager/src/operations/privateEndpointConnections.ts index ffa3117100..0c39d1d6dc 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/privateEndpointConnections.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/privateEndpointConnections.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { PrivateEndpointConnection, PrivateEndpointConnectionsListByServerNextOptionalParams, @@ -184,11 +185,18 @@ export class PrivateEndpointConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -196,9 +204,9 @@ export class PrivateEndpointConnectionsImpl parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -270,15 +278,22 @@ export class PrivateEndpointConnectionsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, privateEndpointConnectionName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/replicationLinks.ts b/test/smoke/generated/sql-resource-manager/src/operations/replicationLinks.ts index 467a023eab..fe6ded49c8 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/replicationLinks.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/replicationLinks.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ReplicationLink, ReplicationLinksListByDatabaseOptionalParams, @@ -199,15 +200,22 @@ export class ReplicationLinksImpl implements ReplicationLinks { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, databaseName, linkId, options }, - failoverOperationSpec, - sendOperation + failoverOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -282,15 +290,22 @@ export class ReplicationLinksImpl implements ReplicationLinks { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, databaseName, linkId, options }, - failoverAllowDataLossOperationSpec, - sendOperation + failoverAllowDataLossOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -367,11 +382,18 @@ export class ReplicationLinksImpl implements ReplicationLinks { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -380,9 +402,9 @@ export class ReplicationLinksImpl implements ReplicationLinks { parameters, options }, - unlinkOperationSpec, - sendOperation + unlinkOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/restorePoints.ts b/test/smoke/generated/sql-resource-manager/src/operations/restorePoints.ts index bedddeeabb..04e49aceb7 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/restorePoints.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/restorePoints.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { RestorePoint, RestorePointsListByDatabaseOptionalParams, @@ -179,15 +180,22 @@ export class RestorePointsImpl implements RestorePoints { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, databaseName, parameters, options }, - createOperationSpec, - sendOperation + createOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/serverAzureADAdministrators.ts b/test/smoke/generated/sql-resource-manager/src/operations/serverAzureADAdministrators.ts index adbeef5a2d..15c9279dfb 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/serverAzureADAdministrators.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/serverAzureADAdministrators.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ServerAzureADAdministrator, ServerAzureADAdministratorsListByServerNextOptionalParams, @@ -188,15 +189,22 @@ export class ServerAzureADAdministratorsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, administratorName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -269,15 +277,22 @@ export class ServerAzureADAdministratorsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, administratorName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -369,15 +384,22 @@ export class ServerAzureADAdministratorsImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, options }, - disableAzureADOnlyAuthenticationOperationSpec, - sendOperation + disableAzureADOnlyAuthenticationOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/serverBlobAuditingPolicies.ts b/test/smoke/generated/sql-resource-manager/src/operations/serverBlobAuditingPolicies.ts index 4ec9774d70..d6e1794e9d 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/serverBlobAuditingPolicies.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/serverBlobAuditingPolicies.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ServerBlobAuditingPolicy, ServerBlobAuditingPoliciesListByServerNextOptionalParams, @@ -179,15 +180,22 @@ export class ServerBlobAuditingPoliciesImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/serverCommunicationLinks.ts b/test/smoke/generated/sql-resource-manager/src/operations/serverCommunicationLinks.ts index 896e9456ae..1fe7ac803a 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/serverCommunicationLinks.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/serverCommunicationLinks.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ServerCommunicationLink, ServerCommunicationLinksListByServerOptionalParams, @@ -190,11 +191,18 @@ export class ServerCommunicationLinksImpl implements ServerCommunicationLinks { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -202,9 +210,9 @@ export class ServerCommunicationLinksImpl implements ServerCommunicationLinks { parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/serverDnsAliases.ts b/test/smoke/generated/sql-resource-manager/src/operations/serverDnsAliases.ts index 59b144b727..94748b50f9 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/serverDnsAliases.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/serverDnsAliases.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ServerDnsAlias, ServerDnsAliasesListByServerNextOptionalParams, @@ -183,15 +184,22 @@ export class ServerDnsAliasesImpl implements ServerDnsAliases { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, dnsAliasName, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -260,15 +268,22 @@ export class ServerDnsAliasesImpl implements ServerDnsAliases { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, dnsAliasName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -357,15 +372,22 @@ export class ServerDnsAliasesImpl implements ServerDnsAliases { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, dnsAliasName, parameters, options }, - acquireOperationSpec, - sendOperation + acquireOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/serverKeys.ts b/test/smoke/generated/sql-resource-manager/src/operations/serverKeys.ts index 3065573087..c1e3221d57 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/serverKeys.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/serverKeys.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ServerKey, ServerKeysListByServerNextOptionalParams, @@ -204,15 +205,22 @@ export class ServerKeysImpl implements ServerKeys { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, keyName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -287,15 +295,22 @@ export class ServerKeysImpl implements ServerKeys { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, keyName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/serverSecurityAlertPolicies.ts b/test/smoke/generated/sql-resource-manager/src/operations/serverSecurityAlertPolicies.ts index c01740db03..7209805eb5 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/serverSecurityAlertPolicies.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/serverSecurityAlertPolicies.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { ServerSecurityAlertPolicy, ServerSecurityAlertPoliciesListByServerNextOptionalParams, @@ -184,11 +185,18 @@ export class ServerSecurityAlertPoliciesImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -196,9 +204,9 @@ export class ServerSecurityAlertPoliciesImpl parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/servers.ts b/test/smoke/generated/sql-resource-manager/src/operations/servers.ts index 4b2eb59edf..995bdaa853 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/servers.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/servers.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { Server, ServersListByResourceGroupNextOptionalParams, @@ -229,15 +230,22 @@ export class ServersImpl implements Servers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -304,15 +312,22 @@ export class ServersImpl implements Servers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -380,15 +395,22 @@ export class ServersImpl implements Servers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/syncAgents.ts b/test/smoke/generated/sql-resource-manager/src/operations/syncAgents.ts index 02954d2240..20ff6b60de 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/syncAgents.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/syncAgents.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { SyncAgent, SyncAgentsListByServerNextOptionalParams, @@ -271,15 +272,22 @@ export class SyncAgentsImpl implements SyncAgents { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, syncAgentName, parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -351,15 +359,22 @@ export class SyncAgentsImpl implements SyncAgents { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, syncAgentName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/syncGroups.ts b/test/smoke/generated/sql-resource-manager/src/operations/syncGroups.ts index dd0f3c77a4..a15a18ac96 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/syncGroups.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/syncGroups.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { SyncDatabaseIdProperties, SyncGroupsListSyncDatabaseIdsNextOptionalParams, @@ -463,15 +464,22 @@ export class SyncGroupsImpl implements SyncGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, databaseName, syncGroupName, options }, - refreshHubSchemaOperationSpec, - sendOperation + refreshHubSchemaOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -677,11 +685,18 @@ export class SyncGroupsImpl implements SyncGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -690,9 +705,9 @@ export class SyncGroupsImpl implements SyncGroups { parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -769,15 +784,22 @@ export class SyncGroupsImpl implements SyncGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, databaseName, syncGroupName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -858,11 +880,18 @@ export class SyncGroupsImpl implements SyncGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -871,9 +900,9 @@ export class SyncGroupsImpl implements SyncGroups { parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/syncMembers.ts b/test/smoke/generated/sql-resource-manager/src/operations/syncMembers.ts index 3236c39503..7e6c2cd9d8 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/syncMembers.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/syncMembers.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { SyncMember, SyncMembersListBySyncGroupNextOptionalParams, @@ -323,11 +324,18 @@ export class SyncMembersImpl implements SyncMembers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -337,9 +345,9 @@ export class SyncMembersImpl implements SyncMembers { parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -421,11 +429,18 @@ export class SyncMembersImpl implements SyncMembers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -434,9 +449,9 @@ export class SyncMembersImpl implements SyncMembers { syncMemberName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -522,11 +537,18 @@ export class SyncMembersImpl implements SyncMembers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -536,9 +558,9 @@ export class SyncMembersImpl implements SyncMembers { parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -673,11 +695,18 @@ export class SyncMembersImpl implements SyncMembers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -686,9 +715,9 @@ export class SyncMembersImpl implements SyncMembers { syncMemberName, options }, - refreshMemberSchemaOperationSpec, - sendOperation + refreshMemberSchemaOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/tdeCertificates.ts b/test/smoke/generated/sql-resource-manager/src/operations/tdeCertificates.ts index a7c82ea9fc..48dd4d6dfe 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/tdeCertificates.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/tdeCertificates.ts @@ -11,8 +11,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { TdeCertificate, TdeCertificatesCreateOptionalParams } from "../models"; /** Class representing a TdeCertificates. */ @@ -70,15 +71,22 @@ export class TdeCertificatesImpl implements TdeCertificates { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, parameters, options }, - createOperationSpec, - sendOperation + createOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/virtualClusters.ts b/test/smoke/generated/sql-resource-manager/src/operations/virtualClusters.ts index 28dbc99af1..03b79e6a51 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/virtualClusters.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/virtualClusters.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualCluster, VirtualClustersListNextOptionalParams, @@ -227,15 +228,22 @@ export class VirtualClustersImpl implements VirtualClusters { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualClusterName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -306,15 +314,22 @@ export class VirtualClustersImpl implements VirtualClusters { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, virtualClusterName, parameters, options }, - updateOperationSpec, - sendOperation + updateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/virtualNetworkRules.ts b/test/smoke/generated/sql-resource-manager/src/operations/virtualNetworkRules.ts index 684ebdf292..f7a593cea6 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/virtualNetworkRules.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/virtualNetworkRules.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { VirtualNetworkRule, VirtualNetworkRulesListByServerNextOptionalParams, @@ -183,11 +184,18 @@ export class VirtualNetworkRulesImpl implements VirtualNetworkRules { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -195,9 +203,9 @@ export class VirtualNetworkRulesImpl implements VirtualNetworkRules { parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -269,15 +277,22 @@ export class VirtualNetworkRulesImpl implements VirtualNetworkRules { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, virtualNetworkRuleName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/workloadClassifiers.ts b/test/smoke/generated/sql-resource-manager/src/operations/workloadClassifiers.ts index 0372089de9..bf0e94eec6 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/workloadClassifiers.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/workloadClassifiers.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { WorkloadClassifier, WorkloadClassifiersListByWorkloadGroupNextOptionalParams, @@ -216,11 +217,18 @@ export class WorkloadClassifiersImpl implements WorkloadClassifiers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -230,9 +238,9 @@ export class WorkloadClassifiersImpl implements WorkloadClassifiers { parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -314,11 +322,18 @@ export class WorkloadClassifiersImpl implements WorkloadClassifiers { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -327,9 +342,9 @@ export class WorkloadClassifiersImpl implements WorkloadClassifiers { workloadClassifierName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/sql-resource-manager/src/operations/workloadGroups.ts b/test/smoke/generated/sql-resource-manager/src/operations/workloadGroups.ts index 981351beb0..dd73711753 100644 --- a/test/smoke/generated/sql-resource-manager/src/operations/workloadGroups.ts +++ b/test/smoke/generated/sql-resource-manager/src/operations/workloadGroups.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { SqlManagementClientContext } from "../sqlManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { WorkloadGroup, WorkloadGroupsListByDatabaseNextOptionalParams, @@ -202,11 +203,18 @@ export class WorkloadGroupsImpl implements WorkloadGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -215,9 +223,9 @@ export class WorkloadGroupsImpl implements WorkloadGroups { parameters, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -294,11 +302,18 @@ export class WorkloadGroupsImpl implements WorkloadGroups { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, serverName, @@ -306,9 +321,9 @@ export class WorkloadGroupsImpl implements WorkloadGroups { workloadGroupName, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/storage-resource-manager/src/coreClientLro.ts b/test/smoke/generated/storage-resource-manager/src/coreClientLro.ts new file mode 100644 index 0000000000..d793a24458 --- /dev/null +++ b/test/smoke/generated/storage-resource-manager/src/coreClientLro.ts @@ -0,0 +1,323 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + OperationArguments, + OperationSpec, + OperationResponseMap, + FullOperationResponse +} from "@azure/core-client"; +import { + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + createGetLroStatusFromResponse, + RawResponse +} from "./lro"; + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +export const terminalStates = successStates.concat(failureStates); + +export type SendOperationFn = ( + args: OperationArguments, + spec: OperationSpec +) => Promise>; + +export function createPollingMethod( + sendOperationFn: SendOperationFn, + GetLroStatusFromResponse: GetLroStatusFromResponse, + args: OperationArguments, + spec: OperationSpec, + mode?: LroMode +): (path?: string) => Promise> { + /** + * Polling calls will always return a status object i.e. {"status": "success"} + * these intermediate responses are not described in the swagger so we need to + * pass custom mappers at runtime. + * This function replaces all the existing mappers to be able to deserialize a status object + * @param responses Original set of responses defined in the operation + */ + function getCompositeMappers(responses: { + [responseCode: string]: OperationResponseMap; + }): { + [responseCode: string]: OperationResponseMap; + } { + return Object.keys(responses).reduce((acc, statusCode) => { + return { + ...acc, + [statusCode]: { + ...responses[statusCode], + bodyMapper: { + type: { + name: "Composite", + modelProperties: { + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } + } + } + }; + }, {} as { [responseCode: string]: OperationResponseMap }); + } + let response: LroStatus | undefined = undefined; + const customerCallback = args?.options?.onResponse; + const updatedArgs = { + ...args, + options: { + ...args.options, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ): void => { + response = GetLroStatusFromResponse( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse as TResult + ); + if (response.done) { + customerCallback?.(rawResponse, flatResponse); + } + } + } + }; + // Make sure we don't send any body to the get request + const { requestBody, responses, ...restSpec } = spec; + if (mode === "AzureAsync") { + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: getCompositeMappers(responses), + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; + } + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: responses, + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; +} + +/** + * We need to selectively deserialize our responses, only deserializing if we + * are in a final Lro response, not deserializing any polling non-terminal responses + */ +export function shouldDeserializeLro(lroResourceLocationConfig?: string) { + let initialOperationInfo: LroResponseInfo | undefined; + let isInitialRequest = true; + + return (response: FullOperationResponse) => { + if (response.status < 200 || response.status >= 300) { + return true; + } + + if (!initialOperationInfo) { + initialOperationInfo = getLroData(response); + } else { + isInitialRequest = false; + } + + if ( + initialOperationInfo.azureAsyncOperation || + initialOperationInfo.operationLocation + ) { + return ( + !isInitialRequest && + isAsyncOperationFinalResponse( + response, + initialOperationInfo, + lroResourceLocationConfig + ) + ); + } + + if (initialOperationInfo.location) { + return isLocationFinalResponse(response); + } + + if (initialOperationInfo.requestMethod === "PUT") { + return isBodyPollingFinalResponse(response); + } + + return true; + }; +} + +function isAsyncOperationFinalResponse( + response: FullOperationResponse, + initialOperationInfo: LroResponseInfo, + lroResourceLocationConfig?: string +): boolean { + const status: string = response.parsedBody?.status || "Succeeded"; + if (!terminalStates.includes(status.toLowerCase())) { + return false; + } + + if (initialOperationInfo.requestMethod === "DELETE") { + return true; + } + + if ( + initialOperationInfo.requestMethod === "PUT" && + lroResourceLocationConfig && + lroResourceLocationConfig.toLowerCase() === "azure-asyncoperation" + ) { + return true; + } + + if ( + initialOperationInfo.requestMethod !== "PUT" && + !initialOperationInfo.location + ) { + return true; + } + + return false; +} + +function isLocationFinalResponse(response: FullOperationResponse): boolean { + return response.status !== 202; +} + +function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { + const provisioningState: string = + response.parsedBody?.properties?.provisioningState || "Succeeded"; + + if (terminalStates.includes(provisioningState.toLowerCase())) { + return true; + } + + return false; +} + +interface LroResponseInfo { + requestMethod: string; + azureAsyncOperation?: string; + operationLocation?: string; + location?: string; +} + +function getLroData(result: FullOperationResponse): LroResponseInfo { + return { + azureAsyncOperation: result.headers.get("azure-asyncoperation"), + operationLocation: result.headers.get("operation-location"), + location: result.headers.get("location"), + requestMethod: result.request.method + }; +} + +export function getSpecPath(spec: OperationSpec): string { + if (spec.path) { + return spec.path; + } else { + throw Error("Bad spec: request path is not found!"); + } +} + +export class CoreClientLro implements LongRunningOperation { + constructor( + private sendOperationFn: SendOperationFn, + private args: OperationArguments, + private spec: OperationSpec, + private lroResourceLocationConfig?: LroResourceLocationConfig, + public requestPath: string = spec.path!, + public requestMethod: string = spec.httpMethod + ) {} + public async sendInitialRequest( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ): Promise> { + const { onResponse, ...restOptions } = this.args.options || {}; + return this.sendOperationFn( + { + ...this.args, + options: { + ...restOptions, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ) => { + const isCompleted = initializeState( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse + ); + if (isCompleted) { + onResponse?.(rawResponse, flatResponse); + } + } + } + }, + this.spec + ); + } + + public async sendPollRequest( + config: LroConfig, + path: string + ): Promise> { + const getLroStatusFromResponse = createGetLroStatusFromResponse( + this, + config, + this.lroResourceLocationConfig + ); + return createPollingMethod( + this.sendOperationFn, + getLroStatusFromResponse, + this.args, + this.spec, + config.mode + )(path); + } + + public async retrieveAzureAsyncResource( + path?: string + ): Promise> { + const updatedArgs = { ...this.args }; + if (updatedArgs.options) { + (updatedArgs.options as any).shouldDeserialize = true; + } + return createPollingMethod( + this.sendOperationFn, + (rawResponse, flatResponse) => ({ + rawResponse, + flatResponse, + done: true + }), + updatedArgs, + this.spec + )(path); + } +} diff --git a/test/smoke/generated/storage-resource-manager/src/lro/azureAsyncPolling.ts b/test/smoke/generated/storage-resource-manager/src/lro/azureAsyncPolling.ts index 0d63c54f60..725578a692 100644 --- a/test/smoke/generated/storage-resource-manager/src/lro/azureAsyncPolling.ts +++ b/test/smoke/generated/storage-resource-manager/src/lro/azureAsyncPolling.ts @@ -7,39 +7,61 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { FinalStateVia, LROResult } from "./models"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroResourceLocationConfig, + LongRunningOperation, + LroBody, + LroResponse, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getResponseStatus(rawResponse: FullOperationResponse): string { - const { status } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getResponseStatus(rawResponse: RawResponse): string { + const { status } = (rawResponse.body as LroBody) ?? {}; return status?.toLowerCase() ?? "succeeded"; } -function isAzureAsyncPollingDone(rawResponse: FullOperationResponse) { +function isAzureAsyncPollingDone(rawResponse: RawResponse): boolean { const state = getResponseStatus(rawResponse); - if (failureStates.includes(state)) { + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { throw new Error(`Operation status: ${state}`); } return successStates.includes(state); } +async function sendFinalRequest( + lro: LongRunningOperation, + lroResourceLocationConfig?: LroResourceLocationConfig, + resourceLocation?: string +): Promise | undefined> { + switch (lroResourceLocationConfig) { + case "original-uri": + return lro.retrieveAzureAsyncResource(); + case "azure-async-operation": + return Promise.resolve(undefined); + case "location": + default: + return lro.retrieveAzureAsyncResource(resourceLocation); + } +} + export function processAzureAsyncOperationResult( - restrieveResource: (path?: string) => Promise>, + lro: LongRunningOperation, resourceLocation?: string, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { + lroResourceLocationConfig?: LroResourceLocationConfig +): (rawResponse: RawResponse, flatResponse: TResult) => LroStatus { return ( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult - ): LROState => { + ): LroStatus => { if (isAzureAsyncPollingDone(rawResponse)) { if (resourceLocation === undefined) { return { rawResponse, flatResponse, done: true }; @@ -49,20 +71,11 @@ export function processAzureAsyncOperationResult( flatResponse, done: false, next: async () => { - async function sendFinalRequest(): Promise< - LROResult | undefined - > { - switch (finalStateVia) { - case "original-uri": - return restrieveResource(); - case "azure-async-operation": - return Promise.resolve(undefined); - case "location": - default: - return restrieveResource(resourceLocation); - } - } - const finalResponse = await sendFinalRequest(); + const finalResponse = await sendFinalRequest( + lro, + lroResourceLocationConfig, + resourceLocation + ); return { ...(finalResponse ?? { rawResponse, diff --git a/test/smoke/generated/storage-resource-manager/src/lro/bodyPolling.ts b/test/smoke/generated/storage-resource-manager/src/lro/bodyPolling.ts index 269d8e6799..b1c87f8bc8 100644 --- a/test/smoke/generated/storage-resource-manager/src/lro/bodyPolling.ts +++ b/test/smoke/generated/storage-resource-manager/src/lro/bodyPolling.ts @@ -7,24 +7,33 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroBody, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getProvisioningState(rawResponse: FullOperationResponse): string { - const { properties, provisioningState } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getProvisioningState(rawResponse: RawResponse): string { + const { properties, provisioningState } = (rawResponse.body as LroBody) ?? {}; const state: string | undefined = properties?.provisioningState ?? provisioningState; return state?.toLowerCase() ?? "succeeded"; } -export function isBodyPollingDone(rawResponse: FullOperationResponse) { +export function isBodyPollingDone(rawResponse: RawResponse): boolean { const state = getProvisioningState(rawResponse); - if (failureStates.includes(state)) { - throw new Error(`Provisioning state: ${state}`); + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { + throw new Error( + `The long running operation has failed. The provisioning state: ${state}.` + ); } return successStates.includes(state); } @@ -34,9 +43,9 @@ export function isBodyPollingDone(rawResponse: FullOperationResponse) { * from the result to determine the current operation state */ export function processBodyPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/storage-resource-manager/src/lro/index.ts b/test/smoke/generated/storage-resource-manager/src/lro/index.ts index 85c2187669..20df608fc8 100644 --- a/test/smoke/generated/storage-resource-manager/src/lro/index.ts +++ b/test/smoke/generated/storage-resource-manager/src/lro/index.ts @@ -6,5 +6,21 @@ * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ -export { shouldDeserializeLRO } from "./requestUtils"; -export { LROPoller } from "./lroPoller"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { LroEngine } from "./lroEngine"; +export { createGetLroStatusFromResponse } from "./stateMachine"; +export { + LroResourceLocationConfig, + GetLroStatusFromResponse, + RawResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + LroTerminalState, + LroInProgressState, + LroEngineOptions +} from "./models"; diff --git a/test/smoke/generated/storage-resource-manager/src/lro/locationPolling.ts b/test/smoke/generated/storage-resource-manager/src/lro/locationPolling.ts index 6fef619384..9d1aadfbde 100644 --- a/test/smoke/generated/storage-resource-manager/src/lro/locationPolling.ts +++ b/test/smoke/generated/storage-resource-manager/src/lro/locationPolling.ts @@ -7,23 +7,21 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function isLocationPollingDone(rawResponse: FullOperationResponse) { - const code = rawResponse.status; - if (![202, 200].includes(code)) { - throw new Error(`Operation failed`); - } - return code !== 202; +function isLocationPollingDone(rawResponse: RawResponse): boolean { + return ( + !isUnexpectedPollingResponse(rawResponse) && rawResponse.statusCode !== 202 + ); } export function processLocationPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/storage-resource-manager/src/lro/lroEngine.ts b/test/smoke/generated/storage-resource-manager/src/lro/lroEngine.ts new file mode 100644 index 0000000000..85cc15e609 --- /dev/null +++ b/test/smoke/generated/storage-resource-manager/src/lro/lroEngine.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Poller, PollOperationState } from "@azure/core-lro"; +import { + LongRunningOperation, + LroEngineOptions, + ResumablePollOperationState +} from "./models"; +import { GenericPollOperation } from "./operation"; + +/** + * The LRO Engine, a class that performs polling. + */ +export class LroEngine< + TResult, + TState extends PollOperationState +> extends Poller { + private intervalInMs: number; + + constructor(lro: LongRunningOperation, options?: LroEngineOptions) { + const { intervalInMs = 2000, resumeFrom } = options || {}; + function deserializeState( + resumeFrom: string + ): TState & ResumablePollOperationState { + try { + return JSON.parse(resumeFrom).state; + } catch (e) { + throw new Error( + `LroEngine: Unable to deserialize state: ${resumeFrom}` + ); + } + } + const state: TState & ResumablePollOperationState = resumeFrom + ? deserializeState(resumeFrom) + : ({} as any); + + const operation = new GenericPollOperation(state, lro); + super(operation); + + this.intervalInMs = intervalInMs; + operation.setPollerConfig(this as any); + } + + /** + * The method used by the poller to wait before attempting to update its operation. + */ + delay(): Promise { + return new Promise((resolve) => + setTimeout(() => resolve(), this.intervalInMs) + ); + } +} diff --git a/test/smoke/generated/storage-resource-manager/src/lro/lroPoller.ts b/test/smoke/generated/storage-resource-manager/src/lro/lroPoller.ts deleted file mode 100644 index cd1cd64fe8..0000000000 --- a/test/smoke/generated/storage-resource-manager/src/lro/lroPoller.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { Poller, PollOperationState } from "@azure/core-lro"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { FinalStateVia, SendOperationFn } from "./models"; -import { GenericPollOperation } from "./operation"; - -export interface LROPollerOptions { - /** - * Defines how much time the poller is going to wait before making a new request to the service. - */ - intervalInMs?: number; - /** - * A serialized poller which can be used to resume an existing paused Long-Running-Operation. - */ - resumeFrom?: string; -} - -export class LROPoller extends Poller< - PollOperationState, - TResult -> { - private intervalInMs: number; - - constructor( - { intervalInMs = 2000, resumeFrom }: LROPollerOptions, - initialOperationArguments: OperationArguments, - initialOperationSpec: OperationSpec, - sendOperation: SendOperationFn, - finalStateVia?: FinalStateVia - ) { - const state: PollOperationState = resumeFrom - ? JSON.parse(resumeFrom).state - : {}; - - const operation = new GenericPollOperation( - state, - initialOperationArguments, - initialOperationSpec, - sendOperation, - finalStateVia - ); - super(operation); - - this.intervalInMs = intervalInMs; - operation.setPollerConfig(this as any); - } - - /** - * The method used by the poller to wait before attempting to update its operation. - */ - delay(): Promise { - return new Promise((resolve) => - setTimeout(() => resolve(), this.intervalInMs) - ); - } -} diff --git a/test/smoke/generated/storage-resource-manager/src/lro/models.ts b/test/smoke/generated/storage-resource-manager/src/lro/models.ts index a4a5a5abd6..93c3437c8e 100644 --- a/test/smoke/generated/storage-resource-manager/src/lro/models.ts +++ b/test/smoke/generated/storage-resource-manager/src/lro/models.ts @@ -7,46 +7,167 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec -} from "@azure/core-client"; import { PollOperationState } from "@azure/core-lro"; -export type FinalStateVia = +/** + * Options for the LRO poller. + */ +export interface LroEngineOptions { + /** + * Defines how much time the poller is going to wait before making a new request to the service. + */ + intervalInMs?: number; + /** + * A serialized poller which can be used to resume an existing paused Long-Running-Operation. + */ + resumeFrom?: string; +} + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +/** + * The LRO states that signal that the LRO has completed. + */ +export const terminalStates = successStates.concat(failureStates); + +/** + * The potential location of the result of the LRO if specified by the LRO extension in the swagger. + */ +export type LroResourceLocationConfig = | "azure-async-operation" | "location" | "original-uri"; -export interface LROResult { +/** + * The type of a LRO response body. This is just a convenience type for checking the status of the operation. + */ + +export interface LroBody extends Record { + /** The status of the operation. */ + status?: string; + /** The state of the provisioning process */ + provisioningState?: string; + /** The properties of the provisioning process */ + properties?: { provisioningState?: string } & Record; +} + +/** + * Simple type of the raw response. + */ +export interface RawResponse { + /** The HTTP status code */ + statusCode: number; + /** A HttpHeaders collection in the response represented as a simple JSON object where all header names have been normalized to be lower-case. */ + headers: { + [headerName: string]: string; + }; + /** The parsed response body */ + body?: unknown; +} + +/** + * The type of the response of a LRO. + */ +export interface LroResponse { + /** The flattened response */ flatResponse: T; - rawResponse: FullOperationResponse; + /** The raw response */ + rawResponse: RawResponse; } -export type LROMode = "AzureAsync" | "Location" | "Body"; +/** The type of which LRO implementation being followed by a specific API. */ +export type LroMode = "AzureAsync" | "Location" | "Body"; -export interface LROConfig { - mode?: LROMode; +/** + * The configuration of a LRO to determine how to perform polling and checking whether the operation has completed. + */ +export interface LroConfig { + /** The LRO mode */ + mode?: LroMode; + /** The path of a provisioned resource */ resourceLocation?: string; } -export type SendOperationFn = ( - args: OperationArguments, - spec: OperationSpec -) => Promise>; - /** * Type of a polling operation state that can actually be resumed. */ export type ResumablePollOperationState = PollOperationState & { - initialRawResponse?: FullOperationResponse; - config?: LROConfig; + initialRawResponse?: RawResponse; + config?: LroConfig; pollingURL?: string; }; export interface PollerConfig { intervalInMs: number; } + +/** + * The type of a terminal state of an LRO. + */ +export interface LroTerminalState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: true; +} + +/** + * The type of an in-progress state of an LRO. + */ +export interface LroInProgressState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: false; + /** + * The request to be sent next if it is different from the standard polling one. + * Notice that it will disregard any polling URLs provided to it. + */ + next?: () => Promise>; +} + +/** + * The type of an LRO state which is a tagged union of terminal and in-progress states. + */ +export type LroStatus = LroTerminalState | LroInProgressState; + +/** + * The type of the getLROStatusFromResponse method. It takes the response as input and returns along the response whether the operation has finished. + */ +export type GetLroStatusFromResponse = ( + rawResponse: RawResponse, + flatResponse: T +) => LroStatus; + +/** + * Description of a long running operation. + */ +export interface LongRunningOperation { + /** + * The request path. + */ + requestPath: string; + /** + * The HTTP request method. + */ + requestMethod: string; + /** + * A function that can be used to send initial request to the service. + */ + sendInitialRequest: ( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ) => Promise>; + /** + * A function that can be used to poll for the current status of a long running operation. + */ + sendPollRequest: (config: LroConfig, path: string) => Promise>; + /** + * A function that can be used to retrieve the provisioned azure resource. + */ + retrieveAzureAsyncResource: (path?: string) => Promise>; +} diff --git a/test/smoke/generated/storage-resource-manager/src/lro/operation.ts b/test/smoke/generated/storage-resource-manager/src/lro/operation.ts index 801d03e720..3ea7b76d89 100644 --- a/test/smoke/generated/storage-resource-manager/src/lro/operation.ts +++ b/test/smoke/generated/storage-resource-manager/src/lro/operation.ts @@ -7,36 +7,34 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. import { AbortSignalLike } from "@azure/abort-controller"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { PollOperation, PollOperationState } from "@azure/core-lro"; +import { PollOperationState, PollOperation } from "@azure/core-lro"; import { - FinalStateVia, PollerConfig, ResumablePollOperationState, - SendOperationFn + LongRunningOperation, + LroStatus } from "./models"; -import { getPollingURL } from "./requestUtils"; -import { createGetLROState, initializeState, LROState } from "./stateMachine"; +import { getPollingUrl } from "./requestUtils"; +import { createInitializeState, createPollForLROStatus } from "./stateMachine"; -export class GenericPollOperation - implements PollOperation, TResult> { - private getLROState?: ( +export class GenericPollOperation< + TResult, + TState extends PollOperationState +> implements PollOperation { + private getLROStatusFromResponse?: ( pollingURL: string, pollerConfig: PollerConfig - ) => Promise>; + ) => Promise>; private pollerConfig?: PollerConfig; constructor( - public state: PollOperationState, - private initialOperationArguments: OperationArguments, - private initialOperationSpec: OperationSpec, - private sendOperation: SendOperationFn, - private finalStateVia?: FinalStateVia + public state: TState & ResumablePollOperationState, + private lro: LongRunningOperation ) {} - public setPollerConfig(pollerConfig: PollerConfig) { + public setPollerConfig(pollerConfig: PollerConfig): void { this.pollerConfig = pollerConfig; } @@ -57,45 +55,36 @@ export class GenericPollOperation */ async update(options?: { abortSignal?: AbortSignalLike | undefined; - fireProgress?: ((state: PollOperationState) => void) | undefined; - }): Promise, TResult>> { - const state = this.state as ResumablePollOperationState; - const { onResponse, ...restOptions } = - this.initialOperationArguments.options || {}; + fireProgress?: ((state: TState) => void) | undefined; + }): Promise> { + const state = this.state; if (!state.isStarted) { - await this.sendOperation( - { - ...this.initialOperationArguments, - options: { - ...restOptions, - onResponse: initializeState( - state, - this.initialOperationSpec, - onResponse - ) - } - }, - this.initialOperationSpec + const initializeState = createInitializeState( + state, + this.lro.requestPath, + this.lro.requestMethod ); + await this.lro.sendInitialRequest(initializeState); } if (!state.isCompleted) { - if (this.getLROState === undefined) { + if (this.getLROStatusFromResponse === undefined) { if (state.config === undefined) { - throw new Error("Bad state: LRO mode is undefined"); + throw new Error( + "Bad state: LRO mode is undefined. Please check if the serialized state is well-formed." + ); } - this.getLROState = createGetLROState( - this.sendOperation, - this.initialOperationArguments, - this.initialOperationSpec, - state.config, - this.finalStateVia + this.getLROStatusFromResponse = createPollForLROStatus( + this.lro, + state.config ); } if (state.pollingURL === undefined) { - throw new Error("Bad state: polling URL is undefined"); + throw new Error( + "Bad state: polling URL is undefined. Please check if the serialized state is well-formed." + ); } - const currentState = await this.getLROState( + const currentState = await this.getLROStatusFromResponse( state.pollingURL, this.pollerConfig! ); @@ -103,20 +92,19 @@ export class GenericPollOperation state.result = currentState.flatResponse; state.isCompleted = true; } else { - this.getLROState = currentState.next ?? this.getLROState; - state.pollingURL = getPollingURL( + this.getLROStatusFromResponse = + currentState.next ?? this.getLROStatusFromResponse; + state.pollingURL = getPollingUrl( currentState.rawResponse, state.pollingURL ); } } - if (options?.fireProgress !== undefined) { - options.fireProgress(state); - } + options?.fireProgress?.(state); return this; } - async cancel(): Promise, TResult>> { + async cancel(): Promise> { this.state.isCancelled = true; return this; } diff --git a/test/smoke/generated/storage-resource-manager/src/lro/passthrough.ts b/test/smoke/generated/storage-resource-manager/src/lro/passthrough.ts index 64c10380c1..ae7f87d384 100644 --- a/test/smoke/generated/storage-resource-manager/src/lro/passthrough.ts +++ b/test/smoke/generated/storage-resource-manager/src/lro/passthrough.ts @@ -7,15 +7,14 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; export function processPassthroughOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/storage-resource-manager/src/lro/pollingMethod.ts b/test/smoke/generated/storage-resource-manager/src/lro/pollingMethod.ts deleted file mode 100644 index cb6482bbde..0000000000 --- a/test/smoke/generated/storage-resource-manager/src/lro/pollingMethod.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - OperationArguments, - OperationSpec, - OperationResponseMap -} from "@azure/core-client"; -import { LROMode, LROResult, SendOperationFn } from "./models"; - -export function createPollingMethod( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - mode?: LROMode -): (path?: string) => Promise> { - /** - * Polling calls will always return a status object i.e. {"status": "success"} - * these intermediate responses are not described in the swagger so we need to - * pass custom mappers at runtime. - * This function replaces all the existing mappers to be able to deserialize a status object - * @param responses Original set of responses defined in the operation - */ - function getCompositeMappers(responses: { - [responseCode: string]: OperationResponseMap; - }): { - [responseCode: string]: OperationResponseMap; - } { - return Object.keys(responses).reduce((acc, statusCode) => { - return { - ...acc, - [statusCode]: { - ...responses[statusCode], - bodyMapper: { - type: { - name: "Composite", - modelProperties: { - status: { - serializedName: "status", - type: { - name: "String" - } - } - } - } - } - } - }; - }, {} as { [responseCode: string]: OperationResponseMap }); - } - // Make sure we don't send any body to the get request - const { requestBody, responses, ...restSpec } = spec; - if (mode === "AzureAsync") { - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: getCompositeMappers(responses), - httpMethod: "GET", - ...(path && { path }) - }); - }; - } - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: responses, - httpMethod: "GET", - ...(path && { path }) - }); - }; -} - -export function createRetrieveAzureAsyncResource( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec -): (path?: string) => Promise> { - const updatedArgs = { ...args }; - if (updatedArgs.options) { - (updatedArgs.options as any).shouldDeserialize = true; - } - return createPollingMethod(sendOperationFn, updatedArgs, spec); -} diff --git a/test/smoke/generated/storage-resource-manager/src/lro/requestUtils.ts b/test/smoke/generated/storage-resource-manager/src/lro/requestUtils.ts index 9162f66339..40d993686f 100644 --- a/test/smoke/generated/storage-resource-manager/src/lro/requestUtils.ts +++ b/test/smoke/generated/storage-resource-manager/src/lro/requestUtils.ts @@ -7,119 +7,9 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse, OperationSpec } from "@azure/core-client"; -import { LROConfig } from "./models"; -import { terminalStates } from "./stateMachine"; - -/** - * We need to selectively deserialize our responses, only deserializing if we - * are in a final LRO response, not deserializing any polling non-terminal responses - */ -export function shouldDeserializeLRO(finalStateVia?: string) { - let initialOperationInfo: LROResponseInfo | undefined; - let isInitialRequest = true; - - return (response: FullOperationResponse) => { - if (response.status < 200 || response.status >= 300) { - return true; - } - - if (!initialOperationInfo) { - initialOperationInfo = getLROData(response); - } else { - isInitialRequest = false; - } - - if ( - initialOperationInfo.azureAsyncOperation || - initialOperationInfo.operationLocation - ) { - return ( - !isInitialRequest && - isAsyncOperationFinalResponse( - response, - initialOperationInfo, - finalStateVia - ) - ); - } - - if (initialOperationInfo.location) { - return isLocationFinalResponse(response); - } - - if (initialOperationInfo.requestMethod === "PUT") { - return isBodyPollingFinalResponse(response); - } - - return true; - }; -} - -function isAsyncOperationFinalResponse( - response: FullOperationResponse, - initialOperationInfo: LROResponseInfo, - finalStateVia?: string -): boolean { - const status: string = response.parsedBody?.status || "Succeeded"; - if (!terminalStates.includes(status.toLowerCase())) { - return false; - } - - if (initialOperationInfo.requestMethod === "DELETE") { - return true; - } - - if ( - initialOperationInfo.requestMethod === "PUT" && - finalStateVia && - finalStateVia.toLowerCase() === "azure-asyncoperation" - ) { - return true; - } - - if ( - initialOperationInfo.requestMethod !== "PUT" && - !initialOperationInfo.location - ) { - return true; - } - - return false; -} - -function isLocationFinalResponse(response: FullOperationResponse): boolean { - return response.status !== 202; -} - -function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { - const provisioningState: string = - response.parsedBody?.properties?.provisioningState || "Succeeded"; - - if (terminalStates.includes(provisioningState.toLowerCase())) { - return true; - } - - return false; -} - -interface LROResponseInfo { - requestMethod: string; - azureAsyncOperation?: string; - operationLocation?: string; - location?: string; -} - -function getLROData(result: FullOperationResponse): LROResponseInfo { - return { - azureAsyncOperation: result.headers.get("azure-asyncoperation"), - operationLocation: result.headers.get("operation-location"), - location: result.headers.get("location"), - requestMethod: result.request.method - }; -} +import { LroConfig, RawResponse } from "./models"; /** * Detects where the continuation token is and returns it. Notice that azure-asyncoperation @@ -127,45 +17,41 @@ function getLROData(result: FullOperationResponse): LROResponseInfo { * where both azure-asyncoperation and location could be present in the same response but * azure-asyncoperation should be the one to use for polling. */ -export function getPollingURL( - rawResponse: FullOperationResponse, +export function getPollingUrl( + rawResponse: RawResponse, defaultPath: string ): string { return ( - getAzureAsyncoperation(rawResponse) ?? + getAzureAsyncOperation(rawResponse) ?? getLocation(rawResponse) ?? getOperationLocation(rawResponse) ?? defaultPath ); } -function getLocation(rawResponse: FullOperationResponse): string | undefined { - return rawResponse.headers?.get("location"); +function getLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["location"]; } -function getOperationLocation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("operation-location"); +function getOperationLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["operation-location"]; } -function getAzureAsyncoperation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("azure-asyncoperation"); +function getAzureAsyncOperation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["azure-asyncoperation"]; } -export function inferLROMode( - spec: OperationSpec, - rawResponse: FullOperationResponse -): LROConfig { - const requestMethod = spec.httpMethod; - if (getAzureAsyncoperation(rawResponse) !== undefined) { +export function inferLroMode( + requestPath: string, + requestMethod: string, + rawResponse: RawResponse +): LroConfig { + if (getAzureAsyncOperation(rawResponse) !== undefined) { return { mode: "AzureAsync", resourceLocation: requestMethod === "PUT" - ? spec.path + ? requestPath : requestMethod === "POST" ? getLocation(rawResponse) : undefined @@ -185,10 +71,35 @@ export function inferLROMode( return {}; } -export function getSpecPath(spec: OperationSpec): string { - if (spec.path) { - return spec.path; - } else { - throw Error("Bad spec: request path is not found!"); +export class RestError extends Error { + public statusCode?: number; + constructor(message: string, statusCode: number) { + super(message); + this.name = "RestError"; + this.statusCode = statusCode; + + Object.setPrototypeOf(this, RestError.prototype); + } +} + +export function isUnexpectedInitialResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![203, 204, 202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} in the initial response. This may indicate a server issue.`, + code + ); } + return false; +} + +export function isUnexpectedPollingResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} while polling. This may indicate a server issue.`, + code + ); + } + return false; } diff --git a/test/smoke/generated/storage-resource-manager/src/lro/stateMachine.ts b/test/smoke/generated/storage-resource-manager/src/lro/stateMachine.ts index b2a69b5546..19a8f67470 100644 --- a/test/smoke/generated/storage-resource-manager/src/lro/stateMachine.ts +++ b/test/smoke/generated/storage-resource-manager/src/lro/stateMachine.ts @@ -7,14 +7,8 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec, - RawResponseCallback -} from "@azure/core-client"; import { processAzureAsyncOperationResult } from "./azureAsyncPolling"; import { isBodyPollingDone, @@ -22,73 +16,36 @@ import { } from "./bodyPolling"; import { processLocationPollingOperationResult } from "./locationPolling"; import { - FinalStateVia, - LROConfig, - LROResult, + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroStatus, PollerConfig, - ResumablePollOperationState, - SendOperationFn + RawResponse, + ResumablePollOperationState } from "./models"; import { processPassthroughOperationResult } from "./passthrough"; import { - createPollingMethod, - createRetrieveAzureAsyncResource -} from "./pollingMethod"; -import { getPollingURL, getSpecPath, inferLROMode } from "./requestUtils"; - -export const successStates = ["succeeded"]; -export const failureStates = ["failed", "canceled", "cancelled"]; -export const terminalStates = successStates.concat(failureStates); - -/** - * The type of a terminal state of an LRO. - */ -interface LROTerminalState extends LROResult { - /** - * Whether the operation has finished. - */ - done: true; -} - -/** - * The type of an in-progress state of an LRO. - */ -interface LROInProgressState extends LROResult { - /** - * Whether the operation has finished. - */ - done: false; - /** - * The request to be sent next if it is different from the standard polling one. - * Notice that it will disregard any polling URLs provided to it. - */ - next?: () => Promise>; -} - -/** - * The type of an LRO state which is a tagged union of terminal and in-progress states. - */ -export type LROState = LROTerminalState | LROInProgressState; + getPollingUrl, + inferLroMode, + isUnexpectedInitialResponse +} from "./requestUtils"; /** * creates a stepping function that maps an LRO state to another. */ -function createTransition( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { +export function createGetLroStatusFromResponse( + lroPrimitives: LongRunningOperation, + config: LroConfig, + lroResourceLocationConfig?: LroResourceLocationConfig +): GetLroStatusFromResponse { switch (config.mode) { case "AzureAsync": { return processAzureAsyncOperationResult( - createRetrieveAzureAsyncResource(sendOperationFn, args, spec), + lroPrimitives, config.resourceLocation, - finalStateVia + lroResourceLocationConfig ); } case "Location": { @@ -106,52 +63,20 @@ function createTransition( /** * Creates a polling operation that returns a LRO state. */ -export function createGetLROState( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia +export function createPollForLROStatus( + lroPrimitives: LongRunningOperation, + config: LroConfig ): ( pollingURL: string, pollerConfig: PollerConfig -) => Promise> { - const step = createTransition( - sendOperationFn, - args, - spec, - config, - finalStateVia - ); - const customerCallback = args?.options?.onResponse; - let response: LROState | undefined = undefined; - let retryAfter: string | undefined = undefined; - const poll = createPollingMethod( - sendOperationFn, - { - ...args, - options: { - ...args.options, - onResponse: ( - rawResponse: FullOperationResponse, - flatResponse: unknown - ): void => { - response = step(rawResponse, flatResponse as TResult); - retryAfter = rawResponse.headers.get("Retry-After"); - if (response.done) { - customerCallback?.(rawResponse, flatResponse); - } - } - } - }, - spec, - config.mode - ); +) => Promise> { return async ( path: string, pollerConfig: PollerConfig - ): Promise> => { - await poll(path); + ): Promise> => { + const response = await lroPrimitives.sendPollRequest(config, path); + const retryAfter: string | undefined = + response.rawResponse.headers["retry-after"]; if (retryAfter !== undefined) { const retryAfterInMs = parseInt(retryAfter); pollerConfig.intervalInMs = isNaN(retryAfterInMs) @@ -161,7 +86,7 @@ export function createGetLROState( ) : retryAfterInMs; } - return response!; + return response; }; } @@ -179,24 +104,26 @@ function calculatePollingIntervalFromDate( /** * Creates a callback to be used to initialize the polling operation state. - * @param state of the polling operation - * @param operationSpec of the LRO - * @param callback callback to be called when the operation is done + * @param state - of the polling operation + * @param operationSpec - of the LRO + * @param callback - callback to be called when the operation is done * @returns callback that initializes the state of the polling operation */ -export function initializeState( +export function createInitializeState( state: ResumablePollOperationState, - operationSpec: OperationSpec, - callback?: RawResponseCallback -): (rawResponse: FullOperationResponse, flatResponse: unknown) => void { - return (rawResponse: FullOperationResponse, flatResponse: unknown) => { + requestPath: string, + requestMethod: string +): (rawResponse: RawResponse, flatResponse: unknown) => boolean { + return (rawResponse: RawResponse, flatResponse: unknown) => { + if (isUnexpectedInitialResponse(rawResponse)) return true; state.initialRawResponse = rawResponse; state.isStarted = true; - state.pollingURL = getPollingURL( - state.initialRawResponse, - getSpecPath(operationSpec) + state.pollingURL = getPollingUrl(state.initialRawResponse, requestPath); + state.config = inferLroMode( + requestPath, + requestMethod, + state.initialRawResponse ); - state.config = inferLROMode(operationSpec, state.initialRawResponse); /** short circuit polling if body polling is done in the initial request */ if ( state.config.mode === undefined || @@ -205,12 +132,7 @@ export function initializeState( ) { state.result = flatResponse as TResult; state.isCompleted = true; - /** - * We need to check if the LRO operation is finished inside the - * call back so that we can call the customer-provided callback - * on that result. - */ - callback?.(rawResponse, flatResponse); } + return Boolean(state.isCompleted); }; } diff --git a/test/smoke/generated/storage-resource-manager/src/operations/storageAccounts.ts b/test/smoke/generated/storage-resource-manager/src/operations/storageAccounts.ts index 72fd9ebd52..c726d9b9ca 100644 --- a/test/smoke/generated/storage-resource-manager/src/operations/storageAccounts.ts +++ b/test/smoke/generated/storage-resource-manager/src/operations/storageAccounts.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { StorageManagementClientContext } from "../storageManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { StorageAccount, StorageAccountsListNextOptionalParams, @@ -224,15 +225,22 @@ export class StorageAccountsImpl implements StorageAccounts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, parameters, options }, - createOperationSpec, - sendOperation + createOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -493,16 +501,23 @@ export class StorageAccountsImpl implements StorageAccounts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, options }, failoverOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -579,16 +594,23 @@ export class StorageAccountsImpl implements StorageAccounts { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, accountName, parameters, options }, restoreBlobRangesOperationSpec, - sendOperation, "location" ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/web-resource-manager/src/coreClientLro.ts b/test/smoke/generated/web-resource-manager/src/coreClientLro.ts new file mode 100644 index 0000000000..d793a24458 --- /dev/null +++ b/test/smoke/generated/web-resource-manager/src/coreClientLro.ts @@ -0,0 +1,323 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + OperationArguments, + OperationSpec, + OperationResponseMap, + FullOperationResponse +} from "@azure/core-client"; +import { + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + createGetLroStatusFromResponse, + RawResponse +} from "./lro"; + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +export const terminalStates = successStates.concat(failureStates); + +export type SendOperationFn = ( + args: OperationArguments, + spec: OperationSpec +) => Promise>; + +export function createPollingMethod( + sendOperationFn: SendOperationFn, + GetLroStatusFromResponse: GetLroStatusFromResponse, + args: OperationArguments, + spec: OperationSpec, + mode?: LroMode +): (path?: string) => Promise> { + /** + * Polling calls will always return a status object i.e. {"status": "success"} + * these intermediate responses are not described in the swagger so we need to + * pass custom mappers at runtime. + * This function replaces all the existing mappers to be able to deserialize a status object + * @param responses Original set of responses defined in the operation + */ + function getCompositeMappers(responses: { + [responseCode: string]: OperationResponseMap; + }): { + [responseCode: string]: OperationResponseMap; + } { + return Object.keys(responses).reduce((acc, statusCode) => { + return { + ...acc, + [statusCode]: { + ...responses[statusCode], + bodyMapper: { + type: { + name: "Composite", + modelProperties: { + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } + } + } + }; + }, {} as { [responseCode: string]: OperationResponseMap }); + } + let response: LroStatus | undefined = undefined; + const customerCallback = args?.options?.onResponse; + const updatedArgs = { + ...args, + options: { + ...args.options, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ): void => { + response = GetLroStatusFromResponse( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse as TResult + ); + if (response.done) { + customerCallback?.(rawResponse, flatResponse); + } + } + } + }; + // Make sure we don't send any body to the get request + const { requestBody, responses, ...restSpec } = spec; + if (mode === "AzureAsync") { + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: getCompositeMappers(responses), + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; + } + return async (path?: string) => { + await sendOperationFn(updatedArgs, { + ...restSpec, + responses: responses, + httpMethod: "GET", + ...(path && { path }) + }); + return response!; + }; +} + +/** + * We need to selectively deserialize our responses, only deserializing if we + * are in a final Lro response, not deserializing any polling non-terminal responses + */ +export function shouldDeserializeLro(lroResourceLocationConfig?: string) { + let initialOperationInfo: LroResponseInfo | undefined; + let isInitialRequest = true; + + return (response: FullOperationResponse) => { + if (response.status < 200 || response.status >= 300) { + return true; + } + + if (!initialOperationInfo) { + initialOperationInfo = getLroData(response); + } else { + isInitialRequest = false; + } + + if ( + initialOperationInfo.azureAsyncOperation || + initialOperationInfo.operationLocation + ) { + return ( + !isInitialRequest && + isAsyncOperationFinalResponse( + response, + initialOperationInfo, + lroResourceLocationConfig + ) + ); + } + + if (initialOperationInfo.location) { + return isLocationFinalResponse(response); + } + + if (initialOperationInfo.requestMethod === "PUT") { + return isBodyPollingFinalResponse(response); + } + + return true; + }; +} + +function isAsyncOperationFinalResponse( + response: FullOperationResponse, + initialOperationInfo: LroResponseInfo, + lroResourceLocationConfig?: string +): boolean { + const status: string = response.parsedBody?.status || "Succeeded"; + if (!terminalStates.includes(status.toLowerCase())) { + return false; + } + + if (initialOperationInfo.requestMethod === "DELETE") { + return true; + } + + if ( + initialOperationInfo.requestMethod === "PUT" && + lroResourceLocationConfig && + lroResourceLocationConfig.toLowerCase() === "azure-asyncoperation" + ) { + return true; + } + + if ( + initialOperationInfo.requestMethod !== "PUT" && + !initialOperationInfo.location + ) { + return true; + } + + return false; +} + +function isLocationFinalResponse(response: FullOperationResponse): boolean { + return response.status !== 202; +} + +function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { + const provisioningState: string = + response.parsedBody?.properties?.provisioningState || "Succeeded"; + + if (terminalStates.includes(provisioningState.toLowerCase())) { + return true; + } + + return false; +} + +interface LroResponseInfo { + requestMethod: string; + azureAsyncOperation?: string; + operationLocation?: string; + location?: string; +} + +function getLroData(result: FullOperationResponse): LroResponseInfo { + return { + azureAsyncOperation: result.headers.get("azure-asyncoperation"), + operationLocation: result.headers.get("operation-location"), + location: result.headers.get("location"), + requestMethod: result.request.method + }; +} + +export function getSpecPath(spec: OperationSpec): string { + if (spec.path) { + return spec.path; + } else { + throw Error("Bad spec: request path is not found!"); + } +} + +export class CoreClientLro implements LongRunningOperation { + constructor( + private sendOperationFn: SendOperationFn, + private args: OperationArguments, + private spec: OperationSpec, + private lroResourceLocationConfig?: LroResourceLocationConfig, + public requestPath: string = spec.path!, + public requestMethod: string = spec.httpMethod + ) {} + public async sendInitialRequest( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ): Promise> { + const { onResponse, ...restOptions } = this.args.options || {}; + return this.sendOperationFn( + { + ...this.args, + options: { + ...restOptions, + onResponse: ( + rawResponse: FullOperationResponse, + flatResponse: unknown + ) => { + const isCompleted = initializeState( + { + statusCode: rawResponse.status, + body: rawResponse.parsedBody, + headers: rawResponse.headers.toJSON() + }, + flatResponse + ); + if (isCompleted) { + onResponse?.(rawResponse, flatResponse); + } + } + } + }, + this.spec + ); + } + + public async sendPollRequest( + config: LroConfig, + path: string + ): Promise> { + const getLroStatusFromResponse = createGetLroStatusFromResponse( + this, + config, + this.lroResourceLocationConfig + ); + return createPollingMethod( + this.sendOperationFn, + getLroStatusFromResponse, + this.args, + this.spec, + config.mode + )(path); + } + + public async retrieveAzureAsyncResource( + path?: string + ): Promise> { + const updatedArgs = { ...this.args }; + if (updatedArgs.options) { + (updatedArgs.options as any).shouldDeserialize = true; + } + return createPollingMethod( + this.sendOperationFn, + (rawResponse, flatResponse) => ({ + rawResponse, + flatResponse, + done: true + }), + updatedArgs, + this.spec + )(path); + } +} diff --git a/test/smoke/generated/web-resource-manager/src/lro/azureAsyncPolling.ts b/test/smoke/generated/web-resource-manager/src/lro/azureAsyncPolling.ts index 0d63c54f60..725578a692 100644 --- a/test/smoke/generated/web-resource-manager/src/lro/azureAsyncPolling.ts +++ b/test/smoke/generated/web-resource-manager/src/lro/azureAsyncPolling.ts @@ -7,39 +7,61 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { FinalStateVia, LROResult } from "./models"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroResourceLocationConfig, + LongRunningOperation, + LroBody, + LroResponse, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getResponseStatus(rawResponse: FullOperationResponse): string { - const { status } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getResponseStatus(rawResponse: RawResponse): string { + const { status } = (rawResponse.body as LroBody) ?? {}; return status?.toLowerCase() ?? "succeeded"; } -function isAzureAsyncPollingDone(rawResponse: FullOperationResponse) { +function isAzureAsyncPollingDone(rawResponse: RawResponse): boolean { const state = getResponseStatus(rawResponse); - if (failureStates.includes(state)) { + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { throw new Error(`Operation status: ${state}`); } return successStates.includes(state); } +async function sendFinalRequest( + lro: LongRunningOperation, + lroResourceLocationConfig?: LroResourceLocationConfig, + resourceLocation?: string +): Promise | undefined> { + switch (lroResourceLocationConfig) { + case "original-uri": + return lro.retrieveAzureAsyncResource(); + case "azure-async-operation": + return Promise.resolve(undefined); + case "location": + default: + return lro.retrieveAzureAsyncResource(resourceLocation); + } +} + export function processAzureAsyncOperationResult( - restrieveResource: (path?: string) => Promise>, + lro: LongRunningOperation, resourceLocation?: string, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { + lroResourceLocationConfig?: LroResourceLocationConfig +): (rawResponse: RawResponse, flatResponse: TResult) => LroStatus { return ( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult - ): LROState => { + ): LroStatus => { if (isAzureAsyncPollingDone(rawResponse)) { if (resourceLocation === undefined) { return { rawResponse, flatResponse, done: true }; @@ -49,20 +71,11 @@ export function processAzureAsyncOperationResult( flatResponse, done: false, next: async () => { - async function sendFinalRequest(): Promise< - LROResult | undefined - > { - switch (finalStateVia) { - case "original-uri": - return restrieveResource(); - case "azure-async-operation": - return Promise.resolve(undefined); - case "location": - default: - return restrieveResource(resourceLocation); - } - } - const finalResponse = await sendFinalRequest(); + const finalResponse = await sendFinalRequest( + lro, + lroResourceLocationConfig, + resourceLocation + ); return { ...(finalResponse ?? { rawResponse, diff --git a/test/smoke/generated/web-resource-manager/src/lro/bodyPolling.ts b/test/smoke/generated/web-resource-manager/src/lro/bodyPolling.ts index 269d8e6799..b1c87f8bc8 100644 --- a/test/smoke/generated/web-resource-manager/src/lro/bodyPolling.ts +++ b/test/smoke/generated/web-resource-manager/src/lro/bodyPolling.ts @@ -7,24 +7,33 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { failureStates, LROState, successStates } from "./stateMachine"; +import { + failureStates, + LroBody, + LroStatus, + RawResponse, + successStates +} from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function getProvisioningState(rawResponse: FullOperationResponse): string { - const { properties, provisioningState } = - rawResponse.parsedBody ?? - (rawResponse.bodyAsText ? JSON.parse(rawResponse.bodyAsText) : {}); +function getProvisioningState(rawResponse: RawResponse): string { + const { properties, provisioningState } = (rawResponse.body as LroBody) ?? {}; const state: string | undefined = properties?.provisioningState ?? provisioningState; return state?.toLowerCase() ?? "succeeded"; } -export function isBodyPollingDone(rawResponse: FullOperationResponse) { +export function isBodyPollingDone(rawResponse: RawResponse): boolean { const state = getProvisioningState(rawResponse); - if (failureStates.includes(state)) { - throw new Error(`Provisioning state: ${state}`); + if ( + isUnexpectedPollingResponse(rawResponse) || + failureStates.includes(state) + ) { + throw new Error( + `The long running operation has failed. The provisioning state: ${state}.` + ); } return successStates.includes(state); } @@ -34,9 +43,9 @@ export function isBodyPollingDone(rawResponse: FullOperationResponse) { * from the result to determine the current operation state */ export function processBodyPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/web-resource-manager/src/lro/index.ts b/test/smoke/generated/web-resource-manager/src/lro/index.ts index 85c2187669..20df608fc8 100644 --- a/test/smoke/generated/web-resource-manager/src/lro/index.ts +++ b/test/smoke/generated/web-resource-manager/src/lro/index.ts @@ -6,5 +6,21 @@ * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ -export { shouldDeserializeLRO } from "./requestUtils"; -export { LROPoller } from "./lroPoller"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { LroEngine } from "./lroEngine"; +export { createGetLroStatusFromResponse } from "./stateMachine"; +export { + LroResourceLocationConfig, + GetLroStatusFromResponse, + RawResponse, + LongRunningOperation, + LroConfig, + LroMode, + LroResponse, + LroStatus, + LroTerminalState, + LroInProgressState, + LroEngineOptions +} from "./models"; diff --git a/test/smoke/generated/web-resource-manager/src/lro/locationPolling.ts b/test/smoke/generated/web-resource-manager/src/lro/locationPolling.ts index 6fef619384..9d1aadfbde 100644 --- a/test/smoke/generated/web-resource-manager/src/lro/locationPolling.ts +++ b/test/smoke/generated/web-resource-manager/src/lro/locationPolling.ts @@ -7,23 +7,21 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; +import { isUnexpectedPollingResponse } from "./requestUtils"; -function isLocationPollingDone(rawResponse: FullOperationResponse) { - const code = rawResponse.status; - if (![202, 200].includes(code)) { - throw new Error(`Operation failed`); - } - return code !== 202; +function isLocationPollingDone(rawResponse: RawResponse): boolean { + return ( + !isUnexpectedPollingResponse(rawResponse) && rawResponse.statusCode !== 202 + ); } export function processLocationPollingOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/web-resource-manager/src/lro/lroEngine.ts b/test/smoke/generated/web-resource-manager/src/lro/lroEngine.ts new file mode 100644 index 0000000000..85cc15e609 --- /dev/null +++ b/test/smoke/generated/web-resource-manager/src/lro/lroEngine.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Poller, PollOperationState } from "@azure/core-lro"; +import { + LongRunningOperation, + LroEngineOptions, + ResumablePollOperationState +} from "./models"; +import { GenericPollOperation } from "./operation"; + +/** + * The LRO Engine, a class that performs polling. + */ +export class LroEngine< + TResult, + TState extends PollOperationState +> extends Poller { + private intervalInMs: number; + + constructor(lro: LongRunningOperation, options?: LroEngineOptions) { + const { intervalInMs = 2000, resumeFrom } = options || {}; + function deserializeState( + resumeFrom: string + ): TState & ResumablePollOperationState { + try { + return JSON.parse(resumeFrom).state; + } catch (e) { + throw new Error( + `LroEngine: Unable to deserialize state: ${resumeFrom}` + ); + } + } + const state: TState & ResumablePollOperationState = resumeFrom + ? deserializeState(resumeFrom) + : ({} as any); + + const operation = new GenericPollOperation(state, lro); + super(operation); + + this.intervalInMs = intervalInMs; + operation.setPollerConfig(this as any); + } + + /** + * The method used by the poller to wait before attempting to update its operation. + */ + delay(): Promise { + return new Promise((resolve) => + setTimeout(() => resolve(), this.intervalInMs) + ); + } +} diff --git a/test/smoke/generated/web-resource-manager/src/lro/lroPoller.ts b/test/smoke/generated/web-resource-manager/src/lro/lroPoller.ts deleted file mode 100644 index cd1cd64fe8..0000000000 --- a/test/smoke/generated/web-resource-manager/src/lro/lroPoller.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { Poller, PollOperationState } from "@azure/core-lro"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { FinalStateVia, SendOperationFn } from "./models"; -import { GenericPollOperation } from "./operation"; - -export interface LROPollerOptions { - /** - * Defines how much time the poller is going to wait before making a new request to the service. - */ - intervalInMs?: number; - /** - * A serialized poller which can be used to resume an existing paused Long-Running-Operation. - */ - resumeFrom?: string; -} - -export class LROPoller extends Poller< - PollOperationState, - TResult -> { - private intervalInMs: number; - - constructor( - { intervalInMs = 2000, resumeFrom }: LROPollerOptions, - initialOperationArguments: OperationArguments, - initialOperationSpec: OperationSpec, - sendOperation: SendOperationFn, - finalStateVia?: FinalStateVia - ) { - const state: PollOperationState = resumeFrom - ? JSON.parse(resumeFrom).state - : {}; - - const operation = new GenericPollOperation( - state, - initialOperationArguments, - initialOperationSpec, - sendOperation, - finalStateVia - ); - super(operation); - - this.intervalInMs = intervalInMs; - operation.setPollerConfig(this as any); - } - - /** - * The method used by the poller to wait before attempting to update its operation. - */ - delay(): Promise { - return new Promise((resolve) => - setTimeout(() => resolve(), this.intervalInMs) - ); - } -} diff --git a/test/smoke/generated/web-resource-manager/src/lro/models.ts b/test/smoke/generated/web-resource-manager/src/lro/models.ts index a4a5a5abd6..93c3437c8e 100644 --- a/test/smoke/generated/web-resource-manager/src/lro/models.ts +++ b/test/smoke/generated/web-resource-manager/src/lro/models.ts @@ -7,46 +7,167 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec -} from "@azure/core-client"; import { PollOperationState } from "@azure/core-lro"; -export type FinalStateVia = +/** + * Options for the LRO poller. + */ +export interface LroEngineOptions { + /** + * Defines how much time the poller is going to wait before making a new request to the service. + */ + intervalInMs?: number; + /** + * A serialized poller which can be used to resume an existing paused Long-Running-Operation. + */ + resumeFrom?: string; +} + +export const successStates = ["succeeded"]; +export const failureStates = ["failed", "canceled", "cancelled"]; +/** + * The LRO states that signal that the LRO has completed. + */ +export const terminalStates = successStates.concat(failureStates); + +/** + * The potential location of the result of the LRO if specified by the LRO extension in the swagger. + */ +export type LroResourceLocationConfig = | "azure-async-operation" | "location" | "original-uri"; -export interface LROResult { +/** + * The type of a LRO response body. This is just a convenience type for checking the status of the operation. + */ + +export interface LroBody extends Record { + /** The status of the operation. */ + status?: string; + /** The state of the provisioning process */ + provisioningState?: string; + /** The properties of the provisioning process */ + properties?: { provisioningState?: string } & Record; +} + +/** + * Simple type of the raw response. + */ +export interface RawResponse { + /** The HTTP status code */ + statusCode: number; + /** A HttpHeaders collection in the response represented as a simple JSON object where all header names have been normalized to be lower-case. */ + headers: { + [headerName: string]: string; + }; + /** The parsed response body */ + body?: unknown; +} + +/** + * The type of the response of a LRO. + */ +export interface LroResponse { + /** The flattened response */ flatResponse: T; - rawResponse: FullOperationResponse; + /** The raw response */ + rawResponse: RawResponse; } -export type LROMode = "AzureAsync" | "Location" | "Body"; +/** The type of which LRO implementation being followed by a specific API. */ +export type LroMode = "AzureAsync" | "Location" | "Body"; -export interface LROConfig { - mode?: LROMode; +/** + * The configuration of a LRO to determine how to perform polling and checking whether the operation has completed. + */ +export interface LroConfig { + /** The LRO mode */ + mode?: LroMode; + /** The path of a provisioned resource */ resourceLocation?: string; } -export type SendOperationFn = ( - args: OperationArguments, - spec: OperationSpec -) => Promise>; - /** * Type of a polling operation state that can actually be resumed. */ export type ResumablePollOperationState = PollOperationState & { - initialRawResponse?: FullOperationResponse; - config?: LROConfig; + initialRawResponse?: RawResponse; + config?: LroConfig; pollingURL?: string; }; export interface PollerConfig { intervalInMs: number; } + +/** + * The type of a terminal state of an LRO. + */ +export interface LroTerminalState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: true; +} + +/** + * The type of an in-progress state of an LRO. + */ +export interface LroInProgressState extends LroResponse { + /** + * Whether the operation has finished. + */ + done: false; + /** + * The request to be sent next if it is different from the standard polling one. + * Notice that it will disregard any polling URLs provided to it. + */ + next?: () => Promise>; +} + +/** + * The type of an LRO state which is a tagged union of terminal and in-progress states. + */ +export type LroStatus = LroTerminalState | LroInProgressState; + +/** + * The type of the getLROStatusFromResponse method. It takes the response as input and returns along the response whether the operation has finished. + */ +export type GetLroStatusFromResponse = ( + rawResponse: RawResponse, + flatResponse: T +) => LroStatus; + +/** + * Description of a long running operation. + */ +export interface LongRunningOperation { + /** + * The request path. + */ + requestPath: string; + /** + * The HTTP request method. + */ + requestMethod: string; + /** + * A function that can be used to send initial request to the service. + */ + sendInitialRequest: ( + initializeState: ( + rawResponse: RawResponse, + flatResponse: unknown + ) => boolean + ) => Promise>; + /** + * A function that can be used to poll for the current status of a long running operation. + */ + sendPollRequest: (config: LroConfig, path: string) => Promise>; + /** + * A function that can be used to retrieve the provisioned azure resource. + */ + retrieveAzureAsyncResource: (path?: string) => Promise>; +} diff --git a/test/smoke/generated/web-resource-manager/src/lro/operation.ts b/test/smoke/generated/web-resource-manager/src/lro/operation.ts index 801d03e720..3ea7b76d89 100644 --- a/test/smoke/generated/web-resource-manager/src/lro/operation.ts +++ b/test/smoke/generated/web-resource-manager/src/lro/operation.ts @@ -7,36 +7,34 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. import { AbortSignalLike } from "@azure/abort-controller"; -import { OperationArguments, OperationSpec } from "@azure/core-client"; -import { PollOperation, PollOperationState } from "@azure/core-lro"; +import { PollOperationState, PollOperation } from "@azure/core-lro"; import { - FinalStateVia, PollerConfig, ResumablePollOperationState, - SendOperationFn + LongRunningOperation, + LroStatus } from "./models"; -import { getPollingURL } from "./requestUtils"; -import { createGetLROState, initializeState, LROState } from "./stateMachine"; +import { getPollingUrl } from "./requestUtils"; +import { createInitializeState, createPollForLROStatus } from "./stateMachine"; -export class GenericPollOperation - implements PollOperation, TResult> { - private getLROState?: ( +export class GenericPollOperation< + TResult, + TState extends PollOperationState +> implements PollOperation { + private getLROStatusFromResponse?: ( pollingURL: string, pollerConfig: PollerConfig - ) => Promise>; + ) => Promise>; private pollerConfig?: PollerConfig; constructor( - public state: PollOperationState, - private initialOperationArguments: OperationArguments, - private initialOperationSpec: OperationSpec, - private sendOperation: SendOperationFn, - private finalStateVia?: FinalStateVia + public state: TState & ResumablePollOperationState, + private lro: LongRunningOperation ) {} - public setPollerConfig(pollerConfig: PollerConfig) { + public setPollerConfig(pollerConfig: PollerConfig): void { this.pollerConfig = pollerConfig; } @@ -57,45 +55,36 @@ export class GenericPollOperation */ async update(options?: { abortSignal?: AbortSignalLike | undefined; - fireProgress?: ((state: PollOperationState) => void) | undefined; - }): Promise, TResult>> { - const state = this.state as ResumablePollOperationState; - const { onResponse, ...restOptions } = - this.initialOperationArguments.options || {}; + fireProgress?: ((state: TState) => void) | undefined; + }): Promise> { + const state = this.state; if (!state.isStarted) { - await this.sendOperation( - { - ...this.initialOperationArguments, - options: { - ...restOptions, - onResponse: initializeState( - state, - this.initialOperationSpec, - onResponse - ) - } - }, - this.initialOperationSpec + const initializeState = createInitializeState( + state, + this.lro.requestPath, + this.lro.requestMethod ); + await this.lro.sendInitialRequest(initializeState); } if (!state.isCompleted) { - if (this.getLROState === undefined) { + if (this.getLROStatusFromResponse === undefined) { if (state.config === undefined) { - throw new Error("Bad state: LRO mode is undefined"); + throw new Error( + "Bad state: LRO mode is undefined. Please check if the serialized state is well-formed." + ); } - this.getLROState = createGetLROState( - this.sendOperation, - this.initialOperationArguments, - this.initialOperationSpec, - state.config, - this.finalStateVia + this.getLROStatusFromResponse = createPollForLROStatus( + this.lro, + state.config ); } if (state.pollingURL === undefined) { - throw new Error("Bad state: polling URL is undefined"); + throw new Error( + "Bad state: polling URL is undefined. Please check if the serialized state is well-formed." + ); } - const currentState = await this.getLROState( + const currentState = await this.getLROStatusFromResponse( state.pollingURL, this.pollerConfig! ); @@ -103,20 +92,19 @@ export class GenericPollOperation state.result = currentState.flatResponse; state.isCompleted = true; } else { - this.getLROState = currentState.next ?? this.getLROState; - state.pollingURL = getPollingURL( + this.getLROStatusFromResponse = + currentState.next ?? this.getLROStatusFromResponse; + state.pollingURL = getPollingUrl( currentState.rawResponse, state.pollingURL ); } } - if (options?.fireProgress !== undefined) { - options.fireProgress(state); - } + options?.fireProgress?.(state); return this; } - async cancel(): Promise, TResult>> { + async cancel(): Promise> { this.state.isCancelled = true; return this; } diff --git a/test/smoke/generated/web-resource-manager/src/lro/passthrough.ts b/test/smoke/generated/web-resource-manager/src/lro/passthrough.ts index 64c10380c1..ae7f87d384 100644 --- a/test/smoke/generated/web-resource-manager/src/lro/passthrough.ts +++ b/test/smoke/generated/web-resource-manager/src/lro/passthrough.ts @@ -7,15 +7,14 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse } from "@azure/core-client"; -import { LROState } from "./stateMachine"; +import { LroStatus, RawResponse } from "./models"; export function processPassthroughOperationResult( - rawResponse: FullOperationResponse, + rawResponse: RawResponse, flatResponse: TResult -): LROState { +): LroStatus { return { rawResponse, flatResponse, diff --git a/test/smoke/generated/web-resource-manager/src/lro/pollingMethod.ts b/test/smoke/generated/web-resource-manager/src/lro/pollingMethod.ts deleted file mode 100644 index cb6482bbde..0000000000 --- a/test/smoke/generated/web-resource-manager/src/lro/pollingMethod.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - * - * Code generated by Microsoft (R) AutoRest Code Generator. - * Changes may cause incorrect behavior and will be lost if the code is regenerated. - */ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - OperationArguments, - OperationSpec, - OperationResponseMap -} from "@azure/core-client"; -import { LROMode, LROResult, SendOperationFn } from "./models"; - -export function createPollingMethod( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - mode?: LROMode -): (path?: string) => Promise> { - /** - * Polling calls will always return a status object i.e. {"status": "success"} - * these intermediate responses are not described in the swagger so we need to - * pass custom mappers at runtime. - * This function replaces all the existing mappers to be able to deserialize a status object - * @param responses Original set of responses defined in the operation - */ - function getCompositeMappers(responses: { - [responseCode: string]: OperationResponseMap; - }): { - [responseCode: string]: OperationResponseMap; - } { - return Object.keys(responses).reduce((acc, statusCode) => { - return { - ...acc, - [statusCode]: { - ...responses[statusCode], - bodyMapper: { - type: { - name: "Composite", - modelProperties: { - status: { - serializedName: "status", - type: { - name: "String" - } - } - } - } - } - } - }; - }, {} as { [responseCode: string]: OperationResponseMap }); - } - // Make sure we don't send any body to the get request - const { requestBody, responses, ...restSpec } = spec; - if (mode === "AzureAsync") { - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: getCompositeMappers(responses), - httpMethod: "GET", - ...(path && { path }) - }); - }; - } - return async (path?: string) => { - return sendOperationFn(args, { - ...restSpec, - responses: responses, - httpMethod: "GET", - ...(path && { path }) - }); - }; -} - -export function createRetrieveAzureAsyncResource( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec -): (path?: string) => Promise> { - const updatedArgs = { ...args }; - if (updatedArgs.options) { - (updatedArgs.options as any).shouldDeserialize = true; - } - return createPollingMethod(sendOperationFn, updatedArgs, spec); -} diff --git a/test/smoke/generated/web-resource-manager/src/lro/requestUtils.ts b/test/smoke/generated/web-resource-manager/src/lro/requestUtils.ts index 9162f66339..40d993686f 100644 --- a/test/smoke/generated/web-resource-manager/src/lro/requestUtils.ts +++ b/test/smoke/generated/web-resource-manager/src/lro/requestUtils.ts @@ -7,119 +7,9 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { FullOperationResponse, OperationSpec } from "@azure/core-client"; -import { LROConfig } from "./models"; -import { terminalStates } from "./stateMachine"; - -/** - * We need to selectively deserialize our responses, only deserializing if we - * are in a final LRO response, not deserializing any polling non-terminal responses - */ -export function shouldDeserializeLRO(finalStateVia?: string) { - let initialOperationInfo: LROResponseInfo | undefined; - let isInitialRequest = true; - - return (response: FullOperationResponse) => { - if (response.status < 200 || response.status >= 300) { - return true; - } - - if (!initialOperationInfo) { - initialOperationInfo = getLROData(response); - } else { - isInitialRequest = false; - } - - if ( - initialOperationInfo.azureAsyncOperation || - initialOperationInfo.operationLocation - ) { - return ( - !isInitialRequest && - isAsyncOperationFinalResponse( - response, - initialOperationInfo, - finalStateVia - ) - ); - } - - if (initialOperationInfo.location) { - return isLocationFinalResponse(response); - } - - if (initialOperationInfo.requestMethod === "PUT") { - return isBodyPollingFinalResponse(response); - } - - return true; - }; -} - -function isAsyncOperationFinalResponse( - response: FullOperationResponse, - initialOperationInfo: LROResponseInfo, - finalStateVia?: string -): boolean { - const status: string = response.parsedBody?.status || "Succeeded"; - if (!terminalStates.includes(status.toLowerCase())) { - return false; - } - - if (initialOperationInfo.requestMethod === "DELETE") { - return true; - } - - if ( - initialOperationInfo.requestMethod === "PUT" && - finalStateVia && - finalStateVia.toLowerCase() === "azure-asyncoperation" - ) { - return true; - } - - if ( - initialOperationInfo.requestMethod !== "PUT" && - !initialOperationInfo.location - ) { - return true; - } - - return false; -} - -function isLocationFinalResponse(response: FullOperationResponse): boolean { - return response.status !== 202; -} - -function isBodyPollingFinalResponse(response: FullOperationResponse): boolean { - const provisioningState: string = - response.parsedBody?.properties?.provisioningState || "Succeeded"; - - if (terminalStates.includes(provisioningState.toLowerCase())) { - return true; - } - - return false; -} - -interface LROResponseInfo { - requestMethod: string; - azureAsyncOperation?: string; - operationLocation?: string; - location?: string; -} - -function getLROData(result: FullOperationResponse): LROResponseInfo { - return { - azureAsyncOperation: result.headers.get("azure-asyncoperation"), - operationLocation: result.headers.get("operation-location"), - location: result.headers.get("location"), - requestMethod: result.request.method - }; -} +import { LroConfig, RawResponse } from "./models"; /** * Detects where the continuation token is and returns it. Notice that azure-asyncoperation @@ -127,45 +17,41 @@ function getLROData(result: FullOperationResponse): LROResponseInfo { * where both azure-asyncoperation and location could be present in the same response but * azure-asyncoperation should be the one to use for polling. */ -export function getPollingURL( - rawResponse: FullOperationResponse, +export function getPollingUrl( + rawResponse: RawResponse, defaultPath: string ): string { return ( - getAzureAsyncoperation(rawResponse) ?? + getAzureAsyncOperation(rawResponse) ?? getLocation(rawResponse) ?? getOperationLocation(rawResponse) ?? defaultPath ); } -function getLocation(rawResponse: FullOperationResponse): string | undefined { - return rawResponse.headers?.get("location"); +function getLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["location"]; } -function getOperationLocation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("operation-location"); +function getOperationLocation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["operation-location"]; } -function getAzureAsyncoperation( - rawResponse: FullOperationResponse -): string | undefined { - return rawResponse.headers?.get("azure-asyncoperation"); +function getAzureAsyncOperation(rawResponse: RawResponse): string | undefined { + return rawResponse.headers["azure-asyncoperation"]; } -export function inferLROMode( - spec: OperationSpec, - rawResponse: FullOperationResponse -): LROConfig { - const requestMethod = spec.httpMethod; - if (getAzureAsyncoperation(rawResponse) !== undefined) { +export function inferLroMode( + requestPath: string, + requestMethod: string, + rawResponse: RawResponse +): LroConfig { + if (getAzureAsyncOperation(rawResponse) !== undefined) { return { mode: "AzureAsync", resourceLocation: requestMethod === "PUT" - ? spec.path + ? requestPath : requestMethod === "POST" ? getLocation(rawResponse) : undefined @@ -185,10 +71,35 @@ export function inferLROMode( return {}; } -export function getSpecPath(spec: OperationSpec): string { - if (spec.path) { - return spec.path; - } else { - throw Error("Bad spec: request path is not found!"); +export class RestError extends Error { + public statusCode?: number; + constructor(message: string, statusCode: number) { + super(message); + this.name = "RestError"; + this.statusCode = statusCode; + + Object.setPrototypeOf(this, RestError.prototype); + } +} + +export function isUnexpectedInitialResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![203, 204, 202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} in the initial response. This may indicate a server issue.`, + code + ); } + return false; +} + +export function isUnexpectedPollingResponse(rawResponse: RawResponse): boolean { + const code = rawResponse.statusCode; + if (![202, 201, 200, 500].includes(code)) { + throw new RestError( + `Received unexpected HTTP status code ${code} while polling. This may indicate a server issue.`, + code + ); + } + return false; } diff --git a/test/smoke/generated/web-resource-manager/src/lro/stateMachine.ts b/test/smoke/generated/web-resource-manager/src/lro/stateMachine.ts index b2a69b5546..19a8f67470 100644 --- a/test/smoke/generated/web-resource-manager/src/lro/stateMachine.ts +++ b/test/smoke/generated/web-resource-manager/src/lro/stateMachine.ts @@ -7,14 +7,8 @@ */ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. +// Licensed under the MIT license. -import { - FullOperationResponse, - OperationArguments, - OperationSpec, - RawResponseCallback -} from "@azure/core-client"; import { processAzureAsyncOperationResult } from "./azureAsyncPolling"; import { isBodyPollingDone, @@ -22,73 +16,36 @@ import { } from "./bodyPolling"; import { processLocationPollingOperationResult } from "./locationPolling"; import { - FinalStateVia, - LROConfig, - LROResult, + LroResourceLocationConfig, + GetLroStatusFromResponse, + LongRunningOperation, + LroConfig, + LroStatus, PollerConfig, - ResumablePollOperationState, - SendOperationFn + RawResponse, + ResumablePollOperationState } from "./models"; import { processPassthroughOperationResult } from "./passthrough"; import { - createPollingMethod, - createRetrieveAzureAsyncResource -} from "./pollingMethod"; -import { getPollingURL, getSpecPath, inferLROMode } from "./requestUtils"; - -export const successStates = ["succeeded"]; -export const failureStates = ["failed", "canceled", "cancelled"]; -export const terminalStates = successStates.concat(failureStates); - -/** - * The type of a terminal state of an LRO. - */ -interface LROTerminalState extends LROResult { - /** - * Whether the operation has finished. - */ - done: true; -} - -/** - * The type of an in-progress state of an LRO. - */ -interface LROInProgressState extends LROResult { - /** - * Whether the operation has finished. - */ - done: false; - /** - * The request to be sent next if it is different from the standard polling one. - * Notice that it will disregard any polling URLs provided to it. - */ - next?: () => Promise>; -} - -/** - * The type of an LRO state which is a tagged union of terminal and in-progress states. - */ -export type LROState = LROTerminalState | LROInProgressState; + getPollingUrl, + inferLroMode, + isUnexpectedInitialResponse +} from "./requestUtils"; /** * creates a stepping function that maps an LRO state to another. */ -function createTransition( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia -): ( - rawResponse: FullOperationResponse, - flatResponse: TResult -) => LROState { +export function createGetLroStatusFromResponse( + lroPrimitives: LongRunningOperation, + config: LroConfig, + lroResourceLocationConfig?: LroResourceLocationConfig +): GetLroStatusFromResponse { switch (config.mode) { case "AzureAsync": { return processAzureAsyncOperationResult( - createRetrieveAzureAsyncResource(sendOperationFn, args, spec), + lroPrimitives, config.resourceLocation, - finalStateVia + lroResourceLocationConfig ); } case "Location": { @@ -106,52 +63,20 @@ function createTransition( /** * Creates a polling operation that returns a LRO state. */ -export function createGetLROState( - sendOperationFn: SendOperationFn, - args: OperationArguments, - spec: OperationSpec, - config: LROConfig, - finalStateVia?: FinalStateVia +export function createPollForLROStatus( + lroPrimitives: LongRunningOperation, + config: LroConfig ): ( pollingURL: string, pollerConfig: PollerConfig -) => Promise> { - const step = createTransition( - sendOperationFn, - args, - spec, - config, - finalStateVia - ); - const customerCallback = args?.options?.onResponse; - let response: LROState | undefined = undefined; - let retryAfter: string | undefined = undefined; - const poll = createPollingMethod( - sendOperationFn, - { - ...args, - options: { - ...args.options, - onResponse: ( - rawResponse: FullOperationResponse, - flatResponse: unknown - ): void => { - response = step(rawResponse, flatResponse as TResult); - retryAfter = rawResponse.headers.get("Retry-After"); - if (response.done) { - customerCallback?.(rawResponse, flatResponse); - } - } - } - }, - spec, - config.mode - ); +) => Promise> { return async ( path: string, pollerConfig: PollerConfig - ): Promise> => { - await poll(path); + ): Promise> => { + const response = await lroPrimitives.sendPollRequest(config, path); + const retryAfter: string | undefined = + response.rawResponse.headers["retry-after"]; if (retryAfter !== undefined) { const retryAfterInMs = parseInt(retryAfter); pollerConfig.intervalInMs = isNaN(retryAfterInMs) @@ -161,7 +86,7 @@ export function createGetLROState( ) : retryAfterInMs; } - return response!; + return response; }; } @@ -179,24 +104,26 @@ function calculatePollingIntervalFromDate( /** * Creates a callback to be used to initialize the polling operation state. - * @param state of the polling operation - * @param operationSpec of the LRO - * @param callback callback to be called when the operation is done + * @param state - of the polling operation + * @param operationSpec - of the LRO + * @param callback - callback to be called when the operation is done * @returns callback that initializes the state of the polling operation */ -export function initializeState( +export function createInitializeState( state: ResumablePollOperationState, - operationSpec: OperationSpec, - callback?: RawResponseCallback -): (rawResponse: FullOperationResponse, flatResponse: unknown) => void { - return (rawResponse: FullOperationResponse, flatResponse: unknown) => { + requestPath: string, + requestMethod: string +): (rawResponse: RawResponse, flatResponse: unknown) => boolean { + return (rawResponse: RawResponse, flatResponse: unknown) => { + if (isUnexpectedInitialResponse(rawResponse)) return true; state.initialRawResponse = rawResponse; state.isStarted = true; - state.pollingURL = getPollingURL( - state.initialRawResponse, - getSpecPath(operationSpec) + state.pollingURL = getPollingUrl(state.initialRawResponse, requestPath); + state.config = inferLroMode( + requestPath, + requestMethod, + state.initialRawResponse ); - state.config = inferLROMode(operationSpec, state.initialRawResponse); /** short circuit polling if body polling is done in the initial request */ if ( state.config.mode === undefined || @@ -205,12 +132,7 @@ export function initializeState( ) { state.result = flatResponse as TResult; state.isCompleted = true; - /** - * We need to check if the LRO operation is finished inside the - * call back so that we can call the customer-provided callback - * on that result. - */ - callback?.(rawResponse, flatResponse); } + return Boolean(state.isCompleted); }; } diff --git a/test/smoke/generated/web-resource-manager/src/operations/appServiceCertificateOrders.ts b/test/smoke/generated/web-resource-manager/src/operations/appServiceCertificateOrders.ts index 5966856cfd..79dd672b01 100644 --- a/test/smoke/generated/web-resource-manager/src/operations/appServiceCertificateOrders.ts +++ b/test/smoke/generated/web-resource-manager/src/operations/appServiceCertificateOrders.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { WebSiteManagementClientContext } from "../webSiteManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { AppServiceCertificateOrder, AppServiceCertificateOrdersListNextOptionalParams, @@ -348,20 +349,27 @@ export class AppServiceCertificateOrdersImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, certificateOrderName, certificateDistinguishedName, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -514,11 +522,18 @@ export class AppServiceCertificateOrdersImpl } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, certificateOrderName, @@ -526,9 +541,9 @@ export class AppServiceCertificateOrdersImpl keyVaultCertificate, options }, - createOrUpdateCertificateOperationSpec, - sendOperation + createOrUpdateCertificateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/web-resource-manager/src/operations/appServiceEnvironments.ts b/test/smoke/generated/web-resource-manager/src/operations/appServiceEnvironments.ts index 63e051a877..7e85d65eee 100644 --- a/test/smoke/generated/web-resource-manager/src/operations/appServiceEnvironments.ts +++ b/test/smoke/generated/web-resource-manager/src/operations/appServiceEnvironments.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { WebSiteManagementClientContext } from "../webSiteManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { AppServiceEnvironmentResource, AppServiceEnvironmentsListNextOptionalParams, @@ -1690,15 +1691,22 @@ export class AppServiceEnvironmentsImpl implements AppServiceEnvironments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, hostingEnvironmentEnvelope, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1763,15 +1771,22 @@ export class AppServiceEnvironmentsImpl implements AppServiceEnvironments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, options }, - deleteOperationSpec, - sendOperation + deleteOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -1889,15 +1904,22 @@ export class AppServiceEnvironmentsImpl implements AppServiceEnvironments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, vnetInfo, options }, - changeVnetOperationSpec, - sendOperation + changeVnetOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -2038,15 +2060,22 @@ export class AppServiceEnvironmentsImpl implements AppServiceEnvironments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, multiRolePoolEnvelope, options }, - createOrUpdateMultiRolePoolOperationSpec, - sendOperation + createOrUpdateMultiRolePoolOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -2262,15 +2291,22 @@ export class AppServiceEnvironmentsImpl implements AppServiceEnvironments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, options }, - resumeOperationSpec, - sendOperation + resumeOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -2352,15 +2388,22 @@ export class AppServiceEnvironmentsImpl implements AppServiceEnvironments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, options }, - suspendOperationSpec, - sendOperation + suspendOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -2467,15 +2510,22 @@ export class AppServiceEnvironmentsImpl implements AppServiceEnvironments { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, workerPoolName, workerPoolEnvelope, options }, - createOrUpdateWorkerPoolOperationSpec, - sendOperation + createOrUpdateWorkerPoolOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/web-resource-manager/src/operations/appServicePlans.ts b/test/smoke/generated/web-resource-manager/src/operations/appServicePlans.ts index ed0470b1fa..2e160197c9 100644 --- a/test/smoke/generated/web-resource-manager/src/operations/appServicePlans.ts +++ b/test/smoke/generated/web-resource-manager/src/operations/appServicePlans.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { WebSiteManagementClientContext } from "../webSiteManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { AppServicePlan, AppServicePlansListNextOptionalParams, @@ -561,15 +562,22 @@ export class AppServicePlansImpl implements AppServicePlans { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, appServicePlan, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/web-resource-manager/src/operations/domains.ts b/test/smoke/generated/web-resource-manager/src/operations/domains.ts index 03948690c1..01d883c9f7 100644 --- a/test/smoke/generated/web-resource-manager/src/operations/domains.ts +++ b/test/smoke/generated/web-resource-manager/src/operations/domains.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { WebSiteManagementClientContext } from "../webSiteManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { Domain, DomainsListNextOptionalParams, @@ -422,15 +423,22 @@ export class DomainsImpl implements Domains { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, domainName, domain, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/smoke/generated/web-resource-manager/src/operations/webApps.ts b/test/smoke/generated/web-resource-manager/src/operations/webApps.ts index e3c4e6e0c1..c5d83b8594 100644 --- a/test/smoke/generated/web-resource-manager/src/operations/webApps.ts +++ b/test/smoke/generated/web-resource-manager/src/operations/webApps.ts @@ -13,8 +13,9 @@ import * as coreClient from "@azure/core-client"; import * as Mappers from "../models/mappers"; import * as Parameters from "../models/parameters"; import { WebSiteManagementClientContext } from "../webSiteManagementClientContext"; -import { LROPoller, shouldDeserializeLRO } from "../lro"; import { PollerLike, PollOperationState } from "@azure/core-lro"; +import { LroEngine } from "../lro"; +import { CoreClientLro, shouldDeserializeLro } from "../coreClientLro"; import { Site, WebAppsListNextOptionalParams, @@ -5127,15 +5128,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, siteEnvelope, options }, - createOrUpdateOperationSpec, - sendOperation + createOrUpdateOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -5378,15 +5386,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, backupId, request, options }, - restoreOperationSpec, - sendOperation + restoreOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -5782,15 +5797,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, options }, - listPublishingCredentialsOperationSpec, - sendOperation + listPublishingCredentialsOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -6417,15 +6439,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, mSDeploy, options }, - createMSDeployOperationOperationSpec, - sendOperation + createMSDeployOperationOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -6569,15 +6598,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, functionName, functionEnvelope, options }, - createFunctionOperationSpec, - sendOperation + createFunctionOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -7199,15 +7235,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, instanceId, mSDeploy, options }, - createInstanceMSDeployOperationOperationSpec, - sendOperation + createInstanceMSDeployOperationOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -7513,15 +7556,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { subscriptionName, resourceGroupName, name, migrationOptions, options }, - migrateStorageOperationSpec, - sendOperation + migrateStorageOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -7596,15 +7646,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, migrationRequestEnvelope, options }, - migrateMySqlOperationSpec, - sendOperation + migrateMySqlOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -7826,15 +7883,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, options }, - startWebSiteNetworkTraceOperationOperationSpec, - sendOperation + startWebSiteNetworkTraceOperationOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -8437,15 +8501,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, request, options }, - restoreFromBackupBlobOperationSpec, - sendOperation + restoreFromBackupBlobOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -8512,15 +8583,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, restoreRequest, options }, - restoreFromDeletedAppOperationSpec, - sendOperation + restoreFromDeletedAppOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -8588,15 +8666,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, restoreRequest, options }, - restoreSnapshotOperationSpec, - sendOperation + restoreSnapshotOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -8705,15 +8790,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, siteExtensionId, options }, - installSiteExtensionOperationSpec, - sendOperation + installSiteExtensionOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -8800,15 +8892,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, copySlotEntity, options }, - copyProductionSlotOperationSpec, - sendOperation + copyProductionSlotOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -8922,15 +9021,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, slot, siteEnvelope, options }, - createOrUpdateSlotOperationSpec, - sendOperation + createOrUpdateSlotOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -9204,15 +9310,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, backupId, slot, request, options }, - restoreSlotOperationSpec, - sendOperation + restoreSlotOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -9626,15 +9739,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, slot, options }, - listPublishingCredentialsSlotOperationSpec, - sendOperation + listPublishingCredentialsSlotOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -10307,15 +10427,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, slot, mSDeploy, options }, - createMSDeployOperationSlotOperationSpec, - sendOperation + createMSDeployOperationSlotOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -10472,11 +10599,18 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, @@ -10485,9 +10619,9 @@ export class WebAppsImpl implements WebApps { functionEnvelope, options }, - createInstanceFunctionSlotOperationSpec, - sendOperation + createInstanceFunctionSlotOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -11195,15 +11329,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, slot, instanceId, mSDeploy, options }, - createInstanceMSDeployOperationSlotOperationSpec, - sendOperation + createInstanceMSDeployOperationSlotOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -11723,15 +11864,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, slot, options }, - startWebSiteNetworkTraceOperationSlotOperationSpec, - sendOperation + startWebSiteNetworkTraceOperationSlotOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -12140,11 +12288,18 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, @@ -12152,9 +12307,9 @@ export class WebAppsImpl implements WebApps { privateEndpointWrapper, options }, - approveOrRejectPrivateEndpointConnectionOperationSpec, - sendOperation + approveOrRejectPrivateEndpointConnectionOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -12229,15 +12384,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, privateEndpointConnectionName, options }, - deletePrivateEndpointConnectionOperationSpec, - sendOperation + deletePrivateEndpointConnectionOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -12643,15 +12805,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, slot, request, options }, - restoreFromBackupBlobSlotOperationSpec, - sendOperation + restoreFromBackupBlobSlotOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -12724,15 +12893,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, slot, restoreRequest, options }, - restoreFromDeletedAppSlotOperationSpec, - sendOperation + restoreFromDeletedAppSlotOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -12805,15 +12981,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, slot, restoreRequest, options }, - restoreSnapshotSlotOperationSpec, - sendOperation + restoreSnapshotSlotOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -12934,15 +13117,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, siteExtensionId, slot, options }, - installSiteExtensionSlotOperationSpec, - sendOperation + installSiteExtensionSlotOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -13039,15 +13229,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, slot, copySlotEntity, options }, - copySlotOperationSpec, - sendOperation + copySlotOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -13144,15 +13341,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, slot, slotSwapEntity, options }, - swapSlotOperationSpec, - sendOperation + swapSlotOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -13289,15 +13493,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, slot, siteSourceControl, options }, - createOrUpdateSourceControlSlotOperationSpec, - sendOperation + createOrUpdateSourceControlSlotOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -13435,15 +13646,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, slot, options }, - startNetworkTraceSlotOperationSpec, - sendOperation + startNetworkTraceSlotOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -14006,15 +14224,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, slotSwapEntity, options }, - swapSlotWithProductionOperationSpec, - sendOperation + swapSlotWithProductionOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -14137,15 +14362,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, siteSourceControl, options }, - createOrUpdateSourceControlOperationSpec, - sendOperation + createOrUpdateSourceControlOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** @@ -14268,15 +14500,22 @@ export class WebAppsImpl implements WebApps { } }; const flatResponse = await directSendOperation(updatedArgs, spec); - return { flatResponse, rawResponse: currentRawResponse! }; + return { + flatResponse, + rawResponse: { + statusCode: currentRawResponse!.status, + body: currentRawResponse!.parsedBody, + headers: currentRawResponse!.headers.toJSON() + } + }; }; - return new LROPoller( - { intervalInMs: options?.updateIntervalInMs }, + const lro = new CoreClientLro( + sendOperation, { resourceGroupName, name, options }, - startNetworkTraceOperationSpec, - sendOperation + startNetworkTraceOperationSpec ); + return new LroEngine(lro, { intervalInMs: options?.updateIntervalInMs }); } /** diff --git a/test/unit/generators/clientFileGenerator.spec.ts b/test/unit/generators/clientFileGenerator.spec.ts index 16e0b46e80..c076c8bbbb 100644 --- a/test/unit/generators/clientFileGenerator.spec.ts +++ b/test/unit/generators/clientFileGenerator.spec.ts @@ -49,7 +49,7 @@ describe("clientFileGenerator", () => { parameters: [], requests: [], responses: [], - isLRO: false, + isLro: false, lroOptions, mediaTypes, typeDetails @@ -62,7 +62,7 @@ describe("clientFileGenerator", () => { parameters: [], requests: [], responses: [], - isLRO: false, + isLro: false, lroOptions, mediaTypes, typeDetails