|
3 | 3 | // BSD-style license that can be found in the LICENSE file.
|
4 | 4 |
|
5 | 5 | import 'dart:async';
|
6 |
| -import 'dart:convert'; |
7 | 6 | import 'dart:io';
|
8 | 7 |
|
9 | 8 | import 'command.dart';
|
10 | 9 |
|
11 | 10 | // Runs tests on a fuchsia emulator with chromium maintained test-scripts and
|
12 | 11 | // CFv2 targets.
|
13 | 12 | class FuchsiaEmulator {
|
14 |
| - static const String testScriptRoot = |
15 |
| - "./third_party/fuchsia/test_scripts/test/"; |
16 | 13 | static const String withEnv = "./build/fuchsia/with_envs.py";
|
17 |
| - static const String tmpRoot = "/tmp/dart_ffi_test/"; |
18 |
| - // TODO(#38752): Once we have vm/cc and AOT tests running, this will sometimes |
19 |
| - // need to be the component for run_vm_tests or dart_precompiled_runtime. |
20 |
| - static const String cmName = "dart_test_component.cm"; |
21 | 14 |
|
22 | 15 | final Map<String, String> envs = <String, String>{};
|
23 |
| - Process? daemonProc; |
24 |
| - Process? emuProc; |
25 |
| - String? emuName; |
26 |
| - Process? repoProc; |
| 16 | + Directory? daemonIsolateDir; |
| 17 | + Process? publisher; |
27 | 18 |
|
28 | 19 | // Publishes the packages to the Fuchsia environment.
|
29 | 20 | Future<void> publishPackage(String buildDir, String mode, String arch) async {
|
30 |
| - try { |
31 |
| - await Directory(tmpRoot).delete(recursive: true); |
32 |
| - } catch (_) {} |
33 |
| - // The /tmp/ should always be present, recursive creation is not expected. |
34 |
| - await Directory(tmpRoot).create(); |
35 |
| - assert(daemonProc == null); |
36 |
| - daemonProc = await _run("isolate_daemon.py", []); |
37 |
| - var isolateDir = await _captureStdout(daemonProc!); |
38 |
| - print("+ ffx daemon running on $isolateDir should be ready now."); |
39 |
| - envs["FFX_ISOLATE_DIR"] = isolateDir; |
40 |
| - assert(emuProc == null); |
41 |
| - emuProc = await _run("start_emulator.py", [ |
42 |
| - "--disable-graphics", |
43 |
| - "--target-id-only", |
44 |
| - "--product", |
45 |
| - arch == "arm64" ? "terminal.qemu-arm64" : "terminal.x64", |
46 |
| - "--device-spec", |
47 |
| - "virtual_device_large" |
48 |
| - ]); |
49 |
| - emuName = await _captureStdout(emuProc!); |
50 |
| - print("+ Targeting emu name $emuName"); |
51 |
| - await _assertRun("test_connection.py", [emuName!]); |
52 |
| - await _assertRun("publish_package.py", [ |
53 |
| - "--packages", |
54 |
| - _testPackagePath(buildDir, mode), |
55 |
| - "--purge-repo", |
56 |
| - "--repo", |
57 |
| - _tempDirectoryOf("repo") |
58 |
| - ]); |
59 |
| - repoProc = await _run("serve_repo.py", [ |
60 |
| - "run", |
61 |
| - "--serve-repo", |
62 |
| - _tempDirectoryOf("repo"), |
63 |
| - "--repo-name", |
64 |
| - "dart-ffi-test-repo", |
65 |
| - "--target-id", |
66 |
| - emuName! |
67 |
| - ]); |
68 |
| - print("+ Fuchsia repo ${await _captureStdout(repoProc!)} is running " |
69 |
| - "at ${_tempDirectoryOf('repo')}"); |
70 |
| - await _assertRun("pkg_resolve.py", [emuName!, _testPackageName(mode)]); |
71 |
| - } |
72 |
| - |
73 |
| - // Tears down the Fuchsia environment. |
74 |
| - Future<void> stop() async { |
75 |
| - assert(repoProc != null); |
76 |
| - repoProc!.kill(); |
77 |
| - await repoProc!.exitCode; |
78 |
| - assert(emuProc != null); |
79 |
| - emuProc!.kill(); |
80 |
| - await emuProc!.exitCode; |
81 |
| - assert(daemonProc != null); |
82 |
| - daemonProc!.kill(); |
83 |
| - await daemonProc!.exitCode; |
| 21 | + assert(daemonIsolateDir == null); |
| 22 | + daemonIsolateDir = Directory.systemTemp.createTempSync(); |
| 23 | + envs["FFX_ISOLATE_DIR"] = daemonIsolateDir!.path; |
| 24 | + assert(publisher == null); |
| 25 | + var args = <String>[ |
| 26 | + "./build/fuchsia/test_env.py", |
| 27 | + "--out-dir=${_outDir(buildDir, mode)}", |
| 28 | + "--device-spec=virtual_device_large", |
| 29 | + "--packages=dart_test_$mode.far", |
| 30 | + "--logs-dir=${daemonIsolateDir!.path}" |
| 31 | + ]; |
| 32 | + if (arch == "arm64") { |
| 33 | + args.add("--product=terminal.qemu-arm64"); |
| 34 | + } |
| 35 | + publisher = await Process.start(withEnv, args, |
| 36 | + environment: envs, mode: ProcessStartMode.inheritStdio); |
| 37 | + while (!await File( |
| 38 | + "${daemonIsolateDir!.path}/test_env_setup.${publisher!.pid}.pid") |
| 39 | + .exists() && |
| 40 | + await _isProcessRunning(publisher!, 1000)) {} |
| 41 | + // TODO(38752): Should return a value to indicate the failure of the |
| 42 | + // enviornment setup. |
| 43 | + if (await _isProcessRunning(publisher!, 1)) { |
| 44 | + print("+ ffx daemon running on $daemonIsolateDir should be ready now."); |
| 45 | + } else { |
| 46 | + print("+ environment setup failure."); |
| 47 | + } |
84 | 48 | }
|
85 | 49 |
|
86 | 50 | // Returns a command to execute a set of tests against the running Fuchsia
|
87 | 51 | // environment.
|
88 |
| - VMCommand getTestCommand( |
89 |
| - String buildDir, String mode, String arch, List<String> arguments) { |
| 52 | + VMCommand getTestCommand(String buildDir, String mode, String arch, |
| 53 | + List<String> arguments, Map<String, String> environmentOverrides) { |
| 54 | + environmentOverrides.addAll(envs); |
90 | 55 | return VMCommand(
|
91 | 56 | withEnv,
|
92 |
| - _runArgs("run_executable_test.py", [ |
93 |
| - "--target-id", |
94 |
| - emuName!, |
95 |
| - "--out-dir", |
96 |
| - _tempDirectoryOf("out"), |
97 |
| - "--test-name", |
98 |
| - "fuchsia-pkg://fuchsia.com/${_testPackageName(mode)}#meta/$cmName", |
99 |
| - "--test-realm", |
| 57 | + [ |
| 58 | + "./third_party/fuchsia/test_scripts/test/run_executable_test.py", |
| 59 | + "--test-name=fuchsia-pkg://fuchsia.com/dart_test_$mode#meta/dart_test_component.cm", |
100 | 60 | // VmexResource not available in default hermetic realm
|
101 | 61 | // TODO(38752): Setup a Dart test realm.
|
102 |
| - "/core/testing:system-tests", |
103 |
| - "--logs-dir", |
104 |
| - _tempDirectoryOf("logs"), |
105 |
| - "--package-deps", |
106 |
| - _testPackagePath(buildDir, mode), |
| 62 | + "--test-realm=/core/testing:system-tests", |
| 63 | + "--out-dir=${_outDir(buildDir, mode)}", |
| 64 | + "--package-deps=dart_test_$mode.far", |
107 | 65 | ...arguments
|
108 |
| - ]), |
109 |
| - envs); |
110 |
| - } |
111 |
| - |
112 |
| - static String _testPackageName(String mode) { |
113 |
| - return "dart_test_$mode"; |
114 |
| - } |
115 |
| - |
116 |
| - static String _testPackagePath(String buildDir, String mode) { |
117 |
| - var farName = _testPackageName(mode); |
118 |
| - return "$buildDir/gen/$farName/$farName.far"; |
| 66 | + ], |
| 67 | + environmentOverrides); |
119 | 68 | }
|
120 | 69 |
|
121 |
| - static String _tempDirectoryOf(String name) { |
122 |
| - return tmpRoot + name; |
123 |
| - } |
124 |
| - |
125 |
| - List<String> _runArgs(String script, List<String> args) { |
126 |
| - return [testScriptRoot + script, ...args]; |
127 |
| - } |
128 |
| - |
129 |
| - /// Executes a test script inside of third_party/fuchsia/test_scripts/test/ |
130 |
| - /// with the required environment setup and the arguments. |
131 |
| - Future<Process> _run(String script, List<String> args) async { |
132 |
| - var newArgs = _runArgs(script, args); |
133 |
| - print("+ Start $withEnv with $newArgs with environment $envs."); |
134 |
| - return Process.start(withEnv, newArgs, environment: envs); |
135 |
| - } |
136 |
| - |
137 |
| - /// Executes a test script and asserts its return code is 0; see _run and |
138 |
| - /// _assert. |
139 |
| - Future<void> _assertRun(String script, List<String> args) async { |
140 |
| - _assert((await (await _run(script, args)).exitCode) == 0); |
| 70 | + // Tears down the Fuchsia environment. |
| 71 | + Future<void> stop() async { |
| 72 | + publisher!.kill(); |
| 73 | + await publisher!.exitCode; |
| 74 | + publisher = null; |
| 75 | + daemonIsolateDir!.deleteSync(recursive: true); |
| 76 | + daemonIsolateDir = null; |
141 | 77 | }
|
142 | 78 |
|
143 |
| - /// Captures the first line of output in utf8. |
144 |
| - Future<String> _captureStdout(Process proc) async { |
145 |
| - // The stderr needs to be fully consumed as well. |
146 |
| - proc.stderr.transform(utf8.decoder).forEach((x) => stderr.write(x)); |
147 |
| - return (await proc.stdout.transform(utf8.decoder).first).trim(); |
| 79 | + Future<bool> _isProcessRunning(Process proc, int waitMs) async { |
| 80 | + try { |
| 81 | + await proc.exitCode.timeout(Duration(milliseconds: waitMs)); |
| 82 | + return false; |
| 83 | + } on TimeoutException { |
| 84 | + return true; |
| 85 | + } |
148 | 86 | }
|
149 | 87 |
|
150 |
| - /// Unlike assert keyword, always evaluates the input function and throws |
151 |
| - /// exception when the evaluated result is false. |
152 |
| - void _assert(bool condition) { |
153 |
| - if (!condition) { |
154 |
| - throw AssertionError(); |
155 |
| - } |
| 88 | + String _outDir(String buildDir, String mode) { |
| 89 | + return "$buildDir/gen/dart_test_$mode"; |
156 | 90 | }
|
157 | 91 |
|
158 | 92 | static final FuchsiaEmulator _instance = _create();
|
|
0 commit comments