Skip to content

Commit 97b679e

Browse files
committed
Adjust tests to show link creation races on windows, fix watcher.
1 parent 9053fae commit 97b679e

File tree

3 files changed

+50
-5
lines changed

3 files changed

+50
-5
lines changed

pkgs/watcher/lib/src/directory_watcher/windows.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,27 @@ class _WindowsDirectoryWatcher
261261
Map<String, Set<Event>> _sortEvents(List<Event> batch) {
262262
var eventsForPaths = <String, Set<Event>>{};
263263

264+
// On Windows new links to directories are sometimes reported by
265+
// Directory.watch as directories. On all other platforms it reports them
266+
// consistently as files. See https://github.com/dart-lang/sdk/issues/61797.
267+
//
268+
// The wrong type is because Windows creates links to directories as actual
269+
// directories, then converts them to links. Directory.watch sometimes
270+
// checks the type too early and gets the wrong result.
271+
//
272+
// The batch delay is plenty for the link to be fully created, so verify the
273+
// file system entity type for all createDirectory` events, converting to
274+
// `createFile` when needed.
275+
for (var i = 0; i != batch.length; ++i) {
276+
final event = batch[i];
277+
if (event.type == EventType.createDirectory) {
278+
if (FileSystemEntity.typeSync(event.path, followLinks: false) ==
279+
FileSystemEntityType.link) {
280+
batch[i] = Event.createFile(event.path);
281+
}
282+
}
283+
}
284+
264285
// Events within directories that already have create events are not needed
265286
// as the directory's full content will be listed.
266287
var createdDirectories = unionAll(batch.map((event) {

pkgs/watcher/test/directory_watcher/link_tests.dart

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ void _linkTests({required bool isNative}) {
2121
writeFile('targets/a.target');
2222
await startWatcher(path: 'links');
2323

24-
writeLink(link: 'links/a.link', target: 'targets/a.target');
24+
writeLink(
25+
link: 'links/a.link', target: 'targets/a.target', unawaitedAsync: true);
2526

2627
await expectAddEvent('links/a.link');
2728
});
@@ -109,7 +110,10 @@ void _linkTests({required bool isNative}) {
109110
createDir('targets/a.targetdir');
110111
await startWatcher(path: 'links');
111112

112-
writeLink(link: 'links/a.link', target: 'targets/a.targetdir');
113+
writeLink(
114+
link: 'links/a.link',
115+
target: 'targets/a.targetdir',
116+
unawaitedAsync: true);
113117

114118
// TODO(davidmorgan): reconcile differences.
115119
if (isNative) {
@@ -128,7 +132,10 @@ void _linkTests({required bool isNative}) {
128132
writeFile('targets/a.targetdir/a.target');
129133
await startWatcher(path: 'links');
130134

131-
writeLink(link: 'links/a.link', target: 'targets/a.targetdir');
135+
writeLink(
136+
link: 'links/a.link',
137+
target: 'targets/a.targetdir',
138+
unawaitedAsync: true);
132139

133140
// TODO(davidmorgan): reconcile differences.
134141
if (isNative) {

pkgs/watcher/test/utils.dart

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import 'package:test_descriptor/test_descriptor.dart' as d;
1212
import 'package:watcher/watcher.dart';
1313

1414
/// Edit this to run fast-running tests many times.
15-
int runsPerTest = 1;
15+
/// DO NOT SUBMIT
16+
int runsPerTest = 5;
1617

1718
typedef WatcherFactory = Watcher Function(String directory);
1819

@@ -239,9 +240,21 @@ void writeFile(String path, {String? contents}) {
239240
/// Writes a file in the sandbox at [link] pointing to [target].
240241
///
241242
/// [target] is relative to the sandbox, not to [link].
243+
///
244+
/// If [unawaitedAsync], the link is written asynchronously and not awaited.
245+
/// Otherwise, it's synchronous.
246+
///
247+
/// Async creation of links Is needed to fully test links on Windows because
248+
/// creation of links to directories on Windows is not atomic. First a directory
249+
/// is created, then it is converted into a link. Directory.watch checks the
250+
/// filesystem entity type to decide what to report, and this races with the
251+
/// second step. As a result it sometimes reports a directory creation and
252+
/// sometimes reports a file creation. See
253+
/// https://github.com/dart-lang/sdk/issues/61797.
242254
void writeLink({
243255
required String link,
244256
required String target,
257+
bool unawaitedAsync = false,
245258
}) {
246259
var fullPath = p.join(d.sandbox, link);
247260

@@ -251,7 +264,11 @@ void writeLink({
251264
dir.createSync(recursive: true);
252265
}
253266

254-
Link(fullPath).createSync(p.join(d.sandbox, target));
267+
if (unawaitedAsync) {
268+
unawaited(Link(fullPath).create(p.join(d.sandbox, target)));
269+
} else {
270+
Link(fullPath).createSync(p.join(d.sandbox, target));
271+
}
255272
}
256273

257274
/// Deletes a file in the sandbox at [path].

0 commit comments

Comments
 (0)