Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fa68ecf

Browse files
authored
Fix the race condition in cache_test.dart (#99423)
This fixes a race condition in test/integration.shard/cache_test.dart which allowed the test to fail if the machine took a very long time to acquire a lock or launch a process.
1 parent 4919b74 commit fa68ecf

File tree

1 file changed

+39
-10
lines changed

1 file changed

+39
-10
lines changed

packages/flutter_tools/test/integration.shard/cache_test.dart

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ void main() {
3939
outputPreferences: OutputPreferences(),
4040
);
4141
logger.fatalWarnings = true;
42+
Process process;
4243
try {
4344
Cache.flutterRoot = tempDir.absolute.path;
4445
final Cache cache = Cache.test(
@@ -56,20 +57,48 @@ import 'dart:async';
5657
import 'dart:io';
5758
5859
Future<void> main(List<String> args) async {
59-
File file = File(args[0]);
60-
RandomAccessFile lock = file.openSync(mode: FileMode.write);
61-
lock.lockSync();
62-
await Future<void>.delayed(const Duration(milliseconds: 1000));
63-
exit(0);
60+
File file = File(args[0]);
61+
final RandomAccessFile lock = file.openSync(mode: FileMode.write);
62+
while (true) {
63+
try {
64+
lock.lockSync();
65+
break;
66+
} on FileSystemException {}
67+
}
68+
await Future<void>.delayed(const Duration(seconds: 1));
69+
exit(0);
6470
}
6571
''');
66-
final Process process = await const LocalProcessManager().start(
72+
// Locks are per-process, so we have to launch a separate process to
73+
// test out cache locking.
74+
process = await const LocalProcessManager().start(
6775
<String>[dart, script.absolute.path, cacheFile.absolute.path],
6876
);
69-
await Future<void>.delayed(const Duration(milliseconds: 500));
77+
// Wait for the script to lock the test cache file before checking to
78+
// see that the cache is unable to.
79+
bool locked = false;
80+
while (!locked) {
81+
// Give the script a chance to try for the lock much more often.
82+
await Future<void>.delayed(const Duration(milliseconds: 100));
83+
final RandomAccessFile lock = cacheFile.openSync(mode: FileMode.write);
84+
try {
85+
// If we can lock it, unlock immediately to give the script a
86+
// chance.
87+
lock.lockSync();
88+
lock.unlockSync();
89+
} on FileSystemException {
90+
// If we can't lock it, then the child script succeeded in locking
91+
// it, and we can now test.
92+
locked = true;
93+
break;
94+
}
95+
}
96+
// Finally, test that the cache cannot lock a locked file. This should
97+
// print a message if it can't lock the file.
7098
await cache.lock();
71-
process.kill(io.ProcessSignal.sigkill);
7299
} finally {
100+
// Just to keep from leaving the process hanging around.
101+
process?.kill(io.ProcessSignal.sighup);
73102
tryToDelete(tempDir);
74103
Cache.flutterRoot = oldRoot;
75104
}
@@ -78,8 +107,8 @@ exit(0);
78107
expect(logger.warningText,
79108
equals('Waiting for another flutter command to release the startup lock...\n'));
80109
expect(logger.hadErrorOutput, isFalse);
81-
// Should still be false, since the particular "Waiting..." message above aims to
82-
// avoid triggering failure as a fatal warning.
110+
// Should still be false, since the particular "Waiting..." message above
111+
// aims to avoid triggering failure as a fatal warning.
83112
expect(logger.hadWarningOutput, isFalse);
84113
});
85114
testWithoutContext(

0 commit comments

Comments
 (0)