This repository has been archived by the owner on Mar 3, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 17.4k
/
path-watcher-spec.js
179 lines (141 loc) · 5.89 KB
/
path-watcher-spec.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/** @babel */
import temp from 'temp';
import fs from 'fs-plus';
import path from 'path';
import { promisify } from 'util';
import { CompositeDisposable } from 'event-kit';
import { watchPath, stopAllWatchers } from '../src/path-watcher';
temp.track();
const writeFile = promisify(fs.writeFile);
const mkdir = promisify(fs.mkdir);
const appendFile = promisify(fs.appendFile);
const realpath = promisify(fs.realpath);
const tempMkdir = promisify(temp.mkdir);
describe('watchPath', function() {
let subs;
beforeEach(function() {
subs = new CompositeDisposable();
});
afterEach(async function() {
subs.dispose();
await stopAllWatchers();
});
function waitForChanges(watcher, ...fileNames) {
const waiting = new Set(fileNames);
let fired = false;
const relevantEvents = [];
return new Promise(resolve => {
const sub = watcher.onDidChange(events => {
for (const event of events) {
if (waiting.delete(event.path)) {
relevantEvents.push(event);
}
}
if (!fired && waiting.size === 0) {
fired = true;
resolve(relevantEvents);
sub.dispose();
}
});
});
}
describe('watchPath()', function() {
it('resolves the returned promise when the watcher begins listening', async function() {
const rootDir = await tempMkdir('atom-fsmanager-test-');
const watcher = await watchPath(rootDir, {}, () => {});
expect(watcher.constructor.name).toBe('PathWatcher');
});
it('reuses an existing native watcher and resolves getStartPromise immediately if attached to a running watcher', async function() {
const rootDir = await tempMkdir('atom-fsmanager-test-');
const watcher0 = await watchPath(rootDir, {}, () => {});
const watcher1 = await watchPath(rootDir, {}, () => {});
expect(watcher0.native).toBe(watcher1.native);
});
it("reuses existing native watchers even while they're still starting", async function() {
const rootDir = await tempMkdir('atom-fsmanager-test-');
const [watcher0, watcher1] = await Promise.all([
watchPath(rootDir, {}, () => {}),
watchPath(rootDir, {}, () => {})
]);
expect(watcher0.native).toBe(watcher1.native);
});
it("doesn't attach new watchers to a native watcher that's stopping", async function() {
const rootDir = await tempMkdir('atom-fsmanager-test-');
const watcher0 = await watchPath(rootDir, {}, () => {});
const native0 = watcher0.native;
watcher0.dispose();
const watcher1 = await watchPath(rootDir, {}, () => {});
expect(watcher1.native).not.toBe(native0);
});
for (let i = 0; i < 10000; i++) {
fit(`reuses an existing native watcher on a parent directory and filters events (#${i})`, async function() {
const rootDir = await tempMkdir('atom-fsmanager-test-').then(realpath);
const rootFile = path.join(rootDir, 'rootfile.txt');
const subDir = path.join(rootDir, 'subdir');
const subFile = path.join(subDir, 'subfile.txt');
await mkdir(subDir);
// Keep the watchers alive with an undisposed subscription
const rootWatcher = await watchPath(rootDir, {}, () => {});
const childWatcher = await watchPath(subDir, {}, () => {});
expect(rootWatcher.native).toBe(childWatcher.native);
expect(rootWatcher.native.isRunning()).toBe(true);
const firstChanges = Promise.all([
waitForChanges(rootWatcher, subFile),
waitForChanges(childWatcher, subFile)
]);
await writeFile(subFile, 'subfile\n', { encoding: 'utf8' });
await firstChanges;
const nextRootEvent = waitForChanges(rootWatcher, rootFile);
await writeFile(rootFile, 'rootfile\n', { encoding: 'utf8' });
await nextRootEvent;
});
}
for (let i = 0; i < 10000; i++) {
fit(`adopts existing child watchers and filters events appropriately to them (#${i})`, async function() {
const parentDir = await tempMkdir('atom-fsmanager-test-').then(
realpath
);
// Create the directory tree
const rootFile = path.join(parentDir, 'rootfile.txt');
const subDir0 = path.join(parentDir, 'subdir0');
const subFile0 = path.join(subDir0, 'subfile0.txt');
const subDir1 = path.join(parentDir, 'subdir1');
const subFile1 = path.join(subDir1, 'subfile1.txt');
await mkdir(subDir0);
await mkdir(subDir1);
await Promise.all([
writeFile(rootFile, 'rootfile\n', { encoding: 'utf8' }),
writeFile(subFile0, 'subfile 0\n', { encoding: 'utf8' }),
writeFile(subFile1, 'subfile 1\n', { encoding: 'utf8' })
]);
// Begin the child watchers and keep them alive
const subWatcher0 = await watchPath(subDir0, {}, () => {});
const subWatcherChanges0 = waitForChanges(subWatcher0, subFile0);
const subWatcher1 = await watchPath(subDir1, {}, () => {});
const subWatcherChanges1 = waitForChanges(subWatcher1, subFile1);
expect(subWatcher0.native).not.toBe(subWatcher1.native);
// Create the parent watcher
const parentWatcher = await watchPath(parentDir, {}, () => {});
const parentWatcherChanges = waitForChanges(
parentWatcher,
rootFile,
subFile0,
subFile1
);
expect(subWatcher0.native).toBe(parentWatcher.native);
expect(subWatcher1.native).toBe(parentWatcher.native);
// Ensure events are filtered correctly
await Promise.all([
appendFile(rootFile, 'change\n', { encoding: 'utf8' }),
appendFile(subFile0, 'change\n', { encoding: 'utf8' }),
appendFile(subFile1, 'change\n', { encoding: 'utf8' })
]);
await Promise.all([
subWatcherChanges0,
subWatcherChanges1,
parentWatcherChanges
]);
});
}
});
});