From 61f964b56dceb7a4451675c289bde638d9a1c248 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Mon, 27 Nov 2023 14:52:08 -0800 Subject: [PATCH 01/22] Updating the legacy loader to use the new DDC module loader API --- dwds/lib/src/loaders/legacy.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dwds/lib/src/loaders/legacy.dart b/dwds/lib/src/loaders/legacy.dart index bfaa50315..fb35c0937 100644 --- a/dwds/lib/src/loaders/legacy.dart +++ b/dwds/lib/src/loaders/legacy.dart @@ -181,7 +181,11 @@ class LegacyStrategy extends LoadStrategy { return ''' $_baseUrlScript var scripts = ${const JsonEncoder.withIndent(" ").convert(scripts)}; -window.\$dartLoader.loadScripts(scripts); +window.\$dartLoader.loadConfig.loadScriptFn = function(loader) { + loader.addScriptsToQueue(scripts, null); + loader.loadEnqueuedModules(); +}; +window.\$dartLoader.loader.nextAttempt(); '''; } From e17f872f132dda5b0ff374ca704fa9fc65be6df8 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Mon, 27 Nov 2023 14:58:20 -0800 Subject: [PATCH 02/22] Adding tests and plumbing for the DDC module system. --- dwds/lib/dart_web_debug_service.dart | 2 + dwds/lib/src/handlers/dev_handler.dart | 3 + .../lib/src/services/expression_compiler.dart | 3 + dwds/lib/utilities.dart | 5 + dwds/test/fixtures/context.dart | 99 +++++- dwds/test/fixtures/server.dart | 6 +- dwds/test/fixtures/utilities.dart | 2 +- ...ontend_server_ddc_evaluate_sound_test.dart | 50 +++ .../lib/src/asset_server.dart | 4 +- frontend_server_common/lib/src/bootstrap.dart | 313 ++++++++++++++++++ frontend_server_common/lib/src/devfs.dart | 77 +++-- .../lib/src/frontend_server_client.dart | 1 + .../lib/src/resident_runner.dart | 1 + test_common/lib/sdk_asset_generator.dart | 4 +- test_common/lib/test_sdk_configuration.dart | 8 +- test_common/lib/test_sdk_layout.dart | 182 +++++----- .../test/sdk_asset_generator_test.dart | 11 +- 17 files changed, 644 insertions(+), 127 deletions(-) create mode 100644 dwds/lib/utilities.dart create mode 100644 dwds/test/frontend_server_ddc_evaluate_sound_test.dart diff --git a/dwds/lib/dart_web_debug_service.dart b/dwds/lib/dart_web_debug_service.dart index 467e568d1..f0f2252ec 100644 --- a/dwds/lib/dart_web_debug_service.dart +++ b/dwds/lib/dart_web_debug_service.dart @@ -65,6 +65,7 @@ class Dwds { required Stream buildResults, required ConnectionProvider chromeConnection, required ToolConfiguration toolConfiguration, + Future? completeBeforeHandlingConnections, }) async { globalToolConfiguration = toolConfiguration; final debugSettings = toolConfiguration.debugSettings; @@ -128,6 +129,7 @@ class Dwds { injected, debugSettings.spawnDds, debugSettings.launchDevToolsInNewWindow, + completeBeforeHandlingConnections, ); return Dwds._( diff --git a/dwds/lib/src/handlers/dev_handler.dart b/dwds/lib/src/handlers/dev_handler.dart index 23e7ca06b..96ad9c934 100644 --- a/dwds/lib/src/handlers/dev_handler.dart +++ b/dwds/lib/src/handlers/dev_handler.dart @@ -67,6 +67,7 @@ class DevHandler { final bool _useSseForInjectedClient; final bool _spawnDds; final bool _launchDevToolsInNewWindow; + final Future? _completeBeforeHandlingConnections; final ExpressionCompiler? _expressionCompiler; final DwdsInjector _injected; @@ -91,6 +92,7 @@ class DevHandler { this._injected, this._spawnDds, this._launchDevToolsInNewWindow, + this._completeBeforeHandlingConnections, ) { _subs.add(buildResults.listen(_emitBuildResults)); _listen(); @@ -494,6 +496,7 @@ class DevHandler { : WebSocketSocketHandler(); _sseHandlers[uri.path] = handler; final injectedConnections = handler.connections; + await _completeBeforeHandlingConnections; while (await injectedConnections.hasNext) { _handleConnection(await injectedConnections.next); } diff --git a/dwds/lib/src/services/expression_compiler.dart b/dwds/lib/src/services/expression_compiler.dart index 6135a707e..8534eb5b4 100644 --- a/dwds/lib/src/services/expression_compiler.dart +++ b/dwds/lib/src/services/expression_compiler.dart @@ -15,6 +15,9 @@ class CompilerOptions { required this.canaryFeatures, required this.experiments, }); + + bool get usesDDCModuleSystem => + moduleFormat == 'ddc' || moduleFormat == 'legacy'; } /// Result of compilation of dart expression to JavaScript diff --git a/dwds/lib/utilities.dart b/dwds/lib/utilities.dart new file mode 100644 index 000000000..02e84d8cc --- /dev/null +++ b/dwds/lib/utilities.dart @@ -0,0 +1,5 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +export 'src/utilities/ddc_names.dart'; diff --git a/dwds/test/fixtures/context.dart b/dwds/test/fixtures/context.dart index 3842aa03c..d1c5abe1f 100644 --- a/dwds/test/fixtures/context.dart +++ b/dwds/test/fixtures/context.dart @@ -2,6 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'dart:async'; import 'dart:convert'; import 'dart:io'; @@ -14,8 +15,9 @@ import 'package:dwds/src/connections/app_connection.dart'; import 'package:dwds/src/connections/debug_connection.dart'; import 'package:dwds/src/debugging/webkit_debugger.dart'; import 'package:dwds/src/loaders/build_runner_require.dart'; +import 'package:dwds/src/loaders/frontend_server_legacy.dart'; import 'package:dwds/src/loaders/frontend_server_require.dart'; -import 'package:dwds/src/loaders/require.dart'; +import 'package:dwds/src/loaders/strategy.dart'; import 'package:dwds/src/readers/proxy_server_asset_reader.dart'; import 'package:dwds/src/services/chrome_proxy_service.dart'; import 'package:dwds/src/services/expression_compiler_service.dart'; @@ -58,7 +60,17 @@ Matcher isRPCErrorWithCode(int code) => isA().having((e) => e.code, 'code', equals(code)); Matcher throwsRPCErrorWithCode(int code) => throwsA(isRPCErrorWithCode(code)); -enum CompilationMode { buildDaemon, frontendServer } +enum CompilationMode { + buildDaemon, + // Uses DDC's AMD module system + frontendServer, + // Uses DDC's DDC/legacy module system + frontendServerDdc; + + bool get usesFrontendServer => + this == CompilationMode.frontendServer || + this == CompilationMode.frontendServerDdc; +} class TestContext { final TestProject project; @@ -204,7 +216,7 @@ class TestContext { ExpressionCompiler? expressionCompiler; AssetReader assetReader; Stream buildResults; - RequireStrategy requireStrategy; + LoadStrategy loadStrategy; String basePath = ''; String filePathToServe = project.filePathToServe; @@ -268,7 +280,7 @@ class TestContext { expressionCompiler = ddcService; } - requireStrategy = BuildRunnerRequireStrategyProvider( + loadStrategy = BuildRunnerRequireStrategyProvider( assetHandler, testSettings.reloadConfiguration, assetReader, @@ -332,7 +344,73 @@ class TestContext { basePath = webRunner.devFS.assetServer.basePath; assetReader = webRunner.devFS.assetServer; _assetHandler = webRunner.devFS.assetServer.handleRequest; - requireStrategy = FrontendServerRequireStrategyProvider( + loadStrategy = FrontendServerRequireStrategyProvider( + testSettings.reloadConfiguration, + assetReader, + packageUriMapper, + () async => {}, + buildSettings, + ).strategy; + + buildResults = const Stream.empty(); + } + break; + case CompilationMode.frontendServerDdc: + { + filePathToServe = webCompatiblePath([ + project.directoryToServe, + project.filePathToServe, + ]); + + _logger.info('Serving: $filePathToServe'); + + final entry = p.toUri( + p.join(project.webAssetsPath, project.dartEntryFileName), + ); + final fileSystem = LocalFileSystem(); + final packageUriMapper = await PackageUriMapper.create( + fileSystem, + project.packageConfigFile, + useDebuggerModuleNames: testSettings.useDebuggerModuleNames, + ); + + final compilerOptions = TestCompilerOptions( + nullSafety: project.nullSafety, + experiments: buildSettings.experiments, + canaryFeatures: buildSettings.canaryFeatures, + moduleFormat: 'ddc', + ); + + _webRunner = ResidentWebRunner( + mainUri: entry, + urlTunneler: debugSettings.urlEncoder, + projectDirectory: p.toUri(project.absolutePackageDirectory), + packageConfigFile: project.packageConfigFile, + packageUriMapper: packageUriMapper, + fileSystemRoots: [p.toUri(project.absolutePackageDirectory)], + fileSystemScheme: 'org-dartlang-app', + outputPath: outputDir.path, + compilerOptions: compilerOptions, + sdkLayout: sdkLayout, + verbose: testSettings.verboseCompiler, + ); + + final assetServerPort = await findUnusedPort(); + await webRunner.run( + fileSystem, + appMetadata.hostname, + assetServerPort, + filePathToServe, + ); + + if (testSettings.enableExpressionEvaluation) { + expressionCompiler = webRunner.expressionCompiler; + } + + basePath = webRunner.devFS.assetServer.basePath; + assetReader = webRunner.devFS.assetServer; + _assetHandler = webRunner.devFS.assetServer.handleRequest; + loadStrategy = FrontendServerLegacyStrategyProvider( testSettings.reloadConfiguration, assetReader, packageUriMapper, @@ -380,6 +458,10 @@ class TestContext { ), ); } + + // The debugger tab must be enabled and connected before certain + // listeners in DWDS run. + final tabConnectionCompleter = Completer(); final connection = ChromeConnection('localhost', debugPort); _testServer = await TestServer.start( @@ -389,11 +471,12 @@ class TestContext { port: port, assetHandler: assetHandler, assetReader: assetReader, - strategy: requireStrategy, + strategy: loadStrategy, target: project.directoryToServe, buildResults: buildResults, chromeConnection: () async => connection, autoRun: testSettings.autoRun, + completeBeforeHandlingConnections: tabConnectionCompleter.future, ); _appUrl = basePath.isEmpty @@ -406,7 +489,9 @@ class TestContext { if (tab != null) { _tabConnection = await tab.connect(); await tabConnection.runtime.enable(); - await tabConnection.debugger.enable(); + await tabConnection.debugger + .enable() + .then((_) => tabConnectionCompleter.complete()); } else { throw StateError('Unable to connect to tab.'); } diff --git a/dwds/test/fixtures/server.dart b/dwds/test/fixtures/server.dart index 88562e73f..98aac8b06 100644 --- a/dwds/test/fixtures/server.dart +++ b/dwds/test/fixtures/server.dart @@ -9,7 +9,7 @@ import 'package:dwds/asset_reader.dart'; import 'package:dwds/dart_web_debug_service.dart'; import 'package:dwds/data/build_result.dart'; import 'package:dwds/src/config/tool_configuration.dart'; -import 'package:dwds/src/loaders/require.dart'; +import 'package:dwds/src/loaders/strategy.dart'; import 'package:dwds/src/utilities/server.dart'; import 'package:logging/logging.dart'; import 'package:shelf/shelf.dart'; @@ -62,12 +62,13 @@ class TestServer { required AppMetadata appMetadata, required Handler assetHandler, required AssetReader assetReader, - required RequireStrategy strategy, + required LoadStrategy strategy, required String target, required Stream buildResults, required Future Function() chromeConnection, required bool autoRun, int? port, + Future? completeBeforeHandlingConnections, }) async { var pipeline = const Pipeline(); @@ -100,6 +101,7 @@ class TestServer { buildResults: filteredBuildResults, chromeConnection: chromeConnection, toolConfiguration: toolConfiguration, + completeBeforeHandlingConnections: completeBeforeHandlingConnections, ); final server = await startHttpServer('localhost', port: port); diff --git a/dwds/test/fixtures/utilities.dart b/dwds/test/fixtures/utilities.dart index 5c722e068..2ce5ee07b 100644 --- a/dwds/test/fixtures/utilities.dart +++ b/dwds/test/fixtures/utilities.dart @@ -296,8 +296,8 @@ class TestCompilerOptions extends CompilerOptions { required NullSafety nullSafety, required super.canaryFeatures, required List experiments, + super.moduleFormat = 'amd', }) : super( - moduleFormat: 'amd', soundNullSafety: nullSafety == NullSafety.sound, experiments: const [], ); diff --git a/dwds/test/frontend_server_ddc_evaluate_sound_test.dart b/dwds/test/frontend_server_ddc_evaluate_sound_test.dart new file mode 100644 index 000000000..b237e326c --- /dev/null +++ b/dwds/test/frontend_server_ddc_evaluate_sound_test.dart @@ -0,0 +1,50 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 5)) + +import 'dart:io'; + +import 'package:test/test.dart'; +import 'package:test_common/test_sdk_configuration.dart'; + +import 'evaluate_common.dart'; +import 'fixtures/context.dart'; +import 'fixtures/project.dart'; + +void main() async { + // Enable verbose logging for debugging. + final debug = false; + + final provider = + TestSdkConfigurationProvider(verbose: debug, ddcModuleSystem: true); + tearDownAll(provider.dispose); + + for (var useDebuggerModuleNames in [false, true]) { + group('Debugger module names: $useDebuggerModuleNames |', () { + final nullSafety = NullSafety.sound; + group('${nullSafety.name} null safety | DDC module system |', () { + for (var indexBaseMode in IndexBaseMode.values) { + group( + 'with ${indexBaseMode.name} |', + () { + testAll( + provider: provider, + compilationMode: CompilationMode.frontendServerDdc, + indexBaseMode: indexBaseMode, + nullSafety: nullSafety, + useDebuggerModuleNames: useDebuggerModuleNames, + debug: debug, + ); + }, + // https://github.com/dart-lang/sdk/issues/49277 + skip: indexBaseMode == IndexBaseMode.base && Platform.isWindows, + ); + } + }); + }); + } +} diff --git a/frontend_server_common/lib/src/asset_server.dart b/frontend_server_common/lib/src/asset_server.dart index b63b6e05e..3729296ea 100644 --- a/frontend_server_common/lib/src/asset_server.dart +++ b/frontend_server_common/lib/src/asset_server.dart @@ -71,10 +71,12 @@ class TestAssetServer implements AssetReader { int port, UrlEncoder? urlTunneler, PackageUriMapper packageUriMapper, + bool ddcModuleSystem, ) async { final address = (await InternetAddress.lookup(hostname)).first; final httpServer = await HttpServer.bind(address, port); - final sdkLayout = TestSdkLayout.createDefault(sdkDirectory); + final sdkLayout = TestSdkLayout.createDefault(sdkDirectory, + ddcModuleSystem: ddcModuleSystem); final server = TestAssetServer( index, httpServer, packageUriMapper, address, fileSystem, sdkLayout); return server; diff --git a/frontend_server_common/lib/src/bootstrap.dart b/frontend_server_common/lib/src/bootstrap.dart index a5d1ba0c4..206e73e51 100644 --- a/frontend_server_common/lib/src/bootstrap.dart +++ b/frontend_server_common/lib/src/bootstrap.dart @@ -4,6 +4,78 @@ // Note: this is a copy from flutter tools, updated to work with dwds tests +/// JavaScript snippet to determine the base URL of the current path. +const String _baseUrlScript = ''' +var baseUrl = (function () { + // Attempt to detect --precompiled mode for tests, and set the base url + // appropriately, otherwise set it to '/'. + var pathParts = location.pathname.split("/"); + if (pathParts[0] == "") { + pathParts.shift(); + } + if (pathParts.length > 1 && pathParts[1] == "test") { + return "/" + pathParts.slice(0, 2).join("/") + "/"; + } + // Attempt to detect base url using html tag + // base href should start and end with "/" + if (typeof document !== 'undefined') { + var el = document.getElementsByTagName('base'); + if (el && el[0] && el[0].getAttribute("href") && el[0].getAttribute + ("href").startsWith("/") && el[0].getAttribute("href").endsWith("/")){ + return el[0].getAttribute("href"); + } + } + // return default value + return "/"; +}()); +var _trimmedBaseUrl = baseUrl.endsWith('/') ? baseUrl.substring(0, baseUrl.length - 1) : baseUrl; +var _currentDirectory = window.location.origin + _trimmedBaseUrl; +'''; + +/// Used to load prerequisite scripts such as ddc_module_loader.js +const String _simpleLoaderScript = r''' +window.$dartCreateScript = (function() { + // Find the nonce value. (Note, this is only computed once.) + var scripts = Array.from(document.getElementsByTagName("script")); + var nonce; + scripts.some( + script => (nonce = script.nonce || script.getAttribute("nonce"))); + // If present, return a closure that automatically appends the nonce. + if (nonce) { + return function() { + var script = document.createElement("script"); + script.nonce = nonce; + return script; + }; + } else { + return function() { + return document.createElement("script"); + }; + } +})(); + +// Loads a module [relativeUrl] relative to [root]. +// +// If not specified, [root] defaults to the directory serving the main app. +var forceLoadModule = function (relativeUrl, root) { + var actualRoot = root ?? _currentDirectory; + var trimmedRoot = actualRoot.endsWith('/') ? actualRoot.substring(0, actualRoot.length - 1) : actualRoot; + return new Promise(function(resolve, reject) { + var script = self.$dartCreateScript(); + let policy = { + createScriptURL: function(src) {return src;} + }; + if (self.trustedTypes && self.trustedTypes.createPolicy) { + policy = self.trustedTypes.createPolicy('dartDdcModuleUrl', policy); + } + script.onload = resolve; + script.onerror = reject; + script.src = policy.createScriptURL(trimmedRoot + "/" + relativeUrl); + document.head.appendChild(script); + }); +}; +'''; + /// The JavaScript bootstrap script to support in-browser hot restart. /// /// The [requireUrl] loads our cached RequireJS script file. The [mapperUrl] @@ -68,3 +140,244 @@ define("main_module.bootstrap", ["$entrypoint", "dart_sdk"], function(app, dart_ }); '''; } + +String generateDDCBootstrapScript({ + required String ddcModuleLoaderUrl, + required String mapperUrl, + required String entrypoint, + required String bootstrapUrl, +}) { + return ''' +$_baseUrlScript +$_simpleLoaderScript + +(function() { + let appName = "$entrypoint"; + + // A uuid that identifies a subapp. + let uuid = "00000000-0000-0000-0000-000000000000"; + + window.postMessage( + {type: "DDC_STATE_CHANGE", state: "initial_load", targetUuid: uuid}, "*"); + + // Load pre-requisite DDC scripts. We intentionally use invalid names to avoid namespace clashes. + let prerequisiteScripts = [ + { + "src": "$ddcModuleLoaderUrl", + "id": "dart_library \x00" + }, + { + "src": "$mapperUrl", + "id": "dart_stack_trace_mapper \x00" + } + ]; + + // Load ddc_module_loader.js to access DDC's module loader API. + let prerequisiteLoads = []; + for (let i = 0; i < prerequisiteScripts.length; i++) { + prerequisiteLoads.push(forceLoadModule(prerequisiteScripts[i].src)); + } + Promise.all(prerequisiteLoads).then((_) => afterPrerequisiteLogic()); + + // Save the current script so we can access it in a closure. + var _currentScript = document.currentScript; + + var afterPrerequisiteLogic = function() { + window.\$dartLoader.rootDirectories.push(_currentDirectory); + let scripts = [ + { + "src": "dart_sdk.js", + "id": "dart_sdk" + }, + { + "src": "$bootstrapUrl", + "id": "data-main" + } + ]; + let loadConfig = new window.\$dartLoader.LoadConfiguration(); + loadConfig.root = _currentDirectory; + loadConfig.bootstrapScript = scripts[scripts.length - 1]; + + if (window.\$dartJITModules) { + loadConfig.loadScriptFn = function(loader) { + // Loads just the entrypoint module and required SDK modules. + let moduleSet = new Set(); + // This cache is populated by ddc_module_loader.js + let libraryCache = JSON.parse(window.localStorage.getItem(`dartLibraryCache:\${appName}`)); + if (libraryCache) { + // TODO(b/165021238) - when should this be invalidated? + moduleSet = new Set(libraryCache["modules"]) + } + loader.addScriptsToQueue(scripts, function(script) { + // Preemptively load the ddc module loader and previously executed modules. + return moduleSet.size == 0 + || script.id.includes("dart_library") + // We preemptively load the stack_trace_mapper module so that we can + // translate JS errors to Dart. + || script.id.includes("stack_trace_mapper") + || moduleSet.has(script.id); + }); + loader.loadEnqueuedModules(); + } + loadConfig.ddcEventForLoadStart = /* LOAD_ENTRYPOINT_MODULES_START */ 4; + loadConfig.ddcEventForLoadedOk = /* LOAD_ENTRYPOINT_MODULES_END_OK */ 5; + loadConfig.ddcEventForLoadedError = /* LOAD_ENTRYPOINT_MODULES_END_ERROR */ 6; + } else { + loadConfig.loadScriptFn = function(loader) { + loader.addScriptsToQueue(scripts, null); + loader.loadEnqueuedModules(); + } + loadConfig.ddcEventForLoadStart = /* LOAD_ALL_MODULES_START */ 1; + loadConfig.ddcEventForLoadedOk = /* LOAD_ALL_MODULES_END_OK */ 2; + loadConfig.ddcEventForLoadedError = /* LOAD_ALL_MODULES_END_ERROR */ 3; + } + + let loader = new window.\$dartLoader.DDCLoader(loadConfig); + + // Record prerequisite scripts' fully resolved URLs. + prerequisiteScripts.forEach(script => loader.registerScript(script)); + + // Note: these variables should only be used in non-multi-app scenarios since + // they can be arbitrarily overridden based on multi-app load order. + window.\$dartLoader.loadConfig = loadConfig; + window.\$dartLoader.loader = loader; + loader.nextAttempt(); + + let currentUri = _currentScript.src; + let fetchEtagsUri; + if (currentUri.indexOf("?") == -1) { + fetchEtagsUri = currentUri + "?fetch-etags=true"; + } else { + fetchEtagsUri = currentUri + "&fetch-etags=true"; + } + + if (!window.\$dartAppNameToMetadata) { + window.\$dartAppNameToMetadata = new Map(); + } + window.\$dartAppNameToMetadata.set(appName, { + currentDirectory: _currentDirectory, + currentUri: currentUri, + fetchEtagsUri: fetchEtagsUri, + }); + + if (!window.\$dartReloadModifiedModules) { + window.\$dartReloadModifiedModules = (function(appName, callback) { + function cb() { + window.postMessage( + { + type: "DDC_STATE_CHANGE", + state: "restart_end", + targetUuid: uuid, + }, + "*"); + callback(); + } + window.postMessage( + { + type: "DDC_STATE_CHANGE", + state: "restart_begin", + targetUuid: uuid, + }, + "*"); + var xhttp = new XMLHttpRequest(); + xhttp.withCredentials = true; + xhttp.onreadystatechange = function() { + // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState + if (this.readyState == 4 && this.status == 200 || this.status == 304) { + var scripts = JSON.parse(this.responseText); + var numToLoad = 0; + var numLoaded = 0; + for (var i = 0; i < scripts.length; i++) { + var script = scripts[i]; + if (script.id == null) continue; + var src = + window.\$dartAppNameToMetadata.get(appName).currentDirectory + + script.src.toString(); + var oldSrc = window.\$dartLoader.moduleIdToUrl.get(script.id); + // Only compare the search parameters which contain the cache + // busting portion of the uri. The path might be different if the + // script is loaded from a different application on the page. + if (new URL(oldSrc).search == new URL(src).search) continue; + + // We might actually load from a different uri, delete the old one + // just to be sure. + window.\$dartLoader.urlToModuleId.delete(oldSrc); + + window.\$dartLoader.moduleIdToUrl.set(script.id, src); + window.\$dartLoader.urlToModuleId.set(src, script.id); + + if (window.\$dartJITModules) { + // Simply invalidate the import and the corresponding module will + // be lazily loaded. + dart_library.invalidateImport(script.id); + continue; + } else { + numToLoad++; + } + + var el = document.getElementById(script.id); + if (el) el.remove(); + el = window.\$dartCreateScript(); + el.src = policy.createScriptURL(src); + el.async = false; + el.defer = true; + el.id = script.id; + el.onload = function() { + numLoaded++; + if (numToLoad == numLoaded) cb(); + }; + document.head.appendChild(el); + } + // Call `cb` right away if we found no updated scripts. + if (numToLoad == 0) cb(); + } + }; + xhttp.open("GET", + window.\$dartAppNameToMetadata.get(appName).fetchEtagsUri, true); + let sdk = dart_library.import("dart_sdk", appName); + let developer = sdk.developer; + if (developer._extensions.containsKey("ext.flutter.disassemble")) { + developer.invokeExtension("ext.flutter.disassemble", "{}").then(() => { + // TODO(b/204210914): we should really be clearing all statics for all + // apps, but for now we just do it for flutter apps which we recognize + // based on this extension. + sdk.dart.hotRestart(); + xhttp.send(); + }); + } else { + xhttp.send(); + } + }); + } + } +})(); +'''; +} + +String generateDDCMainModule( + {required String entrypoint, String? exportedMain}) { + final exportedMainName = exportedMain ?? entrypoint.split('.')[0]; + return '''/* ENTRYPOINT_EXTENTION_MARKER */ + +(function() { + let appName = "$entrypoint"; + + // A uuid that identifies a subapp. + let uuid = "00000000-0000-0000-0000-000000000000"; + + let dart_sdk = dart_library.import('dart_sdk', appName); + + dart_sdk.dart.setStartAsyncSynchronously(true); + dart_sdk._debugger.registerDevtoolsFormatter(); + dart_sdk._isolate_helper.startRootIsolate(() => {}, []); + + let child = {}; + child.main = function() { + dart_library.start(appName, uuid, "$entrypoint", "$exportedMainName"); + } + + /* MAIN_EXTENSION_MARKER */ + child.main(); +})(); +'''; +} diff --git a/frontend_server_common/lib/src/devfs.dart b/frontend_server_common/lib/src/devfs.dart index 64e3e4512..05852f7b5 100644 --- a/frontend_server_common/lib/src/devfs.dart +++ b/frontend_server_common/lib/src/devfs.dart @@ -6,6 +6,7 @@ import 'package:dwds/asset_reader.dart'; import 'package:dwds/config.dart'; +import 'package:dwds/utilities.dart'; import 'package:file/file.dart'; import 'package:path/path.dart' as p; import 'package:test_common/test_sdk_layout.dart'; @@ -25,6 +26,7 @@ class WebDevFS { required this.soundNullSafety, this.urlTunneler, required this.sdkLayout, + required this.ddcModuleSystem, }); final FileSystem fileSystem; @@ -37,6 +39,7 @@ class WebDevFS { final UrlEncoder? urlTunneler; final bool soundNullSafety; final TestSdkLayout sdkLayout; + final bool ddcModuleSystem; late final Directory _savedCurrentDirectory; Future create() async { @@ -44,8 +47,16 @@ class WebDevFS { fileSystem.currentDirectory = projectDirectory.toFilePath(); - assetServer = await TestAssetServer.start(sdkLayout.sdkDirectory, - fileSystem, index, hostname, port, urlTunneler, packageUriMapper); + assetServer = await TestAssetServer.start( + sdkLayout.sdkDirectory, + fileSystem, + index, + hostname, + port, + urlTunneler, + packageUriMapper, + ddcModuleSystem, + ); return Uri.parse('http://$hostname:$port'); } @@ -64,15 +75,18 @@ class WebDevFS { final outputDirectoryPath = fileSystem.file(mainPath).parent.path; final entryPoint = mainUri.toString(); + var ddcModuleLoader = 'ddc_module_loader.js'; var require = 'require.js'; var stackMapper = 'stack_trace_mapper.js'; var main = 'main.dart.js'; var bootstrap = 'main_module.bootstrap.js'; + var dartSdkName = 'dart_sdk.js'; // If base path is not overwritten, use main's subdirectory // to store all files, so the paths match the requests. if (assetServer.basePath.isEmpty) { final directory = p.dirname(entryPoint); + ddcModuleLoader = '$directory/ddc_module_loader.js'; require = '$directory/require.js'; stackMapper = '$directory/stack_trace_mapper.js'; main = '$directory/main.dart.js'; @@ -81,30 +95,53 @@ class WebDevFS { assetServer.writeFile( entryPoint, fileSystem.file(mainPath).readAsStringSync()); - assetServer.writeFile(require, requireJS.readAsStringSync()); + if (ddcModuleSystem) { + assetServer.writeFile( + ddcModuleLoader, ddcModuleLoaderJS.readAsStringSync()); + } else { + assetServer.writeFile(require, requireJS.readAsStringSync()); + } assetServer.writeFile(stackMapper, stackTraceMapper.readAsStringSync()); - assetServer.writeFile( - main, - generateBootstrapScript( - requireUrl: 'require.js', - mapperUrl: 'stack_trace_mapper.js', - entrypoint: entryPoint, - ), - ); - assetServer.writeFile( - bootstrap, - generateMainModule( - entrypoint: entryPoint, - ), - ); + if (ddcModuleSystem) { + assetServer.writeFile( + main, + generateDDCBootstrapScript( + ddcModuleLoaderUrl: ddcModuleLoader, + mapperUrl: stackMapper, + entrypoint: entryPoint, + bootstrapUrl: bootstrap, + ), + ); + assetServer.writeFile( + bootstrap, + generateDDCMainModule( + entrypoint: entryPoint, + exportedMain: pathToJSIdentifier(entryPoint.split('.')[0])), + ); + } else { + assetServer.writeFile( + main, + generateBootstrapScript( + requireUrl: 'require.js', + mapperUrl: 'stack_trace_mapper.js', + entrypoint: entryPoint, + ), + ); + assetServer.writeFile( + bootstrap, + generateMainModule( + entrypoint: entryPoint, + ), + ); + } assetServer.writeFile('main_module.digests', '{}'); var sdk = soundNullSafety ? dartSdk : dartSdkWeak; var sdkSourceMap = soundNullSafety ? dartSdkSourcemap : dartSdkSourcemapWeak; - assetServer.writeFile('dart_sdk.js', sdk.readAsStringSync()); - assetServer.writeFile('dart_sdk.js.map', sdkSourceMap.readAsStringSync()); + assetServer.writeFile(dartSdkName, sdk.readAsStringSync()); + assetServer.writeFile('$dartSdkName.map', sdkSourceMap.readAsStringSync()); generator.reset(); var compilerOutput = await generator.recompile( @@ -144,6 +181,8 @@ class WebDevFS { )..invalidatedModules = modules; } + File get ddcModuleLoaderJS => + fileSystem.file(sdkLayout.ddcModuleLoaderJsPath); File get requireJS => fileSystem.file(sdkLayout.requireJsPath); File get dartSdkWeak => fileSystem.file(sdkLayout.weakJsPath); File get dartSdk => fileSystem.file(sdkLayout.soundJsPath); diff --git a/frontend_server_common/lib/src/frontend_server_client.dart b/frontend_server_common/lib/src/frontend_server_client.dart index aba399997..1b6435290 100644 --- a/frontend_server_common/lib/src/frontend_server_client.dart +++ b/frontend_server_common/lib/src/frontend_server_client.dart @@ -394,6 +394,7 @@ class ResidentCompiler { '--enable-experiment=$experiment', if (compilerOptions.canaryFeatures) '--dartdevc-canary', if (verbose) '--verbose', + if (compilerOptions.usesDDCModuleSystem) '--dartdevc-module-format=legacy' ]; _logger.info(args.join(' ')); diff --git a/frontend_server_common/lib/src/resident_runner.dart b/frontend_server_common/lib/src/resident_runner.dart index 86f142739..d32077450 100644 --- a/frontend_server_common/lib/src/resident_runner.dart +++ b/frontend_server_common/lib/src/resident_runner.dart @@ -81,6 +81,7 @@ class ResidentWebRunner { urlTunneler: urlTunneler, soundNullSafety: compilerOptions.soundNullSafety, sdkLayout: sdkLayout, + ddcModuleSystem: compilerOptions.usesDDCModuleSystem, ); uri = await devFS.create(); diff --git a/test_common/lib/sdk_asset_generator.dart b/test_common/lib/sdk_asset_generator.dart index 16dc7be8e..cf7aa01cf 100644 --- a/test_common/lib/sdk_asset_generator.dart +++ b/test_common/lib/sdk_asset_generator.dart @@ -18,6 +18,7 @@ class SdkAssetGenerator { final FileSystem fileSystem; final bool canaryFeatures; + final bool ddcModuleSystem; final bool verbose; late final TestSdkLayout sdkLayout; @@ -26,6 +27,7 @@ class SdkAssetGenerator { this.fileSystem = const LocalFileSystem(), required this.sdkLayout, required this.canaryFeatures, + required this.ddcModuleSystem, this.verbose = false, }); @@ -98,7 +100,7 @@ class SdkAssetGenerator { '--libraries-file', 'org-dartlang-sdk:///lib/libraries.json', '--modules', - 'amd', + ddcModuleSystem ? 'ddc' : 'amd', soundNullSafety ? '--sound-null-safety' : '--no-sound-null-safety', 'dart:core', '-o', diff --git a/test_common/lib/test_sdk_configuration.dart b/test_common/lib/test_sdk_configuration.dart index 03a321204..3086155af 100644 --- a/test_common/lib/test_sdk_configuration.dart +++ b/test_common/lib/test_sdk_configuration.dart @@ -25,6 +25,7 @@ class TestSdkConfigurationProvider extends SdkConfigurationProvider { final bool _verbose; final bool canaryFeatures; + final bool ddcModuleSystem; late final Directory _sdkDirectory; SdkConfiguration? _configuration; @@ -33,9 +34,13 @@ class TestSdkConfigurationProvider extends SdkConfigurationProvider { TestSdkConfigurationProvider({ this.canaryFeatures = false, bool verbose = false, + this.ddcModuleSystem = false, }) : _verbose = verbose { _sdkDirectory = Directory.systemTemp.createTempSync('sdk copy'); - sdkLayout = TestSdkLayout.createDefault(_sdkDirectory.path); + sdkLayout = TestSdkLayout.createDefault( + _sdkDirectory.path, + ddcModuleSystem: ddcModuleSystem, + ); } @override @@ -62,6 +67,7 @@ class TestSdkConfigurationProvider extends SdkConfigurationProvider { sdkLayout: sdkLayout, canaryFeatures: canaryFeatures, verbose: _verbose, + ddcModuleSystem: ddcModuleSystem, ); await assetGenerator.generateSdkAssets(); diff --git a/test_common/lib/test_sdk_layout.dart b/test_common/lib/test_sdk_layout.dart index 072bd3f1f..d3759f233 100644 --- a/test_common/lib/test_sdk_layout.dart +++ b/test_common/lib/test_sdk_layout.dart @@ -14,102 +14,98 @@ import 'package:path/path.dart' as p; class TestSdkLayout { static final defaultSdkDirectory = SdkLayout.defaultSdkDirectory; static TestSdkLayout defaultSdkLayout = - TestSdkLayout.createDefault(defaultSdkDirectory); + TestSdkLayout.createDefault(defaultSdkDirectory, ddcModuleSystem: false); + static TestSdkLayout defaultDdcSdkLayout = + TestSdkLayout.createDefault(defaultSdkDirectory, ddcModuleSystem: true); static SdkConfiguration defaultSdkConfiguration = createConfiguration(defaultSdkLayout); + static SdkConfiguration defaultDdcSdkConfiguration = + createConfiguration(defaultDdcSdkLayout); - factory TestSdkLayout.createDefault(String sdkDirectory) => + factory TestSdkLayout.createDefault(String sdkDirectory, + {required bool ddcModuleSystem}) => TestSdkLayout.createDefaultFromSdkLayout( - SdkLayout.createDefault(sdkDirectory)); - - factory TestSdkLayout.createDefaultFromSdkLayout(SdkLayout sdkLayout) => - TestSdkLayout( - sdkDirectory: sdkLayout.sdkDirectory, - soundSummaryPath: sdkLayout.soundSummaryPath, - soundFullDillPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - '_internal', - 'ddc_platform.dill', - ), - soundJsPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'kernel', - 'amd', - 'dart_sdk.js', - ), - soundJsMapPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'kernel', - 'amd', - 'dart_sdk.js.map', - ), - weakSummaryPath: sdkLayout.weakSummaryPath, - weakFullDillPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - '_internal', - 'ddc_platform_unsound.dill', - ), - weakJsPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'kernel', - 'amd', - 'dart_sdk_unsound.js', - ), - weakJsMapPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'kernel', - 'amd', - 'dart_sdk_unsound.js.map', - ), - requireJsPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'amd', - 'require.js', - ), - stackTraceMapperPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'web', - 'dart_stack_trace_mapper.js', - ), - dartPath: p.join( - sdkLayout.sdkDirectory, - 'bin', - Platform.isWindows ? 'dart.exe' : 'dart', - ), - frontendServerSnapshotPath: p.join( - sdkLayout.sdkDirectory, - 'bin', - 'snapshots', - 'frontend_server.dart.snapshot', - ), - dartdevcSnapshotPath: sdkLayout.dartdevcSnapshotPath, - kernelWorkerSnapshotPath: p.join( - sdkLayout.sdkDirectory, - 'bin', - 'snapshots', - 'kernel_worker.dart.snapshot', - ), - devToolsDirectory: p.join( - sdkLayout.sdkDirectory, - 'bin', - 'resources', - 'devtools', - ), - ); + SdkLayout.createDefault(sdkDirectory), + ddcModuleSystem: ddcModuleSystem); + + factory TestSdkLayout.createDefaultFromSdkLayout(SdkLayout sdkLayout, + {required bool ddcModuleSystem}) { + final sdkPathSegment = ddcModuleSystem ? 'legacy' : 'amd'; + return TestSdkLayout( + sdkDirectory: sdkLayout.sdkDirectory, + soundSummaryPath: sdkLayout.soundSummaryPath, + soundFullDillPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + '_internal', + 'ddc_platform.dill', + ), + soundJsPath: p.join(sdkLayout.sdkDirectory, + '../gen/utils/ddc/stable/sdk/$sdkPathSegment/dart_sdk.js'), + soundJsMapPath: p.join(sdkLayout.sdkDirectory, + '../gen/utils/ddc/stable/sdk/$sdkPathSegment/dart_sdk.js.map'), + weakSummaryPath: sdkLayout.weakSummaryPath, + weakFullDillPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + '_internal', + 'ddc_platform_unsound.dill', + ), + weakJsPath: p.join(sdkLayout.sdkDirectory, + '../gen/utils/ddc/stable_unsound/sdk/$sdkPathSegment/dart_sdk.js'), + weakJsMapPath: p.join(sdkLayout.sdkDirectory, + '../gen/utils/ddc/stable_unsound/sdk/$sdkPathSegment/dart_sdk.js.map'), + ddcModuleLoaderJsPath: ddcModuleSystem + ? p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'ddc', + 'ddc_module_loader.js', + ) + : '', + requireJsPath: ddcModuleSystem + ? '' + : p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'amd', + 'require.js', + ), + stackTraceMapperPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'web', + 'dart_stack_trace_mapper.js', + ), + dartPath: p.join( + sdkLayout.sdkDirectory, + 'bin', + Platform.isWindows ? 'dart.exe' : 'dart', + ), + frontendServerSnapshotPath: p.join( + sdkLayout.sdkDirectory, + 'bin', + 'snapshots', + 'frontend_server.dart.snapshot', + ), + dartdevcSnapshotPath: sdkLayout.dartdevcSnapshotPath, + kernelWorkerSnapshotPath: p.join( + sdkLayout.sdkDirectory, + 'bin', + 'snapshots', + 'kernel_worker.dart.snapshot', + ), + devToolsDirectory: p.join( + sdkLayout.sdkDirectory, + 'bin', + 'resources', + 'devtools', + ), + ); + } final String sdkDirectory; @@ -133,6 +129,7 @@ class TestSdkLayout { final String weakSummaryPath; final String weakFullDillPath; + final String ddcModuleLoaderJsPath; final String requireJsPath; final String stackTraceMapperPath; @@ -152,6 +149,7 @@ class TestSdkLayout { required this.weakJsMapPath, required this.weakSummaryPath, required this.weakFullDillPath, + required this.ddcModuleLoaderJsPath, required this.requireJsPath, required this.stackTraceMapperPath, required this.dartPath, diff --git a/test_common/test/sdk_asset_generator_test.dart b/test_common/test/sdk_asset_generator_test.dart index fcbcfa3b5..254c92cf5 100644 --- a/test_common/test/sdk_asset_generator_test.dart +++ b/test_common/test/sdk_asset_generator_test.dart @@ -37,7 +37,8 @@ void main() { tempDir = Directory.systemTemp.createTempSync(); sdkDirectory = tempDir.path; - final copySdkLayout = TestSdkLayout.createDefault(sdkDirectory); + final copySdkLayout = + TestSdkLayout.createDefault(sdkDirectory, ddcModuleSystem: false); soundSdkSummaryPath = copySdkLayout.soundSummaryPath; compilerWorkerPath = copySdkLayout.dartdevcSnapshotPath; @@ -72,13 +73,15 @@ void main() { test('Can generate missing SDK assets and validate SDK configuration', () async { - final sdkLayout = TestSdkLayout.createDefault(sdkDirectory); + final sdkLayout = + TestSdkLayout.createDefault(sdkDirectory, ddcModuleSystem: false); final configuration = TestSdkLayout.createConfiguration(sdkLayout); final assetGenerator = SdkAssetGenerator( sdkLayout: sdkLayout, verbose: true, canaryFeatures: false, + ddcModuleSystem: false, ); await assetGenerator.generateSdkAssets(); @@ -114,12 +117,14 @@ void main() { test('Can generate missing SDK assets with canary features enabled', () async { - final sdkLayout = TestSdkLayout.createDefault(sdkDirectory); + final sdkLayout = + TestSdkLayout.createDefault(sdkDirectory, ddcModuleSystem: false); final assetGenerator = SdkAssetGenerator( sdkLayout: sdkLayout, verbose: true, canaryFeatures: true, + ddcModuleSystem: false, ); await assetGenerator.generateSdkAssets(); From 6a01aade24f1daa05b8eaf7cb292954c179948a7 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Thu, 30 Nov 2023 22:41:36 -0800 Subject: [PATCH 03/22] updating changelog --- dwds/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md index 77f341200..82e28bf9a 100644 --- a/dwds/CHANGELOG.md +++ b/dwds/CHANGELOG.md @@ -2,6 +2,7 @@ - Restructure `LoadStrategy` to provide build settings. - [#2270](https://github.com/dart-lang/webdev/pull/2270) - Add `FrontendServerLegacyStrategyProvider` and update bootstrap generation logic for `LegacyStrategy` - [#2285](https://github.com/dart-lang/webdev/pull/2285) - Tolerate failures to detect a dart execution context. - [#2286](https://github.com/dart-lang/webdev/pull/2286) +- Enabling tests that run with the DDC module system. - [#2295](https://github.com/dart-lang/webdev/pull/2295) ## 22.1.0 - Update `package:vm_service` constraint to `^13.0.0`. - [#2265](https://github.com/dart-lang/webdev/pull/2265) From 188a5ae34960adbecf74242a08ae9532e5c43bf5 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Mon, 4 Dec 2023 14:44:56 -0800 Subject: [PATCH 04/22] Restructuring asset bundling and flags --- .../lib/src/services/expression_compiler.dart | 1 + .../lib/src/asset_server.dart | 5 +- frontend_server_common/lib/src/devfs.dart | 13 +- test_common/lib/test_sdk_configuration.dart | 7 +- test_common/lib/test_sdk_layout.dart | 114 +++++++++++++----- .../test/sdk_asset_generator_test.dart | 9 +- 6 files changed, 105 insertions(+), 44 deletions(-) diff --git a/dwds/lib/src/services/expression_compiler.dart b/dwds/lib/src/services/expression_compiler.dart index 8534eb5b4..933b68d33 100644 --- a/dwds/lib/src/services/expression_compiler.dart +++ b/dwds/lib/src/services/expression_compiler.dart @@ -16,6 +16,7 @@ class CompilerOptions { required this.experiments, }); + // TODO(markzipan): Remove this after DDC migrates to a single module system. bool get usesDDCModuleSystem => moduleFormat == 'ddc' || moduleFormat == 'legacy'; } diff --git a/frontend_server_common/lib/src/asset_server.dart b/frontend_server_common/lib/src/asset_server.dart index 3729296ea..534bd3f3d 100644 --- a/frontend_server_common/lib/src/asset_server.dart +++ b/frontend_server_common/lib/src/asset_server.dart @@ -75,8 +75,9 @@ class TestAssetServer implements AssetReader { ) async { final address = (await InternetAddress.lookup(hostname)).first; final httpServer = await HttpServer.bind(address, port); - final sdkLayout = TestSdkLayout.createDefault(sdkDirectory, - ddcModuleSystem: ddcModuleSystem); + final sdkLayout = ddcModuleSystem + ? TestSdkLayout.createDdcDefault(sdkDirectory) + : TestSdkLayout.createDefault(sdkDirectory); final server = TestAssetServer( index, httpServer, packageUriMapper, address, fileSystem, sdkLayout); return server; diff --git a/frontend_server_common/lib/src/devfs.dart b/frontend_server_common/lib/src/devfs.dart index 05852f7b5..a8fac2de7 100644 --- a/frontend_server_common/lib/src/devfs.dart +++ b/frontend_server_common/lib/src/devfs.dart @@ -80,7 +80,6 @@ class WebDevFS { var stackMapper = 'stack_trace_mapper.js'; var main = 'main.dart.js'; var bootstrap = 'main_module.bootstrap.js'; - var dartSdkName = 'dart_sdk.js'; // If base path is not overwritten, use main's subdirectory // to store all files, so the paths match the requests. @@ -112,11 +111,15 @@ class WebDevFS { bootstrapUrl: bootstrap, ), ); + + // DDC uses a simple heuristic to determine exported identifier names. + // The module name (entrypoint name here) has its extension removed, and + // special path elements like '/', '\', and '..' are replaced with '__'. + final exportedMainName = pathToJSIdentifier(entryPoint.split('.')[0]); assetServer.writeFile( bootstrap, generateDDCMainModule( - entrypoint: entryPoint, - exportedMain: pathToJSIdentifier(entryPoint.split('.')[0])), + entrypoint: entryPoint, exportedMain: exportedMainName), ); } else { assetServer.writeFile( @@ -140,8 +143,8 @@ class WebDevFS { var sdk = soundNullSafety ? dartSdk : dartSdkWeak; var sdkSourceMap = soundNullSafety ? dartSdkSourcemap : dartSdkSourcemapWeak; - assetServer.writeFile(dartSdkName, sdk.readAsStringSync()); - assetServer.writeFile('$dartSdkName.map', sdkSourceMap.readAsStringSync()); + assetServer.writeFile('dart_sdk.js', sdk.readAsStringSync()); + assetServer.writeFile('dart_sdk.js.map', sdkSourceMap.readAsStringSync()); generator.reset(); var compilerOutput = await generator.recompile( diff --git a/test_common/lib/test_sdk_configuration.dart b/test_common/lib/test_sdk_configuration.dart index 3086155af..4638d646f 100644 --- a/test_common/lib/test_sdk_configuration.dart +++ b/test_common/lib/test_sdk_configuration.dart @@ -37,10 +37,9 @@ class TestSdkConfigurationProvider extends SdkConfigurationProvider { this.ddcModuleSystem = false, }) : _verbose = verbose { _sdkDirectory = Directory.systemTemp.createTempSync('sdk copy'); - sdkLayout = TestSdkLayout.createDefault( - _sdkDirectory.path, - ddcModuleSystem: ddcModuleSystem, - ); + sdkLayout = this.ddcModuleSystem + ? TestSdkLayout.createDdcDefault(_sdkDirectory.path) + : TestSdkLayout.createDefault(_sdkDirectory.path); } @override diff --git a/test_common/lib/test_sdk_layout.dart b/test_common/lib/test_sdk_layout.dart index d3759f233..9cb4dd4dd 100644 --- a/test_common/lib/test_sdk_layout.dart +++ b/test_common/lib/test_sdk_layout.dart @@ -13,24 +13,94 @@ import 'package:path/path.dart' as p; /// We keep all the path constants in one place for ease of update. class TestSdkLayout { static final defaultSdkDirectory = SdkLayout.defaultSdkDirectory; + static TestSdkLayout defaultSdkLayout = - TestSdkLayout.createDefault(defaultSdkDirectory, ddcModuleSystem: false); + TestSdkLayout.createDefault(defaultSdkDirectory); static TestSdkLayout defaultDdcSdkLayout = - TestSdkLayout.createDefault(defaultSdkDirectory, ddcModuleSystem: true); + TestSdkLayout.createDdcDefault(defaultSdkDirectory); + static SdkConfiguration defaultSdkConfiguration = createConfiguration(defaultSdkLayout); static SdkConfiguration defaultDdcSdkConfiguration = createConfiguration(defaultDdcSdkLayout); - factory TestSdkLayout.createDefault(String sdkDirectory, - {required bool ddcModuleSystem}) => + factory TestSdkLayout.createDefault(String sdkDirectory) => TestSdkLayout.createDefaultFromSdkLayout( - SdkLayout.createDefault(sdkDirectory), - ddcModuleSystem: ddcModuleSystem); + SdkLayout.createDefault(sdkDirectory)); + + factory TestSdkLayout.createDdcDefault(String sdkDirectory) => + TestSdkLayout.createDdcDefaultFromSdkLayout( + SdkLayout.createDefault(sdkDirectory)); - factory TestSdkLayout.createDefaultFromSdkLayout(SdkLayout sdkLayout, - {required bool ddcModuleSystem}) { - final sdkPathSegment = ddcModuleSystem ? 'legacy' : 'amd'; + factory TestSdkLayout.createDefaultFromSdkLayout(SdkLayout sdkLayout) { + return TestSdkLayout( + sdkDirectory: sdkLayout.sdkDirectory, + soundSummaryPath: sdkLayout.soundSummaryPath, + soundFullDillPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + '_internal', + 'ddc_platform.dill', + ), + soundJsPath: p.join(sdkLayout.sdkDirectory, + '../gen/utils/ddc/stable/sdk/amd/dart_sdk.js'), + soundJsMapPath: p.join(sdkLayout.sdkDirectory, + '../gen/utils/ddc/stable/sdk/amd/dart_sdk.js.map'), + weakSummaryPath: sdkLayout.weakSummaryPath, + weakFullDillPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + '_internal', + 'ddc_platform_unsound.dill', + ), + weakJsPath: p.join(sdkLayout.sdkDirectory, + '../gen/utils/ddc/stable_unsound/sdk/amd/dart_sdk.js'), + weakJsMapPath: p.join(sdkLayout.sdkDirectory, + '../gen/utils/ddc/stable_unsound/sdk/amd/dart_sdk.js.map'), + ddcModuleLoaderJsPath: '', + requireJsPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'amd', + 'require.js', + ), + stackTraceMapperPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'web', + 'dart_stack_trace_mapper.js', + ), + dartPath: p.join( + sdkLayout.sdkDirectory, + 'bin', + Platform.isWindows ? 'dart.exe' : 'dart', + ), + frontendServerSnapshotPath: p.join( + sdkLayout.sdkDirectory, + 'bin', + 'snapshots', + 'frontend_server.dart.snapshot', + ), + dartdevcSnapshotPath: sdkLayout.dartdevcSnapshotPath, + kernelWorkerSnapshotPath: p.join( + sdkLayout.sdkDirectory, + 'bin', + 'snapshots', + 'kernel_worker.dart.snapshot', + ), + devToolsDirectory: p.join( + sdkLayout.sdkDirectory, + 'bin', + 'resources', + 'devtools', + ), + ); + } + + factory TestSdkLayout.createDdcDefaultFromSdkLayout(SdkLayout sdkLayout) { + final sdkPathSegment = 'legacy'; return TestSdkLayout( sdkDirectory: sdkLayout.sdkDirectory, soundSummaryPath: sdkLayout.soundSummaryPath, @@ -55,24 +125,14 @@ class TestSdkLayout { '../gen/utils/ddc/stable_unsound/sdk/$sdkPathSegment/dart_sdk.js'), weakJsMapPath: p.join(sdkLayout.sdkDirectory, '../gen/utils/ddc/stable_unsound/sdk/$sdkPathSegment/dart_sdk.js.map'), - ddcModuleLoaderJsPath: ddcModuleSystem - ? p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'ddc', - 'ddc_module_loader.js', - ) - : '', - requireJsPath: ddcModuleSystem - ? '' - : p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'amd', - 'require.js', - ), + ddcModuleLoaderJsPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'ddc', + 'ddc_module_loader.js', + ), + requireJsPath: '', stackTraceMapperPath: p.join( sdkLayout.sdkDirectory, 'lib', diff --git a/test_common/test/sdk_asset_generator_test.dart b/test_common/test/sdk_asset_generator_test.dart index 254c92cf5..51987b851 100644 --- a/test_common/test/sdk_asset_generator_test.dart +++ b/test_common/test/sdk_asset_generator_test.dart @@ -37,8 +37,7 @@ void main() { tempDir = Directory.systemTemp.createTempSync(); sdkDirectory = tempDir.path; - final copySdkLayout = - TestSdkLayout.createDefault(sdkDirectory, ddcModuleSystem: false); + final copySdkLayout = TestSdkLayout.createDefault(sdkDirectory); soundSdkSummaryPath = copySdkLayout.soundSummaryPath; compilerWorkerPath = copySdkLayout.dartdevcSnapshotPath; @@ -73,8 +72,7 @@ void main() { test('Can generate missing SDK assets and validate SDK configuration', () async { - final sdkLayout = - TestSdkLayout.createDefault(sdkDirectory, ddcModuleSystem: false); + final sdkLayout = TestSdkLayout.createDefault(sdkDirectory); final configuration = TestSdkLayout.createConfiguration(sdkLayout); final assetGenerator = SdkAssetGenerator( @@ -117,8 +115,7 @@ void main() { test('Can generate missing SDK assets with canary features enabled', () async { - final sdkLayout = - TestSdkLayout.createDefault(sdkDirectory, ddcModuleSystem: false); + final sdkLayout = TestSdkLayout.createDefault(sdkDirectory); final assetGenerator = SdkAssetGenerator( sdkLayout: sdkLayout, From c05574815e2dfa20c42339154844b5d3f0a18860 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Mon, 4 Dec 2023 14:44:56 -0800 Subject: [PATCH 05/22] Restructuring asset bundling and flags --- test_common/lib/test_sdk_configuration.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_common/lib/test_sdk_configuration.dart b/test_common/lib/test_sdk_configuration.dart index 4638d646f..2ccc297a3 100644 --- a/test_common/lib/test_sdk_configuration.dart +++ b/test_common/lib/test_sdk_configuration.dart @@ -37,7 +37,7 @@ class TestSdkConfigurationProvider extends SdkConfigurationProvider { this.ddcModuleSystem = false, }) : _verbose = verbose { _sdkDirectory = Directory.systemTemp.createTempSync('sdk copy'); - sdkLayout = this.ddcModuleSystem + sdkLayout = ddcModuleSystem ? TestSdkLayout.createDdcDefault(_sdkDirectory.path) : TestSdkLayout.createDefault(_sdkDirectory.path); } From cc66e55917a8ab722f34d6daa3873dd233f03ad5 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Mon, 4 Dec 2023 16:08:59 -0800 Subject: [PATCH 06/22] Updating test sdk paths --- test_common/lib/test_sdk_layout.dart | 311 +++++++++++++++------------ 1 file changed, 178 insertions(+), 133 deletions(-) diff --git a/test_common/lib/test_sdk_layout.dart b/test_common/lib/test_sdk_layout.dart index 9cb4dd4dd..b70cffe32 100644 --- a/test_common/lib/test_sdk_layout.dart +++ b/test_common/lib/test_sdk_layout.dart @@ -32,140 +32,185 @@ class TestSdkLayout { TestSdkLayout.createDdcDefaultFromSdkLayout( SdkLayout.createDefault(sdkDirectory)); - factory TestSdkLayout.createDefaultFromSdkLayout(SdkLayout sdkLayout) { - return TestSdkLayout( - sdkDirectory: sdkLayout.sdkDirectory, - soundSummaryPath: sdkLayout.soundSummaryPath, - soundFullDillPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - '_internal', - 'ddc_platform.dill', - ), - soundJsPath: p.join(sdkLayout.sdkDirectory, - '../gen/utils/ddc/stable/sdk/amd/dart_sdk.js'), - soundJsMapPath: p.join(sdkLayout.sdkDirectory, - '../gen/utils/ddc/stable/sdk/amd/dart_sdk.js.map'), - weakSummaryPath: sdkLayout.weakSummaryPath, - weakFullDillPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - '_internal', - 'ddc_platform_unsound.dill', - ), - weakJsPath: p.join(sdkLayout.sdkDirectory, - '../gen/utils/ddc/stable_unsound/sdk/amd/dart_sdk.js'), - weakJsMapPath: p.join(sdkLayout.sdkDirectory, - '../gen/utils/ddc/stable_unsound/sdk/amd/dart_sdk.js.map'), - ddcModuleLoaderJsPath: '', - requireJsPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'amd', - 'require.js', - ), - stackTraceMapperPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'web', - 'dart_stack_trace_mapper.js', - ), - dartPath: p.join( - sdkLayout.sdkDirectory, - 'bin', - Platform.isWindows ? 'dart.exe' : 'dart', - ), - frontendServerSnapshotPath: p.join( - sdkLayout.sdkDirectory, - 'bin', - 'snapshots', - 'frontend_server.dart.snapshot', - ), - dartdevcSnapshotPath: sdkLayout.dartdevcSnapshotPath, - kernelWorkerSnapshotPath: p.join( - sdkLayout.sdkDirectory, - 'bin', - 'snapshots', - 'kernel_worker.dart.snapshot', - ), - devToolsDirectory: p.join( - sdkLayout.sdkDirectory, - 'bin', - 'resources', - 'devtools', - ), - ); - } + factory TestSdkLayout.createDefaultFromSdkLayout(SdkLayout sdkLayout) => + TestSdkLayout( + sdkDirectory: sdkLayout.sdkDirectory, + soundSummaryPath: sdkLayout.soundSummaryPath, + soundFullDillPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + '_internal', + 'ddc_platform.dill', + ), + soundJsPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'kernel', + 'amd', + 'dart_sdk.js', + ), + soundJsMapPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'kernel', + 'amd', + 'dart_sdk.js.map', + ), + weakSummaryPath: sdkLayout.weakSummaryPath, + weakFullDillPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + '_internal', + 'ddc_platform_unsound.dill', + ), + weakJsPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'kernel', + 'amd', + 'dart_sdk_unsound.js', + ), + weakJsMapPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'kernel', + 'amd', + 'dart_sdk_unsound.js.map', + ), + ddcModuleLoaderJsPath: '', + requireJsPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'amd', + 'require.js', + ), + stackTraceMapperPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'web', + 'dart_stack_trace_mapper.js', + ), + dartPath: p.join( + sdkLayout.sdkDirectory, + 'bin', + Platform.isWindows ? 'dart.exe' : 'dart', + ), + frontendServerSnapshotPath: p.join( + sdkLayout.sdkDirectory, + 'bin', + 'snapshots', + 'frontend_server.dart.snapshot', + ), + dartdevcSnapshotPath: sdkLayout.dartdevcSnapshotPath, + kernelWorkerSnapshotPath: p.join( + sdkLayout.sdkDirectory, + 'bin', + 'snapshots', + 'kernel_worker.dart.snapshot', + ), + devToolsDirectory: p.join( + sdkLayout.sdkDirectory, + 'bin', + 'resources', + 'devtools', + ), + ); - factory TestSdkLayout.createDdcDefaultFromSdkLayout(SdkLayout sdkLayout) { - final sdkPathSegment = 'legacy'; - return TestSdkLayout( - sdkDirectory: sdkLayout.sdkDirectory, - soundSummaryPath: sdkLayout.soundSummaryPath, - soundFullDillPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - '_internal', - 'ddc_platform.dill', - ), - soundJsPath: p.join(sdkLayout.sdkDirectory, - '../gen/utils/ddc/stable/sdk/$sdkPathSegment/dart_sdk.js'), - soundJsMapPath: p.join(sdkLayout.sdkDirectory, - '../gen/utils/ddc/stable/sdk/$sdkPathSegment/dart_sdk.js.map'), - weakSummaryPath: sdkLayout.weakSummaryPath, - weakFullDillPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - '_internal', - 'ddc_platform_unsound.dill', - ), - weakJsPath: p.join(sdkLayout.sdkDirectory, - '../gen/utils/ddc/stable_unsound/sdk/$sdkPathSegment/dart_sdk.js'), - weakJsMapPath: p.join(sdkLayout.sdkDirectory, - '../gen/utils/ddc/stable_unsound/sdk/$sdkPathSegment/dart_sdk.js.map'), - ddcModuleLoaderJsPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'ddc', - 'ddc_module_loader.js', - ), - requireJsPath: '', - stackTraceMapperPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'web', - 'dart_stack_trace_mapper.js', - ), - dartPath: p.join( - sdkLayout.sdkDirectory, - 'bin', - Platform.isWindows ? 'dart.exe' : 'dart', - ), - frontendServerSnapshotPath: p.join( - sdkLayout.sdkDirectory, - 'bin', - 'snapshots', - 'frontend_server.dart.snapshot', - ), - dartdevcSnapshotPath: sdkLayout.dartdevcSnapshotPath, - kernelWorkerSnapshotPath: p.join( - sdkLayout.sdkDirectory, - 'bin', - 'snapshots', - 'kernel_worker.dart.snapshot', - ), - devToolsDirectory: p.join( - sdkLayout.sdkDirectory, - 'bin', - 'resources', - 'devtools', - ), - ); - } + factory TestSdkLayout.createDdcDefaultFromSdkLayout(SdkLayout sdkLayout) => + TestSdkLayout( + sdkDirectory: sdkLayout.sdkDirectory, + soundSummaryPath: sdkLayout.soundSummaryPath, + soundFullDillPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + '_internal', + 'ddc_platform.dill', + ), + soundJsPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'kernel', + 'ddc', + 'dart_sdk.js', + ), + soundJsMapPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'kernel', + 'ddc', + 'dart_sdk.js.map', + ), + weakSummaryPath: sdkLayout.weakSummaryPath, + weakFullDillPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + '_internal', + 'ddc_platform_unsound.dill', + ), + weakJsPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'kernel', + 'ddc', + 'dart_sdk_unsound.js', + ), + weakJsMapPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'kernel', + 'ddc', + 'dart_sdk_unsound.js.map', + ), + ddcModuleLoaderJsPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'ddc', + 'ddc_module_loader.js', + ), + requireJsPath: '', + stackTraceMapperPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'web', + 'dart_stack_trace_mapper.js', + ), + dartPath: p.join( + sdkLayout.sdkDirectory, + 'bin', + Platform.isWindows ? 'dart.exe' : 'dart', + ), + frontendServerSnapshotPath: p.join( + sdkLayout.sdkDirectory, + 'bin', + 'snapshots', + 'frontend_server.dart.snapshot', + ), + dartdevcSnapshotPath: sdkLayout.dartdevcSnapshotPath, + kernelWorkerSnapshotPath: p.join( + sdkLayout.sdkDirectory, + 'bin', + 'snapshots', + 'kernel_worker.dart.snapshot', + ), + devToolsDirectory: p.join( + sdkLayout.sdkDirectory, + 'bin', + 'resources', + 'devtools', + ), + ); final String sdkDirectory; From e37da6bfa46ac731d0c13f8ce37b7daa2b90f3cb Mon Sep 17 00:00:00 2001 From: MarkZ Date: Wed, 6 Dec 2023 16:35:22 -0800 Subject: [PATCH 07/22] Moving the module format specifier to an enum and unioning static assets across module formats --- dwds/lib/expression_compiler.dart | 1 + .../src/services/chrome_proxy_service.dart | 2 +- .../lib/src/services/expression_compiler.dart | 9 +- .../services/expression_compiler_service.dart | 2 +- dwds/test/evaluate_common.dart | 2 + dwds/test/fixtures/context.dart | 107 +++---------- dwds/test/fixtures/utilities.dart | 4 +- ...ontend_server_ddc_evaluate_sound_test.dart | 9 +- .../lib/src/asset_server.dart | 5 +- frontend_server_common/lib/src/devfs.dart | 114 ++++++++------ .../lib/src/frontend_server_client.dart | 3 +- .../lib/src/resident_runner.dart | 2 +- test_common/lib/sdk_asset_generator.dart | 46 ++++-- test_common/lib/test_sdk_configuration.dart | 11 +- test_common/lib/test_sdk_layout.dart | 148 ++++++------------ .../test/sdk_asset_generator_test.dart | 29 ++-- 16 files changed, 214 insertions(+), 280 deletions(-) diff --git a/dwds/lib/expression_compiler.dart b/dwds/lib/expression_compiler.dart index 19283a719..674841406 100644 --- a/dwds/lib/expression_compiler.dart +++ b/dwds/lib/expression_compiler.dart @@ -7,4 +7,5 @@ export 'src/services/expression_compiler.dart' ExpressionCompilationResult, ExpressionCompiler, CompilerOptions, + ModuleFormat, ModuleInfo; diff --git a/dwds/lib/src/services/chrome_proxy_service.dart b/dwds/lib/src/services/chrome_proxy_service.dart index 913db0f5b..4837f4e63 100644 --- a/dwds/lib/src/services/chrome_proxy_service.dart +++ b/dwds/lib/src/services/chrome_proxy_service.dart @@ -187,7 +187,7 @@ class ChromeProxyService implements VmServiceInterface { 'with sound null safety: $soundNullSafety'); final compilerOptions = CompilerOptions( - moduleFormat: moduleFormat, + moduleFormat: ModuleFormat.values.byName(moduleFormat), soundNullSafety: soundNullSafety, canaryFeatures: canaryFeatures, experiments: experiments, diff --git a/dwds/lib/src/services/expression_compiler.dart b/dwds/lib/src/services/expression_compiler.dart index 933b68d33..7cbf262ac 100644 --- a/dwds/lib/src/services/expression_compiler.dart +++ b/dwds/lib/src/services/expression_compiler.dart @@ -4,7 +4,7 @@ /// Options passed to DDC and the expression compiler. class CompilerOptions { - final String moduleFormat; + final ModuleFormat moduleFormat; final bool soundNullSafety; final bool canaryFeatures; final List experiments; @@ -15,12 +15,11 @@ class CompilerOptions { required this.canaryFeatures, required this.experiments, }); - - // TODO(markzipan): Remove this after DDC migrates to a single module system. - bool get usesDDCModuleSystem => - moduleFormat == 'ddc' || moduleFormat == 'legacy'; } +// Indicates the module system DDC is targeting. +enum ModuleFormat { amd, ddc, es6 } + /// Result of compilation of dart expression to JavaScript class ExpressionCompilationResult { final bool isError; diff --git a/dwds/lib/src/services/expression_compiler_service.dart b/dwds/lib/src/services/expression_compiler_service.dart index 36a51f4d6..4865cb1d3 100644 --- a/dwds/lib/src/services/expression_compiler_service.dart +++ b/dwds/lib/src/services/expression_compiler_service.dart @@ -89,7 +89,7 @@ class _Compiler { '--asset-server-port', '$port', '--module-format', - compilerOptions.moduleFormat, + compilerOptions.moduleFormat.name, if (verbose) '--verbose', compilerOptions.soundNullSafety ? '--sound-null-safety' diff --git a/dwds/test/evaluate_common.dart b/dwds/test/evaluate_common.dart index 61025b5be..7c3c9c984 100644 --- a/dwds/test/evaluate_common.dart +++ b/dwds/test/evaluate_common.dart @@ -71,6 +71,7 @@ void testAll({ await context.setUp( testSettings: TestSettings( compilationMode: compilationMode, + moduleFormat: provider.ddcModuleFormat, enableExpressionEvaluation: true, useDebuggerModuleNames: useDebuggerModuleNames, verboseCompiler: debug, @@ -821,6 +822,7 @@ void testAll({ await context.setUp( testSettings: TestSettings( compilationMode: compilationMode, + moduleFormat: provider.ddcModuleFormat, enableExpressionEvaluation: false, verboseCompiler: debug, ), diff --git a/dwds/test/fixtures/context.dart b/dwds/test/fixtures/context.dart index d1c5abe1f..3d711cee4 100644 --- a/dwds/test/fixtures/context.dart +++ b/dwds/test/fixtures/context.dart @@ -10,7 +10,6 @@ import 'package:build_daemon/client.dart'; import 'package:build_daemon/data/build_status.dart'; import 'package:build_daemon/data/build_target.dart'; import 'package:dwds/asset_reader.dart'; -import 'package:dwds/expression_compiler.dart'; import 'package:dwds/src/connections/app_connection.dart'; import 'package:dwds/src/connections/debug_connection.dart'; import 'package:dwds/src/debugging/webkit_debugger.dart'; @@ -20,6 +19,7 @@ import 'package:dwds/src/loaders/frontend_server_require.dart'; import 'package:dwds/src/loaders/strategy.dart'; import 'package:dwds/src/readers/proxy_server_asset_reader.dart'; import 'package:dwds/src/services/chrome_proxy_service.dart'; +import 'package:dwds/src/services/expression_compiler.dart'; import 'package:dwds/src/services/expression_compiler_service.dart'; import 'package:dwds/src/utilities/dart_uri.dart'; import 'package:dwds/src/utilities/server.dart'; @@ -60,17 +60,7 @@ Matcher isRPCErrorWithCode(int code) => isA().having((e) => e.code, 'code', equals(code)); Matcher throwsRPCErrorWithCode(int code) => throwsA(isRPCErrorWithCode(code)); -enum CompilationMode { - buildDaemon, - // Uses DDC's AMD module system - frontendServer, - // Uses DDC's DDC/legacy module system - frontendServerDdc; - - bool get usesFrontendServer => - this == CompilationMode.frontendServer || - this == CompilationMode.frontendServerDdc; -} +enum CompilationMode { buildDaemon, frontendServer } class TestContext { final TestProject project; @@ -313,6 +303,7 @@ class TestContext { nullSafety: project.nullSafety, experiments: buildSettings.experiments, canaryFeatures: buildSettings.canaryFeatures, + moduleFormat: testSettings.moduleFormat, ); _webRunner = ResidentWebRunner( @@ -344,80 +335,24 @@ class TestContext { basePath = webRunner.devFS.assetServer.basePath; assetReader = webRunner.devFS.assetServer; _assetHandler = webRunner.devFS.assetServer.handleRequest; - loadStrategy = FrontendServerRequireStrategyProvider( - testSettings.reloadConfiguration, - assetReader, - packageUriMapper, - () async => {}, - buildSettings, - ).strategy; - - buildResults = const Stream.empty(); - } - break; - case CompilationMode.frontendServerDdc: - { - filePathToServe = webCompatiblePath([ - project.directoryToServe, - project.filePathToServe, - ]); - - _logger.info('Serving: $filePathToServe'); - - final entry = p.toUri( - p.join(project.webAssetsPath, project.dartEntryFileName), - ); - final fileSystem = LocalFileSystem(); - final packageUriMapper = await PackageUriMapper.create( - fileSystem, - project.packageConfigFile, - useDebuggerModuleNames: testSettings.useDebuggerModuleNames, - ); - - final compilerOptions = TestCompilerOptions( - nullSafety: project.nullSafety, - experiments: buildSettings.experiments, - canaryFeatures: buildSettings.canaryFeatures, - moduleFormat: 'ddc', - ); - - _webRunner = ResidentWebRunner( - mainUri: entry, - urlTunneler: debugSettings.urlEncoder, - projectDirectory: p.toUri(project.absolutePackageDirectory), - packageConfigFile: project.packageConfigFile, - packageUriMapper: packageUriMapper, - fileSystemRoots: [p.toUri(project.absolutePackageDirectory)], - fileSystemScheme: 'org-dartlang-app', - outputPath: outputDir.path, - compilerOptions: compilerOptions, - sdkLayout: sdkLayout, - verbose: testSettings.verboseCompiler, - ); - - final assetServerPort = await findUnusedPort(); - await webRunner.run( - fileSystem, - appMetadata.hostname, - assetServerPort, - filePathToServe, - ); - - if (testSettings.enableExpressionEvaluation) { - expressionCompiler = webRunner.expressionCompiler; - } - - basePath = webRunner.devFS.assetServer.basePath; - assetReader = webRunner.devFS.assetServer; - _assetHandler = webRunner.devFS.assetServer.handleRequest; - loadStrategy = FrontendServerLegacyStrategyProvider( - testSettings.reloadConfiguration, - assetReader, - packageUriMapper, - () async => {}, - buildSettings, - ).strategy; - + loadStrategy = switch (testSettings.moduleFormat) { + ModuleFormat.amd => FrontendServerRequireStrategyProvider( + testSettings.reloadConfiguration, + assetReader, + packageUriMapper, + () async => {}, + buildSettings, + ).strategy, + ModuleFormat.ddc => FrontendServerLegacyStrategyProvider( + testSettings.reloadConfiguration, + assetReader, + packageUriMapper, + () async => {}, + buildSettings, + ).strategy, + _ => throw Exception( + 'Unsupported DDC module format ${testSettings.moduleFormat}.') + }; buildResults = const Stream.empty(); } break; diff --git a/dwds/test/fixtures/utilities.dart b/dwds/test/fixtures/utilities.dart index 2ce5ee07b..45c508ac3 100644 --- a/dwds/test/fixtures/utilities.dart +++ b/dwds/test/fixtures/utilities.dart @@ -242,6 +242,7 @@ class TestSettings { // Build settings. final CompilationMode compilationMode; + final ModuleFormat moduleFormat; final bool canaryFeatures; final bool isFlutterApp; final List experiments; @@ -255,6 +256,7 @@ class TestSettings { this.verboseCompiler = false, this.launchChrome = true, this.compilationMode = CompilationMode.buildDaemon, + this.moduleFormat = ModuleFormat.amd, this.canaryFeatures = false, this.isFlutterApp = false, this.experiments = const [], @@ -296,7 +298,7 @@ class TestCompilerOptions extends CompilerOptions { required NullSafety nullSafety, required super.canaryFeatures, required List experiments, - super.moduleFormat = 'amd', + super.moduleFormat = ModuleFormat.amd, }) : super( soundNullSafety: nullSafety == NullSafety.sound, experiments: const [], diff --git a/dwds/test/frontend_server_ddc_evaluate_sound_test.dart b/dwds/test/frontend_server_ddc_evaluate_sound_test.dart index b237e326c..8506896e4 100644 --- a/dwds/test/frontend_server_ddc_evaluate_sound_test.dart +++ b/dwds/test/frontend_server_ddc_evaluate_sound_test.dart @@ -8,6 +8,7 @@ import 'dart:io'; +import 'package:dwds/expression_compiler.dart'; import 'package:test/test.dart'; import 'package:test_common/test_sdk_configuration.dart'; @@ -19,8 +20,10 @@ void main() async { // Enable verbose logging for debugging. final debug = false; - final provider = - TestSdkConfigurationProvider(verbose: debug, ddcModuleSystem: true); + final provider = TestSdkConfigurationProvider( + verbose: debug, + ddcModuleFormat: ModuleFormat.ddc, + ); tearDownAll(provider.dispose); for (var useDebuggerModuleNames in [false, true]) { @@ -33,7 +36,7 @@ void main() async { () { testAll( provider: provider, - compilationMode: CompilationMode.frontendServerDdc, + compilationMode: CompilationMode.frontendServer, indexBaseMode: indexBaseMode, nullSafety: nullSafety, useDebuggerModuleNames: useDebuggerModuleNames, diff --git a/frontend_server_common/lib/src/asset_server.dart b/frontend_server_common/lib/src/asset_server.dart index 534bd3f3d..b63b6e05e 100644 --- a/frontend_server_common/lib/src/asset_server.dart +++ b/frontend_server_common/lib/src/asset_server.dart @@ -71,13 +71,10 @@ class TestAssetServer implements AssetReader { int port, UrlEncoder? urlTunneler, PackageUriMapper packageUriMapper, - bool ddcModuleSystem, ) async { final address = (await InternetAddress.lookup(hostname)).first; final httpServer = await HttpServer.bind(address, port); - final sdkLayout = ddcModuleSystem - ? TestSdkLayout.createDdcDefault(sdkDirectory) - : TestSdkLayout.createDefault(sdkDirectory); + final sdkLayout = TestSdkLayout.createDefault(sdkDirectory); final server = TestAssetServer( index, httpServer, packageUriMapper, address, fileSystem, sdkLayout); return server; diff --git a/frontend_server_common/lib/src/devfs.dart b/frontend_server_common/lib/src/devfs.dart index a8fac2de7..51a8fed65 100644 --- a/frontend_server_common/lib/src/devfs.dart +++ b/frontend_server_common/lib/src/devfs.dart @@ -6,6 +6,7 @@ import 'package:dwds/asset_reader.dart'; import 'package:dwds/config.dart'; +import 'package:dwds/expression_compiler.dart'; import 'package:dwds/utilities.dart'; import 'package:file/file.dart'; import 'package:path/path.dart' as p; @@ -26,7 +27,7 @@ class WebDevFS { required this.soundNullSafety, this.urlTunneler, required this.sdkLayout, - required this.ddcModuleSystem, + required this.ddcModuleFormat, }); final FileSystem fileSystem; @@ -39,7 +40,7 @@ class WebDevFS { final UrlEncoder? urlTunneler; final bool soundNullSafety; final TestSdkLayout sdkLayout; - final bool ddcModuleSystem; + final ModuleFormat ddcModuleFormat; late final Directory _savedCurrentDirectory; Future create() async { @@ -55,7 +56,6 @@ class WebDevFS { port, urlTunneler, packageUriMapper, - ddcModuleSystem, ); return Uri.parse('http://$hostname:$port'); } @@ -94,48 +94,50 @@ class WebDevFS { assetServer.writeFile( entryPoint, fileSystem.file(mainPath).readAsStringSync()); - if (ddcModuleSystem) { - assetServer.writeFile( - ddcModuleLoader, ddcModuleLoaderJS.readAsStringSync()); - } else { - assetServer.writeFile(require, requireJS.readAsStringSync()); - } assetServer.writeFile(stackMapper, stackTraceMapper.readAsStringSync()); - if (ddcModuleSystem) { - assetServer.writeFile( - main, - generateDDCBootstrapScript( - ddcModuleLoaderUrl: ddcModuleLoader, - mapperUrl: stackMapper, - entrypoint: entryPoint, - bootstrapUrl: bootstrap, - ), - ); - - // DDC uses a simple heuristic to determine exported identifier names. - // The module name (entrypoint name here) has its extension removed, and - // special path elements like '/', '\', and '..' are replaced with '__'. - final exportedMainName = pathToJSIdentifier(entryPoint.split('.')[0]); - assetServer.writeFile( - bootstrap, - generateDDCMainModule( - entrypoint: entryPoint, exportedMain: exportedMainName), - ); - } else { - assetServer.writeFile( - main, - generateBootstrapScript( - requireUrl: 'require.js', - mapperUrl: 'stack_trace_mapper.js', - entrypoint: entryPoint, - ), - ); - assetServer.writeFile( - bootstrap, - generateMainModule( - entrypoint: entryPoint, - ), - ); + + switch (ddcModuleFormat) { + case ModuleFormat.amd: + assetServer.writeFile(require, requireJS.readAsStringSync()); + assetServer.writeFile( + main, + generateBootstrapScript( + requireUrl: 'require.js', + mapperUrl: 'stack_trace_mapper.js', + entrypoint: entryPoint, + ), + ); + assetServer.writeFile( + bootstrap, + generateMainModule( + entrypoint: entryPoint, + ), + ); + break; + case ModuleFormat.ddc: + assetServer.writeFile( + ddcModuleLoader, ddcModuleLoaderJS.readAsStringSync()); + assetServer.writeFile( + main, + generateDDCBootstrapScript( + ddcModuleLoaderUrl: ddcModuleLoader, + mapperUrl: stackMapper, + entrypoint: entryPoint, + bootstrapUrl: bootstrap, + ), + ); + // DDC uses a simple heuristic to determine exported identifier names. + // The module name (entrypoint name here) has its extension removed, and + // special path elements like '/', '\', and '..' are replaced with '__'. + final exportedMainName = pathToJSIdentifier(entryPoint.split('.')[0]); + assetServer.writeFile( + bootstrap, + generateDDCMainModule( + entrypoint: entryPoint, exportedMain: exportedMainName), + ); + break; + default: + throw Exception('Unsupported DDC module format $ddcModuleFormat.'); } assetServer.writeFile('main_module.digests', '{}'); @@ -187,10 +189,26 @@ class WebDevFS { File get ddcModuleLoaderJS => fileSystem.file(sdkLayout.ddcModuleLoaderJsPath); File get requireJS => fileSystem.file(sdkLayout.requireJsPath); - File get dartSdkWeak => fileSystem.file(sdkLayout.weakJsPath); - File get dartSdk => fileSystem.file(sdkLayout.soundJsPath); - File get dartSdkSourcemapWeak => fileSystem.file(sdkLayout.weakJsMapPath); - File get dartSdkSourcemap => fileSystem.file(sdkLayout.soundJsMapPath); + File get dartSdkWeak => fileSystem.file(switch (ddcModuleFormat) { + ModuleFormat.amd => sdkLayout.weakAmdJsPath, + ModuleFormat.ddc => sdkLayout.weakDdcJsPath, + _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.') + }); + File get dartSdk => fileSystem.file(switch (ddcModuleFormat) { + ModuleFormat.amd => sdkLayout.soundAmdJsPath, + ModuleFormat.ddc => sdkLayout.soundDdcJsPath, + _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.') + }); + File get dartSdkSourcemapWeak => fileSystem.file(switch (ddcModuleFormat) { + ModuleFormat.amd => sdkLayout.weakAmdJsMapPath, + ModuleFormat.ddc => sdkLayout.weakDdcJsMapPath, + _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.') + }); + File get dartSdkSourcemap => fileSystem.file(switch (ddcModuleFormat) { + ModuleFormat.amd => sdkLayout.soundAmdJsMapPath, + ModuleFormat.ddc => sdkLayout.soundDdcJsMapPath, + _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.') + }); File get stackTraceMapper => fileSystem.file(sdkLayout.stackTraceMapperPath); } diff --git a/frontend_server_common/lib/src/frontend_server_client.dart b/frontend_server_common/lib/src/frontend_server_client.dart index 1b6435290..eba9d2dbc 100644 --- a/frontend_server_common/lib/src/frontend_server_client.dart +++ b/frontend_server_common/lib/src/frontend_server_client.dart @@ -394,7 +394,8 @@ class ResidentCompiler { '--enable-experiment=$experiment', if (compilerOptions.canaryFeatures) '--dartdevc-canary', if (verbose) '--verbose', - if (compilerOptions.usesDDCModuleSystem) '--dartdevc-module-format=legacy' + if (compilerOptions.moduleFormat == ModuleFormat.ddc) + '--dartdevc-module-format=legacy' ]; _logger.info(args.join(' ')); diff --git a/frontend_server_common/lib/src/resident_runner.dart b/frontend_server_common/lib/src/resident_runner.dart index d32077450..f57954bbf 100644 --- a/frontend_server_common/lib/src/resident_runner.dart +++ b/frontend_server_common/lib/src/resident_runner.dart @@ -81,7 +81,7 @@ class ResidentWebRunner { urlTunneler: urlTunneler, soundNullSafety: compilerOptions.soundNullSafety, sdkLayout: sdkLayout, - ddcModuleSystem: compilerOptions.usesDDCModuleSystem, + ddcModuleFormat: compilerOptions.moduleFormat, ); uri = await devFS.create(); diff --git a/test_common/lib/sdk_asset_generator.dart b/test_common/lib/sdk_asset_generator.dart index cf7aa01cf..338279ef2 100644 --- a/test_common/lib/sdk_asset_generator.dart +++ b/test_common/lib/sdk_asset_generator.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:io'; +import 'package:dwds/expression_compiler.dart'; import 'package:file/file.dart'; import 'package:file/local.dart'; import 'package:logging/logging.dart'; @@ -18,7 +19,7 @@ class SdkAssetGenerator { final FileSystem fileSystem; final bool canaryFeatures; - final bool ddcModuleSystem; + final ModuleFormat ddcModuleFormat; final bool verbose; late final TestSdkLayout sdkLayout; @@ -27,7 +28,7 @@ class SdkAssetGenerator { this.fileSystem = const LocalFileSystem(), required this.sdkLayout, required this.canaryFeatures, - required this.ddcModuleSystem, + required this.ddcModuleFormat, this.verbose = false, }); @@ -61,10 +62,20 @@ class SdkAssetGenerator { Directory? outputDir; try { // Files to copy generated files to. - final outputJsPath = - soundNullSafety ? sdkLayout.soundJsPath : sdkLayout.weakJsPath; - final outputJsMapPath = - soundNullSafety ? sdkLayout.soundJsMapPath : sdkLayout.weakJsMapPath; + final outputJsPath = switch ((soundNullSafety, ddcModuleFormat)) { + (true, ModuleFormat.amd) => sdkLayout.soundAmdJsPath, + (false, ModuleFormat.amd) => sdkLayout.weakAmdJsPath, + (true, ModuleFormat.ddc) => sdkLayout.soundDdcJsPath, + (false, ModuleFormat.ddc) => sdkLayout.weakDdcJsPath, + _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.') + }; + final outputJsMapPath = switch ((soundNullSafety, ddcModuleFormat)) { + (true, ModuleFormat.amd) => sdkLayout.soundAmdJsMapPath, + (false, ModuleFormat.amd) => sdkLayout.weakAmdJsMapPath, + (true, ModuleFormat.ddc) => sdkLayout.soundDdcJsMapPath, + (false, ModuleFormat.ddc) => sdkLayout.weakDdcJsMapPath, + _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.') + }; final outputFullDillPath = soundNullSafety ? sdkLayout.soundFullDillPath : sdkLayout.weakFullDillPath; @@ -81,9 +92,17 @@ class SdkAssetGenerator { outputDir = fileSystem.systemTempDirectory.createTempSync(); // Files to generate - final jsPath = soundNullSafety - ? p.join(outputDir.path, sdkLayout.soundJsFileName) - : p.join(outputDir.path, sdkLayout.weakJsFileName); + final jsPath = switch ((soundNullSafety, ddcModuleFormat)) { + (true, ModuleFormat.amd) => + p.join(outputDir.path, sdkLayout.soundAmdJsFileName), + (false, ModuleFormat.amd) => + p.join(outputDir.path, sdkLayout.weakAmdJsFileName), + (true, ModuleFormat.ddc) => + p.join(outputDir.path, sdkLayout.soundDdcJsFileName), + (false, ModuleFormat.ddc) => + p.join(outputDir.path, sdkLayout.weakDdcJsFileName), + _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.') + }; final jsMapPath = p.setExtension(jsPath, '.js.map'); final fullDillPath = p.setExtension(jsPath, '.dill'); @@ -100,7 +119,7 @@ class SdkAssetGenerator { '--libraries-file', 'org-dartlang-sdk:///lib/libraries.json', '--modules', - ddcModuleSystem ? 'ddc' : 'amd', + ddcModuleFormat.name, soundNullSafety ? '--sound-null-safety' : '--no-sound-null-safety', 'dart:core', '-o', @@ -243,12 +262,17 @@ class SdkAssetGenerator { Future _moveAndValidate(String from, String to) async { _logger.fine('Renaming $from to $to'); + if (!_exists(from)) { + _logger.severe('Failed to generate SDK asset at $to'); + throw Exception('File "$from" does not exist.'); + } + if (_exists(to)) _delete(to); await fileSystem.file(from).rename(to); if (!_exists(to)) { _logger.severe('Failed to generate SDK asset at $to'); - throw Exception('File does not exist.'); + throw Exception('File "$to" does not exist.'); } } } diff --git a/test_common/lib/test_sdk_configuration.dart b/test_common/lib/test_sdk_configuration.dart index 2ccc297a3..d4668970a 100644 --- a/test_common/lib/test_sdk_configuration.dart +++ b/test_common/lib/test_sdk_configuration.dart @@ -4,6 +4,7 @@ import 'dart:io'; +import 'package:dwds/expression_compiler.dart'; import 'package:dwds/sdk_configuration.dart'; import 'package:logging/logging.dart'; @@ -25,7 +26,7 @@ class TestSdkConfigurationProvider extends SdkConfigurationProvider { final bool _verbose; final bool canaryFeatures; - final bool ddcModuleSystem; + final ModuleFormat ddcModuleFormat; late final Directory _sdkDirectory; SdkConfiguration? _configuration; @@ -34,12 +35,10 @@ class TestSdkConfigurationProvider extends SdkConfigurationProvider { TestSdkConfigurationProvider({ this.canaryFeatures = false, bool verbose = false, - this.ddcModuleSystem = false, + this.ddcModuleFormat = ModuleFormat.amd, }) : _verbose = verbose { _sdkDirectory = Directory.systemTemp.createTempSync('sdk copy'); - sdkLayout = ddcModuleSystem - ? TestSdkLayout.createDdcDefault(_sdkDirectory.path) - : TestSdkLayout.createDefault(_sdkDirectory.path); + sdkLayout = TestSdkLayout.createDefault(_sdkDirectory.path); } @override @@ -66,7 +65,7 @@ class TestSdkConfigurationProvider extends SdkConfigurationProvider { sdkLayout: sdkLayout, canaryFeatures: canaryFeatures, verbose: _verbose, - ddcModuleSystem: ddcModuleSystem, + ddcModuleFormat: ddcModuleFormat, ); await assetGenerator.generateSdkAssets(); diff --git a/test_common/lib/test_sdk_layout.dart b/test_common/lib/test_sdk_layout.dart index b70cffe32..cdc4d2e9b 100644 --- a/test_common/lib/test_sdk_layout.dart +++ b/test_common/lib/test_sdk_layout.dart @@ -16,22 +16,14 @@ class TestSdkLayout { static TestSdkLayout defaultSdkLayout = TestSdkLayout.createDefault(defaultSdkDirectory); - static TestSdkLayout defaultDdcSdkLayout = - TestSdkLayout.createDdcDefault(defaultSdkDirectory); static SdkConfiguration defaultSdkConfiguration = createConfiguration(defaultSdkLayout); - static SdkConfiguration defaultDdcSdkConfiguration = - createConfiguration(defaultDdcSdkLayout); factory TestSdkLayout.createDefault(String sdkDirectory) => TestSdkLayout.createDefaultFromSdkLayout( SdkLayout.createDefault(sdkDirectory)); - factory TestSdkLayout.createDdcDefault(String sdkDirectory) => - TestSdkLayout.createDdcDefaultFromSdkLayout( - SdkLayout.createDefault(sdkDirectory)); - factory TestSdkLayout.createDefaultFromSdkLayout(SdkLayout sdkLayout) => TestSdkLayout( sdkDirectory: sdkLayout.sdkDirectory, @@ -42,7 +34,7 @@ class TestSdkLayout { '_internal', 'ddc_platform.dill', ), - soundJsPath: p.join( + soundAmdJsPath: p.join( sdkLayout.sdkDirectory, 'lib', 'dev_compiler', @@ -50,7 +42,7 @@ class TestSdkLayout { 'amd', 'dart_sdk.js', ), - soundJsMapPath: p.join( + soundAmdJsMapPath: p.join( sdkLayout.sdkDirectory, 'lib', 'dev_compiler', @@ -58,104 +50,46 @@ class TestSdkLayout { 'amd', 'dart_sdk.js.map', ), - weakSummaryPath: sdkLayout.weakSummaryPath, - weakFullDillPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - '_internal', - 'ddc_platform_unsound.dill', - ), - weakJsPath: p.join( + soundDdcJsPath: p.join( sdkLayout.sdkDirectory, 'lib', 'dev_compiler', 'kernel', - 'amd', - 'dart_sdk_unsound.js', + 'ddc', + 'dart_sdk.js', ), - weakJsMapPath: p.join( + soundDdcJsMapPath: p.join( sdkLayout.sdkDirectory, 'lib', 'dev_compiler', 'kernel', - 'amd', - 'dart_sdk_unsound.js.map', - ), - ddcModuleLoaderJsPath: '', - requireJsPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'amd', - 'require.js', - ), - stackTraceMapperPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'web', - 'dart_stack_trace_mapper.js', - ), - dartPath: p.join( - sdkLayout.sdkDirectory, - 'bin', - Platform.isWindows ? 'dart.exe' : 'dart', - ), - frontendServerSnapshotPath: p.join( - sdkLayout.sdkDirectory, - 'bin', - 'snapshots', - 'frontend_server.dart.snapshot', - ), - dartdevcSnapshotPath: sdkLayout.dartdevcSnapshotPath, - kernelWorkerSnapshotPath: p.join( - sdkLayout.sdkDirectory, - 'bin', - 'snapshots', - 'kernel_worker.dart.snapshot', - ), - devToolsDirectory: p.join( - sdkLayout.sdkDirectory, - 'bin', - 'resources', - 'devtools', + 'ddc', + 'dart_sdk.js.map', ), - ); - - factory TestSdkLayout.createDdcDefaultFromSdkLayout(SdkLayout sdkLayout) => - TestSdkLayout( - sdkDirectory: sdkLayout.sdkDirectory, - soundSummaryPath: sdkLayout.soundSummaryPath, - soundFullDillPath: p.join( + weakSummaryPath: sdkLayout.weakSummaryPath, + weakFullDillPath: p.join( sdkLayout.sdkDirectory, 'lib', '_internal', - 'ddc_platform.dill', + 'ddc_platform_unsound.dill', ), - soundJsPath: p.join( + weakAmdJsPath: p.join( sdkLayout.sdkDirectory, 'lib', 'dev_compiler', 'kernel', - 'ddc', - 'dart_sdk.js', + 'amd', + 'dart_sdk_unsound.js', ), - soundJsMapPath: p.join( + weakAmdJsMapPath: p.join( sdkLayout.sdkDirectory, 'lib', 'dev_compiler', 'kernel', - 'ddc', - 'dart_sdk.js.map', - ), - weakSummaryPath: sdkLayout.weakSummaryPath, - weakFullDillPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - '_internal', - 'ddc_platform_unsound.dill', + 'amd', + 'dart_sdk_unsound.js.map', ), - weakJsPath: p.join( + weakDdcJsPath: p.join( sdkLayout.sdkDirectory, 'lib', 'dev_compiler', @@ -163,7 +97,7 @@ class TestSdkLayout { 'ddc', 'dart_sdk_unsound.js', ), - weakJsMapPath: p.join( + weakDdcJsMapPath: p.join( sdkLayout.sdkDirectory, 'lib', 'dev_compiler', @@ -178,7 +112,13 @@ class TestSdkLayout { 'ddc', 'ddc_module_loader.js', ), - requireJsPath: '', + requireJsPath: p.join( + sdkLayout.sdkDirectory, + 'lib', + 'dev_compiler', + 'amd', + 'require.js', + ), stackTraceMapperPath: p.join( sdkLayout.sdkDirectory, 'lib', @@ -214,23 +154,31 @@ class TestSdkLayout { final String sdkDirectory; - String get soundJsFileName => p.basename(soundJsPath); - String get soundJsMapFileName => p.basename(soundJsMapPath); + String get soundAmdJsFileName => p.basename(soundAmdJsPath); + String get soundAmdJsMapFileName => p.basename(soundAmdJsMapPath); + String get soundDdcJsFileName => p.basename(soundDdcJsPath); + String get soundDdcJsMapFileName => p.basename(soundDdcJsMapPath); String get soundSummaryFileName => p.basename(soundSummaryPath); String get soundFullDillFileName => p.basename(soundFullDillPath); - final String soundJsPath; - final String soundJsMapPath; + final String soundAmdJsPath; + final String soundAmdJsMapPath; + final String soundDdcJsPath; + final String soundDdcJsMapPath; final String soundSummaryPath; final String soundFullDillPath; - String get weakJsFileName => p.basename(weakJsPath); - String get weakJsMapFileName => p.basename(weakJsMapPath); + String get weakAmdJsFileName => p.basename(weakAmdJsPath); + String get weakAmdJsMapFileName => p.basename(weakAmdJsMapPath); + String get weakDdcJsFileName => p.basename(weakDdcJsPath); + String get weakDdcJsMapFileName => p.basename(weakDdcJsMapPath); String get weakSummaryFileName => p.basename(weakSummaryPath); String get weakFullDillFileName => p.basename(weakFullDillPath); - final String weakJsPath; - final String weakJsMapPath; + final String weakAmdJsPath; + final String weakAmdJsMapPath; + final String weakDdcJsPath; + final String weakDdcJsMapPath; final String weakSummaryPath; final String weakFullDillPath; @@ -246,12 +194,16 @@ class TestSdkLayout { const TestSdkLayout({ required this.sdkDirectory, - required this.soundJsPath, - required this.soundJsMapPath, + required this.soundAmdJsPath, + required this.soundAmdJsMapPath, + required this.soundDdcJsPath, + required this.soundDdcJsMapPath, required this.soundSummaryPath, required this.soundFullDillPath, - required this.weakJsPath, - required this.weakJsMapPath, + required this.weakAmdJsPath, + required this.weakAmdJsMapPath, + required this.weakDdcJsPath, + required this.weakDdcJsMapPath, required this.weakSummaryPath, required this.weakFullDillPath, required this.ddcModuleLoaderJsPath, diff --git a/test_common/test/sdk_asset_generator_test.dart b/test_common/test/sdk_asset_generator_test.dart index 51987b851..b609abbdc 100644 --- a/test_common/test/sdk_asset_generator_test.dart +++ b/test_common/test/sdk_asset_generator_test.dart @@ -7,6 +7,7 @@ import 'dart:io'; +import 'package:dwds/expression_compiler.dart'; import 'package:test/test.dart'; import 'package:test_common/logging.dart'; import 'package:test_common/sdk_asset_generator.dart'; @@ -47,8 +48,8 @@ void main() { // Simulate missing sound assets. soundSdkFullDillPath = copySdkLayout.soundFullDillPath; - soundSdkJsPath = copySdkLayout.soundJsPath; - soundSdkJsMapPath = copySdkLayout.soundJsMapPath; + soundSdkJsPath = copySdkLayout.soundAmdJsPath; + soundSdkJsMapPath = copySdkLayout.soundAmdJsMapPath; _deleteIfExists(soundSdkFullDillPath); _deleteIfExists(soundSdkJsPath); @@ -57,8 +58,8 @@ void main() { // Simulate missing weak assets. weakSdkSummaryPath = copySdkLayout.weakSummaryPath; weakSdkFullDillPath = copySdkLayout.weakFullDillPath; - weakSdkJsPath = copySdkLayout.weakJsPath; - weakSdkJsMapPath = copySdkLayout.weakJsMapPath; + weakSdkJsPath = copySdkLayout.weakAmdJsPath; + weakSdkJsMapPath = copySdkLayout.weakAmdJsMapPath; _deleteIfExists(weakSdkSummaryPath); _deleteIfExists(weakSdkFullDillPath); @@ -79,7 +80,7 @@ void main() { sdkLayout: sdkLayout, verbose: true, canaryFeatures: false, - ddcModuleSystem: false, + ddcModuleFormat: ModuleFormat.amd, ); await assetGenerator.generateSdkAssets(); @@ -89,13 +90,13 @@ void main() { expect(sdkLayout.soundSummaryPath, equals(soundSdkSummaryPath)); expect(sdkLayout.soundFullDillPath, equals(soundSdkFullDillPath)); - expect(sdkLayout.soundJsPath, equals(soundSdkJsPath)); - expect(sdkLayout.soundJsMapPath, equals(soundSdkJsMapPath)); + expect(sdkLayout.soundAmdJsPath, equals(soundSdkJsPath)); + expect(sdkLayout.soundAmdJsMapPath, equals(soundSdkJsMapPath)); expect(sdkLayout.weakSummaryPath, equals(weakSdkSummaryPath)); expect(sdkLayout.weakFullDillPath, equals(weakSdkFullDillPath)); - expect(sdkLayout.weakJsPath, equals(weakSdkJsPath)); - expect(sdkLayout.weakJsMapPath, equals(weakSdkJsMapPath)); + expect(sdkLayout.weakAmdJsPath, equals(weakSdkJsPath)); + expect(sdkLayout.weakAmdJsMapPath, equals(weakSdkJsMapPath)); // Validate that configuration files exist. configuration.validateSdkDir(); @@ -104,13 +105,13 @@ void main() { // Validate all assets exist. expect(sdkLayout.soundSummaryPath, _exists); expect(sdkLayout.soundFullDillPath, _exists); - expect(sdkLayout.soundJsPath, _exists); - expect(sdkLayout.soundJsMapPath, _exists); + expect(sdkLayout.soundAmdJsPath, _exists); + expect(sdkLayout.soundAmdJsMapPath, _exists); expect(sdkLayout.weakSummaryPath, _exists); expect(sdkLayout.weakFullDillPath, _exists); - expect(sdkLayout.weakJsPath, _exists); - expect(sdkLayout.weakJsMapPath, _exists); + expect(sdkLayout.weakAmdJsPath, _exists); + expect(sdkLayout.weakAmdJsMapPath, _exists); }); test('Can generate missing SDK assets with canary features enabled', @@ -121,7 +122,7 @@ void main() { sdkLayout: sdkLayout, verbose: true, canaryFeatures: true, - ddcModuleSystem: false, + ddcModuleFormat: ModuleFormat.amd, ); await assetGenerator.generateSdkAssets(); From dcbea773b7142b49b092f1191d592d52a6d57570 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Wed, 6 Dec 2023 16:41:18 -0800 Subject: [PATCH 08/22] Fixing analysis errors --- dwds/test/fixtures/context.dart | 2 +- test_common/test/test_sdk_configuration_test.dart | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dwds/test/fixtures/context.dart b/dwds/test/fixtures/context.dart index 3d711cee4..febd12acf 100644 --- a/dwds/test/fixtures/context.dart +++ b/dwds/test/fixtures/context.dart @@ -351,7 +351,7 @@ class TestContext { buildSettings, ).strategy, _ => throw Exception( - 'Unsupported DDC module format ${testSettings.moduleFormat}.') + 'Unsupported DDC module format ${testSettings.moduleFormat.name}.') }; buildResults = const Stream.empty(); } diff --git a/test_common/test/test_sdk_configuration_test.dart b/test_common/test/test_sdk_configuration_test.dart index 8a701fc45..465f40f67 100644 --- a/test_common/test/test_sdk_configuration_test.dart +++ b/test_common/test/test_sdk_configuration_test.dart @@ -56,13 +56,13 @@ void main() { final sdkLayout = provider.sdkLayout; expect(sdkLayout.sdkDirectory, _directoryExists); - expect(sdkLayout.soundJsPath, _fileExists); - expect(sdkLayout.soundJsMapPath, _fileExists); + expect(sdkLayout.soundAmdJsPath, _fileExists); + expect(sdkLayout.soundAmdJsMapPath, _fileExists); expect(sdkLayout.soundSummaryPath, _fileExists); expect(sdkLayout.soundFullDillPath, _fileExists); - expect(sdkLayout.weakJsPath, _fileExists); - expect(sdkLayout.weakJsMapPath, _fileExists); + expect(sdkLayout.weakAmdJsPath, _fileExists); + expect(sdkLayout.weakAmdJsMapPath, _fileExists); expect(sdkLayout.weakSummaryPath, _fileExists); expect(sdkLayout.weakFullDillPath, _fileExists); From 40ac1941a8a874742fc33811c6d3bf32fc0b07b6 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Thu, 7 Dec 2023 13:11:50 -0800 Subject: [PATCH 09/22] Exposing utilities/ddc_names.dart --- dwds/CHANGELOG.md | 2 +- dwds/lib/dwds.dart | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md index 82e28bf9a..20427302f 100644 --- a/dwds/CHANGELOG.md +++ b/dwds/CHANGELOG.md @@ -2,7 +2,7 @@ - Restructure `LoadStrategy` to provide build settings. - [#2270](https://github.com/dart-lang/webdev/pull/2270) - Add `FrontendServerLegacyStrategyProvider` and update bootstrap generation logic for `LegacyStrategy` - [#2285](https://github.com/dart-lang/webdev/pull/2285) - Tolerate failures to detect a dart execution context. - [#2286](https://github.com/dart-lang/webdev/pull/2286) -- Enabling tests that run with the DDC module system. - [#2295](https://github.com/dart-lang/webdev/pull/2295) +- Enabling tests that run with the DDC module system and exposing `utilities/ddc_names.dart` - [#2295](https://github.com/dart-lang/webdev/pull/2295) ## 22.1.0 - Update `package:vm_service` constraint to `^13.0.0`. - [#2265](https://github.com/dart-lang/webdev/pull/2265) diff --git a/dwds/lib/dwds.dart b/dwds/lib/dwds.dart index a9016398c..d0898d792 100644 --- a/dwds/lib/dwds.dart +++ b/dwds/lib/dwds.dart @@ -41,5 +41,6 @@ export 'src/services/expression_compiler.dart' CompilerOptions; export 'src/services/expression_compiler_service.dart' show ExpressionCompilerService; +export 'src/utilities/ddc_names.dart'; export 'src/utilities/sdk_configuration.dart' show SdkLayout, SdkConfiguration, SdkConfigurationProvider; From 83d5feb97915b08aeb5315a2d347f805e4cd31e6 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Thu, 7 Dec 2023 13:19:03 -0800 Subject: [PATCH 10/22] removing extraneous export --- dwds/lib/dwds.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/dwds/lib/dwds.dart b/dwds/lib/dwds.dart index d0898d792..a9016398c 100644 --- a/dwds/lib/dwds.dart +++ b/dwds/lib/dwds.dart @@ -41,6 +41,5 @@ export 'src/services/expression_compiler.dart' CompilerOptions; export 'src/services/expression_compiler_service.dart' show ExpressionCompilerService; -export 'src/utilities/ddc_names.dart'; export 'src/utilities/sdk_configuration.dart' show SdkLayout, SdkConfiguration, SdkConfigurationProvider; From 6d5bcfef24116af2cc6cac41ecd488d6ad907fe3 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Mon, 11 Dec 2023 18:30:29 -0800 Subject: [PATCH 11/22] Fixing race condition without extraneous plumbing. --- dwds/lib/dart_web_debug_service.dart | 2 -- dwds/lib/src/handlers/dev_handler.dart | 3 --- dwds/test/fixtures/context.dart | 16 ++++++++++++---- dwds/test/fixtures/server.dart | 2 -- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/dwds/lib/dart_web_debug_service.dart b/dwds/lib/dart_web_debug_service.dart index f0f2252ec..467e568d1 100644 --- a/dwds/lib/dart_web_debug_service.dart +++ b/dwds/lib/dart_web_debug_service.dart @@ -65,7 +65,6 @@ class Dwds { required Stream buildResults, required ConnectionProvider chromeConnection, required ToolConfiguration toolConfiguration, - Future? completeBeforeHandlingConnections, }) async { globalToolConfiguration = toolConfiguration; final debugSettings = toolConfiguration.debugSettings; @@ -129,7 +128,6 @@ class Dwds { injected, debugSettings.spawnDds, debugSettings.launchDevToolsInNewWindow, - completeBeforeHandlingConnections, ); return Dwds._( diff --git a/dwds/lib/src/handlers/dev_handler.dart b/dwds/lib/src/handlers/dev_handler.dart index 794bd2b83..9de7a175f 100644 --- a/dwds/lib/src/handlers/dev_handler.dart +++ b/dwds/lib/src/handlers/dev_handler.dart @@ -67,7 +67,6 @@ class DevHandler { final bool _useSseForInjectedClient; final bool _spawnDds; final bool _launchDevToolsInNewWindow; - final Future? _completeBeforeHandlingConnections; final ExpressionCompiler? _expressionCompiler; final DwdsInjector _injected; @@ -92,7 +91,6 @@ class DevHandler { this._injected, this._spawnDds, this._launchDevToolsInNewWindow, - this._completeBeforeHandlingConnections, ) { _subs.add(buildResults.listen(_emitBuildResults)); _listen(); @@ -496,7 +494,6 @@ class DevHandler { : WebSocketSocketHandler(); _sseHandlers[uri.path] = handler; final injectedConnections = handler.connections; - await _completeBeforeHandlingConnections; while (await injectedConnections.hasNext) { _handleConnection(await injectedConnections.next); } diff --git a/dwds/test/fixtures/context.dart b/dwds/test/fixtures/context.dart index febd12acf..182aa5aec 100644 --- a/dwds/test/fixtures/context.dart +++ b/dwds/test/fixtures/context.dart @@ -395,8 +395,9 @@ class TestContext { } // The debugger tab must be enabled and connected before certain - // listeners in DWDS run. + // listeners in DWDS or `main` is run. final tabConnectionCompleter = Completer(); + final appConnectionCompleter = Completer(); final connection = ChromeConnection('localhost', debugPort); _testServer = await TestServer.start( @@ -410,10 +411,17 @@ class TestContext { target: project.directoryToServe, buildResults: buildResults, chromeConnection: () async => connection, - autoRun: testSettings.autoRun, - completeBeforeHandlingConnections: tabConnectionCompleter.future, + autoRun: false, ); + _testServer!.dwds.connectedApps.listen((connection) async { + // Ensure that we've established a tab connection before running main. + await tabConnectionCompleter.future; + connection.runMain(); + appConnection = connection; + appConnectionCompleter.complete(); + }); + _appUrl = basePath.isEmpty ? 'http://localhost:$port/$filePathToServe' : 'http://localhost:$port/$basePath/$filePathToServe'; @@ -437,7 +445,7 @@ class TestContext { await extensionConnection.runtime.enable(); } - appConnection = await testServer.dwds.connectedApps.first; + await appConnectionCompleter.future; if (debugSettings.enableDebugging && !testSettings.waitToDebug) { await startDebugging(); } diff --git a/dwds/test/fixtures/server.dart b/dwds/test/fixtures/server.dart index 98aac8b06..4743f35c9 100644 --- a/dwds/test/fixtures/server.dart +++ b/dwds/test/fixtures/server.dart @@ -68,7 +68,6 @@ class TestServer { required Future Function() chromeConnection, required bool autoRun, int? port, - Future? completeBeforeHandlingConnections, }) async { var pipeline = const Pipeline(); @@ -101,7 +100,6 @@ class TestServer { buildResults: filteredBuildResults, chromeConnection: chromeConnection, toolConfiguration: toolConfiguration, - completeBeforeHandlingConnections: completeBeforeHandlingConnections, ); final server = await startHttpServer('localhost', port: port); From 2cff2ce6d8c5268958daaebf786e5c6537edb61b Mon Sep 17 00:00:00 2001 From: MarkZ Date: Tue, 12 Dec 2023 14:56:07 -0800 Subject: [PATCH 12/22] Extending tests and restructuring logic into helpers --- .../lib/src/services/expression_compiler.dart | 2 +- .../lib/src/frontend_server_client.dart | 2 +- test_common/lib/sdk_asset_generator.dart | 56 ++++++++---- .../test/sdk_asset_generator_test.dart | 91 +++++++++++++++++-- 4 files changed, 121 insertions(+), 30 deletions(-) diff --git a/dwds/lib/src/services/expression_compiler.dart b/dwds/lib/src/services/expression_compiler.dart index 7cbf262ac..c1b7306b3 100644 --- a/dwds/lib/src/services/expression_compiler.dart +++ b/dwds/lib/src/services/expression_compiler.dart @@ -17,7 +17,7 @@ class CompilerOptions { }); } -// Indicates the module system DDC is targeting. +/// Indicates the module system DDC is targeting. enum ModuleFormat { amd, ddc, es6 } /// Result of compilation of dart expression to JavaScript diff --git a/frontend_server_common/lib/src/frontend_server_client.dart b/frontend_server_common/lib/src/frontend_server_client.dart index eba9d2dbc..860a05c56 100644 --- a/frontend_server_common/lib/src/frontend_server_client.dart +++ b/frontend_server_common/lib/src/frontend_server_client.dart @@ -395,7 +395,7 @@ class ResidentCompiler { if (compilerOptions.canaryFeatures) '--dartdevc-canary', if (verbose) '--verbose', if (compilerOptions.moduleFormat == ModuleFormat.ddc) - '--dartdevc-module-format=legacy' + '--dartdevc-module-format=ddc' ]; _logger.info(args.join(' ')); diff --git a/test_common/lib/sdk_asset_generator.dart b/test_common/lib/sdk_asset_generator.dart index 338279ef2..bcf6d7977 100644 --- a/test_common/lib/sdk_asset_generator.dart +++ b/test_common/lib/sdk_asset_generator.dart @@ -55,27 +55,53 @@ class SdkAssetGenerator { } } - Future _generateSdkJavaScript({ + String resolveSdkJsPath({ required bool soundNullSafety, required bool canaryFeatures, - }) async { - Directory? outputDir; - try { - // Files to copy generated files to. - final outputJsPath = switch ((soundNullSafety, ddcModuleFormat)) { + }) => + switch ((soundNullSafety, ddcModuleFormat)) { (true, ModuleFormat.amd) => sdkLayout.soundAmdJsPath, (false, ModuleFormat.amd) => sdkLayout.weakAmdJsPath, (true, ModuleFormat.ddc) => sdkLayout.soundDdcJsPath, (false, ModuleFormat.ddc) => sdkLayout.weakDdcJsPath, _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.') }; - final outputJsMapPath = switch ((soundNullSafety, ddcModuleFormat)) { + + String resolveSdkSourcemapPath({ + required bool soundNullSafety, + required bool canaryFeatures, + }) => + switch ((soundNullSafety, ddcModuleFormat)) { (true, ModuleFormat.amd) => sdkLayout.soundAmdJsMapPath, (false, ModuleFormat.amd) => sdkLayout.weakAmdJsMapPath, (true, ModuleFormat.ddc) => sdkLayout.soundDdcJsMapPath, (false, ModuleFormat.ddc) => sdkLayout.weakDdcJsMapPath, _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.') }; + + String resolveSdkJsFilename({ + required bool soundNullSafety, + required bool canaryFeatures, + }) => + switch ((soundNullSafety, ddcModuleFormat)) { + (true, ModuleFormat.amd) => sdkLayout.soundAmdJsFileName, + (false, ModuleFormat.amd) => sdkLayout.weakAmdJsFileName, + (true, ModuleFormat.ddc) => sdkLayout.soundDdcJsFileName, + (false, ModuleFormat.ddc) => sdkLayout.weakDdcJsFileName, + _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.') + }; + + Future _generateSdkJavaScript({ + required bool soundNullSafety, + required bool canaryFeatures, + }) async { + Directory? outputDir; + try { + // Files to copy generated files to. + final outputJsPath = resolveSdkJsPath( + soundNullSafety: soundNullSafety, canaryFeatures: canaryFeatures); + final outputJsMapPath = resolveSdkSourcemapPath( + soundNullSafety: soundNullSafety, canaryFeatures: canaryFeatures); final outputFullDillPath = soundNullSafety ? sdkLayout.soundFullDillPath : sdkLayout.weakFullDillPath; @@ -92,17 +118,11 @@ class SdkAssetGenerator { outputDir = fileSystem.systemTempDirectory.createTempSync(); // Files to generate - final jsPath = switch ((soundNullSafety, ddcModuleFormat)) { - (true, ModuleFormat.amd) => - p.join(outputDir.path, sdkLayout.soundAmdJsFileName), - (false, ModuleFormat.amd) => - p.join(outputDir.path, sdkLayout.weakAmdJsFileName), - (true, ModuleFormat.ddc) => - p.join(outputDir.path, sdkLayout.soundDdcJsFileName), - (false, ModuleFormat.ddc) => - p.join(outputDir.path, sdkLayout.weakDdcJsFileName), - _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.') - }; + final jsPath = p.join( + outputDir.path, + resolveSdkJsFilename( + soundNullSafety: soundNullSafety, + canaryFeatures: canaryFeatures)); final jsMapPath = p.setExtension(jsPath, '.js.map'); final fullDillPath = p.setExtension(jsPath, '.dill'); diff --git a/test_common/test/sdk_asset_generator_test.dart b/test_common/test/sdk_asset_generator_test.dart index b609abbdc..12cb1d28d 100644 --- a/test_common/test/sdk_asset_generator_test.dart +++ b/test_common/test/sdk_asset_generator_test.dart @@ -30,8 +30,10 @@ void main() { // Missing weak assets late String weakSdkSummaryPath; late String weakSdkFullDillPath; - late String weakSdkJsPath; - late String weakSdkJsMapPath; + late String weakAmdSdkJsPath; + late String weakAmdSdkJsMapPath; + late String weakDdcSdkJsPath; + late String weakDdcSdkJsMapPath; setUp(() async { setCurrentLogWriter(debug: debug); @@ -58,20 +60,25 @@ void main() { // Simulate missing weak assets. weakSdkSummaryPath = copySdkLayout.weakSummaryPath; weakSdkFullDillPath = copySdkLayout.weakFullDillPath; - weakSdkJsPath = copySdkLayout.weakAmdJsPath; - weakSdkJsMapPath = copySdkLayout.weakAmdJsMapPath; + weakAmdSdkJsPath = copySdkLayout.weakAmdJsPath; + weakAmdSdkJsMapPath = copySdkLayout.weakAmdJsMapPath; + weakDdcSdkJsPath = copySdkLayout.weakAmdJsPath; + weakDdcSdkJsMapPath = copySdkLayout.weakAmdJsMapPath; _deleteIfExists(weakSdkSummaryPath); _deleteIfExists(weakSdkFullDillPath); - _deleteIfExists(weakSdkJsPath); - _deleteIfExists(weakSdkJsMapPath); + _deleteIfExists(weakAmdSdkJsPath); + _deleteIfExists(weakAmdSdkJsMapPath); + _deleteIfExists(weakDdcSdkJsPath); + _deleteIfExists(weakDdcSdkJsMapPath); }); tearDown(() { tempDir.deleteSync(recursive: true); }); - test('Can generate missing SDK assets and validate SDK configuration', + test( + 'Can generate missing SDK assets and validate SDK configuration for the AMD module system', () async { final sdkLayout = TestSdkLayout.createDefault(sdkDirectory); final configuration = TestSdkLayout.createConfiguration(sdkLayout); @@ -95,8 +102,8 @@ void main() { expect(sdkLayout.weakSummaryPath, equals(weakSdkSummaryPath)); expect(sdkLayout.weakFullDillPath, equals(weakSdkFullDillPath)); - expect(sdkLayout.weakAmdJsPath, equals(weakSdkJsPath)); - expect(sdkLayout.weakAmdJsMapPath, equals(weakSdkJsMapPath)); + expect(sdkLayout.weakAmdJsPath, equals(weakAmdSdkJsPath)); + expect(sdkLayout.weakAmdJsMapPath, equals(weakAmdSdkJsMapPath)); // Validate that configuration files exist. configuration.validateSdkDir(); @@ -114,6 +121,50 @@ void main() { expect(sdkLayout.weakAmdJsMapPath, _exists); }); + test( + 'Can generate missing SDK assets and validate SDK configuration for the DDC module system', + () async { + final sdkLayout = TestSdkLayout.createDefault(sdkDirectory); + final configuration = TestSdkLayout.createConfiguration(sdkLayout); + + final assetGenerator = SdkAssetGenerator( + sdkLayout: sdkLayout, + verbose: true, + canaryFeatures: false, + ddcModuleFormat: ModuleFormat.ddc, + ); + await assetGenerator.generateSdkAssets(); + + // Make sure SDK configuration and asset generator agree on the file paths. + expect(configuration.sdkDirectory, equals(sdkDirectory)); + expect(configuration.compilerWorkerPath, equals(compilerWorkerPath)); + + expect(sdkLayout.soundSummaryPath, equals(soundSdkSummaryPath)); + expect(sdkLayout.soundFullDillPath, equals(soundSdkFullDillPath)); + expect(sdkLayout.soundDdcJsPath, equals(soundSdkJsPath)); + expect(sdkLayout.soundDdcJsMapPath, equals(soundSdkJsMapPath)); + + expect(sdkLayout.weakSummaryPath, equals(weakSdkSummaryPath)); + expect(sdkLayout.weakFullDillPath, equals(weakSdkFullDillPath)); + expect(sdkLayout.weakDdcJsPath, equals(weakDdcSdkJsPath)); + expect(sdkLayout.weakDdcJsMapPath, equals(weakDdcSdkJsMapPath)); + + // Validate that configuration files exist. + configuration.validateSdkDir(); + configuration.validate(); + + // Validate all assets exist. + expect(sdkLayout.soundSummaryPath, _exists); + expect(sdkLayout.soundFullDillPath, _exists); + expect(sdkLayout.soundDdcJsPath, _exists); + expect(sdkLayout.soundDdcJsMapPath, _exists); + + expect(sdkLayout.weakSummaryPath, _exists); + expect(sdkLayout.weakFullDillPath, _exists); + expect(sdkLayout.weakDdcJsPath, _exists); + expect(sdkLayout.weakDdcJsMapPath, _exists); + }); + test('Can generate missing SDK assets with canary features enabled', () async { final sdkLayout = TestSdkLayout.createDefault(sdkDirectory); @@ -129,7 +180,27 @@ void main() { final soundSdk = File(soundSdkJsPath).readAsStringSync(); expect(soundSdk, contains('canary')); - final weakSdk = File(weakSdkJsPath).readAsStringSync(); + final weakSdk = File(weakAmdSdkJsPath).readAsStringSync(); + expect(weakSdk, contains('canary')); + }); + + test( + 'Can generate missing SDK assets with canary features enabled for the DDC module system', + () async { + final sdkLayout = TestSdkLayout.createDefault(sdkDirectory); + + final assetGenerator = SdkAssetGenerator( + sdkLayout: sdkLayout, + verbose: true, + canaryFeatures: true, + ddcModuleFormat: ModuleFormat.ddc, + ); + await assetGenerator.generateSdkAssets(); + + final soundSdk = File(soundSdkJsPath).readAsStringSync(); + expect(soundSdk, contains('canary')); + + final weakSdk = File(weakDdcSdkJsPath).readAsStringSync(); expect(weakSdk, contains('canary')); }); }); From 77bd6ebbd93945f749a90bc65611c4963b05c09f Mon Sep 17 00:00:00 2001 From: MarkZ Date: Wed, 13 Dec 2023 15:26:02 -0800 Subject: [PATCH 13/22] Extending sdk config tests and moving autorun functionality into the test context. --- dwds/test/fixtures/context.dart | 5 +++-- dwds/test/fixtures/server.dart | 11 +---------- test_common/test/test_sdk_configuration_test.dart | 5 +++++ 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/dwds/test/fixtures/context.dart b/dwds/test/fixtures/context.dart index 182aa5aec..4b7403a73 100644 --- a/dwds/test/fixtures/context.dart +++ b/dwds/test/fixtures/context.dart @@ -411,13 +411,14 @@ class TestContext { target: project.directoryToServe, buildResults: buildResults, chromeConnection: () async => connection, - autoRun: false, ); _testServer!.dwds.connectedApps.listen((connection) async { // Ensure that we've established a tab connection before running main. await tabConnectionCompleter.future; - connection.runMain(); + if (testSettings.autoRun) { + connection.runMain(); + } appConnection = connection; appConnectionCompleter.complete(); }); diff --git a/dwds/test/fixtures/server.dart b/dwds/test/fixtures/server.dart index 4743f35c9..9de66c3f0 100644 --- a/dwds/test/fixtures/server.dart +++ b/dwds/test/fixtures/server.dart @@ -39,15 +39,8 @@ class TestServer { this._server, this.dwds, this.buildResults, - bool autoRun, this.assetReader, - ) { - if (autoRun) { - dwds.connectedApps.listen((connection) { - connection.runMain(); - }); - } - } + ); String get host => _server.address.host; int get port => _server.port; @@ -66,7 +59,6 @@ class TestServer { required String target, required Stream buildResults, required Future Function() chromeConnection, - required bool autoRun, int? port, }) async { var pipeline = const Pipeline(); @@ -121,7 +113,6 @@ class TestServer { server, dwds, filteredBuildResults, - autoRun, assetReader, ); } diff --git a/test_common/test/test_sdk_configuration_test.dart b/test_common/test/test_sdk_configuration_test.dart index 465f40f67..5b01d0613 100644 --- a/test_common/test/test_sdk_configuration_test.dart +++ b/test_common/test/test_sdk_configuration_test.dart @@ -58,15 +58,20 @@ void main() { expect(sdkLayout.sdkDirectory, _directoryExists); expect(sdkLayout.soundAmdJsPath, _fileExists); expect(sdkLayout.soundAmdJsMapPath, _fileExists); + expect(sdkLayout.soundDdcJsPath, _fileExists); + expect(sdkLayout.soundDdcJsMapPath, _fileExists); expect(sdkLayout.soundSummaryPath, _fileExists); expect(sdkLayout.soundFullDillPath, _fileExists); expect(sdkLayout.weakAmdJsPath, _fileExists); expect(sdkLayout.weakAmdJsMapPath, _fileExists); + expect(sdkLayout.weakDdcJsPath, _fileExists); + expect(sdkLayout.weakDdcJsMapPath, _fileExists); expect(sdkLayout.weakSummaryPath, _fileExists); expect(sdkLayout.weakFullDillPath, _fileExists); expect(sdkLayout.requireJsPath, _fileExists); + expect(sdkLayout.ddcModuleLoaderJsPath, _fileExists); expect(sdkLayout.stackTraceMapperPath, _fileExists); expect(sdkLayout.dartPath, _fileExists); From 7330d99736f50db12472745810dd39459d10b4af Mon Sep 17 00:00:00 2001 From: MarkZ Date: Thu, 14 Dec 2023 09:12:08 -0800 Subject: [PATCH 14/22] Fixing analysis errors --- dwds/test/expression_compiler_service_test.dart | 2 +- dwds/test/fixtures/context.dart | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dwds/test/expression_compiler_service_test.dart b/dwds/test/expression_compiler_service_test.dart index d791aebd6..0531764b7 100644 --- a/dwds/test/expression_compiler_service_test.dart +++ b/dwds/test/expression_compiler_service_test.dart @@ -80,7 +80,7 @@ void main() async { ); final compilerOptions = CompilerOptions( - moduleFormat: 'amd', + moduleFormat: ModuleFormat.amd, soundNullSafety: true, canaryFeatures: false, experiments: const [], diff --git a/dwds/test/fixtures/context.dart b/dwds/test/fixtures/context.dart index 4b7403a73..f2adf7634 100644 --- a/dwds/test/fixtures/context.dart +++ b/dwds/test/fixtures/context.dart @@ -351,7 +351,8 @@ class TestContext { buildSettings, ).strategy, _ => throw Exception( - 'Unsupported DDC module format ${testSettings.moduleFormat.name}.') + 'Unsupported DDC module format ${testSettings.moduleFormat.name}.', + ) }; buildResults = const Stream.empty(); } From b30a41f0f3234cda55de3a32c7004312f1cc793c Mon Sep 17 00:00:00 2001 From: MarkZ Date: Thu, 14 Dec 2023 09:25:02 -0800 Subject: [PATCH 15/22] adding missing DDC sound sdks to asset generator test --- .../test/sdk_asset_generator_test.dart | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/test_common/test/sdk_asset_generator_test.dart b/test_common/test/sdk_asset_generator_test.dart index 12cb1d28d..3933d9172 100644 --- a/test_common/test/sdk_asset_generator_test.dart +++ b/test_common/test/sdk_asset_generator_test.dart @@ -24,8 +24,10 @@ void main() { // Missing sound assets late String soundSdkFullDillPath; - late String soundSdkJsPath; - late String soundSdkJsMapPath; + late String soundAmdSdkJsPath; + late String soundAmdSdkJsMapPath; + late String soundDdcSdkJsPath; + late String soundDdcSdkJsMapPath; // Missing weak assets late String weakSdkSummaryPath; @@ -50,12 +52,16 @@ void main() { // Simulate missing sound assets. soundSdkFullDillPath = copySdkLayout.soundFullDillPath; - soundSdkJsPath = copySdkLayout.soundAmdJsPath; - soundSdkJsMapPath = copySdkLayout.soundAmdJsMapPath; + soundAmdSdkJsPath = copySdkLayout.soundAmdJsPath; + soundAmdSdkJsMapPath = copySdkLayout.soundAmdJsMapPath; + soundDdcSdkJsPath = copySdkLayout.soundDdcJsPath; + soundDdcSdkJsMapPath = copySdkLayout.soundDdcJsMapPath; _deleteIfExists(soundSdkFullDillPath); - _deleteIfExists(soundSdkJsPath); - _deleteIfExists(soundSdkJsMapPath); + _deleteIfExists(soundAmdSdkJsPath); + _deleteIfExists(soundAmdSdkJsMapPath); + _deleteIfExists(soundDdcSdkJsPath); + _deleteIfExists(soundDdcSdkJsMapPath); // Simulate missing weak assets. weakSdkSummaryPath = copySdkLayout.weakSummaryPath; @@ -97,8 +103,8 @@ void main() { expect(sdkLayout.soundSummaryPath, equals(soundSdkSummaryPath)); expect(sdkLayout.soundFullDillPath, equals(soundSdkFullDillPath)); - expect(sdkLayout.soundAmdJsPath, equals(soundSdkJsPath)); - expect(sdkLayout.soundAmdJsMapPath, equals(soundSdkJsMapPath)); + expect(sdkLayout.soundAmdJsPath, equals(soundAmdSdkJsPath)); + expect(sdkLayout.soundAmdJsMapPath, equals(soundAmdSdkJsMapPath)); expect(sdkLayout.weakSummaryPath, equals(weakSdkSummaryPath)); expect(sdkLayout.weakFullDillPath, equals(weakSdkFullDillPath)); @@ -141,8 +147,8 @@ void main() { expect(sdkLayout.soundSummaryPath, equals(soundSdkSummaryPath)); expect(sdkLayout.soundFullDillPath, equals(soundSdkFullDillPath)); - expect(sdkLayout.soundDdcJsPath, equals(soundSdkJsPath)); - expect(sdkLayout.soundDdcJsMapPath, equals(soundSdkJsMapPath)); + expect(sdkLayout.soundDdcJsPath, equals(soundDdcSdkJsPath)); + expect(sdkLayout.soundDdcJsMapPath, equals(soundDdcSdkJsMapPath)); expect(sdkLayout.weakSummaryPath, equals(weakSdkSummaryPath)); expect(sdkLayout.weakFullDillPath, equals(weakSdkFullDillPath)); @@ -177,7 +183,7 @@ void main() { ); await assetGenerator.generateSdkAssets(); - final soundSdk = File(soundSdkJsPath).readAsStringSync(); + final soundSdk = File(soundAmdSdkJsPath).readAsStringSync(); expect(soundSdk, contains('canary')); final weakSdk = File(weakAmdSdkJsPath).readAsStringSync(); @@ -197,7 +203,7 @@ void main() { ); await assetGenerator.generateSdkAssets(); - final soundSdk = File(soundSdkJsPath).readAsStringSync(); + final soundSdk = File(soundDdcSdkJsPath).readAsStringSync(); expect(soundSdk, contains('canary')); final weakSdk = File(weakDdcSdkJsPath).readAsStringSync(); From 5b9854ea8156cba4fd2c184df5461db6b9eb5da2 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Thu, 14 Dec 2023 09:42:49 -0800 Subject: [PATCH 16/22] Fixing ddc and amd paths --- test_common/test/sdk_asset_generator_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test_common/test/sdk_asset_generator_test.dart b/test_common/test/sdk_asset_generator_test.dart index 3933d9172..2d45cd0ea 100644 --- a/test_common/test/sdk_asset_generator_test.dart +++ b/test_common/test/sdk_asset_generator_test.dart @@ -68,8 +68,8 @@ void main() { weakSdkFullDillPath = copySdkLayout.weakFullDillPath; weakAmdSdkJsPath = copySdkLayout.weakAmdJsPath; weakAmdSdkJsMapPath = copySdkLayout.weakAmdJsMapPath; - weakDdcSdkJsPath = copySdkLayout.weakAmdJsPath; - weakDdcSdkJsMapPath = copySdkLayout.weakAmdJsMapPath; + weakDdcSdkJsPath = copySdkLayout.weakDdcJsPath; + weakDdcSdkJsMapPath = copySdkLayout.weakDdcJsMapPath; _deleteIfExists(weakSdkSummaryPath); _deleteIfExists(weakSdkFullDillPath); From c60669670db1931af2efca79ed83d3344ce64ac8 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Mon, 18 Dec 2023 14:28:36 -0800 Subject: [PATCH 17/22] Keeping the first instance of an app connection and extending timeouts --- dwds/test/devtools_test.dart | 196 ++-- dwds/test/fixtures/context.dart | 12 +- dwds/test/reload_test.dart | 835 +++++++++--------- dwds/test/run_request_test.dart | 2 +- .../test/test_sdk_configuration_test.dart | 46 +- 5 files changed, 577 insertions(+), 514 deletions(-) diff --git a/dwds/test/devtools_test.dart b/dwds/test/devtools_test.dart index b7e1ddf1b..8e9fb4868 100644 --- a/dwds/test/devtools_test.dart +++ b/dwds/test/devtools_test.dart @@ -32,110 +32,115 @@ void main() { final context = TestContext(TestProject.testWithSoundNullSafety, provider); - group('Injected client', () { - setUp(() async { - await context.setUp( - debugSettings: TestDebugSettings.withDevTools(context), - ); - await context.webDriver.driver.keyboard.sendChord([Keyboard.alt, 'd']); - // Wait for DevTools to actually open. - await Future.delayed(const Duration(seconds: 2)); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test( - 'can launch devtools', - () async { - final windows = await context.webDriver.windows.toList(); - await context.webDriver.driver.switchTo.window(windows.last); - expect(await context.webDriver.pageSource, contains('DevTools')); - expect(await context.webDriver.currentUrl, contains('ide=Dwds')); - // TODO(https://github.com/dart-lang/webdev/issues/1888): Re-enable. - }, - skip: Platform.isWindows, - ); - - test('can not launch devtools for the same app in multiple tabs', () async { - final appUrl = await context.webDriver.currentUrl; - // Open a new tab, select it, and navigate to the app - await context.webDriver.driver - .execute("window.open('$appUrl', '_blank');", []); - await Future.delayed(const Duration(seconds: 2)); - final newAppWindow = await context.webDriver.windows.last; - await newAppWindow.setAsActive(); + group( + 'Injected client', + () { + setUp(() async { + await context.setUp( + debugSettings: TestDebugSettings.withDevTools(context), + ); + await context.webDriver.driver.keyboard.sendChord([Keyboard.alt, 'd']); + // Wait for DevTools to actually open. + await Future.delayed(const Duration(seconds: 2)); + }); - // Wait for the page to be ready before trying to open DevTools again. - await _waitForPageReady(context); + tearDown(() async { + await context.tearDown(); + }); - // Try to open devtools and check for the alert. - await context.webDriver.driver.keyboard.sendChord([Keyboard.alt, 'd']); - await Future.delayed(const Duration(seconds: 2)); - final alert = context.webDriver.driver.switchTo.alert; - expect(alert, isNotNull); - expect( - await alert.text, - contains('This app is already being debugged in a different tab'), + test( + 'can launch devtools', + () async { + final windows = await context.webDriver.windows.toList(); + await context.webDriver.driver.switchTo.window(windows.last); + expect(await context.webDriver.pageSource, contains('DevTools')); + expect(await context.webDriver.currentUrl, contains('ide=Dwds')); + // TODO(https://github.com/dart-lang/webdev/issues/1888): Re-enable. + }, + skip: Platform.isWindows, ); - await alert.accept(); - var windows = await context.webDriver.windows.toList(); - for (final window in windows) { - if (window.id != newAppWindow.id) { - await window.setAsActive(); - await window.close(); - } - } + test('can not launch devtools for the same app in multiple tabs', + () async { + final appUrl = await context.webDriver.currentUrl; + // Open a new tab, select it, and navigate to the app + await context.webDriver.driver + .execute("window.open('$appUrl', '_blank');", []); + await Future.delayed(const Duration(seconds: 2)); + final newAppWindow = await context.webDriver.windows.last; + await newAppWindow.setAsActive(); - await newAppWindow.setAsActive(); - await context.webDriver.driver.keyboard.sendChord([Keyboard.alt, 'd']); - await Future.delayed(const Duration(seconds: 2)); - windows = await context.webDriver.windows.toList(); - final devToolsWindow = - windows.firstWhere((window) => window != newAppWindow); - await devToolsWindow.setAsActive(); - expect(await context.webDriver.pageSource, contains('DevTools')); - }); + // Wait for the page to be ready before trying to open DevTools again. + await _waitForPageReady(context); - test( - 'destroys and recreates the isolate during a page refresh', - () async { - // This test is the same as one in reload_test, but runs here when there - // is a connected client (DevTools) since it can behave differently. - // https://github.com/dart-lang/webdev/pull/901#issuecomment-586438132 - final client = context.debugConnection.vmService; - await client.streamListen('Isolate'); - context.makeEditToDartEntryFile( - toReplace: 'Hello World!', - replaceWith: 'Bonjour le monde!', - ); - await context.waitForSuccessfulBuild(propagateToBrowser: true); - - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - emitsInOrder([ - _hasKind(EventKind.kIsolateExit), - _hasKind(EventKind.kIsolateStart), - _hasKind(EventKind.kIsolateRunnable), - ]), - ), + // Try to open devtools and check for the alert. + await context.webDriver.driver.keyboard.sendChord([Keyboard.alt, 'd']); + await Future.delayed(const Duration(seconds: 2)); + final alert = context.webDriver.driver.switchTo.alert; + expect(alert, isNotNull); + expect( + await alert.text, + contains('This app is already being debugged in a different tab'), ); + await alert.accept(); - await context.webDriver.driver.refresh(); + var windows = await context.webDriver.windows.toList(); + for (final window in windows) { + if (window.id != newAppWindow.id) { + await window.setAsActive(); + await window.close(); + } + } - await eventsDone; - // Re-set the edited file: - context.makeEditToDartEntryFile( - toReplace: 'Bonjour le monde!', - replaceWith: 'Hello World!', - ); - }, - skip: 'https://github.com/dart-lang/webdev/issues/1888', - ); - }); + await newAppWindow.setAsActive(); + await context.webDriver.driver.keyboard.sendChord([Keyboard.alt, 'd']); + await Future.delayed(const Duration(seconds: 2)); + windows = await context.webDriver.windows.toList(); + final devToolsWindow = + windows.firstWhere((window) => window != newAppWindow); + await devToolsWindow.setAsActive(); + expect(await context.webDriver.pageSource, contains('DevTools')); + }); + + test( + 'destroys and recreates the isolate during a page refresh', + () async { + // This test is the same as one in reload_test, but runs here when there + // is a connected client (DevTools) since it can behave differently. + // https://github.com/dart-lang/webdev/pull/901#issuecomment-586438132 + final client = context.debugConnection.vmService; + await client.streamListen('Isolate'); + context.makeEditToDartEntryFile( + toReplace: 'Hello World!', + replaceWith: 'Bonjour le monde!', + ); + await context.waitForSuccessfulBuild(propagateToBrowser: true); + + final eventsDone = expectLater( + client.onIsolateEvent, + emitsThrough( + emitsInOrder([ + _hasKind(EventKind.kIsolateExit), + _hasKind(EventKind.kIsolateStart), + _hasKind(EventKind.kIsolateRunnable), + ]), + ), + ); + + await context.webDriver.driver.refresh(); + + await eventsDone; + // Re-set the edited file: + context.makeEditToDartEntryFile( + toReplace: 'Bonjour le monde!', + replaceWith: 'Hello World!', + ); + }, + skip: 'https://github.com/dart-lang/webdev/issues/1888', + ); + }, + timeout: Timeout.factor(2), + ); group('Injected client without a DevTools server', () { setUp(() async { @@ -193,6 +198,7 @@ void main() { }, tags: ['extension'], skip: 'https://github.com/dart-lang/webdev/issues/2114', + timeout: Timeout.factor(2), ); } diff --git a/dwds/test/fixtures/context.dart b/dwds/test/fixtures/context.dart index f2adf7634..34a45e76e 100644 --- a/dwds/test/fixtures/context.dart +++ b/dwds/test/fixtures/context.dart @@ -420,8 +420,13 @@ class TestContext { if (testSettings.autoRun) { connection.runMain(); } - appConnection = connection; - appConnectionCompleter.complete(); + + // We may reuse the app connection, so only save it the first time + // it's encountered. + if (!appConnectionCompleter.isCompleted) { + appConnection = connection; + appConnectionCompleter.complete(); + } }); _appUrl = basePath.isEmpty @@ -451,6 +456,9 @@ class TestContext { if (debugSettings.enableDebugging && !testSettings.waitToDebug) { await startDebugging(); } + } else { + // No tab needs to be dicovered, so fulfill the relevant completer. + tabConnectionCompleter.complete(); } } catch (e, s) { _logger.severe('Failed to setup the service, $e:$s'); diff --git a/dwds/test/reload_test.dart b/dwds/test/reload_test.dart index 6c425eaff..8a0d8eb10 100644 --- a/dwds/test/reload_test.dart +++ b/dwds/test/reload_test.dart @@ -42,438 +42,290 @@ void main() { ); } - group('Injected client with live reload', () { - group('and with debugging', () { - setUp(() async { - setCurrentLogWriter(debug: debug); - await context.setUp( - testSettings: TestSettings( - reloadConfiguration: ReloadConfiguration.liveReload, - ), - ); + group( + 'Injected client with live reload', + () { + group('and with debugging', () { + setUp(() async { + setCurrentLogWriter(debug: debug); + await context.setUp( + testSettings: TestSettings( + reloadConfiguration: ReloadConfiguration.liveReload, + ), + ); + }); + + tearDown(() async { + undoEdit(); + await context.tearDown(); + }); + + test('can live reload changes ', () async { + await makeEditAndWaitForRebuild(); + final source = await context.webDriver.pageSource; + + // A full reload should clear the state. + expect(source.contains(originalString), isFalse); + expect(source.contains(newString), isTrue); + }); }); - tearDown(() async { - undoEdit(); - await context.tearDown(); + group('and without debugging', () { + setUp(() async { + setCurrentLogWriter(debug: debug); + await context.setUp( + testSettings: TestSettings( + reloadConfiguration: ReloadConfiguration.liveReload, + ), + debugSettings: TestDebugSettings.noDevTools().copyWith( + enableDebugging: false, + ), + ); + }); + + tearDown(() async { + undoEdit(); + await context.tearDown(); + }); + + test('can live reload changes ', () async { + await makeEditAndWaitForRebuild(); + + final source = await context.webDriver.pageSource; + + // A full reload should clear the state. + expect(source.contains(originalString), isFalse); + expect(source.contains(newString), isTrue); + }); }); - test('can live reload changes ', () async { - await makeEditAndWaitForRebuild(); - final source = await context.webDriver.pageSource; - - // A full reload should clear the state. - expect(source.contains(originalString), isFalse); - expect(source.contains(newString), isTrue); + group('and without debugging using WebSockets', () { + setUp(() async { + setCurrentLogWriter(debug: debug); + await context.setUp( + testSettings: TestSettings( + reloadConfiguration: ReloadConfiguration.liveReload, + ), + debugSettings: TestDebugSettings.noDevTools().copyWith( + enableDebugging: false, + useSse: false, + ), + ); + }); + + tearDown(() async { + await context.tearDown(); + undoEdit(); + }); + + test('can live reload changes ', () async { + await makeEditAndWaitForRebuild(); + + final source = await context.webDriver.pageSource; + + // A full reload should clear the state. + expect(source.contains(originalString), isFalse); + expect(source.contains(newString), isTrue); + }); }); - }); + }, + timeout: Timeout.factor(2), + ); - group('and without debugging', () { + group( + 'Injected client', + () { setUp(() async { setCurrentLogWriter(debug: debug); await context.setUp( testSettings: TestSettings( - reloadConfiguration: ReloadConfiguration.liveReload, - ), - debugSettings: TestDebugSettings.noDevTools().copyWith( - enableDebugging: false, + enableExpressionEvaluation: true, ), ); }); tearDown(() async { - undoEdit(); await context.tearDown(); + undoEdit(); }); - test('can live reload changes ', () async { + test('destroys and recreates the isolate during a hot restart', () async { + final client = context.debugConnection.vmService; + await client.streamListen('Isolate'); await makeEditAndWaitForRebuild(); - final source = await context.webDriver.pageSource; + final eventsDone = expectLater( + client.onIsolateEvent, + emitsThrough( + emitsInOrder([ + _hasKind(EventKind.kIsolateExit), + _hasKind(EventKind.kIsolateStart), + _hasKind(EventKind.kIsolateRunnable), + ]), + ), + ); - // A full reload should clear the state. - expect(source.contains(originalString), isFalse); - expect(source.contains(newString), isTrue); + expect( + await client.callServiceExtension('hotRestart'), + const TypeMatcher(), + ); + + await eventsDone; }); - }); - group('and without debugging using WebSockets', () { - setUp(() async { - setCurrentLogWriter(debug: debug); - await context.setUp( - testSettings: TestSettings( - reloadConfiguration: ReloadConfiguration.liveReload, + test('can execute simultaneous hot restarts', () async { + final client = context.debugConnection.vmService; + await client.streamListen('Isolate'); + await makeEditAndWaitForRebuild(); + + final eventsDone = expectLater( + client.onIsolateEvent, + emitsThrough( + emitsInOrder([ + _hasKind(EventKind.kIsolateExit), + _hasKind(EventKind.kIsolateStart), + _hasKind(EventKind.kIsolateRunnable), + ]), ), - debugSettings: TestDebugSettings.noDevTools().copyWith( - enableDebugging: false, - useSse: false, + ); + + // Execute two hot restart calls in parallel. + final done = Future.wait([ + client.callServiceExtension('hotRestart'), + client.callServiceExtension('hotRestart'), + ]); + expect( + await done, + [const TypeMatcher(), const TypeMatcher()], + ); + + // The debugger is still working. + final vm = await client.getVM(); + final isolateId = vm.isolates!.first.id!; + final isolate = await client.getIsolate(isolateId); + final library = isolate.rootLib!.uri!; + + final result = await client.evaluate(isolateId, library, 'true'); + expect( + result, + isA().having( + (instance) => instance.valueAsString, + 'valueAsString', + 'true', ), ); - }); - tearDown(() async { - await context.tearDown(); - undoEdit(); + await eventsDone; }); - test('can live reload changes ', () async { + test('destroys and recreates the isolate during a page refresh', + () async { + final client = context.debugConnection.vmService; + await client.streamListen('Isolate'); await makeEditAndWaitForRebuild(); - final source = await context.webDriver.pageSource; - - // A full reload should clear the state. - expect(source.contains(originalString), isFalse); - expect(source.contains(newString), isTrue); - }); - }); - }); - - group('Injected client', () { - setUp(() async { - setCurrentLogWriter(debug: debug); - await context.setUp( - testSettings: TestSettings( - enableExpressionEvaluation: true, - ), - ); - }); - - tearDown(() async { - await context.tearDown(); - undoEdit(); - }); - - test('destroys and recreates the isolate during a hot restart', () async { - final client = context.debugConnection.vmService; - await client.streamListen('Isolate'); - await makeEditAndWaitForRebuild(); - - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - emitsInOrder([ - _hasKind(EventKind.kIsolateExit), - _hasKind(EventKind.kIsolateStart), - _hasKind(EventKind.kIsolateRunnable), - ]), - ), - ); - - expect( - await client.callServiceExtension('hotRestart'), - const TypeMatcher(), - ); - - await eventsDone; - }); - - test('can execute simultaneous hot restarts', () async { - final client = context.debugConnection.vmService; - await client.streamListen('Isolate'); - await makeEditAndWaitForRebuild(); - - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - emitsInOrder([ - _hasKind(EventKind.kIsolateExit), - _hasKind(EventKind.kIsolateStart), - _hasKind(EventKind.kIsolateRunnable), - ]), - ), - ); - - // Execute two hot restart calls in parallel. - final done = Future.wait([ - client.callServiceExtension('hotRestart'), - client.callServiceExtension('hotRestart'), - ]); - expect( - await done, - [const TypeMatcher(), const TypeMatcher()], - ); - - // The debugger is still working. - final vm = await client.getVM(); - final isolateId = vm.isolates!.first.id!; - final isolate = await client.getIsolate(isolateId); - final library = isolate.rootLib!.uri!; - - final result = await client.evaluate(isolateId, library, 'true'); - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - 'true', - ), - ); - - await eventsDone; - }); - - test('destroys and recreates the isolate during a page refresh', () async { - final client = context.debugConnection.vmService; - await client.streamListen('Isolate'); - await makeEditAndWaitForRebuild(); - - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - emitsInOrder([ - _hasKind(EventKind.kIsolateExit), - _hasKind(EventKind.kIsolateStart), - _hasKind(EventKind.kIsolateRunnable), - ]), - ), - ); - - await context.webDriver.driver.refresh(); - - await eventsDone; - }); - - test('can hot restart via the service extension', () async { - final client = context.debugConnection.vmService; - await client.streamListen('Isolate'); - await makeEditAndWaitForRebuild(); - - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - emitsInOrder([ - _hasKind(EventKind.kIsolateExit), - _hasKind(EventKind.kIsolateStart), - _hasKind(EventKind.kIsolateRunnable), - ]), - ), - ); - - expect( - await client.callServiceExtension('hotRestart'), - const TypeMatcher(), - ); - - await eventsDone; - - final source = await context.webDriver.pageSource; - // Main is re-invoked which shouldn't clear the state. - expect(source, contains(originalString)); - expect(source, contains(newString)); - }); - - test('can send events before and after hot restart', () async { - final client = context.debugConnection.vmService; - await client.streamListen('Isolate'); - - // The event just before hot restart might never be received, - // but the injected client continues to work and send events - // after hot restart. - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - _hasKind(EventKind.kServiceExtensionAdded) - .having((e) => e.extensionRPC, 'service', 'ext.bar'), - ), - ); - - var vm = await client.getVM(); - var isolateId = vm.isolates!.first.id!; - var isolate = await client.getIsolate(isolateId); - var library = isolate.rootLib!.uri!; - - final String callback = - '(_, __) async => ServiceExtensionResponse.result("")'; - - await client.evaluate( - isolateId, - library, - "registerExtension('ext.foo', $callback)", - ); - - expect( - await client.callServiceExtension('hotRestart'), - const TypeMatcher(), - ); - - vm = await client.getVM(); - isolateId = vm.isolates!.first.id!; - isolate = await client.getIsolate(isolateId); - library = isolate.rootLib!.uri!; - - await client.evaluate( - isolateId, - library, - "registerExtension('ext.bar', $callback)", - ); - - await eventsDone; - - final source = await context.webDriver.pageSource; - // Main is re-invoked which shouldn't clear the state. - expect(source, contains('Hello World!')); - }); - - test('can refresh the page via the fullReload service extension', () async { - final client = context.debugConnection.vmService; - await client.streamListen('Isolate'); - await makeEditAndWaitForRebuild(); - - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - emitsInOrder([ - _hasKind(EventKind.kIsolateExit), - _hasKind(EventKind.kIsolateStart), - _hasKind(EventKind.kIsolateRunnable), - ]), - ), - ); - - expect(await client.callServiceExtension('fullReload'), isA()); - - await eventsDone; - - final source = await context.webDriver.pageSource; - // Should see only the new text - expect(source.contains(originalString), isFalse); - expect(source.contains(newString), isTrue); - }); - - test('can hot restart while paused', () async { - final client = context.debugConnection.vmService; - var vm = await client.getVM(); - var isolateId = vm.isolates!.first.id!; - await client.streamListen('Debug'); - final stream = client.onEvent('Debug'); - final scriptList = await client.getScripts(isolateId); - final main = scriptList.scripts! - .firstWhere((script) => script.uri!.contains('main.dart')); - final bpLine = - await context.findBreakpointLine('printCount', isolateId, main); - await client.addBreakpoint(isolateId, main.id!, bpLine); - await stream - .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - await makeEditAndWaitForRebuild(); - await client.callServiceExtension('hotRestart'); - final source = await context.webDriver.pageSource; - - // Main is re-invoked which shouldn't clear the state. - expect(source.contains(originalString), isTrue); - expect(source.contains(newString), isTrue); - - vm = await client.getVM(); - isolateId = vm.isolates!.first.id!; - final isolate = await client.getIsolate(isolateId); - - // Previous breakpoint should still exist. - expect(isolate.breakpoints!.isNotEmpty, isTrue); - final bp = isolate.breakpoints!.first; - - // Should pause eventually. - await stream - .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - expect( - await client.removeBreakpoint(isolate.id!, bp.id!), - isA(), - ); - expect(await client.resume(isolate.id!), isA()); - }); - - test('can evaluate expressions after hot restart ', () async { - final client = context.debugConnection.vmService; - var vm = await client.getVM(); - var isolateId = vm.isolates!.first.id!; - await client.streamListen('Debug'); - final stream = client.onEvent('Debug'); - final scriptList = await client.getScripts(isolateId); - final main = scriptList.scripts! - .firstWhere((script) => script.uri!.contains('main.dart')); - final bpLine = - await context.findBreakpointLine('printCount', isolateId, main); - await client.addBreakpoint(isolateId, main.id!, bpLine); - await stream - .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - await client.callServiceExtension('hotRestart'); - - vm = await client.getVM(); - isolateId = vm.isolates!.first.id!; - final isolate = await client.getIsolate(isolateId); - final library = isolate.rootLib!.uri!; - final bp = isolate.breakpoints!.first; - - // Should pause eventually. - final event = await stream - .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - // Expression evaluation while paused on a breakpoint should work. - var result = await client.evaluateInFrame( - isolate.id!, - event.topFrame!.index!, - 'count', - ); - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - greaterThanOrEqualTo('0'), - ), - ); - - await client.removeBreakpoint(isolateId, bp.id!); - await client.resume(isolateId); - - // Expression evaluation while running should work. - result = await client.evaluate(isolateId, library, 'true'); - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - 'true', - ), - ); - }); - }); - - group('Injected client with hot restart', () { - group('and with debugging', () { - setUp(() async { - setCurrentLogWriter(debug: debug); - await context.setUp( - testSettings: TestSettings( - reloadConfiguration: ReloadConfiguration.hotRestart, + final eventsDone = expectLater( + client.onIsolateEvent, + emitsThrough( + emitsInOrder([ + _hasKind(EventKind.kIsolateExit), + _hasKind(EventKind.kIsolateStart), + _hasKind(EventKind.kIsolateRunnable), + ]), ), ); - }); - tearDown(() async { - await context.tearDown(); - undoEdit(); + await context.webDriver.driver.refresh(); + + await eventsDone; }); - test('can hot restart changes ', () async { + test('can hot restart via the service extension', () async { + final client = context.debugConnection.vmService; + await client.streamListen('Isolate'); await makeEditAndWaitForRebuild(); - final source = await context.webDriver.pageSource; + final eventsDone = expectLater( + client.onIsolateEvent, + emitsThrough( + emitsInOrder([ + _hasKind(EventKind.kIsolateExit), + _hasKind(EventKind.kIsolateStart), + _hasKind(EventKind.kIsolateRunnable), + ]), + ), + ); + + expect( + await client.callServiceExtension('hotRestart'), + const TypeMatcher(), + ); + + await eventsDone; + final source = await context.webDriver.pageSource; // Main is re-invoked which shouldn't clear the state. - expect(source.contains(originalString), isTrue); - expect(source.contains(newString), isTrue); - // The ext.flutter.disassemble callback is invoked and waited for. + expect(source, contains(originalString)); + expect(source, contains(newString)); + }); + + test('can send events before and after hot restart', () async { + final client = context.debugConnection.vmService; + await client.streamListen('Isolate'); + + // The event just before hot restart might never be received, + // but the injected client continues to work and send events + // after hot restart. + final eventsDone = expectLater( + client.onIsolateEvent, + emitsThrough( + _hasKind(EventKind.kServiceExtensionAdded) + .having((e) => e.extensionRPC, 'service', 'ext.bar'), + ), + ); + + var vm = await client.getVM(); + var isolateId = vm.isolates!.first.id!; + var isolate = await client.getIsolate(isolateId); + var library = isolate.rootLib!.uri!; + + final String callback = + '(_, __) async => ServiceExtensionResponse.result("")'; + + await client.evaluate( + isolateId, + library, + "registerExtension('ext.foo', $callback)", + ); + expect( - source, - contains('start disassemble end disassemble $newString'), + await client.callServiceExtension('hotRestart'), + const TypeMatcher(), + ); + + vm = await client.getVM(); + isolateId = vm.isolates!.first.id!; + isolate = await client.getIsolate(isolateId); + library = isolate.rootLib!.uri!; + + await client.evaluate( + isolateId, + library, + "registerExtension('ext.bar', $callback)", ); + + await eventsDone; + + final source = await context.webDriver.pageSource; + // Main is re-invoked which shouldn't clear the state. + expect(source, contains('Hello World!')); }); - test('fires isolate create/destroy events during hot restart', () async { + test('can refresh the page via the fullReload service extension', + () async { final client = context.debugConnection.vmService; await client.streamListen('Isolate'); + await makeEditAndWaitForRebuild(); final eventsDone = expectLater( client.onIsolateEvent, @@ -486,45 +338,208 @@ void main() { ), ); - await makeEditAndWaitForRebuild(); + expect(await client.callServiceExtension('fullReload'), isA()); await eventsDone; - }); - }); - group('and without debugging', () { - setUp(() async { - setCurrentLogWriter(debug: debug); - await context.setUp( - testSettings: TestSettings( - reloadConfiguration: ReloadConfiguration.hotRestart, - ), - debugSettings: - TestDebugSettings.noDevTools().copyWith(enableDebugging: false), - ); + final source = await context.webDriver.pageSource; + // Should see only the new text + expect(source.contains(originalString), isFalse); + expect(source.contains(newString), isTrue); }); - tearDown(() async { - await context.tearDown(); - undoEdit(); - }); + test('can hot restart while paused', () async { + final client = context.debugConnection.vmService; + var vm = await client.getVM(); + var isolateId = vm.isolates!.first.id!; + await client.streamListen('Debug'); + final stream = client.onEvent('Debug'); + final scriptList = await client.getScripts(isolateId); + final main = scriptList.scripts! + .firstWhere((script) => script.uri!.contains('main.dart')); + final bpLine = + await context.findBreakpointLine('printCount', isolateId, main); + await client.addBreakpoint(isolateId, main.id!, bpLine); + await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - test('can hot restart changes ', () async { await makeEditAndWaitForRebuild(); - + await client.callServiceExtension('hotRestart'); final source = await context.webDriver.pageSource; // Main is re-invoked which shouldn't clear the state. expect(source.contains(originalString), isTrue); expect(source.contains(newString), isTrue); - // The ext.flutter.disassemble callback is invoked and waited for. + + vm = await client.getVM(); + isolateId = vm.isolates!.first.id!; + final isolate = await client.getIsolate(isolateId); + + // Previous breakpoint should still exist. + expect(isolate.breakpoints!.isNotEmpty, isTrue); + final bp = isolate.breakpoints!.first; + + // Should pause eventually. + await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + expect( - source, - contains('start disassemble end disassemble $newString'), + await client.removeBreakpoint(isolate.id!, bp.id!), + isA(), ); + expect(await client.resume(isolate.id!), isA()); + }); + + test('can evaluate expressions after hot restart ', () async { + final client = context.debugConnection.vmService; + var vm = await client.getVM(); + var isolateId = vm.isolates!.first.id!; + await client.streamListen('Debug'); + final stream = client.onEvent('Debug'); + final scriptList = await client.getScripts(isolateId); + final main = scriptList.scripts! + .firstWhere((script) => script.uri!.contains('main.dart')); + final bpLine = + await context.findBreakpointLine('printCount', isolateId, main); + await client.addBreakpoint(isolateId, main.id!, bpLine); + await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + await client.callServiceExtension('hotRestart'); + + vm = await client.getVM(); + isolateId = vm.isolates!.first.id!; + final isolate = await client.getIsolate(isolateId); + final library = isolate.rootLib!.uri!; + final bp = isolate.breakpoints!.first; + + // Should pause eventually. + final event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + // Expression evaluation while paused on a breakpoint should work. + var result = await client.evaluateInFrame( + isolate.id!, + event.topFrame!.index!, + 'count', + ); + expect( + result, + isA().having( + (instance) => instance.valueAsString, + 'valueAsString', + greaterThanOrEqualTo('0'), + ), + ); + + await client.removeBreakpoint(isolateId, bp.id!); + await client.resume(isolateId); + + // Expression evaluation while running should work. + result = await client.evaluate(isolateId, library, 'true'); + expect( + result, + isA().having( + (instance) => instance.valueAsString, + 'valueAsString', + 'true', + ), + ); + }); + }, + timeout: Timeout.factor(2), + ); + + group( + 'Injected client with hot restart', + () { + group('and with debugging', () { + setUp(() async { + setCurrentLogWriter(debug: debug); + await context.setUp( + testSettings: TestSettings( + reloadConfiguration: ReloadConfiguration.hotRestart, + ), + ); + }); + + tearDown(() async { + await context.tearDown(); + undoEdit(); + }); + + test('can hot restart changes ', () async { + await makeEditAndWaitForRebuild(); + + final source = await context.webDriver.pageSource; + + // Main is re-invoked which shouldn't clear the state. + expect(source.contains(originalString), isTrue); + expect(source.contains(newString), isTrue); + // The ext.flutter.disassemble callback is invoked and waited for. + expect( + source, + contains('start disassemble end disassemble $newString'), + ); + }); + + test('fires isolate create/destroy events during hot restart', + () async { + final client = context.debugConnection.vmService; + await client.streamListen('Isolate'); + + final eventsDone = expectLater( + client.onIsolateEvent, + emitsThrough( + emitsInOrder([ + _hasKind(EventKind.kIsolateExit), + _hasKind(EventKind.kIsolateStart), + _hasKind(EventKind.kIsolateRunnable), + ]), + ), + ); + + await makeEditAndWaitForRebuild(); + + await eventsDone; + }); + }); + + group('and without debugging', () { + setUp(() async { + setCurrentLogWriter(debug: debug); + await context.setUp( + testSettings: TestSettings( + reloadConfiguration: ReloadConfiguration.hotRestart, + ), + debugSettings: + TestDebugSettings.noDevTools().copyWith(enableDebugging: false), + ); + }); + + tearDown(() async { + await context.tearDown(); + undoEdit(); + }); + + test('can hot restart changes ', () async { + await makeEditAndWaitForRebuild(); + + final source = await context.webDriver.pageSource; + + // Main is re-invoked which shouldn't clear the state. + expect(source.contains(originalString), isTrue); + expect(source.contains(newString), isTrue); + // The ext.flutter.disassemble callback is invoked and waited for. + expect( + source, + contains('start disassemble end disassemble $newString'), + ); + }); }); - }); - }); + }, + timeout: Timeout.factor(2), + ); } TypeMatcher _hasKind(String kind) => diff --git a/dwds/test/run_request_test.dart b/dwds/test/run_request_test.dart index 89db646a5..1ce04425b 100644 --- a/dwds/test/run_request_test.dart +++ b/dwds/test/run_request_test.dart @@ -68,7 +68,7 @@ void main() { await stream.firstWhere((event) => event.kind == EventKind.kResume); expect(isolate.pauseEvent!.kind, EventKind.kResume); }); - }); + }, timeout: Timeout.factor(2),); group('while debugger is not attached', () { setUp(() async { diff --git a/test_common/test/test_sdk_configuration_test.dart b/test_common/test/test_sdk_configuration_test.dart index 5b01d0613..2e5febef5 100644 --- a/test_common/test/test_sdk_configuration_test.dart +++ b/test_common/test/test_sdk_configuration_test.dart @@ -7,6 +7,7 @@ import 'dart:io'; +import 'package:dwds/expression_compiler.dart'; import 'package:test/test.dart'; import 'package:test_common/logging.dart'; import 'package:test_common/test_sdk_configuration.dart'; @@ -40,7 +41,45 @@ void main() { }); }); - group('Test SDK configuration |', () { + group('Test SDK configuration | DDC with DDC modules |', () { + setCurrentLogWriter(debug: debug); + final provider = TestSdkConfigurationProvider( + verbose: debug, ddcModuleFormat: ModuleFormat.ddc); + tearDownAll(provider.dispose); + + test('Can validate configuration with generated assets', () async { + final sdkConfiguration = await provider.configuration; + sdkConfiguration.validateSdkDir(); + sdkConfiguration.validate(); + }); + + test('SDK layout exists', () async { + await provider.configuration; + final sdkLayout = provider.sdkLayout; + + expect(sdkLayout.sdkDirectory, _directoryExists); + expect(sdkLayout.soundDdcJsPath, _fileExists); + expect(sdkLayout.soundDdcJsMapPath, _fileExists); + expect(sdkLayout.soundSummaryPath, _fileExists); + expect(sdkLayout.soundFullDillPath, _fileExists); + + expect(sdkLayout.weakDdcJsPath, _fileExists); + expect(sdkLayout.weakDdcJsMapPath, _fileExists); + expect(sdkLayout.weakSummaryPath, _fileExists); + expect(sdkLayout.weakFullDillPath, _fileExists); + + expect(sdkLayout.ddcModuleLoaderJsPath, _fileExists); + expect(sdkLayout.stackTraceMapperPath, _fileExists); + + expect(sdkLayout.dartPath, _fileExists); + expect(sdkLayout.frontendServerSnapshotPath, _fileExists); + expect(sdkLayout.dartdevcSnapshotPath, _fileExists); + expect(sdkLayout.kernelWorkerSnapshotPath, _fileExists); + expect(sdkLayout.devToolsDirectory, _directoryExists); + }); + }); + + group('Test SDK configuration | DDC with AMD modules |', () { setCurrentLogWriter(debug: debug); final provider = TestSdkConfigurationProvider(verbose: debug); tearDownAll(provider.dispose); @@ -58,20 +97,15 @@ void main() { expect(sdkLayout.sdkDirectory, _directoryExists); expect(sdkLayout.soundAmdJsPath, _fileExists); expect(sdkLayout.soundAmdJsMapPath, _fileExists); - expect(sdkLayout.soundDdcJsPath, _fileExists); - expect(sdkLayout.soundDdcJsMapPath, _fileExists); expect(sdkLayout.soundSummaryPath, _fileExists); expect(sdkLayout.soundFullDillPath, _fileExists); expect(sdkLayout.weakAmdJsPath, _fileExists); expect(sdkLayout.weakAmdJsMapPath, _fileExists); - expect(sdkLayout.weakDdcJsPath, _fileExists); - expect(sdkLayout.weakDdcJsMapPath, _fileExists); expect(sdkLayout.weakSummaryPath, _fileExists); expect(sdkLayout.weakFullDillPath, _fileExists); expect(sdkLayout.requireJsPath, _fileExists); - expect(sdkLayout.ddcModuleLoaderJsPath, _fileExists); expect(sdkLayout.stackTraceMapperPath, _fileExists); expect(sdkLayout.dartPath, _fileExists); From dafca8ae3e5a4074485ec890cb7f7f7cb8ea16fd Mon Sep 17 00:00:00 2001 From: MarkZ Date: Mon, 18 Dec 2023 16:17:09 -0800 Subject: [PATCH 18/22] formatting files --- dwds/test/run_request_test.dart | 90 ++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 42 deletions(-) diff --git a/dwds/test/run_request_test.dart b/dwds/test/run_request_test.dart index 1ce04425b..8efd4f0c4 100644 --- a/dwds/test/run_request_test.dart +++ b/dwds/test/run_request_test.dart @@ -24,51 +24,57 @@ void main() { final context = TestContext(TestProject.testWithSoundNullSafety, provider); - group('while debugger is attached', () { - late VmServiceInterface service; - setUp(() async { - setCurrentLogWriter(debug: debug); - await context.setUp( - testSettings: TestSettings( - autoRun: false, - verboseCompiler: debug, - ), - ); - service = context.service; - }); + group( + 'while debugger is attached', + () { + late VmServiceInterface service; + setUp(() async { + setCurrentLogWriter(debug: debug); + await context.setUp( + testSettings: TestSettings( + autoRun: false, + verboseCompiler: debug, + ), + ); + service = context.service; + }); - tearDown(() async { - await context.tearDown(); - }); + tearDown(() async { + await context.tearDown(); + }); - test('can resume while paused at the start', () async { - final vm = await service.getVM(); - final isolate = await service.getIsolate(vm.isolates!.first.id!); - expect(isolate.pauseEvent!.kind, EventKind.kPauseStart); - final stream = service.onEvent('Debug'); - final resumeCompleter = Completer(); - // The underlying stream is a broadcast stream so we need to add a - // listener before calling resume so that we don't miss events. - unawaited( - stream.firstWhere((event) => event.kind == EventKind.kResume).then((_) { - resumeCompleter.complete(); - }), - ); - await service.resume(isolate.id!); - await resumeCompleter.future; - expect(isolate.pauseEvent!.kind, EventKind.kResume); - }); + test('can resume while paused at the start', () async { + final vm = await service.getVM(); + final isolate = await service.getIsolate(vm.isolates!.first.id!); + expect(isolate.pauseEvent!.kind, EventKind.kPauseStart); + final stream = service.onEvent('Debug'); + final resumeCompleter = Completer(); + // The underlying stream is a broadcast stream so we need to add a + // listener before calling resume so that we don't miss events. + unawaited( + stream + .firstWhere((event) => event.kind == EventKind.kResume) + .then((_) { + resumeCompleter.complete(); + }), + ); + await service.resume(isolate.id!); + await resumeCompleter.future; + expect(isolate.pauseEvent!.kind, EventKind.kResume); + }); - test('correctly sets the isolate pauseEvent', () async { - final vm = await service.getVM(); - final isolate = await service.getIsolate(vm.isolates!.first.id!); - expect(isolate.pauseEvent!.kind, EventKind.kPauseStart); - final stream = service.onEvent('Debug'); - context.appConnection.runMain(); - await stream.firstWhere((event) => event.kind == EventKind.kResume); - expect(isolate.pauseEvent!.kind, EventKind.kResume); - }); - }, timeout: Timeout.factor(2),); + test('correctly sets the isolate pauseEvent', () async { + final vm = await service.getVM(); + final isolate = await service.getIsolate(vm.isolates!.first.id!); + expect(isolate.pauseEvent!.kind, EventKind.kPauseStart); + final stream = service.onEvent('Debug'); + context.appConnection.runMain(); + await stream.firstWhere((event) => event.kind == EventKind.kResume); + expect(isolate.pauseEvent!.kind, EventKind.kResume); + }); + }, + timeout: Timeout.factor(2), + ); group('while debugger is not attached', () { setUp(() async { From 42c674e6aef75e7b7ec97665ad7aae6af1d7a9f8 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Thu, 7 Dec 2023 13:11:50 -0800 Subject: [PATCH 19/22] Exposing utilities/ddc_names.dart --- dwds/lib/dwds.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/dwds/lib/dwds.dart b/dwds/lib/dwds.dart index a9016398c..d0898d792 100644 --- a/dwds/lib/dwds.dart +++ b/dwds/lib/dwds.dart @@ -41,5 +41,6 @@ export 'src/services/expression_compiler.dart' CompilerOptions; export 'src/services/expression_compiler_service.dart' show ExpressionCompilerService; +export 'src/utilities/ddc_names.dart'; export 'src/utilities/sdk_configuration.dart' show SdkLayout, SdkConfiguration, SdkConfigurationProvider; From f4ae7e2b80982f399db06a0ec22c54bd1c0b6d57 Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Tue, 9 Jan 2024 12:38:42 -0800 Subject: [PATCH 20/22] Loosen `vm_service` constraints and prepare DWDS for release to 23.1.1 (#2329) --- dwds/CHANGELOG.md | 5 ++++- dwds/lib/src/version.dart | 2 +- dwds/pubspec.yaml | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md index 0b98d5f76..2bcdbec2b 100644 --- a/dwds/CHANGELOG.md +++ b/dwds/CHANGELOG.md @@ -1,7 +1,10 @@ +## 23.1.1 + +- Loosen `package:vm_service` constraints to allow `>=13.0.0 <15.0.0`. - [#2329](https://github.com/dart-lang/webdev/pull/2329) + ## 23.1.0 - Update `package:vm_service` constraints to allow version `14.x.x` - [#2307](https://github.com/dart-lang/webdev/pull/2307) -- Enabling tests that run with the DDC module system and exposing `utilities/ddc_names.dart` - [#2295](https://github.com/dart-lang/webdev/pull/2295) ## 23.0.0 diff --git a/dwds/lib/src/version.dart b/dwds/lib/src/version.dart index 9dbf4fcd4..8f524dd3d 100644 --- a/dwds/lib/src/version.dart +++ b/dwds/lib/src/version.dart @@ -1,2 +1,2 @@ // Generated code. Do not modify. -const packageVersion = '23.1.0'; +const packageVersion = '23.1.1'; diff --git a/dwds/pubspec.yaml b/dwds/pubspec.yaml index 1049cee95..76aa5c68f 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: 23.1.0 +version: 23.1.1 description: >- A service that proxies between the Chrome debug protocol and the Dart VM service protocol. @@ -33,7 +33,7 @@ dependencies: stack_trace: ^1.10.0 sse: ^4.1.2 uuid: ^3.0.6 - vm_service: ^14.0.0 + vm_service: ">=13.0.0 <15.0.0" vm_service_interface: 1.0.1 web_socket_channel: ^2.2.0 webkit_inspection_protocol: ^1.0.1 From 4f143c902f06e2fefe69c5783781424f2ac37e68 Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Wed, 10 Jan 2024 10:24:33 -0800 Subject: [PATCH 21/22] Reset DWDS to version `23.2.0-wip` after release (#2334) --- dwds/CHANGELOG.md | 2 ++ dwds/lib/src/version.dart | 2 +- dwds/pubspec.yaml | 2 +- dwds/{ignore_pubspec_overrides.yaml => pubspec_overrides.yaml} | 0 4 files changed, 4 insertions(+), 2 deletions(-) rename dwds/{ignore_pubspec_overrides.yaml => pubspec_overrides.yaml} (100%) diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md index 2bcdbec2b..d596e5849 100644 --- a/dwds/CHANGELOG.md +++ b/dwds/CHANGELOG.md @@ -1,3 +1,5 @@ +## 23.2.0-wip + ## 23.1.1 - Loosen `package:vm_service` constraints to allow `>=13.0.0 <15.0.0`. - [#2329](https://github.com/dart-lang/webdev/pull/2329) diff --git a/dwds/lib/src/version.dart b/dwds/lib/src/version.dart index 8f524dd3d..dc527920e 100644 --- a/dwds/lib/src/version.dart +++ b/dwds/lib/src/version.dart @@ -1,2 +1,2 @@ // Generated code. Do not modify. -const packageVersion = '23.1.1'; +const packageVersion = '23.2.0-wip'; diff --git a/dwds/pubspec.yaml b/dwds/pubspec.yaml index 76aa5c68f..def292d10 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: 23.1.1 +version: 23.2.0-wip description: >- A service that proxies between the Chrome debug protocol and the Dart VM service protocol. diff --git a/dwds/ignore_pubspec_overrides.yaml b/dwds/pubspec_overrides.yaml similarity index 100% rename from dwds/ignore_pubspec_overrides.yaml rename to dwds/pubspec_overrides.yaml From ac28b963db3f901f6a5e976bb18a9fd8d64c93c6 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Wed, 10 Jan 2024 12:35:30 -0800 Subject: [PATCH 22/22] Adding changelog --- dwds/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md index d596e5849..05b8209bb 100644 --- a/dwds/CHANGELOG.md +++ b/dwds/CHANGELOG.md @@ -1,5 +1,7 @@ ## 23.2.0-wip +- Enabling tests that run with the DDC module system and exposing `utilities/ddc_names.dart` - [#2295](https://github.com/dart-lang/webdev/pull/2295) + ## 23.1.1 - Loosen `package:vm_service` constraints to allow `>=13.0.0 <15.0.0`. - [#2329](https://github.com/dart-lang/webdev/pull/2329)