@@ -16,6 +16,7 @@ const libTestFolder: string = path.resolve(__dirname, '../../lib/test');
16
16
17
17
describe ( LockFile . name , ( ) => {
18
18
afterEach ( ( ) => {
19
+ jest . restoreAllMocks ( ) ;
19
20
setLockFileGetProcessStartTime ( getProcessStartTime ) ;
20
21
} ) ;
21
22
@@ -201,6 +202,86 @@ describe(LockFile.name, () => {
201
202
// this lock should be undefined since there is an existing lock
202
203
expect ( lock ) . toBeUndefined ( ) ;
203
204
} ) ;
205
+
206
+ test ( 'deletes other hanging lockfiles if corresponding processes are not running anymore' , ( ) => {
207
+ // ensure test folder is clean
208
+ const testFolder : string = path . join ( libTestFolder , '4' ) ;
209
+ FileSystem . ensureEmptyFolder ( testFolder ) ;
210
+
211
+ const resourceName : string = 'test' ;
212
+
213
+ const otherPid : number = 999999999 ;
214
+ const otherPidInitialStartTime : string = '2012-01-02 12:53:12' ;
215
+
216
+ // simulate a hanging lockfile that was not cleaned by other process
217
+ const otherPidLockFileName : string = LockFile . getLockFilePath ( testFolder , resourceName , otherPid ) ;
218
+ const lockFileHandle : FileWriter = FileWriter . open ( otherPidLockFileName ) ;
219
+ lockFileHandle . write ( otherPidInitialStartTime ) ;
220
+ lockFileHandle . close ( ) ;
221
+ FileSystem . updateTimes ( otherPidLockFileName , {
222
+ accessedTime : 10000 ,
223
+ modifiedTime : 10000
224
+ } ) ;
225
+
226
+ // return undefined as if the process was not running anymore
227
+ setLockFileGetProcessStartTime ( ( pid : number ) => {
228
+ return pid === otherPid ? undefined : getProcessStartTime ( pid ) ;
229
+ } ) ;
230
+
231
+ const deleteFileSpy = jest . spyOn ( FileSystem , 'deleteFile' ) ;
232
+ LockFile . tryAcquire ( testFolder , resourceName ) ;
233
+
234
+ expect ( deleteFileSpy ) . toHaveBeenCalledTimes ( 1 ) ;
235
+ expect ( deleteFileSpy ) . toHaveBeenNthCalledWith ( 1 , otherPidLockFileName ) ;
236
+ } ) ;
237
+
238
+ test ( 'doesn’t attempt deleting other process lockfile if it is released in the middle of acquiring process' , ( ) => {
239
+ // ensure test folder is clean
240
+ const testFolder : string = path . join ( libTestFolder , '5' ) ;
241
+ FileSystem . ensureEmptyFolder ( testFolder ) ;
242
+
243
+ const resourceName : string = 'test' ;
244
+
245
+ const otherPid : number = 999999999 ;
246
+ const otherPidStartTime : string = '2012-01-02 12:53:12' ;
247
+
248
+ const otherPidLockFileName : string = LockFile . getLockFilePath ( testFolder , resourceName , otherPid ) ;
249
+
250
+ // create an open lockfile for other process
251
+ const lockFileHandle : FileWriter = FileWriter . open ( otherPidLockFileName ) ;
252
+ lockFileHandle . write ( otherPidStartTime ) ;
253
+ lockFileHandle . close ( ) ;
254
+ FileSystem . updateTimes ( otherPidLockFileName , {
255
+ accessedTime : 10000 ,
256
+ modifiedTime : 10000
257
+ } ) ;
258
+
259
+ // return other process start time as if it was still running
260
+ setLockFileGetProcessStartTime ( ( pid : number ) => {
261
+ return pid === otherPid ? otherPidStartTime : getProcessStartTime ( pid ) ;
262
+ } ) ;
263
+
264
+ const originalReadFile = FileSystem . readFile ;
265
+ jest . spyOn ( FileSystem , 'readFile' ) . mockImplementation ( ( filePath : string ) => {
266
+ if ( filePath === otherPidLockFileName ) {
267
+ // simulate other process lock release right before the current process reads
268
+ // other process lockfile to decide on next steps for acquiring the lock
269
+ FileSystem . deleteFile ( filePath ) ;
270
+ }
271
+
272
+ return originalReadFile ( filePath ) ;
273
+ } ) ;
274
+
275
+ const deleteFileSpy = jest . spyOn ( FileSystem , 'deleteFile' ) ;
276
+
277
+ LockFile . tryAcquire ( testFolder , resourceName ) ;
278
+
279
+ // Ensure there were no other FileSystem.deleteFile calls after our lock release simulation.
280
+ // An extra attempt to delete the lockfile might lead to unexpectedly deleting a new lockfile
281
+ // created by another process right after releasing/deleting the previous lockfile
282
+ expect ( deleteFileSpy ) . toHaveBeenCalledTimes ( 1 ) ;
283
+ expect ( deleteFileSpy ) . toHaveBeenNthCalledWith ( 1 , otherPidLockFileName ) ;
284
+ } ) ;
204
285
} ) ;
205
286
}
206
287
0 commit comments