2
2
// SPDX-License-Identifier: Apache-2.0
3
3
4
4
import { AmplifyClassV6 } from '@aws-amplify/core' ;
5
- import { parseJsonError } from '@aws-amplify/core/internals/aws-client-utils' ;
5
+ import {
6
+ getRetryDecider ,
7
+ parseJsonError ,
8
+ } from '@aws-amplify/core/internals/aws-client-utils' ;
6
9
import { ApiError } from '@aws-amplify/core/internals/utils' ;
7
10
8
11
import { authenticatedHandler } from '../../../src/apis/common/baseHandlers/authenticatedHandler' ;
@@ -75,6 +78,10 @@ const mockSuccessResponse = {
75
78
text : jest . fn ( ) ,
76
79
} ,
77
80
} ;
81
+ const mockGetRetryDecider = getRetryDecider as jest . Mock ;
82
+ const mockRetryResponse = { retryable : true } ;
83
+ const mockNoRetryResponse = { retryable : false } ;
84
+ const mockRetryDeciderResponse = ( ) => Promise . resolve ( mockRetryResponse ) ;
78
85
79
86
describe ( 'public APIs' , ( ) => {
80
87
beforeEach ( ( ) => {
@@ -86,6 +93,7 @@ describe('public APIs', () => {
86
93
mockAuthenticatedHandler . mockResolvedValue ( mockSuccessResponse ) ;
87
94
mockUnauthenticatedHandler . mockResolvedValue ( mockSuccessResponse ) ;
88
95
mockGetConfig . mockReturnValue ( mockConfig ) ;
96
+ mockGetRetryDecider . mockReturnValue ( mockRetryDeciderResponse ) ;
89
97
} ) ;
90
98
const APIs = [
91
99
{ name : 'get' , fn : get , method : 'GET' } ,
@@ -415,6 +423,160 @@ describe('public APIs', () => {
415
423
expect ( error . message ) . toBe ( cancelMessage ) ;
416
424
}
417
425
} ) ;
426
+
427
+ describe ( 'retry strategy' , ( ) => {
428
+ beforeEach ( ( ) => {
429
+ mockAuthenticatedHandler . mockReset ( ) ;
430
+ mockAuthenticatedHandler . mockResolvedValue ( mockSuccessResponse ) ;
431
+ } ) ;
432
+
433
+ it ( 'should not retry when retry is set to "no-retry"' , async ( ) => {
434
+ expect . assertions ( 2 ) ;
435
+ await fn ( mockAmplifyInstance , {
436
+ apiName : 'restApi1' ,
437
+ path : '/items' ,
438
+ retryStrategy : {
439
+ strategy : 'no-retry' ,
440
+ } ,
441
+ } ) . response ;
442
+ expect ( mockAuthenticatedHandler ) . toHaveBeenCalledWith (
443
+ expect . any ( Object ) ,
444
+ expect . objectContaining ( { retryDecider : expect . any ( Function ) } ) ,
445
+ ) ;
446
+ const callArgs = mockAuthenticatedHandler . mock . calls [ 0 ] ;
447
+ const { retryDecider } = callArgs [ 1 ] ;
448
+ const result = await retryDecider ( ) ;
449
+ expect ( result ) . toEqual ( mockNoRetryResponse ) ;
450
+ } ) ;
451
+
452
+ it ( 'should retry when retry is set to "jittered-exponential-backoff"' , async ( ) => {
453
+ expect . assertions ( 2 ) ;
454
+ await fn ( mockAmplifyInstance , {
455
+ apiName : 'restApi1' ,
456
+ path : '/items' ,
457
+ retryStrategy : {
458
+ strategy : 'jittered-exponential-backoff' ,
459
+ } ,
460
+ } ) . response ;
461
+ expect ( mockAuthenticatedHandler ) . toHaveBeenCalledWith (
462
+ expect . any ( Object ) ,
463
+ expect . objectContaining ( { retryDecider : expect . any ( Function ) } ) ,
464
+ ) ;
465
+ const callArgs = mockAuthenticatedHandler . mock . calls [ 0 ] ;
466
+ const { retryDecider } = callArgs [ 1 ] ;
467
+ const result = await retryDecider ( ) ;
468
+ expect ( result ) . toEqual ( mockRetryResponse ) ;
469
+ } ) ;
470
+
471
+ it ( 'should retry when retry strategy is not provided' , async ( ) => {
472
+ expect . assertions ( 2 ) ;
473
+ await fn ( mockAmplifyInstance , {
474
+ apiName : 'restApi1' ,
475
+ path : '/items' ,
476
+ } ) . response ;
477
+ expect ( mockAuthenticatedHandler ) . toHaveBeenCalledWith (
478
+ expect . any ( Object ) ,
479
+ expect . objectContaining ( { retryDecider : expect . any ( Function ) } ) ,
480
+ ) ;
481
+ const callArgs = mockAuthenticatedHandler . mock . calls [ 0 ] ;
482
+ const { retryDecider } = callArgs [ 1 ] ;
483
+ const result = await retryDecider ( ) ;
484
+ expect ( result ) . toEqual ( mockRetryResponse ) ;
485
+ } ) ;
486
+
487
+ it ( 'should retry and prefer the individual retry strategy over the library options' , async ( ) => {
488
+ expect . assertions ( 2 ) ;
489
+ const mockAmplifyInstanceWithNoRetry = {
490
+ ...mockAmplifyInstance ,
491
+ libraryOptions : {
492
+ API : {
493
+ REST : {
494
+ retryStrategy : {
495
+ strategy : 'no-retry' ,
496
+ } ,
497
+ } ,
498
+ } ,
499
+ } ,
500
+ } as any as AmplifyClassV6 ;
501
+ await fn ( mockAmplifyInstanceWithNoRetry , {
502
+ apiName : 'restApi1' ,
503
+ path : 'items' ,
504
+ retryStrategy : {
505
+ strategy : 'jittered-exponential-backoff' ,
506
+ } ,
507
+ } ) . response ;
508
+
509
+ expect ( mockAuthenticatedHandler ) . toHaveBeenCalledWith (
510
+ expect . any ( Object ) ,
511
+ expect . objectContaining ( { retryDecider : expect . any ( Function ) } ) ,
512
+ ) ;
513
+ const callArgs = mockAuthenticatedHandler . mock . calls [ 0 ] ;
514
+ const { retryDecider } = callArgs [ 1 ] ;
515
+ const result = await retryDecider ( ) ;
516
+ expect ( result ) . toEqual ( mockRetryResponse ) ;
517
+ } ) ;
518
+
519
+ it ( 'should not retry and prefer the individual retry strategy over the library options' , async ( ) => {
520
+ expect . assertions ( 2 ) ;
521
+ const mockAmplifyInstanceWithRetry = {
522
+ ...mockAmplifyInstance ,
523
+ libraryOptions : {
524
+ API : {
525
+ REST : {
526
+ retryStrategy : {
527
+ strategy : 'jittered-exponential-backoff' ,
528
+ } ,
529
+ } ,
530
+ } ,
531
+ } ,
532
+ } as any as AmplifyClassV6 ;
533
+ await fn ( mockAmplifyInstanceWithRetry , {
534
+ apiName : 'restApi1' ,
535
+ path : 'items' ,
536
+ retryStrategy : {
537
+ strategy : 'no-retry' ,
538
+ } ,
539
+ } ) . response ;
540
+
541
+ expect ( mockAuthenticatedHandler ) . toHaveBeenCalledWith (
542
+ expect . any ( Object ) ,
543
+ expect . objectContaining ( { retryDecider : expect . any ( Function ) } ) ,
544
+ ) ;
545
+ const callArgs = mockAuthenticatedHandler . mock . calls [ 0 ] ;
546
+ const { retryDecider } = callArgs [ 1 ] ;
547
+ const result = await retryDecider ( ) ;
548
+ expect ( result ) . toEqual ( mockNoRetryResponse ) ;
549
+ } ) ;
550
+
551
+ it ( 'should not retry when configured through library options' , async ( ) => {
552
+ expect . assertions ( 2 ) ;
553
+ const mockAmplifyInstanceWithRetry = {
554
+ ...mockAmplifyInstance ,
555
+ libraryOptions : {
556
+ API : {
557
+ REST : {
558
+ retryStrategy : {
559
+ strategy : 'no-retry' ,
560
+ } ,
561
+ } ,
562
+ } ,
563
+ } ,
564
+ } as any as AmplifyClassV6 ;
565
+ await fn ( mockAmplifyInstanceWithRetry , {
566
+ apiName : 'restApi1' ,
567
+ path : 'items' ,
568
+ } ) . response ;
569
+
570
+ expect ( mockAuthenticatedHandler ) . toHaveBeenCalledWith (
571
+ expect . any ( Object ) ,
572
+ expect . objectContaining ( { retryDecider : expect . any ( Function ) } ) ,
573
+ ) ;
574
+ const callArgs = mockAuthenticatedHandler . mock . calls [ 0 ] ;
575
+ const { retryDecider } = callArgs [ 1 ] ;
576
+ const result = await retryDecider ( ) ;
577
+ expect ( result ) . toEqual ( mockNoRetryResponse ) ;
578
+ } ) ;
579
+ } ) ;
418
580
} ) ;
419
581
} ) ;
420
582
} ) ;
0 commit comments