diff --git a/test/parallel/test-fs-watch-recursive-add-file-to-existing-subfolder.js b/test/parallel/test-fs-watch-recursive-add-file-to-existing-subfolder.js new file mode 100644 index 00000000000000..5563dc6a525958 --- /dev/null +++ b/test/parallel/test-fs-watch-recursive-add-file-to-existing-subfolder.js @@ -0,0 +1,59 @@ +'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 file to subfolder of a watching folder + + const rootDirectory = fs.mkdtempSync(testDir + path.sep); + const testDirectory = path.join(rootDirectory, 'test-4'); + fs.mkdirSync(testDirectory); + + const file = 'folder-5'; + const filePath = path.join(testDirectory, file); + fs.mkdirSync(filePath); + + const subfolderPath = path.join(filePath, 'subfolder-6'); + fs.mkdirSync(subfolderPath); + + const childrenFile = 'file-7.txt'; + const childrenAbsolutePath = path.join(subfolderPath, childrenFile); + const relativePath = path.join(file, path.basename(subfolderPath), childrenFile); + + const watcher = fs.watch(testDirectory, { recursive: true }); + let watcherClosed = false; + watcher.on('change', function(event, filename) { + assert.strictEqual(event, 'rename'); + + if (filename === relativePath) { + watcher.close(); + watcherClosed = true; + } + }); + + await setTimeout(common.platformTimeout(100)); + fs.writeFileSync(childrenAbsolutePath, 'world'); + + process.once('exit', function() { + assert(watcherClosed, 'watcher Object was not closed'); + }); +})().then(common.mustCall()); diff --git a/test/parallel/test-fs-watch-recursive-add-file-to-new-folder.js b/test/parallel/test-fs-watch-recursive-add-file-to-new-folder.js new file mode 100644 index 00000000000000..9b74cd281b62ec --- /dev/null +++ b/test/parallel/test-fs-watch-recursive-add-file-to-new-folder.js @@ -0,0 +1,57 @@ +'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 file to newly created folder to already watching folder + + const rootDirectory = fs.mkdtempSync(testDir + path.sep); + const testDirectory = path.join(rootDirectory, 'test-3'); + fs.mkdirSync(testDirectory); + + const filePath = path.join(testDirectory, 'folder-3'); + + const childrenFile = 'file-4.txt'; + const childrenAbsolutePath = path.join(filePath, childrenFile); + const childrenRelativePath = path.join(path.basename(filePath), childrenFile); + + const watcher = fs.watch(testDirectory, { recursive: true }); + let watcherClosed = false; + watcher.on('change', function(event, filename) { + assert.strictEqual(event, 'rename'); + assert.ok(filename === path.basename(filePath) || filename === childrenRelativePath); + + if (filename === childrenRelativePath) { + watcher.close(); + watcherClosed = true; + } + }); + + await setTimeout(common.platformTimeout(100)); + fs.mkdirSync(filePath); + await setTimeout(common.platformTimeout(100)); + fs.writeFileSync(childrenAbsolutePath, 'world'); + + process.once('exit', function() { + assert(watcherClosed, 'watcher Object was not closed'); + }); +})().then(common.mustCall()); diff --git a/test/parallel/test-fs-watch-recursive-add-file-with-url.js b/test/parallel/test-fs-watch-recursive-add-file-with-url.js new file mode 100644 index 00000000000000..ee726961c41e9e --- /dev/null +++ b/test/parallel/test-fs-watch-recursive-add-file-with-url.js @@ -0,0 +1,52 @@ +'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 { pathToFileURL } = require('url'); + +const tmpdir = require('../common/tmpdir'); +const testDir = tmpdir.path; +tmpdir.refresh(); + +(async () => { + // Add a file to already watching folder, and use URL as the path + + const rootDirectory = fs.mkdtempSync(testDir + path.sep); + const testDirectory = path.join(rootDirectory, 'test-5'); + fs.mkdirSync(testDirectory); + + const filePath = path.join(testDirectory, 'file-8.txt'); + const url = pathToFileURL(testDirectory); + + const watcher = fs.watch(url, { recursive: true }); + let watcherClosed = false; + watcher.on('change', function(event, filename) { + assert.strictEqual(event, 'rename'); + + if (filename === path.basename(filePath)) { + watcher.close(); + watcherClosed = true; + } + }); + + await setTimeout(common.platformTimeout(100)); + fs.writeFileSync(filePath, 'world'); + + process.on('exit', function() { + assert(watcherClosed, 'watcher Object was not closed'); + }); +})().then(common.mustCall()); diff --git a/test/parallel/test-fs-watch-recursive-add-file.js b/test/parallel/test-fs-watch-recursive-add-file.js new file mode 100644 index 00000000000000..d23d417cfaa410 --- /dev/null +++ b/test/parallel/test-fs-watch-recursive-add-file.js @@ -0,0 +1,50 @@ +'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 file to already watching folder + + const rootDirectory = fs.mkdtempSync(testDir + path.sep); + const testDirectory = path.join(rootDirectory, 'test-1'); + fs.mkdirSync(testDirectory); + + const testFile = path.join(testDirectory, 'file-1.txt'); + + const watcher = fs.watch(testDirectory, { recursive: true }); + let watcherClosed = false; + watcher.on('change', function(event, filename) { + assert.strictEqual(event, 'rename'); + + if (filename === path.basename(testFile)) { + watcher.close(); + watcherClosed = true; + } + }); + + await setTimeout(common.platformTimeout(100)); + fs.writeFileSync(testFile, 'world'); + + process.once('exit', function() { + assert(watcherClosed, 'watcher Object was not closed'); + }); +})().then(common.mustCall()); diff --git a/test/parallel/test-fs-watch-recursive-add-folder.js b/test/parallel/test-fs-watch-recursive-add-folder.js new file mode 100644 index 00000000000000..1851a7850f66ff --- /dev/null +++ b/test/parallel/test-fs-watch-recursive-add-folder.js @@ -0,0 +1,50 @@ +'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 folder to already watching folder + + const rootDirectory = fs.mkdtempSync(testDir + path.sep); + const testDirectory = path.join(rootDirectory, 'test-2'); + fs.mkdirSync(testDirectory); + + const testFile = path.join(testDirectory, 'folder-2'); + + const watcher = fs.watch(testDirectory, { recursive: true }); + let watcherClosed = false; + watcher.on('change', function(event, filename) { + assert.strictEqual(event, 'rename'); + + if (filename === path.basename(testFile)) { + watcher.close(); + watcherClosed = true; + } + }); + + await setTimeout(common.platformTimeout(100)); + fs.mkdirSync(testFile); + + process.once('exit', function() { + assert(watcherClosed, 'watcher Object was not closed'); + }); +})().then(common.mustCall()); diff --git a/test/parallel/test-fs-watch-recursive-assert-leaks.js b/test/parallel/test-fs-watch-recursive-assert-leaks.js new file mode 100644 index 00000000000000..ac2010cfb26376 --- /dev/null +++ b/test/parallel/test-fs-watch-recursive-assert-leaks.js @@ -0,0 +1,48 @@ +'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 () => { + // Assert recursive watch does not leak handles + const rootDirectory = fs.mkdtempSync(testDir + path.sep); + const testDirectory = path.join(rootDirectory, 'test-7'); + const filePath = path.join(testDirectory, 'only-file.txt'); + fs.mkdirSync(testDirectory); + + let watcherClosed = false; + const watcher = fs.watch(testDirectory, { recursive: true }); + watcher.on('change', common.mustCallAtLeast(async (event, filename) => { + await setTimeout(common.platformTimeout(100)); + if (filename === path.basename(filePath)) { + watcher.close(); + watcherClosed = true; + } + await setTimeout(common.platformTimeout(100)); + assert(!process._getActiveHandles().some((handle) => handle.constructor.name === 'StatWatcher')); + })); + + process.on('exit', function() { + assert(watcherClosed, 'watcher Object was not closed'); + }); + await setTimeout(common.platformTimeout(100)); + fs.writeFileSync(filePath, 'content'); +})().then(common.mustCall()); diff --git a/test/parallel/test-fs-watch-recursive-update-file.js b/test/parallel/test-fs-watch-recursive-update-file.js new file mode 100644 index 00000000000000..57d3bffc7a92b0 --- /dev/null +++ b/test/parallel/test-fs-watch-recursive-update-file.js @@ -0,0 +1,52 @@ +'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 () => { + // Watch a folder and update an already existing file in it. + + const rootDirectory = fs.mkdtempSync(testDir + path.sep); + const testDirectory = path.join(rootDirectory, 'test-0'); + fs.mkdirSync(testDirectory); + + const testFile = path.join(testDirectory, 'file-1.txt'); + fs.writeFileSync(testFile, 'hello'); + + const watcher = fs.watch(testDirectory, { recursive: true }); + let watcherClosed = false; + watcher.on('change', common.mustCallAtLeast(function(event, filename) { + // Libuv inconsistenly emits a rename event for the file we are watching + assert.ok(event === 'change' || event === 'rename'); + + if (filename === path.basename(testFile)) { + watcher.close(); + watcherClosed = true; + } + })); + + await setTimeout(common.platformTimeout(100)); + fs.writeFileSync(testFile, 'hello'); + + process.once('exit', function() { + assert(watcherClosed, 'watcher Object was not closed'); + }); +})().then(common.mustCall()); diff --git a/test/parallel/test-fs-watch-recursive-validate.js b/test/parallel/test-fs-watch-recursive-validate.js new file mode 100644 index 00000000000000..cfebc64818283e --- /dev/null +++ b/test/parallel/test-fs-watch-recursive-validate.js @@ -0,0 +1,34 @@ +'use strict'; + +const common = require('../common'); + +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 () => { + // Handle non-boolean values for options.recursive + + if (!common.isWindows && !common.isOSX) { + assert.throws(() => { + const testsubdir = fs.mkdtempSync(testDir + path.sep); + fs.watch(testsubdir, { recursive: '1' }); + }, { + code: 'ERR_INVALID_ARG_TYPE', + }); + } +})().then(common.mustCall()); diff --git a/test/parallel/test-fs-watch-recursive-watch-file.js b/test/parallel/test-fs-watch-recursive-watch-file.js new file mode 100644 index 00000000000000..3449db8e59ad01 --- /dev/null +++ b/test/parallel/test-fs-watch-recursive-watch-file.js @@ -0,0 +1,55 @@ +'use strict'; + +const common = require('../common'); + +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 () => { + // Watch a file (not a folder) using fs.watch + + const rootDirectory = fs.mkdtempSync(testDir + path.sep); + const testDirectory = path.join(rootDirectory, 'test-6'); + fs.mkdirSync(testDirectory); + + const filePath = path.join(testDirectory, 'only-file.txt'); + fs.writeFileSync(filePath, 'hello'); + + const watcher = fs.watch(filePath, { recursive: true }); + let watcherClosed = false; + let interval; + watcher.on('change', function(event, filename) { + assert.strictEqual(event, 'change'); + + if (filename === path.basename(filePath)) { + clearInterval(interval); + interval = null; + watcher.close(); + watcherClosed = true; + } + }); + + interval = setInterval(() => { + fs.writeFileSync(filePath, 'world'); + }, common.platformTimeout(10)); + + process.on('exit', function() { + assert(watcherClosed, 'watcher Object was not closed'); + assert.strictEqual(interval, null); + }); +})().then(common.mustCall()); diff --git a/test/parallel/test-fs-watch-recursive.js b/test/parallel/test-fs-watch-recursive.js deleted file mode 100644 index 70b413814e78f4..00000000000000 --- a/test/parallel/test-fs-watch-recursive.js +++ /dev/null @@ -1,54 +0,0 @@ -'use strict'; - -const common = require('../common'); - - -const assert = require('assert'); -const path = require('path'); -const fs = require('fs'); - -const tmpdir = require('../common/tmpdir'); - -const testDir = tmpdir.path; -const filenameOne = 'watch.txt'; - -tmpdir.refresh(); - -const testsubdir = fs.mkdtempSync(testDir + path.sep); -const relativePathOne = path.join(path.basename(testsubdir), filenameOne); -const filepathOne = path.join(testsubdir, filenameOne); - -if (!common.isOSX && !common.isWindows) { - assert.throws(() => { fs.watch(testDir, { recursive: true }); }, - { code: 'ERR_FEATURE_UNAVAILABLE_ON_PLATFORM' }); - return; -} -const watcher = fs.watch(testDir, { recursive: true }); - -let watcherClosed = false; -watcher.on('change', function(event, filename) { - assert.ok(event === 'change' || event === 'rename'); - - // Ignore stale events generated by mkdir and other tests - if (filename !== relativePathOne) - return; - - if (common.isOSX) { - clearInterval(interval); - } - watcher.close(); - watcherClosed = true; -}); - -let interval; -if (common.isOSX) { - interval = setInterval(function() { - fs.writeFileSync(filepathOne, 'world'); - }, 10); -} else { - fs.writeFileSync(filepathOne, 'world'); -} - -process.on('exit', function() { - assert(watcherClosed, 'watcher Object was not closed'); -});