@@ -17,6 +17,51 @@ const testClient = new TestFetchClient()
17
17
const makeReqSpy = jest . spyOn ( testClient , 'makeRequest' )
18
18
const getLastRequest = ( ) => makeReqSpy . mock . lastCall ! [ 0 ]
19
19
20
+ class TestHeaders implements Headers {
21
+ private headers : Record < string , string >
22
+
23
+ constructor ( ) {
24
+ this . headers = { }
25
+ }
26
+
27
+ append ( name : string , value : string ) : void {
28
+ if ( this . headers [ name ] ) {
29
+ this . headers [ name ] += `, ${ value } `
30
+ } else {
31
+ this . headers [ name ] = value
32
+ }
33
+ }
34
+
35
+ delete ( name : string ) : void {
36
+ delete this . headers [ name ]
37
+ }
38
+
39
+ get ( name : string ) : string | null {
40
+ return this . headers [ name ] || null
41
+ }
42
+
43
+ has ( name : string ) : boolean {
44
+ return name in this . headers
45
+ }
46
+
47
+ set ( name : string , value : string ) : void {
48
+ this . headers [ name ] = value
49
+ }
50
+
51
+ forEach (
52
+ callback : ( value : string , name : string , parent : Headers ) => void
53
+ ) : void {
54
+ for ( const name in this . headers ) {
55
+ callback ( this . headers [ name ] , name , this )
56
+ }
57
+ }
58
+
59
+ getSetCookie ( ) : string [ ] {
60
+ // Implement the getSetCookie method here
61
+ return [ ]
62
+ }
63
+ }
64
+
20
65
const createTestNodePlugin = ( props : Partial < PublisherProps > = { } ) =>
21
66
createConfiguredNodePlugin (
22
67
{
@@ -306,6 +351,36 @@ describe('error handling', () => {
306
351
` )
307
352
} )
308
353
354
+ it ( 'delays retrying 429 errors' , async ( ) => {
355
+ jest . useRealTimers ( )
356
+ const headers = new TestHeaders ( )
357
+ const resetTime = Date . now ( ) + 350
358
+ headers . set ( 'x-ratelimit-reset' , resetTime . toString ( ) )
359
+ makeReqSpy
360
+ . mockReturnValueOnce (
361
+ createError ( {
362
+ status : 429 ,
363
+ statusText : 'Too Many Requests' ,
364
+ ...headers ,
365
+ } )
366
+ )
367
+ . mockReturnValue ( createSuccess ( ) )
368
+
369
+ const { plugin : segmentPlugin } = createTestNodePlugin ( {
370
+ maxRetries : 3 ,
371
+ flushAt : 1 ,
372
+ } )
373
+
374
+ const context = new Context ( eventFactory . alias ( 'to' , 'from' ) )
375
+ const pendingContext = segmentPlugin . alias ( context )
376
+ validateMakeReqInputs ( context )
377
+ expect ( await pendingContext ) . toBe ( context )
378
+ expect ( makeReqSpy ) . toHaveBeenCalledTimes ( 2 )
379
+ // Check that we've waited until roughly the reset time.
380
+ expect ( Date . now ( ) ) . toBeLessThanOrEqual ( resetTime + 20 )
381
+ expect ( Date . now ( ) ) . toBeGreaterThanOrEqual ( resetTime - 20 )
382
+ } )
383
+
309
384
it . each ( [
310
385
{ status : 500 , statusText : 'Internal Server Error' } ,
311
386
{ status : 300 , statusText : 'Multiple Choices' } ,
0 commit comments