@@ -876,93 +876,119 @@ describe('Replay', () => {
876876 } ) ;
877877
878878 describe ( 'rate-limiting behaviour' , ( ) => {
879- it ( 'pauses recording and flushing a rate limit is hit and resumes both after the rate limit duration is over' , async ( ) => {
880- expect ( replay . session ?. segmentId ) . toBe ( 0 ) ;
881- jest . spyOn ( replay , 'sendReplay' ) ;
882- jest . spyOn ( replay , 'pause' ) ;
883- jest . spyOn ( replay , 'resume' ) ;
884- // @ts -ignore private API
885- jest . spyOn ( replay , '_handleRateLimit' ) ;
886-
887- const TEST_EVENT = { data : { } , timestamp : BASE_TIMESTAMP , type : 2 } ;
888-
889- mockTransportSend . mockImplementationOnce ( ( ) => {
890- return Promise . resolve ( {
891- statusCode : 429 ,
892- headers : {
893- 'x-sentry-rate-limits' : null ,
894- 'retry-after' : `30` ,
895- } ,
896- } as TransportMakeRequestResponse ) ;
897- } ) ;
898-
899- mockRecord . _emitter ( TEST_EVENT ) ;
900-
901- // T = base + 5
902- await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
879+ it . each ( [
880+ {
881+ statusCode : 429 ,
882+ headers : {
883+ 'x-sentry-rate-limits' : '30' ,
884+ 'retry-after' : null ,
885+ } ,
886+ } ,
887+ {
888+ statusCode : 429 ,
889+ headers : {
890+ 'x-sentry-rate-limits' : '30:replay_event' ,
891+ 'retry-after' : null ,
892+ } ,
893+ } ,
894+ {
895+ statusCode : 429 ,
896+ headers : {
897+ 'x-sentry-rate-limits' : '30:replay_recording' ,
898+ 'retry-after' : null ,
899+ } ,
900+ } ,
901+ {
902+ statusCode : 429 ,
903+ headers : {
904+ 'x-sentry-rate-limits' : null ,
905+ 'retry-after' : '30' ,
906+ } ,
907+ } ,
908+ ] as TransportMakeRequestResponse [ ] ) (
909+ 'pauses recording and flushing a rate limit is hit and resumes both after the rate limit duration is over' ,
910+ async ratelimitResponse => {
911+ expect ( replay . session ?. segmentId ) . toBe ( 0 ) ;
912+ jest . spyOn ( replay , 'sendReplay' ) ;
913+ jest . spyOn ( replay , 'pause' ) ;
914+ jest . spyOn ( replay , 'resume' ) ;
915+ // @ts -ignore private API
916+ jest . spyOn ( replay , '_handleRateLimit' ) ;
903917
904- expect ( mockRecord . takeFullSnapshot ) . not . toHaveBeenCalled ( ) ;
905- expect ( mockTransportSend ) . toHaveBeenCalledTimes ( 1 ) ;
906- expect ( replay ) . toHaveLastSentReplay ( { events : JSON . stringify ( [ TEST_EVENT ] ) } ) ;
918+ const TEST_EVENT = { data : { } , timestamp : BASE_TIMESTAMP , type : 2 } ;
907919
908- expect ( replay [ '_handleRateLimit' ] ) . toHaveBeenCalledTimes ( 1 ) ;
909- // resume() was called once before we even started
910- expect ( replay . resume ) . not . toHaveBeenCalled ( ) ;
911- expect ( replay . pause ) . toHaveBeenCalledTimes ( 1 ) ;
920+ mockTransportSend . mockImplementationOnce ( ( ) => {
921+ return Promise . resolve ( ratelimitResponse ) ;
922+ } ) ;
912923
913- // No user activity to trigger an update
914- expect ( replay . session ?. lastActivity ) . toBe ( BASE_TIMESTAMP ) ;
915- expect ( replay . session ?. segmentId ) . toBe ( 1 ) ;
924+ mockRecord . _emitter ( TEST_EVENT ) ;
916925
917- // let's simulate the rate-limit time of inactivity (30secs) and check that we don't do anything in the meantime
918- const TEST_EVENT2 = { data : { } , timestamp : BASE_TIMESTAMP + DEFAULT_FLUSH_MIN_DELAY , type : 3 } ;
919- for ( let i = 0 ; i < 5 ; i ++ ) {
920- const ev = {
921- ...TEST_EVENT2 ,
922- timestamp : BASE_TIMESTAMP + DEFAULT_FLUSH_MIN_DELAY * ( i + 1 ) ,
923- } ;
924- mockRecord . _emitter ( ev ) ;
926+ // T = base + 5
925927 await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
926- expect ( replay . isPaused ( ) ) . toBe ( true ) ;
927- expect ( replay . sendReplay ) . toHaveBeenCalledTimes ( 1 ) ;
928+
929+ expect ( mockRecord . takeFullSnapshot ) . not . toHaveBeenCalled ( ) ;
928930 expect ( mockTransportSend ) . toHaveBeenCalledTimes ( 1 ) ;
929- }
931+ expect ( replay ) . toHaveLastSentReplay ( { events : JSON . stringify ( [ TEST_EVENT ] ) } ) ;
932+
933+ expect ( replay [ '_handleRateLimit' ] ) . toHaveBeenCalledTimes ( 1 ) ;
934+ // resume() was called once before we even started
935+ expect ( replay . resume ) . not . toHaveBeenCalled ( ) ;
936+ expect ( replay . pause ) . toHaveBeenCalledTimes ( 1 ) ;
937+
938+ // No user activity to trigger an update
939+ expect ( replay . session ?. lastActivity ) . toBe ( BASE_TIMESTAMP ) ;
940+ expect ( replay . session ?. segmentId ) . toBe ( 1 ) ;
941+
942+ // let's simulate the rate-limit time of inactivity (30secs) and check that we don't do anything in the meantime
943+ const TEST_EVENT2 = { data : { } , timestamp : BASE_TIMESTAMP + DEFAULT_FLUSH_MIN_DELAY , type : 3 } ;
944+ for ( let i = 0 ; i < 5 ; i ++ ) {
945+ const ev = {
946+ ...TEST_EVENT2 ,
947+ timestamp : BASE_TIMESTAMP + DEFAULT_FLUSH_MIN_DELAY * ( i + 1 ) ,
948+ } ;
949+ mockRecord . _emitter ( ev ) ;
950+ await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
951+ expect ( replay . isPaused ( ) ) . toBe ( true ) ;
952+ expect ( replay . sendReplay ) . toHaveBeenCalledTimes ( 1 ) ;
953+ expect ( mockTransportSend ) . toHaveBeenCalledTimes ( 1 ) ;
954+ }
955+
956+ // T = base + 35
957+ await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
930958
931- // T = base + 35
932- await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
959+ // now, recording should resume and first, we expect a checkout event to be sent, as resume()
960+ // should trigger a full snapshot
961+ expect ( replay . resume ) . toHaveBeenCalledTimes ( 1 ) ;
962+ expect ( replay . isPaused ( ) ) . toBe ( false ) ;
963+
964+ expect ( replay . sendReplay ) . toHaveBeenCalledTimes ( 2 ) ;
965+ expect ( replay ) . toHaveLastSentReplay ( {
966+ events : '[{"data":{"isCheckout":true},"timestamp":1580598035000,"type":2}]' ,
967+ } ) ;
968+
969+ // and let's also emit a new event and check that it is recorded
970+ const TEST_EVENT3 = {
971+ data : { } ,
972+ timestamp : BASE_TIMESTAMP + 7 * DEFAULT_FLUSH_MIN_DELAY ,
973+ type : 3 ,
974+ } ;
975+ mockRecord . _emitter ( TEST_EVENT3 ) ;
933976
934- // now, recording should resume and first, we expect a checkout event to be sent, as resume()
935- // should trigger a full snapshot
936- expect ( replay . resume ) . toHaveBeenCalledTimes ( 1 ) ;
937- expect ( replay . isPaused ( ) ) . toBe ( false ) ;
977+ // T = base + 40
978+ await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
979+ expect ( replay . sendReplay ) . toHaveBeenCalledTimes ( 3 ) ;
980+ expect ( replay ) . toHaveLastSentReplay ( { events : JSON . stringify ( [ TEST_EVENT3 ] ) } ) ;
938981
939- expect ( replay . sendReplay ) . toHaveBeenCalledTimes ( 2 ) ;
940- expect ( replay ) . toHaveLastSentReplay ( {
941- events : '[{"data":{"isCheckout":true},"timestamp":1580598035000,"type":2}]' ,
942- } ) ;
982+ // nothing should happen afterwards
983+ // T = base + 60
984+ await advanceTimers ( 20_000 ) ;
985+ expect ( replay . sendReplay ) . toHaveBeenCalledTimes ( 3 ) ;
986+ expect ( replay ) . toHaveLastSentReplay ( { events : JSON . stringify ( [ TEST_EVENT3 ] ) } ) ;
943987
944- // and let's also emit a new event and check that it is recorded
945- const TEST_EVENT3 = {
946- data : { } ,
947- timestamp : BASE_TIMESTAMP + 7 * DEFAULT_FLUSH_MIN_DELAY ,
948- type : 3 ,
949- } ;
950- mockRecord . _emitter ( TEST_EVENT3 ) ;
951-
952- // T = base + 40
953- await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
954- expect ( replay . sendReplay ) . toHaveBeenCalledTimes ( 3 ) ;
955- expect ( replay ) . toHaveLastSentReplay ( { events : JSON . stringify ( [ TEST_EVENT3 ] ) } ) ;
956-
957- // nothing should happen afterwards
958- // T = base + 60
959- await advanceTimers ( 20_000 ) ;
960- expect ( replay . sendReplay ) . toHaveBeenCalledTimes ( 3 ) ;
961- expect ( replay ) . toHaveLastSentReplay ( { events : JSON . stringify ( [ TEST_EVENT3 ] ) } ) ;
962-
963- // events array should be empty
964- expect ( replay . eventBuffer ?. length ) . toBe ( 0 ) ;
965- } ) ;
988+ // events array should be empty
989+ expect ( replay . eventBuffer ?. length ) . toBe ( 0 ) ;
990+ } ,
991+ ) ;
966992 } ) ;
967993} ) ;
968994
0 commit comments