Skip to content

Commit 7f0a475

Browse files
committed
Add change and delete of file as well for fsEvents with dir watcher
1 parent 187681a commit 7f0a475

File tree

1 file changed

+159
-55
lines changed

1 file changed

+159
-55
lines changed

src/testRunner/unittests/sys/symlinkWatching.ts

Lines changed: 159 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
import * as ts from "../../_namespaces/ts";
77
import {
88
defer,
9+
Deferred,
910
} from "../../_namespaces/Utils";
1011
import {
1112
createWatchedSystem,
@@ -31,38 +32,39 @@ describe("unittests:: sys:: symlinkWatching::", () => {
3132
it(scenario, async () => {
3233
const fileResult = watchFile(file);
3334
const linkResult = watchFile(link);
34-
delayedOp(() => sys.writeFile(getFileName?.(file) ?? file, "export const x = 100;"));
3535

36-
// Should invoke on file as well as link
37-
await fileResult.deferred[0].promise;
38-
await linkResult.deferred[0].promise;
39-
40-
delayedOp(() => sys.writeFile(getFileName?.(link) ?? link, "export const x = 100;"));
41-
// Should invoke on file as well as link
42-
await fileResult.deferred[1].promise;
43-
await linkResult.deferred[1].promise;
36+
await writeFile(file);
37+
await writeFile(link);
4438

4539
fileResult.watcher.close();
4640
linkResult.watcher.close();
4741

4842
function watchFile(toWatch: string) {
49-
const deferred = [defer(), defer()];
50-
let indexForDefer = 0;
51-
return {
43+
const result = {
5244
watcher: sys.watchFile!(
5345
toWatch,
5446
(fileName, eventKind, modifiedTime) => {
5547
assert.equal(fileName, toWatch);
5648
assert.equal(eventKind, ts.FileWatcherEventKind.Changed);
5749
const actual = modifiedTimeToString(modifiedTime);
5850
assert(actual === undefined || actual === modifiedTimeToString(sys.getModifiedTime!(file)));
59-
deferred[indexForDefer++].resolve();
51+
result.deferred.resolve();
6052
},
6153
10,
6254
watchOptions,
6355
),
64-
deferred,
56+
deferred: undefined! as Deferred<void>,
6557
};
58+
return result;
59+
}
60+
61+
async function writeFile(onFile: string) {
62+
fileResult.deferred = defer();
63+
linkResult.deferred = defer();
64+
delayedOp(() => sys.writeFile(getFileName?.(onFile) ?? onFile, "export const x = 100;"));
65+
// Should invoke on file as well as link
66+
await fileResult.deferred.promise;
67+
await linkResult.deferred.promise;
6668
}
6769
});
6870
}
@@ -73,52 +75,140 @@ describe("unittests:: sys:: symlinkWatching::", () => {
7375
link: string,
7476
fsWatch: (dir: string, cb: ts.FsWatchCallback, sys: System) => ts.FileWatcher,
7577
isMacOs: boolean,
78+
isWindows: boolean,
7679
) {
7780
it(`watchDirectory using fsEvents`, async () => {
78-
const expectedEvent = ["rename", "change", "rename", "change"];
79-
const expectedFileName = ["file1.ts", "file1.ts", "file2.ts", "file2.ts"];
80-
const fileResult = watchDirectory(dir);
81-
const linkResult = watchDirectory(link);
82-
delayedOp(() => sys.writeFile(`${dir}/file1.ts`, "export const x = 100;"));
83-
84-
// Should invoke on file as well as link, rename and change
85-
await fileResult.deferred[0].promise;
86-
await linkResult.deferred[0].promise;
87-
if (!isMacOs) {
88-
// MacOs does not get change events when new file is created
89-
await fileResult.deferred[1].promise;
90-
await linkResult.deferred[1].promise;
81+
interface Expected {
82+
indexForDefer: number;
83+
deferred: readonly Deferred<void>[];
84+
expectedFileName: string;
85+
expectedEvent: string[];
9186
}
92-
93-
delayedOp(() => sys.writeFile(`${link}/file2.ts`, "export const x = 100;"));
94-
// // Should invoke on file as well as link, rename and change
95-
await fileResult.deferred[2].promise;
96-
await linkResult.deferred[2].promise;
97-
if (!isMacOs) {
98-
// MacOs does not get change events when new file is created
99-
await fileResult.deferred[3].promise;
100-
await linkResult.deferred[3].promise;
87+
type ExpectedForOperation = Pick<Expected, "expectedEvent" | "expectedFileName">;
88+
interface TableOfEvents {
89+
fileCreate: ExpectedForOperation;
90+
linkFileCreate: ExpectedForOperation;
91+
fileChange: ExpectedForOperation;
92+
fileModifiedTimeChange: ExpectedForOperation;
93+
linkModifiedTimeChange: ExpectedForOperation;
94+
linkFileChange: ExpectedForOperation;
95+
fileDelete: ExpectedForOperation;
96+
linkFileDelete: ExpectedForOperation;
10197
}
102-
fileResult.watcher.close();
98+
const tableOfEvents: TableOfEvents = isMacOs ?
99+
{
100+
fileCreate: { expectedEvent: ["rename"], expectedFileName: "file1.ts" },
101+
linkFileCreate: { expectedEvent: ["rename"], expectedFileName: "file2.ts" },
102+
fileChange: { expectedEvent: ["rename"], expectedFileName: "file1.ts" },
103+
linkFileChange: { expectedEvent: ["rename"], expectedFileName: "file2.ts" },
104+
fileModifiedTimeChange: { expectedEvent: ["rename"], expectedFileName: "file1.ts" },
105+
linkModifiedTimeChange: { expectedEvent: ["rename"], expectedFileName: "file2.ts" },
106+
fileDelete: { expectedEvent: ["rename"], expectedFileName: "file1.ts" },
107+
linkFileDelete: { expectedEvent: ["rename"], expectedFileName: "file2.ts" },
108+
} :
109+
isWindows ?
110+
{
111+
fileCreate: { expectedEvent: ["rename", "change"], expectedFileName: "file1.ts" },
112+
linkFileCreate: { expectedEvent: ["rename", "change"], expectedFileName: "file2.ts" },
113+
fileChange: { expectedEvent: ["change", "change"], expectedFileName: "file1.ts" },
114+
linkFileChange: { expectedEvent: ["change", "change"], expectedFileName: "file2.ts" },
115+
fileModifiedTimeChange: { expectedEvent: ["change"], expectedFileName: "file1.ts" },
116+
linkModifiedTimeChange: { expectedEvent: ["change"], expectedFileName: "file2.ts" },
117+
fileDelete: { expectedEvent: ["rename"], expectedFileName: "file1.ts" },
118+
linkFileDelete: { expectedEvent: ["rename"], expectedFileName: "file2.ts" },
119+
} :
120+
{
121+
fileCreate: { expectedEvent: ["rename", "change"], expectedFileName: "file1.ts" },
122+
linkFileCreate: { expectedEvent: ["rename", "change"], expectedFileName: "file2.ts" },
123+
fileChange: { expectedEvent: ["change"], expectedFileName: "file1.ts" },
124+
linkFileChange: { expectedEvent: ["change"], expectedFileName: "file2.ts" },
125+
fileModifiedTimeChange: { expectedEvent: ["change"], expectedFileName: "file1.ts" },
126+
linkModifiedTimeChange: { expectedEvent: ["change"], expectedFileName: "file2.ts" },
127+
fileDelete: { expectedEvent: ["rename"], expectedFileName: "file1.ts" },
128+
linkFileDelete: { expectedEvent: ["rename"], expectedFileName: "file2.ts" },
129+
};
130+
const dirResult = watchDirectory(dir);
131+
const linkResult = watchDirectory(link);
132+
133+
await operation("fileCreate");
134+
await operation("linkFileCreate");
135+
136+
await operation("fileChange");
137+
await operation("linkFileChange");
138+
139+
await operation("fileModifiedTimeChange");
140+
await operation("linkModifiedTimeChange");
141+
142+
await operation("fileDelete");
143+
await operation("linkFileDelete");
144+
145+
dirResult.watcher.close();
103146
linkResult.watcher.close();
104147

105148
function watchDirectory(dir: string) {
106-
const deferred = [defer(), defer(), defer(), defer()];
107-
let indexForDefer = 0;
108-
return {
149+
const result = {
109150
dir,
110151
watcher: fsWatch(
111152
dir,
112153
(event, fileName) => {
113-
assert.equal(event, expectedEvent[indexForDefer]);
114-
assert(!fileName || fileName === expectedFileName[indexForDefer]);
115-
deferred[indexForDefer++].resolve();
116-
if (isMacOs) indexForDefer++; // MacOs does not get change events when new file is created so skip that one
154+
console.log(dir, result.expected.indexForDefer, event, fileName); // To ensure we can get the data on all OS
155+
assert.equal(event, result.expected.expectedEvent[result.expected.indexForDefer]);
156+
assert.equal(fileName, result.expected.expectedFileName);
157+
result.expected.deferred[result.expected.indexForDefer++].resolve();
117158
},
118159
sys,
119160
),
120-
deferred,
161+
expected: undefined! as Expected,
121162
};
163+
return result;
164+
}
165+
166+
async function operation(opType: keyof TableOfEvents) {
167+
const expected = tableOfEvents[opType];
168+
console.log("");
169+
console.log(opType);
170+
dirResult.expected = {
171+
indexForDefer: 0,
172+
deferred: ts.arrayOf(expected.expectedEvent.length, defer),
173+
...expected,
174+
};
175+
linkResult.expected = {
176+
indexForDefer: 0,
177+
deferred: ts.arrayOf(expected.expectedEvent.length, defer),
178+
...expected,
179+
};
180+
let op;
181+
switch (opType) {
182+
case "fileCreate":
183+
op = () => sys.writeFile(`${dir}/file1.ts`, "export const x = 100;");
184+
break;
185+
case "linkFileCreate":
186+
op = () => sys.writeFile(`${link}/file2.ts`, "export const x = 100;");
187+
break;
188+
case "fileChange":
189+
op = () => sys.writeFile(`${dir}/file1.ts`, "export const x2 = 100;");
190+
break;
191+
case "linkFileChange":
192+
op = () => sys.writeFile(`${link}/file2.ts`, "export const x2 = 100;");
193+
break;
194+
case "fileModifiedTimeChange":
195+
op = () => sys.setModifiedTime!(`${dir}/file1.ts`, new Date());
196+
break;
197+
case "linkModifiedTimeChange":
198+
op = () => sys.setModifiedTime!(`${link}/file2.ts`, new Date());
199+
break;
200+
case "fileDelete":
201+
op = () => sys.deleteFile!(`${dir}/file1.ts`);
202+
break;
203+
case "linkFileDelete":
204+
op = () => sys.deleteFile!(`${link}/file2.ts`);
205+
break;
206+
default:
207+
ts.Debug.assertNever(opType);
208+
}
209+
delayedOp(op);
210+
await Promise.all(dirResult.expected.deferred.map(d => d.promise));
211+
await Promise.all(linkResult.expected.deferred.map(d => d.promise));
122212
}
123213
});
124214
}
@@ -129,6 +219,8 @@ describe("unittests:: sys:: symlinkWatching::", () => {
129219

130220
describe("with ts.sys::", () => {
131221
const root = ts.normalizePath(IO.joinPath(IO.getWorkspaceRoot(), "tests/baselines/symlinks"));
222+
const isMacOs = process.platform === "darwin";
223+
const isWindows = process.platform === "win32";
132224
before(() => {
133225
cleanup();
134226
ts.sys.writeFile(`${root}/polling/file.ts`, "export const x = 10;");
@@ -184,7 +276,8 @@ describe("unittests:: sys:: symlinkWatching::", () => {
184276
`${root}/dirfsevents`,
185277
`${root}/linkeddirfsevents`,
186278
(dir, cb) => fs.watch(dir, { persistent: true }, cb),
187-
process.platform === "darwin",
279+
isMacOs,
280+
isWindows,
188281
);
189282
});
190283

@@ -220,21 +313,32 @@ describe("unittests:: sys:: symlinkWatching::", () => {
220313
getFileName(),
221314
);
222315

223-
verifyWatchDirectoryUsingFsEvents(
224-
getSys(),
225-
`${root}/folder`,
226-
`${root}/linked`,
227-
(dir, cb, sys) => sys.fsWatchWorker(dir, /*recursive*/ false, cb),
228-
/*isMacOs*/ false,
229-
);
316+
// TODO (sheetal) add test for each os behaviour
317+
// verifyWatchDirectoryUsingFsEvents(
318+
// getSys(),
319+
// `${root}/folder`,
320+
// `${root}/linked`,
321+
// (dir, cb, sys) => sys.fsWatchWorker(dir, /*recursive*/ false, cb),
322+
// /*isMacOs*/ false,
323+
// /*isWindows*/ true,
324+
// );
325+
326+
// verifyWatchDirectoryUsingFsEvents(
327+
// getSys(),
328+
// `${root}/folder`,
329+
// `${root}/linked`,
330+
// (dir, cb, sys) => sys.fsWatchWorker(dir, /*recursive*/ false, cb),
331+
// /*isMacOs*/ true,
332+
// /*isWindows*/ false,
333+
// );
230334

231-
// TODO (sheetal) add test for mac os behaviour so we have it on host to verify
232335
// verifyWatchDirectoryUsingFsEvents(
233336
// getSys(),
234337
// `${root}/folder`,
235338
// `${root}/linked`,
236339
// (dir, cb, sys) => sys.fsWatchWorker(dir, /*recursive*/ false, cb),
237-
// /*isMacOs*/ true
340+
// /*isMacOs*/ false,
341+
// /*isWindows*/ false,
238342
// );
239343
});
240344
});

0 commit comments

Comments
 (0)