@@ -50,6 +50,8 @@ describe('Integration | rate-limiting behaviour', () => {
50
50
replay . loadSession ( { expiry : 0 } ) ;
51
51
52
52
mockSendReplayRequest . mockClear ( ) ;
53
+
54
+ replay [ '_rateLimits' ] = { } ;
53
55
} ) ;
54
56
55
57
afterEach ( async ( ) => {
@@ -171,4 +173,87 @@ describe('Integration | rate-limiting behaviour', () => {
171
173
expect ( replay . eventBuffer ?. length ) . toBe ( 0 ) ;
172
174
} ,
173
175
) ;
176
+
177
+ it ( 'handles rate-limits from a plain 429 response without any retry time' , async ( ) => {
178
+ expect ( replay . session ?. segmentId ) . toBe ( 0 ) ;
179
+ jest . spyOn ( replay , 'sendReplay' ) ;
180
+ jest . spyOn ( replay , 'pause' ) ;
181
+ jest . spyOn ( replay , 'resume' ) ;
182
+ // @ts -ignore private API
183
+ jest . spyOn ( replay , '_handleRateLimit' ) ;
184
+
185
+ const TEST_EVENT = { data : { } , timestamp : BASE_TIMESTAMP , type : 2 } ;
186
+
187
+ mockTransportSend . mockImplementationOnce ( ( ) => {
188
+ return Promise . resolve ( { statusCode : 429 } ) ;
189
+ } ) ;
190
+
191
+ mockRecord . _emitter ( TEST_EVENT ) ;
192
+
193
+ // T = base + 5
194
+ await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
195
+
196
+ expect ( mockRecord . takeFullSnapshot ) . not . toHaveBeenCalled ( ) ;
197
+ expect ( mockTransportSend ) . toHaveBeenCalledTimes ( 1 ) ;
198
+ expect ( replay ) . toHaveLastSentReplay ( { events : JSON . stringify ( [ TEST_EVENT ] ) } ) ;
199
+
200
+ expect ( replay [ '_handleRateLimit' ] ) . toHaveBeenCalledTimes ( 1 ) ;
201
+ // resume() was called once before we even started
202
+ expect ( replay . resume ) . not . toHaveBeenCalled ( ) ;
203
+ expect ( replay . pause ) . toHaveBeenCalledTimes ( 1 ) ;
204
+
205
+ // No user activity to trigger an update
206
+ expect ( replay . session ?. lastActivity ) . toBe ( BASE_TIMESTAMP ) ;
207
+ expect ( replay . session ?. segmentId ) . toBe ( 1 ) ;
208
+
209
+ // let's simulate the rate-limit time of inactivity (60secs) and check that we don't do anything in the meantime
210
+ // 60secs are the default we fall back to in the plain 429 case in updateRateLimits()
211
+ const TEST_EVENT2 = { data : { } , timestamp : BASE_TIMESTAMP + DEFAULT_FLUSH_MIN_DELAY , type : 3 } ;
212
+ for ( let i = 0 ; i < 11 ; i ++ ) {
213
+ const ev = {
214
+ ...TEST_EVENT2 ,
215
+ timestamp : BASE_TIMESTAMP + DEFAULT_FLUSH_MIN_DELAY * ( i + 1 ) ,
216
+ } ;
217
+ mockRecord . _emitter ( ev ) ;
218
+ await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
219
+ expect ( replay . isPaused ( ) ) . toBe ( true ) ;
220
+ expect ( replay . sendReplay ) . toHaveBeenCalledTimes ( 1 ) ;
221
+ expect ( mockTransportSend ) . toHaveBeenCalledTimes ( 1 ) ;
222
+ }
223
+
224
+ // T = base + 60
225
+ await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
226
+
227
+ // now, recording should resume and first, we expect a checkout event to be sent, as resume()
228
+ // should trigger a full snapshot
229
+ expect ( replay . resume ) . toHaveBeenCalledTimes ( 1 ) ;
230
+ expect ( replay . isPaused ( ) ) . toBe ( false ) ;
231
+
232
+ expect ( replay . sendReplay ) . toHaveBeenCalledTimes ( 2 ) ;
233
+ expect ( replay ) . toHaveLastSentReplay ( {
234
+ events : '[{"data":{"isCheckout":true},"timestamp":1580598065000,"type":2}]' ,
235
+ } ) ;
236
+
237
+ // and let's also emit a new event and check that it is recorded
238
+ const TEST_EVENT3 = {
239
+ data : { } ,
240
+ timestamp : BASE_TIMESTAMP + 7 * DEFAULT_FLUSH_MIN_DELAY ,
241
+ type : 3 ,
242
+ } ;
243
+ mockRecord . _emitter ( TEST_EVENT3 ) ;
244
+
245
+ // T = base + 65
246
+ await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
247
+ expect ( replay . sendReplay ) . toHaveBeenCalledTimes ( 3 ) ;
248
+ expect ( replay ) . toHaveLastSentReplay ( { events : JSON . stringify ( [ TEST_EVENT3 ] ) } ) ;
249
+
250
+ // nothing should happen afterwards
251
+ // T = base + 85
252
+ await advanceTimers ( 20_000 ) ;
253
+ expect ( replay . sendReplay ) . toHaveBeenCalledTimes ( 3 ) ;
254
+ expect ( replay ) . toHaveLastSentReplay ( { events : JSON . stringify ( [ TEST_EVENT3 ] ) } ) ;
255
+
256
+ // events array should be empty
257
+ expect ( replay . eventBuffer ?. length ) . toBe ( 0 ) ;
258
+ } ) ;
174
259
} ) ;
0 commit comments