[test] Add compiler `dart test -c cli` to run hooks (#2660)
Bug:
* https://github.com/dart-lang/sdk/issues/63372
This PR uses `dart build cli` under the `-c cli` flag.
Implementation:
* The wrapper Dart script around the test that package test creates is the new entry-point and **must** be within the package root to run the correct hooks.
* So, this PR updates the temp dir to be in `.dart_tool/test/temp/<...>` rather than in the system temp.
* Gates the implementation on the next dev release after https://dart-review.googlesource.com/c/sdk/+/506242.
Testing:
* The integration tests run with the `cli` compiler
* The integration tests must run on a valid package with a valid pubspec and package_config.json (otherwise the hooks-runner cannot determine which hooks to run).
* The integration tests do _not_ actually run a hook and include c code. `dart build cli` bundles are already properly tested in the dartdev tests for `dart build cli` in the SDK. If you feel we should add an integration test running native code here, I'm happy to add one.
* Skips the tests before the next dev release.
* **TODO**: Rerun tests on Tuesday after new dev release has come out.
diff --git a/pkgs/test/CHANGELOG.md b/pkgs/test/CHANGELOG.md
index c148eac..438b506 100644
--- a/pkgs/test/CHANGELOG.md
+++ b/pkgs/test/CHANGELOG.md
@@ -1,5 +1,7 @@
## 1.31.2-wip
+* Add support for running tests as native CLI bundles (vm platform only).
+ * You can run tests this way with `--compiler cli`.
* **Impacts Configuration** Support using the OS platform selector to configure
browser tests.
Previously tests loaded for the browser would have an operating system of
diff --git a/pkgs/test/lib/src/runner/browser/compilers/precompiled.dart b/pkgs/test/lib/src/runner/browser/compilers/precompiled.dart
index f5d2d78..77fd36d 100644
--- a/pkgs/test/lib/src/runner/browser/compilers/precompiled.dart
+++ b/pkgs/test/lib/src/runner/browser/compilers/precompiled.dart
@@ -112,6 +112,7 @@
faviconPath,
),
Compiler.exe ||
+ Compiler.cli ||
Compiler.kernel ||
Compiler.source => throw UnsupportedError(
'The browser platform does not support $compiler',
diff --git a/pkgs/test/pubspec.yaml b/pkgs/test/pubspec.yaml
index 9cbda09..8c8f47c 100644
--- a/pkgs/test/pubspec.yaml
+++ b/pkgs/test/pubspec.yaml
@@ -46,6 +46,7 @@
dev_dependencies:
fake_async: ^1.0.0
glob: ^2.0.0
+ pub_semver: ^2.0.0
test_descriptor: ^2.0.0
test_process: ^2.0.0
diff --git a/pkgs/test/test/io.dart b/pkgs/test/test/io.dart
index ef7eb96..d1780be 100644
--- a/pkgs/test/test/io.dart
+++ b/pkgs/test/test/io.dart
@@ -7,6 +7,7 @@
import 'dart:isolate';
import 'package:path/path.dart' as p;
+import 'package:pub_semver/pub_semver.dart';
import 'package:test/test.dart';
import 'package:test_descriptor/test_descriptor.dart' as d;
import 'package:test_process/test_process.dart';
@@ -25,6 +26,11 @@
/// The root directory of the Dart SDK.
final String sdkDir = p.dirname(p.dirname(Platform.resolvedExecutable));
+final bool supportsCliCompiler = () {
+ var current = Version.parse(Platform.version.split(' ').first);
+ return current > Version.parse('3.13.0-159.0.dev');
+}();
+
/// The platform-specific message emitted when a nonexistent file is loaded.
final String noSuchFileMessage = Platform.isWindows
? 'The system cannot find the file specified.'
diff --git a/pkgs/test/test/runner/compiler_runtime_matrix_test.dart b/pkgs/test/test/runner/compiler_runtime_matrix_test.dart
index 6d90a2d..f6ec7da 100644
--- a/pkgs/test/test/runner/compiler_runtime_matrix_test.dart
+++ b/pkgs/test/test/runner/compiler_runtime_matrix_test.dart
@@ -48,6 +48,8 @@
} else if (runtime == Runtime.vmTsan &&
!File('$sdkDir/bin/dartaotruntime_tsan').existsSync()) {
skipReason = 'SDK too old';
+ } else if (compiler == Compiler.cli && !supportsCliCompiler) {
+ skipReason = 'SDK too old';
}
group(
'--runtime ${runtime.identifier} --compiler ${compiler.identifier}',
diff --git a/pkgs/test/test/runner/runner_test.dart b/pkgs/test/test/runner/runner_test.dart
index 8a8594f..5647ef9 100644
--- a/pkgs/test/test/runner/runner_test.dart
+++ b/pkgs/test/test/runner/runner_test.dart
@@ -75,7 +75,7 @@
$_runtimes.
Each platform supports the following compilers:
$_runtimeCompilers
--c, --compiler The compiler(s) to use to run tests, supported compilers are [dart2js, dart2wasm, exe, kernel, source].
+-c, --compiler The compiler(s) to use to run tests, supported compilers are [dart2js, dart2wasm, exe, cli, kernel, source].
Each platform has a default compiler but may support other compilers.
You can target a compiler to a specific platform using arguments of the following form [<platform-selector>:]<compiler>.
If a platform is specified but no given compiler is supported for that platform, then it will use its default compiler.
@@ -137,7 +137,7 @@
', edge, node]';
final _runtimeCompilers = [
- '[vm]: kernel (default), source, exe',
+ '[vm]: kernel (default), source, exe, cli',
'[vm-asan]: exe (default)',
'[vm-msan]: exe (default)',
'[vm-tsan]: exe (default)',
diff --git a/pkgs/test/test/runner/subprocess_crash_test.dart b/pkgs/test/test/runner/subprocess_crash_test.dart
index e98f634..59bea2f 100644
--- a/pkgs/test/test/runner/subprocess_crash_test.dart
+++ b/pkgs/test/test/runner/subprocess_crash_test.dart
@@ -13,27 +13,35 @@
void main() {
setUpAll(precompileTestExecutable);
- test('gracefully handles an early test suite exit', () async {
- await d.file('test.dart', '''
- import 'dart:io';
+ for (var compiler in ['exe', 'cli']) {
+ test(
+ 'gracefully handles an early test suite exit with the $compiler compiler',
+ () async {
+ await d.file('test.dart', '''
+ import 'dart:io';
- import 'package:test/test.dart';
+ import 'package:test/test.dart';
- void main() {
- test('runs', () {});
- test('exits', () {
- exit(0);
- });
- }''').create();
+ void main() {
+ test('runs', () {});
+ test('exits', () {
+ exit(0);
+ });
+ }''').create();
- var test = await runTest(['--compiler', 'exe', 'test.dart']);
- expect(
- test.stdout,
- containsInOrder([
- '+1: [VM, Exe] exits - did not complete [E]',
- '+1: Some tests failed.',
- ]),
+ var test = await runTest(['--compiler', compiler, 'test.dart']);
+ expect(
+ test.stdout,
+ containsInOrder([
+ '+1: [VM, ${compiler == 'exe' ? 'Exe' : 'Cli'}] exits - did not complete [E]',
+ '+1: Some tests failed.',
+ ]),
+ );
+ await test.shouldExit(1);
+ },
+ skip: compiler == 'cli' && !supportsCliCompiler
+ ? 'Dart version does not support build cli'
+ : null,
);
- await test.shouldExit(1);
- });
+ }
}
diff --git a/pkgs/test_api/CHANGELOG.md b/pkgs/test_api/CHANGELOG.md
index 3f36614..cfc807c 100644
--- a/pkgs/test_api/CHANGELOG.md
+++ b/pkgs/test_api/CHANGELOG.md
@@ -1,5 +1,6 @@
## 0.7.13-wip
+* Add `Compiler.cli` (the native CLI compiler).
* Expose several more backend APIs for use in `flutter_test`.
* Allow using browser platforms with a specified OS.
diff --git a/pkgs/test_api/lib/src/backend/compiler.dart b/pkgs/test_api/lib/src/backend/compiler.dart
index dc41e92..5df6bf6 100644
--- a/pkgs/test_api/lib/src/backend/compiler.dart
+++ b/pkgs/test_api/lib/src/backend/compiler.dart
@@ -10,9 +10,14 @@
/// Experimental Dart to Wasm compiler.
dart2wasm('Dart2Wasm', 'dart2wasm'),
- /// Compiles dart code to a native executable.
+ /// Compiles dart code to a native executable. This compiler does not
+ /// support code assets from build and link hooks.
exe('Exe', 'exe'),
+ /// Compiles dart code to a native CLI bundle. This compiler supports
+ /// code assets from build and link hooks.
+ cli('Cli', 'cli'),
+
/// The standard compiler for vm tests, compiles tests to kernel before
/// running them on the VM.
kernel('Kernel', 'kernel'),
@@ -25,6 +30,7 @@
Compiler.dart2js,
Compiler.dart2wasm,
Compiler.exe,
+ Compiler.cli,
Compiler.kernel,
Compiler.source,
];
diff --git a/pkgs/test_api/lib/src/backend/runtime.dart b/pkgs/test_api/lib/src/backend/runtime.dart
index 0ce9cd7..3e1e4cd 100644
--- a/pkgs/test_api/lib/src/backend/runtime.dart
+++ b/pkgs/test_api/lib/src/backend/runtime.dart
@@ -14,6 +14,7 @@
Compiler.kernel,
Compiler.source,
Compiler.exe,
+ Compiler.cli,
], isDartVM: true);
static const Runtime vmAsan = Runtime(
'VM with Address Sanitizer',
diff --git a/pkgs/test_core/CHANGELOG.md b/pkgs/test_core/CHANGELOG.md
index 6907873..d77a622 100644
--- a/pkgs/test_core/CHANGELOG.md
+++ b/pkgs/test_core/CHANGELOG.md
@@ -1,5 +1,6 @@
## 0.6.19-wip
+* Add support for `-c cli` (the native CLI compiler) to the vm platform.
* Support using the OS platform selector to configure browser tests.
* Use a DevTools URL instead of a defunct observatory URL.
diff --git a/pkgs/test_core/lib/src/runner/vm/platform.dart b/pkgs/test_core/lib/src/runner/vm/platform.dart
index 8916e77..1c1f596 100644
--- a/pkgs/test_core/lib/src/runner/vm/platform.dart
+++ b/pkgs/test_core/lib/src/runner/vm/platform.dart
@@ -57,7 +57,8 @@
MultiChannel outerChannel;
var cleanupCallbacks = <void Function()>[];
Isolate? isolate;
- if (platform.compiler == Compiler.exe) {
+ if (platform.compiler == Compiler.exe ||
+ platform.compiler == Compiler.cli) {
var serverSocket = await ServerSocket.bind('localhost', 0);
Process process;
try {
@@ -131,10 +132,11 @@
String? isolateID;
Uri? serverUri;
if (_config.debug) {
- if (platform.compiler == Compiler.exe) {
+ if (platform.compiler == Compiler.exe ||
+ platform.compiler == Compiler.cli) {
throw UnsupportedError(
- 'Unable to debug tests compiled to `exe` (tried to debug $path with '
- 'the `exe` compiler).',
+ 'Unable to debug tests compiled to `${platform.compiler.identifier}` '
+ '(tried to debug $path with the `${platform.compiler.identifier}` compiler).',
);
}
var info = await Service.controlWebServer(
@@ -239,13 +241,79 @@
);
}
- var sharedLibrary = await _compileToNative(platform, path, suiteMetadata);
- return await Process.start(
- _aotRuntimeFor(platform),
- [sharedLibrary, socket.address.host, socket.port.toString()],
- environment: _environmentFor(platform),
- mode: ProcessStartMode.inheritStdio,
+ switch (platform.compiler) {
+ case Compiler.cli:
+ var executable = await _compileToCli(platform, path, suiteMetadata);
+ return await Process.start(executable, [
+ socket.address.host,
+ socket.port.toString(),
+ ], mode: ProcessStartMode.inheritStdio);
+ case Compiler.exe:
+ var sharedLibrary = await _compileToNative(
+ platform,
+ path,
+ suiteMetadata,
+ );
+ return await Process.start(
+ _aotRuntimeFor(platform),
+ [sharedLibrary, socket.address.host, socket.port.toString()],
+ environment: _environmentFor(platform),
+ mode: ProcessStartMode.inheritStdio,
+ );
+ default:
+ throw StateError(
+ 'Unsupported compiler ${platform.compiler} for spawning an executable',
+ );
+ }
+ }
+
+ /// Compiles [path] to a native CLI bundle using `dart build cli`.
+ Future<String> _compileToCli(
+ SuitePlatform platform,
+ String path,
+ Metadata suiteMetadata,
+ ) async {
+ var bootstrapPath = await _bootstrapNativeTestFile(
+ path,
+ suiteMetadata.languageVersionComment ??
+ await rootPackageLanguageVersionComment,
);
+
+ var outputDir = p.join(_tempDir.path, 'cli_build');
+ var processResult = await Process.run(Platform.resolvedExecutable, [
+ 'build',
+ 'cli',
+ '--target',
+ bootstrapPath,
+ '--output',
+ outputDir,
+ '--packages',
+ (await packageConfigUri).toFilePath(),
+ '--root-package',
+ (await currentPackage).name,
+ if (platform.runtime == Runtime.vmAsan) '--target-sanitizer=asan',
+ if (platform.runtime == Runtime.vmMsan) '--target-sanitizer=msan',
+ if (platform.runtime == Runtime.vmTsan) '--target-sanitizer=tsan',
+ ]);
+ if (processResult.exitCode != 0) {
+ throw LoadException(path, '''
+exitCode: ${processResult.exitCode}
+stdout: ${processResult.stdout}
+stderr: ${processResult.stderr}''');
+ }
+ var executablePath = p.join(
+ outputDir,
+ 'bundle',
+ 'bin',
+ p.basenameWithoutExtension(bootstrapPath),
+ );
+ if (!await File(executablePath).exists()) {
+ throw LoadException(
+ path,
+ 'Compiled executable not found at $executablePath',
+ );
+ }
+ return executablePath;
}
/// Compiles [path] to a native shared library using