Skip to content

Commit

Permalink
Add change and delete of file as well for fsEvents with dir watcher
Browse files Browse the repository at this point in the history
  • Loading branch information
sheetalkamat committed Mar 14, 2024
1 parent 187681a commit 7f0a475
Showing 1 changed file with 159 additions and 55 deletions.
214 changes: 159 additions & 55 deletions src/testRunner/unittests/sys/symlinkWatching.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
import * as ts from "../../_namespaces/ts";
import {
defer,
Deferred,
} from "../../_namespaces/Utils";
import {
createWatchedSystem,
Expand All @@ -31,38 +32,39 @@ describe("unittests:: sys:: symlinkWatching::", () => {
it(scenario, async () => {
const fileResult = watchFile(file);
const linkResult = watchFile(link);
delayedOp(() => sys.writeFile(getFileName?.(file) ?? file, "export const x = 100;"));

// Should invoke on file as well as link
await fileResult.deferred[0].promise;
await linkResult.deferred[0].promise;

delayedOp(() => sys.writeFile(getFileName?.(link) ?? link, "export const x = 100;"));
// Should invoke on file as well as link
await fileResult.deferred[1].promise;
await linkResult.deferred[1].promise;
await writeFile(file);
await writeFile(link);

fileResult.watcher.close();
linkResult.watcher.close();

function watchFile(toWatch: string) {
const deferred = [defer(), defer()];
let indexForDefer = 0;
return {
const result = {
watcher: sys.watchFile!(
toWatch,
(fileName, eventKind, modifiedTime) => {
assert.equal(fileName, toWatch);
assert.equal(eventKind, ts.FileWatcherEventKind.Changed);
const actual = modifiedTimeToString(modifiedTime);
assert(actual === undefined || actual === modifiedTimeToString(sys.getModifiedTime!(file)));
deferred[indexForDefer++].resolve();
result.deferred.resolve();
},
10,
watchOptions,
),
deferred,
deferred: undefined! as Deferred<void>,
};
return result;
}

async function writeFile(onFile: string) {
fileResult.deferred = defer();
linkResult.deferred = defer();
delayedOp(() => sys.writeFile(getFileName?.(onFile) ?? onFile, "export const x = 100;"));
// Should invoke on file as well as link
await fileResult.deferred.promise;
await linkResult.deferred.promise;
}
});
}
Expand All @@ -73,52 +75,140 @@ describe("unittests:: sys:: symlinkWatching::", () => {
link: string,
fsWatch: (dir: string, cb: ts.FsWatchCallback, sys: System) => ts.FileWatcher,
isMacOs: boolean,
isWindows: boolean,
) {
it(`watchDirectory using fsEvents`, async () => {
const expectedEvent = ["rename", "change", "rename", "change"];
const expectedFileName = ["file1.ts", "file1.ts", "file2.ts", "file2.ts"];
const fileResult = watchDirectory(dir);
const linkResult = watchDirectory(link);
delayedOp(() => sys.writeFile(`${dir}/file1.ts`, "export const x = 100;"));

// Should invoke on file as well as link, rename and change
await fileResult.deferred[0].promise;
await linkResult.deferred[0].promise;
if (!isMacOs) {
// MacOs does not get change events when new file is created
await fileResult.deferred[1].promise;
await linkResult.deferred[1].promise;
interface Expected {
indexForDefer: number;
deferred: readonly Deferred<void>[];
expectedFileName: string;
expectedEvent: string[];
}

delayedOp(() => sys.writeFile(`${link}/file2.ts`, "export const x = 100;"));
// // Should invoke on file as well as link, rename and change
await fileResult.deferred[2].promise;
await linkResult.deferred[2].promise;
if (!isMacOs) {
// MacOs does not get change events when new file is created
await fileResult.deferred[3].promise;
await linkResult.deferred[3].promise;
type ExpectedForOperation = Pick<Expected, "expectedEvent" | "expectedFileName">;
interface TableOfEvents {
fileCreate: ExpectedForOperation;
linkFileCreate: ExpectedForOperation;
fileChange: ExpectedForOperation;
fileModifiedTimeChange: ExpectedForOperation;
linkModifiedTimeChange: ExpectedForOperation;
linkFileChange: ExpectedForOperation;
fileDelete: ExpectedForOperation;
linkFileDelete: ExpectedForOperation;
}
fileResult.watcher.close();
const tableOfEvents: TableOfEvents = isMacOs ?
{
fileCreate: { expectedEvent: ["rename"], expectedFileName: "file1.ts" },
linkFileCreate: { expectedEvent: ["rename"], expectedFileName: "file2.ts" },
fileChange: { expectedEvent: ["rename"], expectedFileName: "file1.ts" },
linkFileChange: { expectedEvent: ["rename"], expectedFileName: "file2.ts" },
fileModifiedTimeChange: { expectedEvent: ["rename"], expectedFileName: "file1.ts" },
linkModifiedTimeChange: { expectedEvent: ["rename"], expectedFileName: "file2.ts" },
fileDelete: { expectedEvent: ["rename"], expectedFileName: "file1.ts" },
linkFileDelete: { expectedEvent: ["rename"], expectedFileName: "file2.ts" },
} :
isWindows ?
{
fileCreate: { expectedEvent: ["rename", "change"], expectedFileName: "file1.ts" },
linkFileCreate: { expectedEvent: ["rename", "change"], expectedFileName: "file2.ts" },
fileChange: { expectedEvent: ["change", "change"], expectedFileName: "file1.ts" },
linkFileChange: { expectedEvent: ["change", "change"], expectedFileName: "file2.ts" },
fileModifiedTimeChange: { expectedEvent: ["change"], expectedFileName: "file1.ts" },
linkModifiedTimeChange: { expectedEvent: ["change"], expectedFileName: "file2.ts" },
fileDelete: { expectedEvent: ["rename"], expectedFileName: "file1.ts" },
linkFileDelete: { expectedEvent: ["rename"], expectedFileName: "file2.ts" },
} :
{
fileCreate: { expectedEvent: ["rename", "change"], expectedFileName: "file1.ts" },
linkFileCreate: { expectedEvent: ["rename", "change"], expectedFileName: "file2.ts" },
fileChange: { expectedEvent: ["change"], expectedFileName: "file1.ts" },
linkFileChange: { expectedEvent: ["change"], expectedFileName: "file2.ts" },
fileModifiedTimeChange: { expectedEvent: ["change"], expectedFileName: "file1.ts" },
linkModifiedTimeChange: { expectedEvent: ["change"], expectedFileName: "file2.ts" },
fileDelete: { expectedEvent: ["rename"], expectedFileName: "file1.ts" },
linkFileDelete: { expectedEvent: ["rename"], expectedFileName: "file2.ts" },
};
const dirResult = watchDirectory(dir);
const linkResult = watchDirectory(link);

await operation("fileCreate");
await operation("linkFileCreate");

await operation("fileChange");
await operation("linkFileChange");

await operation("fileModifiedTimeChange");
await operation("linkModifiedTimeChange");

await operation("fileDelete");
await operation("linkFileDelete");

dirResult.watcher.close();
linkResult.watcher.close();

function watchDirectory(dir: string) {
const deferred = [defer(), defer(), defer(), defer()];
let indexForDefer = 0;
return {
const result = {
dir,
watcher: fsWatch(
dir,
(event, fileName) => {
assert.equal(event, expectedEvent[indexForDefer]);
assert(!fileName || fileName === expectedFileName[indexForDefer]);
deferred[indexForDefer++].resolve();
if (isMacOs) indexForDefer++; // MacOs does not get change events when new file is created so skip that one
console.log(dir, result.expected.indexForDefer, event, fileName); // To ensure we can get the data on all OS
assert.equal(event, result.expected.expectedEvent[result.expected.indexForDefer]);
assert.equal(fileName, result.expected.expectedFileName);
result.expected.deferred[result.expected.indexForDefer++].resolve();
},
sys,
),
deferred,
expected: undefined! as Expected,
};
return result;
}

async function operation(opType: keyof TableOfEvents) {
const expected = tableOfEvents[opType];
console.log("");
console.log(opType);
dirResult.expected = {
indexForDefer: 0,
deferred: ts.arrayOf(expected.expectedEvent.length, defer),
...expected,
};
linkResult.expected = {
indexForDefer: 0,
deferred: ts.arrayOf(expected.expectedEvent.length, defer),
...expected,
};
let op;
switch (opType) {
case "fileCreate":
op = () => sys.writeFile(`${dir}/file1.ts`, "export const x = 100;");
break;
case "linkFileCreate":
op = () => sys.writeFile(`${link}/file2.ts`, "export const x = 100;");
break;
case "fileChange":
op = () => sys.writeFile(`${dir}/file1.ts`, "export const x2 = 100;");
break;
case "linkFileChange":
op = () => sys.writeFile(`${link}/file2.ts`, "export const x2 = 100;");
break;
case "fileModifiedTimeChange":
op = () => sys.setModifiedTime!(`${dir}/file1.ts`, new Date());
break;
case "linkModifiedTimeChange":
op = () => sys.setModifiedTime!(`${link}/file2.ts`, new Date());
break;
case "fileDelete":
op = () => sys.deleteFile!(`${dir}/file1.ts`);
break;
case "linkFileDelete":
op = () => sys.deleteFile!(`${link}/file2.ts`);
break;
default:
ts.Debug.assertNever(opType);
}
delayedOp(op);
await Promise.all(dirResult.expected.deferred.map(d => d.promise));
await Promise.all(linkResult.expected.deferred.map(d => d.promise));
}
});
}
Expand All @@ -129,6 +219,8 @@ describe("unittests:: sys:: symlinkWatching::", () => {

describe("with ts.sys::", () => {
const root = ts.normalizePath(IO.joinPath(IO.getWorkspaceRoot(), "tests/baselines/symlinks"));
const isMacOs = process.platform === "darwin";
const isWindows = process.platform === "win32";
before(() => {
cleanup();
ts.sys.writeFile(`${root}/polling/file.ts`, "export const x = 10;");
Expand Down Expand Up @@ -184,7 +276,8 @@ describe("unittests:: sys:: symlinkWatching::", () => {
`${root}/dirfsevents`,
`${root}/linkeddirfsevents`,
(dir, cb) => fs.watch(dir, { persistent: true }, cb),
process.platform === "darwin",
isMacOs,
isWindows,
);
});

Expand Down Expand Up @@ -220,21 +313,32 @@ describe("unittests:: sys:: symlinkWatching::", () => {
getFileName(),
);

verifyWatchDirectoryUsingFsEvents(
getSys(),
`${root}/folder`,
`${root}/linked`,
(dir, cb, sys) => sys.fsWatchWorker(dir, /*recursive*/ false, cb),
/*isMacOs*/ false,
);
// TODO (sheetal) add test for each os behaviour
// verifyWatchDirectoryUsingFsEvents(
// getSys(),
// `${root}/folder`,
// `${root}/linked`,
// (dir, cb, sys) => sys.fsWatchWorker(dir, /*recursive*/ false, cb),
// /*isMacOs*/ false,
// /*isWindows*/ true,
// );

// verifyWatchDirectoryUsingFsEvents(
// getSys(),
// `${root}/folder`,
// `${root}/linked`,
// (dir, cb, sys) => sys.fsWatchWorker(dir, /*recursive*/ false, cb),
// /*isMacOs*/ true,
// /*isWindows*/ false,
// );

// TODO (sheetal) add test for mac os behaviour so we have it on host to verify
// verifyWatchDirectoryUsingFsEvents(
// getSys(),
// `${root}/folder`,
// `${root}/linked`,
// (dir, cb, sys) => sys.fsWatchWorker(dir, /*recursive*/ false, cb),
// /*isMacOs*/ true
// /*isMacOs*/ false,
// /*isWindows*/ false,
// );
});
});

0 comments on commit 7f0a475

Please sign in to comment.