11import { MongoLogManager , mongoLogId } from '.' ;
22import { ObjectId } from 'bson' ;
33import { once } from 'events' ;
4+ import type { Stats } from 'fs' ;
45import { promises as fs } from 'fs' ;
56import path from 'path' ;
67import os from 'os' ;
@@ -27,6 +28,7 @@ describe('MongoLogManager', function () {
2728 } ) ;
2829 afterEach ( async function ( ) {
2930 await fs . rmdir ( directory , { recursive : true } ) ;
31+ sinon . restore ( ) ;
3032 } ) ;
3133
3234 it ( 'allows creating and writing to log files' , async function ( ) {
@@ -124,6 +126,58 @@ describe('MongoLogManager', function () {
124126 expect ( await getFilesState ( paths ) ) . to . equal ( '0000011111' ) ;
125127 } ) ;
126128
129+ it ( 'if fs.stat fails, it errors and is not considered towards the logs limit' , async function ( ) {
130+ const manager = new MongoLogManager ( {
131+ directory,
132+ retentionDays,
133+ retentionGB : 3 ,
134+ onwarn,
135+ onerror,
136+ } ) ;
137+
138+ const offset = Math . floor ( Date . now ( ) / 1000 ) ;
139+
140+ const faultyFile = path . join (
141+ directory ,
142+ ObjectId . createFromTime ( offset - 10 ) . toHexString ( ) + '_log'
143+ ) ;
144+ await fs . writeFile ( faultyFile , '' ) ;
145+
146+ const faultyFileError = new Error ( 'test error' ) ;
147+
148+ const validFiles : string [ ] = [ ] ;
149+ // Create 5 valid files.
150+ for ( let i = 5 ; i >= 0 ; i -- ) {
151+ const filename = path . join (
152+ directory ,
153+ ObjectId . createFromTime ( offset - i ) . toHexString ( ) + '_log'
154+ ) ;
155+ await fs . writeFile ( filename , '' ) ;
156+ validFiles . push ( filename ) ;
157+ }
158+
159+ expect ( onerror ) . not . called ;
160+
161+ const fsStatStub = sinon . stub ( fs , 'stat' ) ;
162+
163+ fsStatStub . resolves ( {
164+ size : 1024 * 1024 * 1024 ,
165+ } as Stats ) ;
166+ fsStatStub . withArgs ( faultyFile ) . rejects ( faultyFileError ) ;
167+
168+ await manager . cleanupOldLogFiles ( ) ;
169+
170+ expect ( onerror ) . calledOnceWithExactly ( faultyFileError , faultyFile ) ;
171+
172+ // fs.stat is stubbed so getFilesState will not be accurate.
173+ const leftoverFiles = ( await fs . readdir ( directory ) )
174+ . sort ( )
175+ . map ( ( file ) => path . join ( directory , file ) ) ;
176+
177+ expect ( leftoverFiles ) . to . have . lengthOf ( 4 ) ;
178+ expect ( leftoverFiles ) . deep . equals ( [ faultyFile , ...validFiles . slice ( 3 ) ] ) ;
179+ } ) ;
180+
127181 it ( 'cleans up least recent log files when requested with a storage limit' , async function ( ) {
128182 const manager = new MongoLogManager ( {
129183 directory,
0 commit comments