@@ -876,93 +876,119 @@ describe('Replay', () => {
876
876
} ) ;
877
877
878
878
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' ) ;
903
917
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 } ;
907
919
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
+ } ) ;
912
923
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 ) ;
916
925
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
925
927
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 ( ) ;
928
930
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 ) ;
930
958
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 ) ;
933
976
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 ] ) } ) ;
938
981
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 ] ) } ) ;
943
987
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
+ ) ;
966
992
} ) ;
967
993
} ) ;
968
994
0 commit comments