From e7e813542ac5bac320995a77e7ea828d9f583d34 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Wed, 17 Jul 2024 16:51:44 -0400 Subject: [PATCH] Work around inconsistent recursive directory watch events (#59328) --- .../unittests/sys/symlinkWatching.ts | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/testRunner/unittests/sys/symlinkWatching.ts b/src/testRunner/unittests/sys/symlinkWatching.ts index f4bf768d046..353d778d617 100644 --- a/src/testRunner/unittests/sys/symlinkWatching.ts +++ b/src/testRunner/unittests/sys/symlinkWatching.ts @@ -89,6 +89,7 @@ describe("unittests:: sys:: symlinkWatching::", () => { event: "rename" | "change" | readonly ["rename", "change"]; // Its expected event name or any of the event names // eslint-disable-next-line no-restricted-syntax fileName: string | null | undefined; + optional?: boolean; // This event is optional and may or may not be triggered on a given OS (see https://github.com/nodejs/node/issues/53903) } type FsWatch = (dir: string, recursive: boolean, cb: ts.FsWatchCallback, sys: System) => ts.FileWatcher; interface WatchDirectoryResult { @@ -156,18 +157,39 @@ describe("unittests:: sys:: symlinkWatching::", () => { actual: readonly EventAndFileName[], expected: readonly ExpectedEventAndFileName[] | undefined, ) { - assert(actual.length >= (expected?.length ?? 0), `${prefix}:: Expected ${JSON.stringify(expected)} events, got ${JSON.stringify(actual)}`); + const maxExpected = expected?.length ?? 0; + const minExpected = expected?.reduce((m, e) => e.optional ? m : m + 1, 0) ?? maxExpected; const sortedActual = ts.sortAndDeduplicate(actual, compareEventAndFileName); + assert(sortedActual.length >= minExpected && sortedActual.length <= maxExpected, `${prefix}:: Expected ${JSON.stringify(expected)} events, got ${JSON.stringify(actual)}`); + let actualIndex = 0; let expectedIndex = 0; - for (const a of sortedActual) { - if (isExpectedEventAndFileName(a, expected![expectedIndex])) { + while (actualIndex < sortedActual.length && expectedIndex < maxExpected) { + const a = sortedActual[actualIndex]; + const e = expected![expectedIndex]; + if (isExpectedEventAndFileName(a, e)) { + actualIndex++; expectedIndex++; continue; } + if (e.optional) { + expectedIndex++; + continue; + } + break; + } + if (actualIndex < sortedActual.length) { ts.Debug.fail(`${prefix}:: Expected ${JSON.stringify(expected)} events, got ${JSON.stringify(actual)} Sorted: ${JSON.stringify(sortedActual)}`); } - assert(expectedIndex >= (expected?.length ?? 0), `${prefix}:: Should get all events: Expected ${JSON.stringify(expected)} events, got ${JSON.stringify(actual)} Sorted: ${JSON.stringify(sortedActual)}`); + while (expectedIndex < maxExpected) { + const e = expected![expectedIndex]; + if (e.optional) { + expectedIndex++; + continue; + } + break; + } + assert(expectedIndex >= maxExpected, `${prefix}:: Should get all events: Expected ${JSON.stringify(expected)} events, got ${JSON.stringify(actual)} Sorted: ${JSON.stringify(sortedActual)}`); } function isExpectedEventAndFileName(actual: EventAndFileName, expected: ExpectedEventAndFileName | undefined) { @@ -444,6 +466,7 @@ describe("unittests:: sys:: symlinkWatching::", () => { ], linkFileDelete: [ { event: "rename", fileName: "sub/folder/file2.ts" }, + { event: "change", fileName: "sub/folder", optional: osFlavor === TestServerHostOsFlavor.Windows }, ], linkSubFileCreate: [