@@ -20,14 +20,16 @@ import '../test/setup';
2020import {
2121 countBytes ,
2222 HeartbeatServiceImpl ,
23- extractHeartbeatsForHeader
23+ extractHeartbeatsForHeader ,
24+ getEarliestHeartbeatIdx ,
25+ MAX_NUM_STORED_HEARTBEATS
2426} from './heartbeatService' ;
2527import {
2628 Component ,
2729 ComponentType ,
2830 ComponentContainer
2931} from '@firebase/component' ;
30- import { PlatformLoggerService } from './types' ;
32+ import { PlatformLoggerService , SingleDateHeartbeat } from './types' ;
3133import { FirebaseApp } from './public-types' ;
3234import * as firebaseUtil from '@firebase/util' ;
3335import { SinonStub , stub , useFakeTimers } from 'sinon' ;
@@ -173,7 +175,6 @@ describe('HeartbeatServiceImpl', () => {
173175 let writeStub : SinonStub ;
174176 let userAgentString = USER_AGENT_STRING_1 ;
175177 const mockIndexedDBHeartbeats = [
176- // Chosen so one will exceed 30 day limit and one will not.
177178 {
178179 agent : 'old-user-agent' ,
179180 date : '1969-12-01'
@@ -236,15 +237,14 @@ describe('HeartbeatServiceImpl', () => {
236237 } ) ;
237238 }
238239 } ) ;
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 ( ) => {
240241 userAgentString = USER_AGENT_STRING_2 ;
241242 clock . tick ( 3 * 24 * 60 * 60 * 1000 ) ;
242243 await heartbeatService . triggerHeartbeat ( ) ;
243244 if ( firebaseUtil . isIndexedDBAvailable ( ) ) {
244245 expect ( writeStub ) . to . be . calledWith ( {
245246 heartbeats : [
246- // The first entry exceeds the 30 day retention limit.
247- mockIndexedDBHeartbeats [ 1 ] ,
247+ ...mockIndexedDBHeartbeats ,
248248 { agent : USER_AGENT_STRING_2 , date : '1970-01-04' }
249249 ]
250250 } ) ;
@@ -260,6 +260,7 @@ describe('HeartbeatServiceImpl', () => {
260260 ) ;
261261 if ( firebaseUtil . isIndexedDBAvailable ( ) ) {
262262 expect ( heartbeatHeaders ) . to . include ( 'old-user-agent' ) ;
263+ expect ( heartbeatHeaders ) . to . include ( '1969-12-01' ) ;
263264 expect ( heartbeatHeaders ) . to . include ( '1969-12-31' ) ;
264265 }
265266 expect ( heartbeatHeaders ) . to . include ( USER_AGENT_STRING_2 ) ;
@@ -273,14 +274,47 @@ describe('HeartbeatServiceImpl', () => {
273274 const emptyHeaders = await heartbeatService . getHeartbeatsHeader ( ) ;
274275 expect ( emptyHeaders ) . to . equal ( '' ) ;
275276 } ) ;
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+ } ) ;
276311 } ) ;
277312
278313 describe ( 'If IndexedDB records that a header was sent today' , ( ) => {
279314 let heartbeatService : HeartbeatServiceImpl ;
280315 let writeStub : SinonStub ;
281316 const userAgentString = USER_AGENT_STRING_1 ;
282317 const mockIndexedDBHeartbeats = [
283- // Chosen so one will exceed 30 day limit and one will not.
284318 {
285319 agent : 'old-user-agent' ,
286320 date : '1969-12-01'
@@ -426,4 +460,22 @@ describe('HeartbeatServiceImpl', () => {
426460 ) ;
427461 } ) ;
428462 } ) ;
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+ } ) ;
429481} ) ;
0 commit comments