@@ -20,14 +20,16 @@ import '../test/setup';
20
20
import {
21
21
countBytes ,
22
22
HeartbeatServiceImpl ,
23
- extractHeartbeatsForHeader
23
+ extractHeartbeatsForHeader ,
24
+ getEarliestHeartbeatIdx ,
25
+ MAX_NUM_STORED_HEARTBEATS
24
26
} from './heartbeatService' ;
25
27
import {
26
28
Component ,
27
29
ComponentType ,
28
30
ComponentContainer
29
31
} from '@firebase/component' ;
30
- import { PlatformLoggerService } from './types' ;
32
+ import { PlatformLoggerService , SingleDateHeartbeat } from './types' ;
31
33
import { FirebaseApp } from './public-types' ;
32
34
import * as firebaseUtil from '@firebase/util' ;
33
35
import { SinonStub , stub , useFakeTimers } from 'sinon' ;
@@ -173,7 +175,6 @@ describe('HeartbeatServiceImpl', () => {
173
175
let writeStub : SinonStub ;
174
176
let userAgentString = USER_AGENT_STRING_1 ;
175
177
const mockIndexedDBHeartbeats = [
176
- // Chosen so one will exceed 30 day limit and one will not.
177
178
{
178
179
agent : 'old-user-agent' ,
179
180
date : '1969-12-01'
@@ -236,15 +237,14 @@ describe('HeartbeatServiceImpl', () => {
236
237
} ) ;
237
238
}
238
239
} ) ;
239
- it ( `triggerHeartbeat() writes new heartbeats and retains old ones newer than 30 days ` , async ( ) => {
240
+ it ( `triggerHeartbeat() writes new heartbeats and retains old ones` , async ( ) => {
240
241
userAgentString = USER_AGENT_STRING_2 ;
241
242
clock . tick ( 3 * 24 * 60 * 60 * 1000 ) ;
242
243
await heartbeatService . triggerHeartbeat ( ) ;
243
244
if ( firebaseUtil . isIndexedDBAvailable ( ) ) {
244
245
expect ( writeStub ) . to . be . calledWith ( {
245
246
heartbeats : [
246
- // The first entry exceeds the 30 day retention limit.
247
- mockIndexedDBHeartbeats [ 1 ] ,
247
+ ...mockIndexedDBHeartbeats ,
248
248
{ agent : USER_AGENT_STRING_2 , date : '1970-01-04' }
249
249
]
250
250
} ) ;
@@ -260,6 +260,7 @@ describe('HeartbeatServiceImpl', () => {
260
260
) ;
261
261
if ( firebaseUtil . isIndexedDBAvailable ( ) ) {
262
262
expect ( heartbeatHeaders ) . to . include ( 'old-user-agent' ) ;
263
+ expect ( heartbeatHeaders ) . to . include ( '1969-12-01' ) ;
263
264
expect ( heartbeatHeaders ) . to . include ( '1969-12-31' ) ;
264
265
}
265
266
expect ( heartbeatHeaders ) . to . include ( USER_AGENT_STRING_2 ) ;
@@ -273,14 +274,47 @@ describe('HeartbeatServiceImpl', () => {
273
274
const emptyHeaders = await heartbeatService . getHeartbeatsHeader ( ) ;
274
275
expect ( emptyHeaders ) . to . equal ( '' ) ;
275
276
} ) ;
277
+ it ( 'triggerHeartbeat() removes the earliest heartbeat once the max number of heartbeats is exceeded' , async ( ) => {
278
+ // Trigger heartbeats until we reach the limit
279
+ const numHeartbeats =
280
+ heartbeatService . _heartbeatsCache ?. heartbeats . length ! ;
281
+ for ( let i = numHeartbeats ; i <= MAX_NUM_STORED_HEARTBEATS ; i ++ ) {
282
+ await heartbeatService . triggerHeartbeat ( ) ;
283
+ clock . tick ( 24 * 60 * 60 * 1000 ) ;
284
+ }
285
+
286
+ expect ( heartbeatService . _heartbeatsCache ?. heartbeats . length ) . to . equal (
287
+ MAX_NUM_STORED_HEARTBEATS
288
+ ) ;
289
+ const earliestHeartbeatDate = getEarliestHeartbeatIdx (
290
+ heartbeatService . _heartbeatsCache ?. heartbeats !
291
+ ) ;
292
+ const earliestHeartbeat =
293
+ heartbeatService . _heartbeatsCache ?. heartbeats [ earliestHeartbeatDate ] ! ;
294
+ await heartbeatService . triggerHeartbeat ( ) ;
295
+ expect ( heartbeatService . _heartbeatsCache ?. heartbeats . length ) . to . equal (
296
+ MAX_NUM_STORED_HEARTBEATS
297
+ ) ;
298
+ expect (
299
+ heartbeatService . _heartbeatsCache ?. heartbeats . indexOf ( earliestHeartbeat )
300
+ ) . to . equal ( - 1 ) ;
301
+ } ) ;
302
+ it ( 'triggerHeartbeat() never causes the heartbeat count to exceed the max' , async ( ) => {
303
+ for ( let i = 0 ; i <= 50 ; i ++ ) {
304
+ await heartbeatService . triggerHeartbeat ( ) ;
305
+ clock . tick ( 24 * 60 * 60 * 1000 ) ;
306
+ expect (
307
+ heartbeatService . _heartbeatsCache ?. heartbeats . length
308
+ ) . to . be . lessThanOrEqual ( MAX_NUM_STORED_HEARTBEATS ) ;
309
+ }
310
+ } ) ;
276
311
} ) ;
277
312
278
313
describe ( 'If IndexedDB records that a header was sent today' , ( ) => {
279
314
let heartbeatService : HeartbeatServiceImpl ;
280
315
let writeStub : SinonStub ;
281
316
const userAgentString = USER_AGENT_STRING_1 ;
282
317
const mockIndexedDBHeartbeats = [
283
- // Chosen so one will exceed 30 day limit and one will not.
284
318
{
285
319
agent : 'old-user-agent' ,
286
320
date : '1969-12-01'
@@ -426,4 +460,22 @@ describe('HeartbeatServiceImpl', () => {
426
460
) ;
427
461
} ) ;
428
462
} ) ;
463
+
464
+ describe ( 'getEarliestHeartbeatIdx()' , ( ) => {
465
+ it ( 'returns -1 if the heartbeats array is empty' , ( ) => {
466
+ const heartbeats : SingleDateHeartbeat [ ] = [ ] ;
467
+ const idx = getEarliestHeartbeatIdx ( heartbeats ) ;
468
+ expect ( idx ) . to . equal ( - 1 ) ;
469
+ } ) ;
470
+
471
+ it ( 'returns the index of the earliest date' , ( ) => {
472
+ const heartbeats = [
473
+ { agent : generateUserAgentString ( 2 ) , date : '2022-01-02' } ,
474
+ { agent : generateUserAgentString ( 1 ) , date : '2022-01-01' } ,
475
+ { agent : generateUserAgentString ( 3 ) , date : '2022-01-03' }
476
+ ] ;
477
+ const idx = getEarliestHeartbeatIdx ( heartbeats ) ;
478
+ expect ( idx ) . to . equal ( 1 ) ;
479
+ } ) ;
480
+ } ) ;
429
481
} ) ;
0 commit comments