import * as path from 'path' ; import { LockFile , getProcessStartTime , getProcessStartTimeFromProcStat } from '../LockFile' ; import { FileSystem } from '../FileSystem' ; import { FileWriter } from '../FileWriter' ; function setLockFileGetProcessStartTime ( fn ) { ( LockFile as any ) . _getStartTime = fn ; } describe ( 'LockFile' , ( ) => { afterEach ( ( ) => { setLockFileGetProcessStartTime ( getProcessStartTime ) ; } ) ; describe ( 'getLockFilePath' , ( ) => { test ( 'only accepts alphabetical characters for resource name' , ( ) => { expect ( ( ) => { LockFile . getLockFilePath ( process . cwd ( ) , 'foo123' ) ; } ) . not . toThrow ( ) ; expect ( ( ) => { LockFile . getLockFilePath ( process . cwd ( ) , 'bar.123' ) ; } ) . not . toThrow ( ) ; expect ( ( ) => { LockFile . getLockFilePath ( process . cwd ( ) , 'foo.bar' ) ; } ) . not . toThrow ( ) ; expect ( ( ) => { LockFile . getLockFilePath ( process . cwd ( ) , 'lock-file.123' ) ; } ) . not . toThrow ( ) ; expect ( ( ) => { LockFile . getLockFilePath ( process . cwd ( ) , '.foo123' ) ; } ) . toThrow ( ) ; expect ( ( ) => { LockFile . getLockFilePath ( process . cwd ( ) , 'foo123.' ) ; } ) . toThrow ( ) ; expect ( ( ) => { LockFile . getLockFilePath ( process . cwd ( ) , '-foo123' ) ; } ) . toThrow ( ) ; expect ( ( ) => { LockFile . getLockFilePath ( process . cwd ( ) , 'foo123-' ) ; } ) . toThrow ( ) ; expect ( ( ) => { LockFile . getLockFilePath ( process . cwd ( ) , '' ) ; } ) . toThrow ( ) ; } ) ; } ) ; describe ( 'getProcessStartTimeFromProcStat' , ( ) => { function createStatOutput ( value2 , n ) { let statOutput = `0 ${ value2 } S` ; for ( let i = 0 ; i < n ; i ++ ) { statOutput += ' 0' ; } return statOutput ; } test ( 'returns undefined if too few values are contained in /proc/[pid]/stat (1)' , ( ) => { const stat = createStatOutput ( '(bash)' , 1 ) ; const ret = getProcessStartTimeFromProcStat ( stat ) ; expect ( ret ) . toBeUndefined ( ) ; } ) ; test ( 'returns undefined if too few values are contained in /proc/[pid]/stat (2)' , ( ) => { const stat = createStatOutput ( '(bash)' , 0 ) ; const ret = getProcessStartTimeFromProcStat ( stat ) ; expect ( ret ) . toBeUndefined ( ) ; } ) ; test ( 'returns the correct start time if the second value in /proc/[pid]/stat contains spaces' , ( ) => { let stat = createStatOutput ( '(bash 2)' , 18 ) ; const value22 = '12345' ; stat += ` ${ value22 }` ; const ret = getProcessStartTimeFromProcStat ( stat ) ; expect ( ret ) . toEqual ( value22 ) ; } ) ; test ( 'returns the correct start time if there are 22 values in /proc/[pid]/stat, including a trailing line ' + 'terminator' , ( ) => { let stat = createStatOutput ( '(bash)' , 18 ) ; const value22 = '12345' ; stat += ` ${ value22 }\n` ; const ret = getProcessStartTimeFromProcStat ( stat ) ; expect ( ret ) . toEqual ( value22 ) ; } ) ; test ( 'returns the correct start time if the second value in /proc/[pid]/stat does not contain spaces' , ( ) => { let stat = createStatOutput ( '(bash)' , 18 ) ; const value22 = '12345' ; stat += ` ${ value22 }` ; const ret = getProcessStartTimeFromProcStat ( stat ) ; expect ( ret ) . toEqual ( value22 ) ; } ) ; } ) ; if ( process . platform === 'darwin' || process . platform === 'linux' ) { describe ( 'Linux and Mac' , ( ) => { describe ( 'getLockFilePath()' , ( ) => { test ( 'returns a resolved path containing the pid' , ( ) => { expect ( path . join ( process . cwd ( ) , `test#${ process . pid }.lock` ) ) . toEqual ( LockFile . getLockFilePath ( './' , 'test' ) ) ; } ) ; test ( 'allows for overridden pid' , ( ) => { expect ( path . join ( process . cwd ( ) , `test#99.lock` ) ) . toEqual ( LockFile . getLockFilePath ( './' , 'test' , 99 ) ) ; } ) ; } ) ; test ( 'can acquire and close a clean lockfile' , ( ) => { const testFolder = path . join ( __dirname , '1' ) ; FileSystem . ensureEmptyFolder ( testFolder ) ; const resourceName = 'test' ; const pidLockFileName = LockFile . getLockFilePath ( testFolder , resourceName ) ; const lock = LockFile . tryAcquire ( testFolder , resourceName ) ; expect ( lock ) . toBeDefined ( ) ; expect ( lock ! . dirtyWhenAcquired ) . toEqual ( false ) ; expect ( lock ! . isReleased ) . toEqual ( false ) ; expect ( FileSystem . exists ( pidLockFileName ) ) . toEqual ( true ) ; lock ! . release ( ) ; expect ( FileSystem . exists ( pidLockFileName ) ) . toEqual ( false ) ; expect ( lock ! . isReleased ) . toEqual ( true ) ; expect ( ( ) => { lock ! . release ( ) ; } ) . toThrow ( ) ; } ) ; test ( 'cannot acquire a lock if another valid lock exists' , ( ) => { const testFolder = path . join ( __dirname , '2' ) ; FileSystem . ensureEmptyFolder ( testFolder ) ; const otherPid = 999999999 ; const otherPidStartTime = '2012-01-02 12:53:12' ; const resourceName = 'test' ; const otherPidLockFileName = LockFile . getLockFilePath ( testFolder , resourceName , otherPid ) ; setLockFileGetProcessStartTime ( ( pid ) => { return pid === process . pid ? getProcessStartTime ( process . pid ) : otherPidStartTime ; } ) ; const lockFileHandle = FileWriter . open ( otherPidLockFileName ) ; lockFileHandle . write ( otherPidStartTime ) ; lockFileHandle . close ( ) ; FileSystem . updateTimes ( otherPidLockFileName , { accessedTime : 10000 , modifiedTime : 10000 } ) ; const lock = LockFile . tryAcquire ( testFolder , resourceName ) ; expect ( lock ) . toBeUndefined ( ) ; } ) ; } ) ; } if ( process . platform === 'win32' ) { describe ( 'getLockFilePath()' , ( ) => { test ( "returns a resolved path that doesn't contain" , ( ) => { expect ( path . join ( process . cwd ( ) , `test.lock` ) ) . toEqual ( LockFile . getLockFilePath ( './' , 'test' ) ) ; } ) ; test ( 'ignores pid that is passed in' , ( ) => { expect ( path . join ( process . cwd ( ) , `test.lock` ) ) . toEqual ( LockFile . getLockFilePath ( './' , 'test' , 99 ) ) ; } ) ; } ) ; test ( 'will not acquire if existing lock is there' , ( ) => { const testFolder = path . join ( __dirname , '1' ) ; FileSystem . deleteFolder ( testFolder ) ; FileSystem . ensureFolder ( testFolder ) ; const resourceName = 'test' ; const lockFileName = LockFile . getLockFilePath ( testFolder , resourceName ) ; const lockFileHandle = FileWriter . open ( lockFileName , { exclusive : true } ) ; const lock = LockFile . tryAcquire ( testFolder , resourceName ) ; expect ( lock ) . toBeUndefined ( ) ; lockFileHandle . close ( ) ; } ) ; test ( 'can acquire and close a dirty lockfile' , ( ) => { const testFolder = path . join ( __dirname , '1' ) ; FileSystem . deleteFolder ( testFolder ) ; FileSystem . ensureFolder ( testFolder ) ; const resourceName = 'test' ; const lockFileName = LockFile . getLockFilePath ( testFolder , resourceName ) ; FileWriter . open ( lockFileName , { exclusive : true } ) . close ( ) ; const lock = LockFile . tryAcquire ( testFolder , resourceName ) ; expect ( lock ) . toBeDefined ( ) ; expect ( lock ! . dirtyWhenAcquired ) . toEqual ( true ) ; expect ( lock ! . isReleased ) . toEqual ( false ) ; expect ( FileSystem . exists ( lockFileName ) ) . toEqual ( true ) ; lock ! . release ( ) ; expect ( FileSystem . exists ( lockFileName ) ) . toEqual ( false ) ; expect ( lock ! . isReleased ) . toEqual ( true ) ; } ) ; test ( 'can acquire and close a clean lockfile' , ( ) => { const testFolder = path . join ( __dirname , '1' ) ; FileSystem . deleteFolder ( testFolder ) ; FileSystem . ensureFolder ( testFolder ) ; const resourceName = 'test' ; const lockFileName = LockFile . getLockFilePath ( testFolder , resourceName ) ; const lock = LockFile . tryAcquire ( testFolder , resourceName ) ; expect ( lock ) . toBeDefined ( ) ; expect ( lock ! . dirtyWhenAcquired ) . toEqual ( false ) ; expect ( lock ! . isReleased ) . toEqual ( false ) ; expect ( FileSystem . exists ( lockFileName ) ) . toEqual ( true ) ; lock ! . release ( ) ; expect ( FileSystem . exists ( lockFileName ) ) . toEqual ( false ) ; expect ( lock ! . isReleased ) . toEqual ( true ) ; expect ( ( ) => { lock ! . release ( ) ; } ) . toThrow ( ) ; } ) ; } } ) ;