1'use strict'; 2 3const fs = require('fs'); 4const path = require('path'); 5const { isMainThread } = require('worker_threads'); 6 7function rmSync(pathname) { 8 fs.rmSync(pathname, { maxRetries: 3, recursive: true, force: true }); 9} 10 11const testRoot = process.env.NODE_TEST_DIR ? 12 fs.realpathSync(process.env.NODE_TEST_DIR) : path.resolve(__dirname, '..'); 13 14// Using a `.` prefixed name, which is the convention for "hidden" on POSIX, 15// gets tools to ignore it by default or by simple rules, especially eslint. 16const tmpdirName = '.tmp.' + 17 (process.env.TEST_SERIAL_ID || process.env.TEST_THREAD_ID || '0'); 18const tmpPath = path.join(testRoot, tmpdirName); 19 20let firstRefresh = true; 21function refresh() { 22 rmSync(tmpPath); 23 fs.mkdirSync(tmpPath); 24 25 if (firstRefresh) { 26 firstRefresh = false; 27 // Clean only when a test uses refresh. This allows for child processes to 28 // use the tmpdir and only the parent will clean on exit. 29 process.on('exit', onexit); 30 } 31} 32 33function onexit() { 34 // Change directory to avoid possible EBUSY 35 if (isMainThread) 36 process.chdir(testRoot); 37 38 try { 39 rmSync(tmpPath); 40 } catch (e) { 41 console.error('Can\'t clean tmpdir:', tmpPath); 42 43 const files = fs.readdirSync(tmpPath); 44 console.error('Files blocking:', files); 45 46 if (files.some((f) => f.startsWith('.nfs'))) { 47 // Warn about NFS "silly rename" 48 console.error('Note: ".nfs*" might be files that were open and ' + 49 'unlinked but not closed.'); 50 console.error('See http://nfs.sourceforge.net/#faq_d2 for details.'); 51 } 52 53 console.error(); 54 throw e; 55 } 56} 57 58function resolve(...paths) { 59 return path.resolve(tmpPath, ...paths); 60} 61 62function hasEnoughSpace(size) { 63 const { bavail, bsize } = fs.statfsSync(tmpPath); 64 return bavail >= Math.ceil(size / bsize); 65} 66 67module.exports = { 68 path: tmpPath, 69 refresh, 70 hasEnoughSpace, 71 resolve, 72}; 73