From 9a8908153216fc825f01e327ac028242fb762fe8 Mon Sep 17 00:00:00 2001 From: Srujan Gaddam Date: Tue, 8 Jul 2025 17:25:06 -0700 Subject: [PATCH 1/7] Address flakes from using temp directory to run tests https://github.com/dart-lang/webdev/commit/2172ba7024d8885afc30f6634d98c00a003bb0cc added support to run tests in a temporary directory. This results in two flaky issues: 1. On Windows, build_daemon tests may fail to delete the temp directory because the process may have not been torn down yet, so it may still be accessing the file system. There was an initial retry after 1 second, but that appears to be not enough looking at a recent test run. 2. If a test times out, its tearDown may not be called. In this case, the ResidentWebRunner in frontend_server may not restore the current directory in the LocalFileSystem. This leads to cascading failures in subsequent tests due to no longer being in a path that contains 'webdev'. See https://github.com/dart-lang/webdev/actions/runs/15989286213/job/45099373212?pr=2641 for an example. See https://github.com/dart-lang/test/issues/897 as well for tracking work to call tearDown on timeouts. To address the above issues: 1. Increase the delay between the two tries and assert this only occurs on Windows. 2. Cache the current directory so that it can be used in utilities.dart with the same (correct) value every time. --- dwds/test/fixtures/project.dart | 5 +++-- test_common/lib/utilities.dart | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dwds/test/fixtures/project.dart b/dwds/test/fixtures/project.dart index 46bd9193b..9dc8e3def 100644 --- a/dwds/test/fixtures/project.dart +++ b/dwds/test/fixtures/project.dart @@ -240,9 +240,10 @@ class TestProject { try { _fixturesCopy.deleteSync(recursive: true); } on FileSystemException catch (_) { + assert(Platform.isWindows); // On Windows, the build daemon process might still be accessing the - // working directory, so wait a second and then try again. - await Future.delayed(const Duration(seconds: 1)); + // working directory, so wait a few seconds and then try again. + await Future.delayed(const Duration(seconds: 5)); _fixturesCopy.deleteSync(recursive: true); } } diff --git a/test_common/lib/utilities.dart b/test_common/lib/utilities.dart index d4d3619be..1a960a509 100644 --- a/test_common/lib/utilities.dart +++ b/test_common/lib/utilities.dart @@ -12,10 +12,12 @@ const fixturesDirName = 'fixtures'; const newDdcTypeSystemVersion = '3.3.0-242.0.dev'; +final _currentDirectory = p.current; + /// The path to the webdev directory in the local machine, e.g. /// '/workstation/webdev'. String get webdevPath { - final pathParts = p.split(p.current); + final pathParts = p.split(_currentDirectory); assert(pathParts.contains(webdevDirName)); return p.joinAll( pathParts.sublist(0, pathParts.lastIndexOf(webdevDirName) + 1), From 3bd14482062155a7544df1c28e3c341fcaa02347 Mon Sep 17 00:00:00 2001 From: Srujan Gaddam Date: Tue, 8 Jul 2025 17:37:01 -0700 Subject: [PATCH 2/7] Add artificial delay to test changes --- dwds/test/instances/common/patterns_inspection_common.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/dwds/test/instances/common/patterns_inspection_common.dart b/dwds/test/instances/common/patterns_inspection_common.dart index b2f75b5fe..31a52c91a 100644 --- a/dwds/test/instances/common/patterns_inspection_common.dart +++ b/dwds/test/instances/common/patterns_inspection_common.dart @@ -83,6 +83,7 @@ void runTests({ tearDown(() => service.resume(isolateId)); test('pattern match case 1', () async { + await Future.delayed(Duration(minutes: 20)); await onBreakPoint('testPatternCase1', (event) async { final frame = event.topFrame!; From e3e63ecfc53599c2f0d2d541307e721254127d8a Mon Sep 17 00:00:00 2001 From: Srujan Gaddam Date: Tue, 8 Jul 2025 19:48:42 -0700 Subject: [PATCH 3/7] Revert "Add artificial delay to test changes" This reverts commit 3bd14482062155a7544df1c28e3c341fcaa02347. --- dwds/test/instances/common/patterns_inspection_common.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/dwds/test/instances/common/patterns_inspection_common.dart b/dwds/test/instances/common/patterns_inspection_common.dart index 31a52c91a..b2f75b5fe 100644 --- a/dwds/test/instances/common/patterns_inspection_common.dart +++ b/dwds/test/instances/common/patterns_inspection_common.dart @@ -83,7 +83,6 @@ void runTests({ tearDown(() => service.resume(isolateId)); test('pattern match case 1', () async { - await Future.delayed(Duration(minutes: 20)); await onBreakPoint('testPatternCase1', (event) async { final frame = event.topFrame!; From 4426bc378d40b6ed4751621057e7a5c9428ea913 Mon Sep 17 00:00:00 2001 From: Srujan Gaddam Date: Fri, 11 Jul 2025 13:41:13 -0700 Subject: [PATCH 4/7] Avoid changing current directory in dart:io --- dwds/test/fixtures/project.dart | 22 +++++++++++++---- .../lib/src/asset_server.dart | 19 +++++++++------ frontend_server_common/lib/src/devfs.dart | 24 +++++++++---------- .../lib/src/frontend_server_client.dart | 3 +-- test_common/lib/utilities.dart | 4 +--- 5 files changed, 42 insertions(+), 30 deletions(-) diff --git a/dwds/test/fixtures/project.dart b/dwds/test/fixtures/project.dart index 9dc8e3def..82c6aba26 100644 --- a/dwds/test/fixtures/project.dart +++ b/dwds/test/fixtures/project.dart @@ -22,9 +22,12 @@ class TestProject { late Directory _fixturesCopy; /// The top level directory in which we run the test server, e.g. - /// "/tmp/_testSound". + /// "/tmp/_testSound/". String get absolutePackageDirectory => - p.join(_fixturesCopy.absolute.path, packageDirectory); + // Return it as a directory with a trailing slash. + Directory.fromUri( + _fixturesCopy.absolute.uri.resolve(packageDirectory), + ).uri.path; /// The directory to build and serve, e.g. "example". String get directoryToServe => p.split(webAssetsPath).first; @@ -242,9 +245,18 @@ class TestProject { } on FileSystemException catch (_) { assert(Platform.isWindows); // On Windows, the build daemon process might still be accessing the - // working directory, so wait a few seconds and then try again. - await Future.delayed(const Duration(seconds: 5)); - _fixturesCopy.deleteSync(recursive: true); + // working directory, so try again with an exponential backoff. + var seconds = 1; + final maxAttempts = 3; + for (var attempt = 0; attempt < maxAttempts; attempt++) { + try { + _fixturesCopy.deleteSync(recursive: true); + break; + } on FileSystemException catch (_) { + await Future.delayed(Duration(seconds: seconds)); + seconds *= 2; + } + } } } diff --git a/frontend_server_common/lib/src/asset_server.dart b/frontend_server_common/lib/src/asset_server.dart index 095320902..f8060b661 100644 --- a/frontend_server_common/lib/src/asset_server.dart +++ b/frontend_server_common/lib/src/asset_server.dart @@ -26,6 +26,7 @@ class TestAssetServer implements AssetReader { // Fallback to "application/octet-stream" on null which // makes no claims as to the structure of the data. static const String _defaultMimeType = 'application/octet-stream'; + final Uri _projectDirectory; final FileSystem _fileSystem; final HttpServer _httpServer; final Map _files = {}; @@ -41,6 +42,7 @@ class TestAssetServer implements AssetReader { this._httpServer, this._packageUriMapper, this.internetAddress, + this._projectDirectory, this._fileSystem, this._sdkLayout, ) { @@ -65,6 +67,7 @@ class TestAssetServer implements AssetReader { /// trace. static Future start( String sdkDirectory, + Uri projectDirectory, FileSystem fileSystem, String index, String hostname, @@ -75,8 +78,8 @@ class TestAssetServer implements AssetReader { final address = (await InternetAddress.lookup(hostname)).first; final httpServer = await HttpServer.bind(address, port); final sdkLayout = TestSdkLayout.createDefault(sdkDirectory); - final server = TestAssetServer( - index, httpServer, packageUriMapper, address, fileSystem, sdkLayout); + final server = TestAssetServer(index, httpServer, packageUriMapper, address, + projectDirectory, fileSystem, sdkLayout); return server; } @@ -94,7 +97,7 @@ class TestAssetServer implements AssetReader { final headers = {}; if (request.url.path.endsWith('.html')) { - final indexFile = _fileSystem.file(index); + final indexFile = _fileSystem.file(_projectDirectory.resolve(index)); if (indexFile.existsSync()) { headers[HttpHeaders.contentTypeHeader] = 'text/html'; headers[HttpHeaders.contentLengthHeader] = @@ -244,8 +247,7 @@ class TestAssetServer implements AssetReader { // If this is a dart file, it must be on the local file system and is // likely coming from a source map request. The tool doesn't currently // consider the case of Dart files as assets. - final dartFile = - _fileSystem.file(_fileSystem.currentDirectory.uri.resolve(path)); + final dartFile = _fileSystem.file(_projectDirectory.resolve(path)); if (dartFile.existsSync()) { return dartFile; } @@ -255,7 +257,10 @@ class TestAssetServer implements AssetReader { // The file might have been a package file which is signaled by a // `/packages//` request. if (segments.first == 'packages') { - final resolved = _packageUriMapper.serverPathToResolvedUri(path); + var resolved = _packageUriMapper.serverPathToResolvedUri(path); + if (resolved != null) { + resolved = _projectDirectory.resolveUri(resolved); + } final packageFile = _fileSystem.file(resolved); if (packageFile.existsSync()) { return packageFile; @@ -311,7 +316,7 @@ class TestAssetServer implements AssetReader { } String _parseBasePathFromIndexHtml(String index) { - final file = _fileSystem.file(index); + final file = _fileSystem.file(_projectDirectory.resolve(index)); if (!file.existsSync()) { throw StateError('Index file $index is not found'); } diff --git a/frontend_server_common/lib/src/devfs.dart b/frontend_server_common/lib/src/devfs.dart index ace83aa7c..a334b832a 100644 --- a/frontend_server_common/lib/src/devfs.dart +++ b/frontend_server_common/lib/src/devfs.dart @@ -51,15 +51,11 @@ class WebDevFS { final TestSdkLayout sdkLayout; final CompilerOptions compilerOptions; - late final Directory _savedCurrentDirectory; Future create() async { - _savedCurrentDirectory = fileSystem.currentDirectory; - - fileSystem.currentDirectory = projectDirectory.toFilePath(); - assetServer = await TestAssetServer.start( sdkLayout.sdkDirectory, + projectDirectory, fileSystem, index, hostname, @@ -71,7 +67,6 @@ class WebDevFS { } Future dispose() { - fileSystem.currentDirectory = _savedCurrentDirectory; return assetServer.close(); } @@ -84,7 +79,8 @@ class WebDevFS { required bool fullRestart, }) async { final mainPath = mainUri.toFilePath(); - final outputDirectoryPath = fileSystem.file(mainPath).parent.path; + final outputDirectory = fileSystem.directory( + fileSystem.file(projectDirectory.resolve(mainPath)).parent.path); final entryPoint = mainUri.toString(); var prefix = ''; @@ -103,7 +99,10 @@ class WebDevFS { final bootstrap = '${prefix}main_module.bootstrap.js'; assetServer.writeFile( - entryPoint, fileSystem.file(mainPath).readAsStringSync()); + entryPoint, + fileSystem + .file(projectDirectory.resolve(mainPath)) + .readAsStringSync()); assetServer.writeFile(stackMapper, stackTraceMapper.readAsStringSync()); switch (ddcModuleFormat) { @@ -199,14 +198,13 @@ class WebDevFS { File metadataFile; List modules; try { - final parentDirectory = fileSystem.directory(outputDirectoryPath); codeFile = - parentDirectory.childFile('${compilerOutput.outputFilename}.sources'); + outputDirectory.childFile('${compilerOutput.outputFilename}.sources'); manifestFile = - parentDirectory.childFile('${compilerOutput.outputFilename}.json'); + outputDirectory.childFile('${compilerOutput.outputFilename}.json'); sourcemapFile = - parentDirectory.childFile('${compilerOutput.outputFilename}.map'); - metadataFile = parentDirectory + outputDirectory.childFile('${compilerOutput.outputFilename}.map'); + metadataFile = outputDirectory .childFile('${compilerOutput.outputFilename}.metadata'); modules = assetServer.write( codeFile, manifestFile, sourcemapFile, metadataFile); diff --git a/frontend_server_common/lib/src/frontend_server_client.dart b/frontend_server_common/lib/src/frontend_server_client.dart index e500646b4..3c3ae3c1d 100644 --- a/frontend_server_common/lib/src/frontend_server_client.dart +++ b/frontend_server_common/lib/src/frontend_server_client.dart @@ -402,7 +402,6 @@ class ResidentCompiler { if (compilerOptions.moduleFormat == ModuleFormat.ddc) '--dartdevc-module-format=ddc' ]; - _logger.info(args.join(' ')); final workingDirectory = projectDirectory.toFilePath(); _server = await Process.start(sdkLayout.dartAotRuntimePath, args, @@ -657,7 +656,7 @@ String _toMultiRootPath( for (final fileSystemRoot in fileSystemRoots) { final rootPath = fileSystemRoot.toFilePath(windows: Platform.isWindows); if (filePath.startsWith(rootPath)) { - return '$scheme://${filePath.substring(rootPath.length)}'; + return '$scheme:///${filePath.substring(rootPath.length)}'; } } return fileUri.toString(); diff --git a/test_common/lib/utilities.dart b/test_common/lib/utilities.dart index 1a960a509..d4d3619be 100644 --- a/test_common/lib/utilities.dart +++ b/test_common/lib/utilities.dart @@ -12,12 +12,10 @@ const fixturesDirName = 'fixtures'; const newDdcTypeSystemVersion = '3.3.0-242.0.dev'; -final _currentDirectory = p.current; - /// The path to the webdev directory in the local machine, e.g. /// '/workstation/webdev'. String get webdevPath { - final pathParts = p.split(_currentDirectory); + final pathParts = p.split(p.current); assert(pathParts.contains(webdevDirName)); return p.joinAll( pathParts.sublist(0, pathParts.lastIndexOf(webdevDirName) + 1), From 8ac0cb9b3322be7a89685564ac294fb2f023c41d Mon Sep 17 00:00:00 2001 From: Srujan Gaddam Date: Sat, 12 Jul 2025 14:35:28 -0700 Subject: [PATCH 5/7] Fix up paths --- dwds/test/fixtures/context.dart | 6 ++++-- dwds/test/fixtures/project.dart | 8 ++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/dwds/test/fixtures/context.dart b/dwds/test/fixtures/context.dart index a6a1ab373..68687d0f6 100644 --- a/dwds/test/fixtures/context.dart +++ b/dwds/test/fixtures/context.dart @@ -322,10 +322,12 @@ class TestContext { _webRunner = ResidentWebRunner( mainUri: entry, urlTunneler: debugSettings.urlEncoder, - projectDirectory: p.toUri(project.absolutePackageDirectory), + projectDirectory: Directory(project.absolutePackageDirectory).uri, packageConfigFile: project.packageConfigFile, packageUriMapper: packageUriMapper, - fileSystemRoots: [p.toUri(project.absolutePackageDirectory)], + fileSystemRoots: [ + Directory(project.absolutePackageDirectory).uri, + ], fileSystemScheme: 'org-dartlang-app', outputPath: outputDir.path, compilerOptions: compilerOptions, diff --git a/dwds/test/fixtures/project.dart b/dwds/test/fixtures/project.dart index 82c6aba26..3a828b35c 100644 --- a/dwds/test/fixtures/project.dart +++ b/dwds/test/fixtures/project.dart @@ -22,12 +22,9 @@ class TestProject { late Directory _fixturesCopy; /// The top level directory in which we run the test server, e.g. - /// "/tmp/_testSound/". + /// "/tmp/_testSound". String get absolutePackageDirectory => - // Return it as a directory with a trailing slash. - Directory.fromUri( - _fixturesCopy.absolute.uri.resolve(packageDirectory), - ).uri.path; + _fixturesCopy.absolute.uri.resolve(packageDirectory).path; /// The directory to build and serve, e.g. "example". String get directoryToServe => p.split(webAssetsPath).first; @@ -243,7 +240,6 @@ class TestProject { try { _fixturesCopy.deleteSync(recursive: true); } on FileSystemException catch (_) { - assert(Platform.isWindows); // On Windows, the build daemon process might still be accessing the // working directory, so try again with an exponential backoff. var seconds = 1; From 1c824259efbec6aff75ccfc8ccc66a55fdd8b851 Mon Sep 17 00:00:00 2001 From: Srujan Gaddam Date: Sat, 12 Jul 2025 15:27:38 -0700 Subject: [PATCH 6/7] Fix paths again --- dwds/test/fixtures/project.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwds/test/fixtures/project.dart b/dwds/test/fixtures/project.dart index 3a828b35c..85c921f2d 100644 --- a/dwds/test/fixtures/project.dart +++ b/dwds/test/fixtures/project.dart @@ -24,7 +24,7 @@ class TestProject { /// The top level directory in which we run the test server, e.g. /// "/tmp/_testSound". String get absolutePackageDirectory => - _fixturesCopy.absolute.uri.resolve(packageDirectory).path; + p.join(_fixturesCopy.absolute.path, packageDirectory); /// The directory to build and serve, e.g. "example". String get directoryToServe => p.split(webAssetsPath).first; From 1b8586dd680292aeec33a0d9378c31e2a8ebebd3 Mon Sep 17 00:00:00 2001 From: Srujan Gaddam Date: Mon, 14 Jul 2025 10:56:53 -0700 Subject: [PATCH 7/7] Move to 24.4.1-wip --- dwds/CHANGELOG.md | 2 ++ dwds/lib/src/version.dart | 2 +- dwds/pubspec.yaml | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md index 17f414c11..8a6ba0c5a 100644 --- a/dwds/CHANGELOG.md +++ b/dwds/CHANGELOG.md @@ -1,3 +1,5 @@ +## 24.4.1-wip + ## 24.4.0 - Added support for breakpoint registering on a hot reload with the DDC library bundle format using PausePostRequests. diff --git a/dwds/lib/src/version.dart b/dwds/lib/src/version.dart index 2786a7b0a..c8bd103ab 100644 --- a/dwds/lib/src/version.dart +++ b/dwds/lib/src/version.dart @@ -1,2 +1,2 @@ // Generated code. Do not modify. -const packageVersion = '24.4.0'; +const packageVersion = '24.4.1-wip'; diff --git a/dwds/pubspec.yaml b/dwds/pubspec.yaml index f139974a6..da11ad7f1 100644 --- a/dwds/pubspec.yaml +++ b/dwds/pubspec.yaml @@ -1,6 +1,6 @@ name: dwds # Every time this changes you need to run `dart run build_runner build`. -version: 24.4.0 +version: 24.4.1-wip description: >- A service that proxies between the Chrome debug protocol and the Dart VM