11import { getCurrentHub } from '@sentry/core' ;
2- import type { Transport } from '@sentry/types' ;
2+ import type { Transport , TransportMakeRequestResponse } from '@sentry/types' ;
33
44import { DEFAULT_FLUSH_MIN_DELAY } from '../../src/constants' ;
55import type { ReplayContainer } from '../../src/replay' ;
66import { clearSession } from '../../src/session/clearSession' ;
7- import * as SendReplayRequest from '../../src/util/sendReplayRequest' ;
87import { BASE_TIMESTAMP , mockSdk } from '../index' ;
9- import { mockRrweb } from '../mocks/mockRrweb' ;
10- import { getTestEventCheckout , getTestEventIncremental } from '../utils/getTestEvent' ;
118import { useFakeTimers } from '../utils/use-fake-timers' ;
129
1310useFakeTimers ( ) ;
@@ -22,93 +19,91 @@ type MockTransportSend = jest.MockedFunction<Transport['send']>;
2219describe ( 'Integration | rate-limiting behaviour' , ( ) => {
2320 let replay : ReplayContainer ;
2421 let mockTransportSend : MockTransportSend ;
25- let mockSendReplayRequest : jest . MockedFunction < any > ;
26- const { record : mockRecord } = mockRrweb ( ) ;
2722
28- beforeAll ( async ( ) => {
23+ beforeEach ( async ( ) => {
2924 jest . setSystemTime ( new Date ( BASE_TIMESTAMP ) ) ;
3025
3126 ( { replay } = await mockSdk ( {
27+ autoStart : false ,
3228 replayOptions : {
3329 stickySession : false ,
3430 } ,
3531 } ) ) ;
3632
37- jest . runAllTimers ( ) ;
3833 mockTransportSend = getCurrentHub ( ) ?. getClient ( ) ?. getTransport ( ) ?. send as MockTransportSend ;
39- mockSendReplayRequest = jest . spyOn ( SendReplayRequest , 'sendReplayRequest' ) ;
40- } ) ;
41-
42- beforeEach ( ( ) => {
43- jest . setSystemTime ( new Date ( BASE_TIMESTAMP ) ) ;
44- mockRecord . takeFullSnapshot . mockClear ( ) ;
45- mockTransportSend . mockClear ( ) ;
46-
47- // Create a new session and clear mocks because a segment (from initial
48- // checkout) will have already been uploaded by the time the tests run
49- clearSession ( replay ) ;
50- replay [ '_initializeSessionForSampling' ] ( ) ;
51- replay . setInitialState ( ) ;
52-
53- mockSendReplayRequest . mockClear ( ) ;
5434 } ) ;
5535
5636 afterEach ( async ( ) => {
57- jest . runAllTimers ( ) ;
58- await new Promise ( process . nextTick ) ;
59- jest . setSystemTime ( new Date ( BASE_TIMESTAMP ) ) ;
6037 clearSession ( replay ) ;
6138 jest . clearAllMocks ( ) ;
62- } ) ;
6339
64- afterAll ( ( ) => {
6540 replay && replay . stop ( ) ;
6641 } ) ;
6742
68- it ( 'handles rate-limit 429 responses by stopping the replay' , async ( ) => {
69- expect ( replay . session ?. segmentId ) . toBe ( 0 ) ;
70- jest . spyOn ( replay , 'stop' ) ;
71-
72- const TEST_EVENT = getTestEventCheckout ( { timestamp : BASE_TIMESTAMP } ) ;
43+ it . each ( [
44+ [ '429 status code' , { statusCode : 429 , headers : { } } as TransportMakeRequestResponse ] ,
45+ [
46+ '200 status code with x-sentry-rate-limits header' ,
47+ {
48+ statusCode : 200 ,
49+ headers : {
50+ 'x-sentry-rate-limits' : '30' ,
51+ } ,
52+ } as TransportMakeRequestResponse ,
53+ ] ,
54+ [
55+ '200 status code with x-sentry-rate-limits replay header' ,
56+ {
57+ statusCode : 200 ,
58+ headers : {
59+ 'x-sentry-rate-limits' : '30:replay' ,
60+ } ,
61+ } as TransportMakeRequestResponse ,
62+ ] ,
63+ ] ) ( 'handles %s responses by stopping the replay' , async ( _name , { statusCode, headers } ) => {
64+ const mockStop = jest . spyOn ( replay , 'stop' ) ;
7365
7466 mockTransportSend . mockImplementationOnce ( ( ) => {
75- return Promise . resolve ( { statusCode : 429 } ) ;
67+ return Promise . resolve ( { statusCode, headers } ) ;
7668 } ) ;
7769
78- mockRecord . _emitter ( TEST_EVENT ) ;
79-
80- // T = base + 5
70+ replay . start ( ) ;
8171 await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
8272
83- expect ( mockRecord . takeFullSnapshot ) . not . toHaveBeenCalled ( ) ;
84- expect ( mockTransportSend ) . toHaveBeenCalledTimes ( 1 ) ;
85- expect ( replay ) . toHaveLastSentReplay ( { recordingData : JSON . stringify ( [ TEST_EVENT ] ) } ) ;
86-
87- expect ( replay . stop ) . toHaveBeenCalledTimes ( 1 ) ;
88-
89- // No user activity to trigger an update
90- expect ( replay . session ) . toBe ( undefined ) ;
91-
92- // let's simulate the default rate-limit time of inactivity (60secs) and check that we
93- // don't do anything in the meantime or after the time has passed
94- // 60secs are the default we fall back to in the plain 429 case in updateRateLimits()
95-
96- // T = base + 60
97- await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY * 12 ) ;
73+ expect ( mockStop ) . toHaveBeenCalledTimes ( 1 ) ;
74+ expect ( replay . session ) . toBeUndefined ( ) ;
75+ expect ( replay . isEnabled ( ) ) . toBe ( false ) ;
76+ } ) ;
9877
99- expect ( mockSendReplayRequest ) . toHaveBeenCalledTimes ( 1 ) ;
100- expect ( mockTransportSend ) . toHaveBeenCalledTimes ( 1 ) ;
78+ it . each ( [
79+ [
80+ '200 status code without x-sentry-rate-limits header' ,
81+ {
82+ statusCode : 200 ,
83+ headers : { } ,
84+ } as TransportMakeRequestResponse ,
85+ ] ,
86+ [
87+ '200 status code with x-sentry-rate-limits profile header' ,
88+ {
89+ statusCode : 200 ,
90+ headers : {
91+ 'x-sentry-rate-limits' : '30:profile' ,
92+ } ,
93+ } as TransportMakeRequestResponse ,
94+ ] ,
95+ ] ) ( 'handles %s responses by not stopping' , async ( _name , { statusCode, headers } ) => {
96+ const mockStop = jest . spyOn ( replay , 'stop' ) ;
10197
102- // and let's also emit a new event and check that it is not recorded
103- const TEST_EVENT3 = getTestEventIncremental ( {
104- data : { } ,
105- timestamp : BASE_TIMESTAMP + 7 * DEFAULT_FLUSH_MIN_DELAY ,
98+ mockTransportSend . mockImplementationOnce ( ( ) => {
99+ return Promise . resolve ( { statusCode, headers } ) ;
106100 } ) ;
107- mockRecord . _emitter ( TEST_EVENT3 ) ;
108101
109- // T = base + 80
110- await advanceTimers ( 20_000 ) ;
111- expect ( mockSendReplayRequest ) . toHaveBeenCalledTimes ( 1 ) ;
112- expect ( mockTransportSend ) . toHaveBeenCalledTimes ( 1 ) ;
102+ replay . start ( ) ;
103+ await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
104+
105+ expect ( mockStop ) . not . toHaveBeenCalled ( ) ;
106+ expect ( replay . session ) . toBeDefined ( ) ;
107+ expect ( replay . isEnabled ( ) ) . toBe ( true ) ;
113108 } ) ;
114109} ) ;
0 commit comments