@@ -22,7 +22,7 @@ describe('MongoLogManager', function () {
22
22
onerror = sinon . stub ( ) ;
23
23
directory = path . join (
24
24
os . tmpdir ( ) ,
25
- `log-writer-test-${ Math . random ( ) } -${ Date . now ( ) } `
25
+ `log-writer-test-${ Math . random ( ) } -${ Date . now ( ) } ` ,
26
26
) ;
27
27
await fs . mkdir ( directory , { recursive : true } ) ;
28
28
} ) ;
@@ -84,10 +84,10 @@ describe('MongoLogManager', function () {
84
84
85
85
const writer = await manager . createLogWriter ( ) ;
86
86
expect (
87
- path . relative ( directory , writer . logFilePath as string ) [ 0 ]
87
+ path . relative ( directory , writer . logFilePath as string ) [ 0 ] ,
88
88
) . to . not . equal ( '.' ) ;
89
89
expect ( ( writer . logFilePath as string ) . includes ( writer . logId ) ) . to . equal (
90
- true
90
+ true ,
91
91
) ;
92
92
93
93
writer . info ( 'component' , mongoLogId ( 12345 ) , 'context' , 'message' , {
@@ -147,15 +147,54 @@ describe('MongoLogManager', function () {
147
147
}
148
148
} ) ;
149
149
150
+ it ( 'can recursively clean up old files' , async function ( ) {
151
+ const childDirectory = path . join ( directory , 'child' , '1' ) ;
152
+ await fs . mkdir ( childDirectory , { recursive : true } ) ;
153
+ // The child manager writes in a subdirectory of the log directory
154
+ // The expectation is that when the parent manager recursively cleans up the
155
+ // old log files, it will be able to delete the files of the child manager.
156
+ const childManager = new MongoLogManager ( {
157
+ directory : childDirectory ,
158
+ retentionDays : 60 ,
159
+ onwarn,
160
+ onerror,
161
+ } ) ;
162
+
163
+ const childWriter = await childManager . createLogWriter ( ) ;
164
+ childWriter . info ( 'child' , mongoLogId ( 12345 ) , 'context' , 'message' ) ;
165
+
166
+ childWriter . end ( ) ;
167
+ await once ( childWriter , 'finish' ) ;
168
+ await fs . stat ( childWriter . logFilePath as string ) ;
169
+ await new Promise ( ( resolve ) => setTimeout ( resolve , 100 ) ) ;
170
+
171
+ const parentManager = new MongoLogManager ( {
172
+ directory,
173
+ retentionDays : 0.000001 , // 86.4 ms
174
+ onwarn,
175
+ onerror,
176
+ } ) ;
177
+
178
+ await parentManager . cleanupOldLogFiles ( { recursive : true } ) ;
179
+
180
+ try {
181
+ await fs . stat ( childWriter . logFilePath as string ) ;
182
+
183
+ expect . fail ( 'missed exception' ) ;
184
+ } catch ( err : any ) {
185
+ expect ( err . code ) . to . equal ( 'ENOENT' ) ;
186
+ }
187
+ } ) ;
188
+
150
189
const getFilesState = async ( paths : string [ ] ) => {
151
190
return (
152
191
await Promise . all (
153
192
paths . map ( ( path ) =>
154
193
fs . stat ( path ) . then (
155
194
( ) => 1 ,
156
- ( ) => 0
157
- )
158
- )
195
+ ( ) => 0 ,
196
+ ) ,
197
+ ) ,
159
198
)
160
199
) . join ( '' ) ;
161
200
} ;
@@ -174,7 +213,7 @@ describe('MongoLogManager', function () {
174
213
for ( let i = 0 ; i < 10 ; i ++ ) {
175
214
const filename = path . join (
176
215
directory ,
177
- ObjectId . createFromTime ( offset - i ) . toHexString ( ) + '_log'
216
+ ObjectId . createFromTime ( offset - i ) . toHexString ( ) + '_log' ,
178
217
) ;
179
218
await fs . writeFile ( filename , '' ) ;
180
219
paths . unshift ( filename ) ;
@@ -198,7 +237,7 @@ describe('MongoLogManager', function () {
198
237
199
238
const faultyFile = path . join (
200
239
directory ,
201
- ObjectId . createFromTime ( offset - 10 ) . toHexString ( ) + '_log'
240
+ ObjectId . createFromTime ( offset - 10 ) . toHexString ( ) + '_log' ,
202
241
) ;
203
242
await fs . writeFile ( faultyFile , '' ) ;
204
243
@@ -209,7 +248,7 @@ describe('MongoLogManager', function () {
209
248
for ( let i = 5 ; i >= 0 ; i -- ) {
210
249
const filename = path . join (
211
250
directory ,
212
- ObjectId . createFromTime ( offset - i ) . toHexString ( ) + '_log'
251
+ ObjectId . createFromTime ( offset - i ) . toHexString ( ) + '_log' ,
213
252
) ;
214
253
await fs . writeFile ( filename , '' ) ;
215
254
validFiles . push ( filename ) ;
@@ -254,7 +293,7 @@ describe('MongoLogManager', function () {
254
293
for ( let i = 1 ; i >= 0 ; i -- ) {
255
294
const withoutPrefix = path . join (
256
295
directory ,
257
- ObjectId . createFromTime ( offset - i ) . toHexString ( ) + '_log'
296
+ ObjectId . createFromTime ( offset - i ) . toHexString ( ) + '_log' ,
258
297
) ;
259
298
await fs . writeFile ( withoutPrefix , '' ) ;
260
299
paths . push ( withoutPrefix ) ;
@@ -263,7 +302,7 @@ describe('MongoLogManager', function () {
263
302
directory ,
264
303
'different_' +
265
304
ObjectId . createFromTime ( offset - i ) . toHexString ( ) +
266
- '_log'
305
+ '_log' ,
267
306
) ;
268
307
await fs . writeFile ( withDifferentPrefix , '' ) ;
269
308
paths . push ( withDifferentPrefix ) ;
@@ -273,7 +312,7 @@ describe('MongoLogManager', function () {
273
312
for ( let i = 9 ; i >= 0 ; i -- ) {
274
313
const filename = path . join (
275
314
directory ,
276
- `custom_${ ObjectId . createFromTime ( offset - i ) . toHexString ( ) } _log`
315
+ `custom_${ ObjectId . createFromTime ( offset - i ) . toHexString ( ) } _log` ,
277
316
) ;
278
317
await fs . writeFile ( filename , '' ) ;
279
318
paths . push ( filename ) ;
@@ -305,7 +344,7 @@ describe('MongoLogManager', function () {
305
344
for ( let i = 0 ; i < 10 ; i ++ ) {
306
345
const filename = path . join (
307
346
directory ,
308
- ObjectId . createFromTime ( offset - i ) . toHexString ( ) + '_log'
347
+ ObjectId . createFromTime ( offset - i ) . toHexString ( ) + '_log' ,
309
348
) ;
310
349
await fs . writeFile ( filename , '0' . repeat ( 1024 ) ) ;
311
350
paths . unshift ( filename ) ;
@@ -332,7 +371,7 @@ describe('MongoLogManager', function () {
332
371
for ( let i = 0 ; i < 10 ; i ++ ) {
333
372
const filename = path . join (
334
373
directory ,
335
- ObjectId . createFromTime ( offset - i ) . toHexString ( ) + '_log'
374
+ ObjectId . createFromTime ( offset - i ) . toHexString ( ) + '_log' ,
336
375
) ;
337
376
await fs . writeFile ( filename , '' ) ;
338
377
}
@@ -345,11 +384,12 @@ describe('MongoLogManager', function () {
345
384
describe ( 'with a random file order' , function ( ) {
346
385
let paths : string [ ] = [ ] ;
347
386
const times = [ 92 , 90 , 1 , 2 , 3 , 91 ] ;
387
+ let offset : number ;
348
388
349
389
beforeEach ( async function ( ) {
350
390
const fileNames : string [ ] = [ ] ;
351
391
paths = [ ] ;
352
- const offset = Math . floor ( Date . now ( ) / 1000 ) ;
392
+ offset = Math . floor ( Date . now ( ) / 1000 ) ;
353
393
354
394
for ( const time of times ) {
355
395
const fileName =
@@ -359,19 +399,6 @@ describe('MongoLogManager', function () {
359
399
fileNames . push ( fileName ) ;
360
400
paths . push ( fullPath ) ;
361
401
}
362
-
363
- sinon . replace ( fs , 'opendir' , async ( ) =>
364
- Promise . resolve ( {
365
- [ Symbol . asyncIterator ] : function * ( ) {
366
- for ( const fileName of fileNames ) {
367
- yield {
368
- name : fileName ,
369
- isFile : ( ) => true ,
370
- } ;
371
- }
372
- } ,
373
- } as unknown as Dir )
374
- ) ;
375
402
} ) ;
376
403
377
404
it ( 'cleans up in the expected order with maxLogFileCount' , async function ( ) {
@@ -405,6 +432,44 @@ describe('MongoLogManager', function () {
405
432
406
433
expect ( await getFilesState ( paths ) ) . to . equal ( '001110' ) ;
407
434
} ) ;
435
+
436
+ describe ( 'with subdirectories' , function ( ) {
437
+ it ( 'cleans up in the expected order with maxLogFileCount' , async function ( ) {
438
+ // This should exist since the file was created recently
439
+ const childPath1 = path . join (
440
+ directory ,
441
+ 'subdir1' ,
442
+ ObjectId . createFromTime ( offset - 2 ) . toHexString ( ) + '_log' ,
443
+ ) ;
444
+ await fs . mkdir ( path . join ( directory , 'subdir1' ) , { recursive : true } ) ;
445
+ await fs . writeFile ( childPath1 , '0' . repeat ( 1024 ) ) ;
446
+ paths . push ( childPath1 ) ;
447
+
448
+ // This should not exist since it was created a long time ago
449
+ const childPath2 = path . join (
450
+ directory ,
451
+ 'subdir2' ,
452
+ ObjectId . createFromTime ( offset - 20 ) . toHexString ( ) + '_log' ,
453
+ ) ;
454
+ await fs . mkdir ( path . join ( directory , 'subdir2' ) , { recursive : true } ) ;
455
+ await fs . writeFile ( childPath2 , '0' . repeat ( 1024 ) ) ;
456
+ paths . push ( childPath2 ) ;
457
+
458
+ const manager = new MongoLogManager ( {
459
+ directory,
460
+ retentionDays,
461
+ maxLogFileCount : 3 ,
462
+ onwarn,
463
+ onerror,
464
+ } ) ;
465
+
466
+ expect ( await getFilesState ( paths ) ) . to . equal ( '11111111' ) ;
467
+
468
+ await manager . cleanupOldLogFiles ( { recursive : true } ) ;
469
+
470
+ expect ( await getFilesState ( paths ) ) . to . equal ( '00110010' ) ;
471
+ } ) ;
472
+ } ) ;
408
473
} ) ;
409
474
410
475
describe ( 'with multiple log retention settings' , function ( ) {
@@ -426,13 +491,13 @@ describe('MongoLogManager', function () {
426
491
const yesterday = today - 25 * 60 * 60 ;
427
492
const todayFile = path . join (
428
493
directory ,
429
- ObjectId . createFromTime ( today - i ) . toHexString ( ) + '_log'
494
+ ObjectId . createFromTime ( today - i ) . toHexString ( ) + '_log' ,
430
495
) ;
431
496
await fs . writeFile ( todayFile , '0' . repeat ( 1024 ) ) ;
432
497
433
498
const yesterdayFile = path . join (
434
499
directory ,
435
- ObjectId . createFromTime ( yesterday - i ) . toHexString ( ) + '_log'
500
+ ObjectId . createFromTime ( yesterday - i ) . toHexString ( ) + '_log' ,
436
501
) ;
437
502
await fs . writeFile ( yesterdayFile , '0' . repeat ( 1024 ) ) ;
438
503
@@ -467,7 +532,7 @@ describe('MongoLogManager', function () {
467
532
for ( let i = 0 ; i < 10 ; i ++ ) {
468
533
const filename = path . join (
469
534
directory ,
470
- ObjectId . createFromTime ( offset - i ) . toHexString ( ) + '_log'
535
+ ObjectId . createFromTime ( offset - i ) . toHexString ( ) + '_log' ,
471
536
) ;
472
537
await fs . writeFile ( filename , '0' . repeat ( 1024 ) ) ;
473
538
paths . unshift ( filename ) ;
@@ -496,7 +561,7 @@ describe('MongoLogManager', function () {
496
561
for ( let i = 0 ; i < 10 ; i ++ ) {
497
562
const filename = path . join (
498
563
directory ,
499
- ObjectId . createFromTime ( offset - i ) . toHexString ( ) + '_log'
564
+ ObjectId . createFromTime ( offset - i ) . toHexString ( ) + '_log' ,
500
565
) ;
501
566
await fs . writeFile ( filename , '0' . repeat ( 1024 ) ) ;
502
567
paths . unshift ( filename ) ;
@@ -528,7 +593,7 @@ describe('MongoLogManager', function () {
528
593
} ) ;
529
594
530
595
const writer = await manager . createLogWriter ( ) ;
531
- expect ( onwarn ) . to . have . been . calledOnce ; // eslint-disable-line
596
+ expect ( onwarn ) . to . have . been . calledOnce ;
532
597
expect ( writer . logFilePath ) . to . equal ( null ) ;
533
598
534
599
writer . info ( 'component' , mongoLogId ( 12345 ) , 'context' , 'message' , {
@@ -538,7 +603,7 @@ describe('MongoLogManager', function () {
538
603
await once ( writer , 'finish' ) ;
539
604
} ) ;
540
605
541
- it ( ' optionally allow gzip’ ed log files' , async function ( ) {
606
+ it ( " optionally allow gzip' ed log files" , async function ( ) {
542
607
const manager = new MongoLogManager ( {
543
608
directory,
544
609
retentionDays,
@@ -566,7 +631,7 @@ describe('MongoLogManager', function () {
566
631
expect ( log [ 0 ] . t . $date ) . to . be . a ( 'string' ) ;
567
632
} ) ;
568
633
569
- it ( ' optionally can read truncated gzip’ ed log files' , async function ( ) {
634
+ it ( " optionally can read truncated gzip' ed log files" , async function ( ) {
570
635
const manager = new MongoLogManager ( {
571
636
directory,
572
637
retentionDays,
@@ -608,7 +673,7 @@ describe('MongoLogManager', function () {
608
673
} ;
609
674
const opendirStub = sinon
610
675
. stub ( fs , 'opendir' )
611
- . resolves ( fakeDirHandle as any ) ;
676
+ . resolves ( fakeDirHandle as unknown as Dir ) ;
612
677
613
678
retentionDays = 0.000001 ; // 86.4 ms
614
679
const manager = new MongoLogManager ( {
0 commit comments