@@ -353,6 +353,7 @@ describe('#db IAMAuth Plugin', function() {
353353 'response_type' : 'cloud_iam' ,
354354 'apikey' : IAM_API_KEY
355355 } )
356+ . times ( 3 )
356357 . reply ( 500 , 'Internal Error 500\nThe server encountered an unexpected condition which prevented it from fulfilling the request.' ) ;
357358
358359 var cloudantMocks = nock ( SERVER )
@@ -418,10 +419,12 @@ describe('#db IAMAuth Plugin', function() {
418419 'response_type' : 'cloud_iam' ,
419420 'apikey' : IAM_API_KEY
420421 } )
422+ . times ( 3 )
421423 . reply ( 200 , MOCK_IAM_TOKEN_RESPONSE ) ;
422424
423425 var cloudantMocks = nock ( SERVER )
424426 . post ( '/_iam_session' , { access_token : MOCK_ACCESS_TOKEN } )
427+ . times ( 3 )
425428 . reply ( 500 , { error : 'internal_server_error' , reason : 'Internal Server Error' } )
426429 . get ( DBNAME )
427430 . reply ( 401 , { error : 'unauthorized' , reason : 'Unauthorized' } ) ;
@@ -510,10 +513,10 @@ describe('#db IAMAuth Plugin', function() {
510513 } ) ;
511514
512515 it ( 'throws error for unspecified IAM API key' , function ( ) {
513- var cloudantClient = new Client ( { plugins : 'iamauth' } ) ;
514516 assert . throws (
515517 ( ) => {
516- cloudantClient . request ( { url : SERVER + DBNAME } ) ;
518+ /* eslint-disable no-new */
519+ new Client ( { plugins : 'iamauth' } ) ;
517520 } ,
518521 / M i s s i n g I A M A P I k e y f r o m c o n f i g u r a t i o n / ,
519522 'did not throw with expected message'
@@ -554,4 +557,105 @@ describe('#db IAMAuth Plugin', function() {
554557 assert . fail ( `Unexpected reject: ${ err } ` ) ;
555558 } ) ;
556559 } ) ;
560+
561+ it ( 'successfully retries request on 500 IAM token service response and returns 200 response' , function ( done ) {
562+ if ( process . env . NOCK_OFF ) {
563+ this . skip ( ) ;
564+ }
565+
566+ var iamMocks = nock ( TOKEN_SERVER )
567+ . post ( '/identity/token' , {
568+ 'grant_type' : 'urn:ibm:params:oauth:grant-type:apikey' ,
569+ 'response_type' : 'cloud_iam' ,
570+ 'apikey' : IAM_API_KEY
571+ } )
572+ . times ( 2 )
573+ . reply ( 500 , { error : 'internal_server_error' , reason : 'Internal Server Error' } )
574+ . post ( '/identity/token' , {
575+ 'grant_type' : 'urn:ibm:params:oauth:grant-type:apikey' ,
576+ 'response_type' : 'cloud_iam' ,
577+ 'apikey' : IAM_API_KEY
578+ } )
579+ . reply ( 200 , MOCK_IAM_TOKEN_RESPONSE ) ;
580+
581+ var cloudantMocks = nock ( SERVER )
582+ . post ( '/_iam_session' , { access_token : MOCK_ACCESS_TOKEN } )
583+ . reply ( 200 , { ok : true } , MOCK_SET_IAM_SESSION_HEADER )
584+ . get ( DBNAME )
585+ . reply ( 200 , { doc_count : 0 } ) ;
586+
587+ var cloudantClient = new Client ( { maxAttempt : 3 , plugins : { iamauth : { iamApiKey : IAM_API_KEY } } } ) ;
588+ var req = { url : SERVER + DBNAME , method : 'GET' } ;
589+
590+ var startTs = ( new Date ( ) ) . getTime ( ) ;
591+
592+ cloudantClient . request ( req , function ( err , resp , data ) {
593+ assert . equal ( err , null ) ;
594+ assert . equal ( resp . request . headers . cookie , MOCK_IAM_SESSION ) ;
595+ assert . equal ( resp . statusCode , 200 ) ;
596+ assert . ok ( data . indexOf ( '"doc_count":0' ) > - 1 ) ;
597+
598+ // validate retry delay
599+ var now = ( new Date ( ) ) . getTime ( ) ;
600+ assert . ok ( now - startTs > ( 500 + 1000 ) ) ;
601+
602+ iamMocks . done ( ) ;
603+ cloudantMocks . done ( ) ;
604+ done ( ) ;
605+ } ) ;
606+ } ) ;
607+
608+ it ( 'supports changing the IAM API key' , function ( done ) {
609+ if ( process . env . NOCK_OFF ) {
610+ this . skip ( ) ;
611+ }
612+
613+ var iamMocks = nock ( TOKEN_SERVER )
614+ . post ( '/identity/token' , {
615+ 'grant_type' : 'urn:ibm:params:oauth:grant-type:apikey' ,
616+ 'response_type' : 'cloud_iam' ,
617+ 'apikey' : 'bad_key'
618+ } )
619+ . reply ( 400 , {
620+ errorCode : 'BXNIM0415E' ,
621+ errorMessage : 'Provided API key could not be found'
622+ } )
623+ . post ( '/identity/token' , {
624+ 'grant_type' : 'urn:ibm:params:oauth:grant-type:apikey' ,
625+ 'response_type' : 'cloud_iam' ,
626+ 'apikey' : IAM_API_KEY
627+ } )
628+ . reply ( 200 , MOCK_IAM_TOKEN_RESPONSE ) ;
629+
630+ var cloudantMocks = nock ( SERVER )
631+ . get ( DBNAME )
632+ . reply ( 401 , { error : 'unauthorized' , reason : 'Unauthorized' } )
633+ . post ( '/_iam_session' , { access_token : MOCK_ACCESS_TOKEN } )
634+ . reply ( 200 , { ok : true } , MOCK_SET_IAM_SESSION_HEADER )
635+ . get ( DBNAME )
636+ . reply ( 200 , { doc_count : 0 } ) ;
637+
638+ var cloudantClient = new Client ( { plugins : { iamauth : { iamApiKey : 'bad_key' } } } ) ;
639+ var req = { url : SERVER + DBNAME , method : 'GET' } ;
640+ cloudantClient . request ( req , function ( err , resp , data ) {
641+ assert . equal ( err , null ) ;
642+ assert . equal ( resp . request . headers . cookie , null ) ;
643+ assert . equal ( resp . statusCode , 401 ) ;
644+ assert . ok ( data . indexOf ( '"error":"unauthorized"' ) > - 1 ) ;
645+
646+ // update IAM API key
647+ cloudantClient . getPlugin ( 'iamauth' ) . setIamApiKey ( IAM_API_KEY ) ;
648+
649+ cloudantClient . request ( req , function ( err , resp , data ) {
650+ assert . equal ( err , null ) ;
651+ assert . equal ( resp . request . headers . cookie , MOCK_IAM_SESSION ) ;
652+ assert . equal ( resp . statusCode , 200 ) ;
653+ assert . ok ( data . indexOf ( '"doc_count":0' ) > - 1 ) ;
654+
655+ iamMocks . done ( ) ;
656+ cloudantMocks . done ( ) ;
657+ done ( ) ;
658+ } ) ;
659+ } ) ;
660+ } ) ;
557661} ) ;
0 commit comments