import { assert } from "chai" ; import { SystemErrorRetryPolicy } from "../../lib/policies/systemErrorRetryPolicy" ; import { RetryError } from "../../lib/policies/systemErrorRetryPolicy" ; import { WebResource } from "../../lib/webResource" ; import { HttpOperationResponse } from "../../lib/httpOperationResponse" ; import { HttpHeaders , RequestPolicyOptions } from "../../lib/msRest" ; describe ( "SystemErrorRetryPolicy" , ( ) => { class PassThroughPolicy { constructor ( private _response ) { } public sendRequest ( request ) { const response = { ... this . _response , request : request , } ; return Promise . resolve ( response ) ; } } class FailFirstRequestPolicy { count = 0 ; constructor ( private _response , private errorCode ) { } public sendRequest ( request ) { if ( this . count === 0 ) { this . count ++ ; const error = { code : this . errorCode , name : "RetryError" , message : `Error message for ${ this . errorCode }` , } ; return Promise . reject ( error ) ; } const response = { ... this . _response , request : request , } ; return Promise . resolve ( response ) ; } } const defaultResponse = { status : 200 , request : new WebResource ( ) , headers : new HttpHeaders ( ) , } ; function createDefaultSystemErrorRetryPolicy ( response ? ) { if ( ! response ) { response = defaultResponse ; } const passThroughPolicy = new PassThroughPolicy ( response ) ; return new SystemErrorRetryPolicy ( passThroughPolicy , new RequestPolicyOptions ( ) ) ; } describe ( "sendRequest" , ( ) => { it ( "should clone the request" , async ( ) => { const request = new WebResource ( ) ; const nextPolicy = { sendRequest : ( requestToSend ) : Promise < HttpOperationResponse > => { assert ( request !== requestToSend ) ; return Promise . resolve ( defaultResponse ) ; } , } ; const policy = new SystemErrorRetryPolicy ( nextPolicy , new RequestPolicyOptions ( ) ) ; await policy . sendRequest ( request ) ; } ) ; it ( "should not modify the request" , async ( ) => { const request = new WebResource ( ) ; request . url = "http://url" ; request . method = "PATCH" ; request . body = { someProperty : "someValue" } ; request . headers = new HttpHeaders ( { header : "abc" } ) ; request . query = { q : "param" } ; const policy = createDefaultSystemErrorRetryPolicy ( ) ; const response = await policy . sendRequest ( request ) ; delete ( response . request as any ) . requestId ; delete ( request as any ) . requestId ; assert . deepEqual ( response . request , request ) ; } ) ; [ "ETIMEDOUT" , "ESOCKETTIMEDOUT" , "ECONNREFUSED" , "ECONNRESET" , "ENOENT" ] . forEach ( ( code ) => { it ( `should retry if the error code is ${ code }` , async ( ) => { const request = new WebResource ( ) ; const mockResponse = { status : 200 , headers : new HttpHeaders ( ) , request : request , } ; const faultyPolicy = new FailFirstRequestPolicy ( mockResponse , code ) ; const policy = new SystemErrorRetryPolicy ( faultyPolicy , new RequestPolicyOptions ( ) , 3 , 10 , 10 , 20 ) ; const response = await policy . sendRequest ( request ) ; delete ( request as any ) . requestId ; delete ( response . request as any ) . requestId ; assert . deepEqual ( response , mockResponse , "Expecting response matches after retrying" ) ; } ) ; } ) ; it ( "should do nothing when error code is not one of the retriable errors" , async ( ) => { const request = new WebResource ( ) ; const faultyPolicy = new FailFirstRequestPolicy ( defaultResponse , "NonRetriableError" ) ; const policy = new SystemErrorRetryPolicy ( faultyPolicy , new RequestPolicyOptions ( ) , 3 , 10 , 10 , 20 ) ; try { await policy . sendRequest ( request ) ; assert . fail ( "Expecting that an error has been thrown" ) ; } catch ( err ) { assert . equal ( ( err as Error ) . message , "Error message for NonRetriableError" ) ; } } ) ; [ "ETIMEDOUT" , "ESOCKETTIMEDOUT" , "ECONNREFUSED" , "ECONNRESET" , "ENOENT" ] . forEach ( ( code ) => { it ( `should fail after max retry count for error code ${ code }` , async ( ) => { class FailEveryRequestPolicy { count = 0 ; constructor ( private errorCode ) { } public sendRequest ( _request ) { const error = { code : this . errorCode , name : "RetryError" , message : `Error message for ${ this . errorCode }` , } ; return Promise . reject ( error ) ; } } const request = new WebResource ( ) ; const faultyPolicy = new FailEveryRequestPolicy ( code ) ; const policy = new SystemErrorRetryPolicy ( faultyPolicy , new RequestPolicyOptions ( ) , 3 , 10 , 10 , 20 ) ; try { await policy . sendRequest ( request ) ; assert . fail ( "Expecting that an error has been thrown" ) ; } catch ( err ) { assert . equal ( ( err as Error ) . message , `Error message for ${ code }` ) ; } } ) ; } ) ; } ) ; } ) . timeout ( 60000 ) ;