Skip to content

Commit 143c165

Browse files
committed
add test for a plain 429 response w/o retry-after period
1 parent e1d8815 commit 143c165

File tree

1 file changed

+85
-0
lines changed

1 file changed

+85
-0
lines changed

packages/replay/test/integration/rateLimiting.test.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ describe('Integration | rate-limiting behaviour', () => {
5050
replay.loadSession({ expiry: 0 });
5151

5252
mockSendReplayRequest.mockClear();
53+
54+
replay['_rateLimits'] = {};
5355
});
5456

5557
afterEach(async () => {
@@ -171,4 +173,87 @@ describe('Integration | rate-limiting behaviour', () => {
171173
expect(replay.eventBuffer?.length).toBe(0);
172174
},
173175
);
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+
});
174259
});

0 commit comments

Comments
 (0)