@@ -520,3 +520,83 @@ it('should not fail to update mtime when we are over the threshold but mtime is
520520 } , 1000 ) ;
521521 await pDelay ( 5000 ) ;
522522} , 16000 ) ;
523+
524+ it ( 'should allow truncated second precision mtime' , async ( ) => {
525+ fs . writeFileSync ( `${ tmpDir } /foo` , '' ) ;
526+
527+ const customFs = {
528+ ...fs ,
529+ stat ( path , cb ) {
530+ fs . stat ( path , ( err , stat ) => {
531+ if ( err ) {
532+ return cb ( err ) ;
533+ }
534+
535+ // Make second precision if not already
536+ stat . mtime = new Date ( Math . trunc ( stat . mtime . getTime ( ) / 1000 ) * 1000 ) ;
537+ cb ( null , stat ) ;
538+ } ) ;
539+ } ,
540+ } ;
541+
542+ const deferred = pDefer ( ) ;
543+
544+ // If the module does not detect second precision for mtime, the mtime
545+ // comparison will cause the lock to appear compromised.
546+ const handleCompromised = ( err ) => {
547+ clearTimeout ( successTimeoutId ) ;
548+ deferred . reject ( err ) ;
549+ } ;
550+
551+ await lockfile . lock ( `${ tmpDir } /foo` , {
552+ fs : customFs ,
553+ update : 1000 ,
554+ onCompromised : handleCompromised ,
555+ } ) ;
556+
557+ // First update is fine because we `stat` after we `mkdir`, it'll fail on
558+ // the second update when we use `utimes` and do not `stat` for the `mtime`
559+ const successTimeoutId = setTimeout ( deferred . resolve , 3000 ) ;
560+
561+ await deferred . promise ;
562+ } ) ;
563+
564+ it ( 'should allow rounded second precision mtime' , async ( ) => {
565+ fs . writeFileSync ( `${ tmpDir } /foo` , '' ) ;
566+
567+ const customFs = {
568+ ...fs ,
569+ stat ( path , cb ) {
570+ fs . stat ( path , ( err , stat ) => {
571+ if ( err ) {
572+ return cb ( err ) ;
573+ }
574+
575+ // Make second precision if not already
576+ stat . mtime = new Date ( Math . round ( stat . mtime . getTime ( ) / 1000 ) * 1000 ) ;
577+ cb ( null , stat ) ;
578+ } ) ;
579+ } ,
580+ } ;
581+
582+ const deferred = pDefer ( ) ;
583+
584+ // If the module does not detect second precision for mtime, the mtime
585+ // comparison will cause the lock to appear compromised.
586+ const handleCompromised = ( err ) => {
587+ clearTimeout ( successTimeoutId ) ;
588+ deferred . reject ( err ) ;
589+ } ;
590+
591+ await lockfile . lock ( `${ tmpDir } /foo` , {
592+ fs : customFs ,
593+ update : 1000 ,
594+ onCompromised : handleCompromised ,
595+ } ) ;
596+
597+ // First update is fine because we `stat` after we `mkdir`, it'll fail on
598+ // the second update when we use `utimes` and do not `stat` for the `mtime`
599+ const successTimeoutId = setTimeout ( deferred . resolve , 3000 ) ;
600+
601+ await deferred . promise ;
602+ } ) ;
0 commit comments