| 'use strict'; |
| |
| const common = require('../common'); |
| const { setTimeout } = require('timers/promises'); |
| |
| if (common.isIBMi) |
| common.skip('IBMi does not support `fs.watch()`'); |
| |
| // fs-watch on folders have limited capability in AIX. |
| // The testcase makes use of folder watching, and causes |
| // hang. This behavior is documented. Skip this for AIX. |
| |
| if (common.isAIX) |
| common.skip('folder watch capability is limited in AIX.'); |
| |
| const assert = require('assert'); |
| const path = require('path'); |
| const fs = require('fs'); |
| |
| const tmpdir = require('../common/tmpdir'); |
| const testDir = tmpdir.path; |
| tmpdir.refresh(); |
| |
| (async () => { |
| // Add a recursive symlink to the parent folder |
| |
| const testDirectory = fs.mkdtempSync(testDir + path.sep); |
| |
| // Do not use `testDirectory` as base. It will hang the tests. |
| const rootDirectory = path.join(testDirectory, 'test-1'); |
| fs.mkdirSync(rootDirectory); |
| |
| const filePath = path.join(rootDirectory, 'file.txt'); |
| |
| const symlinkFolder = path.join(rootDirectory, 'symlink-folder'); |
| fs.symlinkSync(rootDirectory, symlinkFolder); |
| |
| |
| const watcher = fs.watch(rootDirectory, { recursive: true }); |
| let watcherClosed = false; |
| watcher.on('change', function(event, filename) { |
| assert.ok(event === 'rename', `Received ${event}`); |
| assert.ok(filename === path.basename(symlinkFolder) || filename === path.basename(filePath), `Received ${filename}`); |
| |
| if (filename === path.basename(filePath)) { |
| watcher.close(); |
| watcherClosed = true; |
| } |
| }); |
| |
| await setTimeout(common.platformTimeout(100)); |
| fs.writeFileSync(filePath, 'world'); |
| |
| process.once('exit', function() { |
| assert(watcherClosed, 'watcher Object was not closed'); |
| }); |
| })().then(common.mustCall()); |
| |
| (async () => { |
| // This test checks how a symlink to outside the tracking folder can trigger change |
| // tmp/sub-directory/tracking-folder/symlink-folder -> tmp/sub-directory |
| |
| const rootDirectory = fs.mkdtempSync(testDir + path.sep); |
| |
| const subDirectory = path.join(rootDirectory, 'sub-directory'); |
| fs.mkdirSync(subDirectory); |
| |
| const trackingSubDirectory = path.join(subDirectory, 'tracking-folder'); |
| fs.mkdirSync(trackingSubDirectory); |
| |
| const symlinkFolder = path.join(trackingSubDirectory, 'symlink-folder'); |
| fs.symlinkSync(subDirectory, symlinkFolder); |
| |
| const forbiddenFile = path.join(subDirectory, 'forbidden.txt'); |
| const acceptableFile = path.join(trackingSubDirectory, 'acceptable.txt'); |
| |
| const watcher = fs.watch(trackingSubDirectory, { recursive: true }); |
| let watcherClosed = false; |
| watcher.on('change', function(event, filename) { |
| // macOS will only change the following events: |
| // { event: 'rename', filename: 'symlink-folder' } |
| // { event: 'rename', filename: 'acceptable.txt' } |
| assert.ok(event === 'rename', `Received ${event}`); |
| assert.ok(filename === path.basename(symlinkFolder) || filename === path.basename(acceptableFile), `Received ${filename}`); |
| |
| if (filename === path.basename(acceptableFile)) { |
| watcher.close(); |
| watcherClosed = true; |
| } |
| }); |
| |
| await setTimeout(common.platformTimeout(100)); |
| fs.writeFileSync(forbiddenFile, 'world'); |
| await setTimeout(common.platformTimeout(100)); |
| fs.writeFileSync(acceptableFile, 'acceptable'); |
| |
| process.once('exit', function() { |
| assert(watcherClosed, 'watcher Object was not closed'); |
| }); |
| })().then(common.mustCall()); |