|  | // Copyright 2019 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | import 'package:fxtest/fxtest.dart'; | 
|  |  | 
|  | /// Concrete flag for an individual test, indicating how it should be executed. | 
|  | enum TestType { | 
|  | command, | 
|  | component, | 
|  | host, | 
|  | suite, | 
|  |  | 
|  | /// Special tests that start on the host and then interact with a device. | 
|  | /// These tests do not always clean up after themselves and thus must be | 
|  | /// opted-in to for any given test run. | 
|  | e2e, | 
|  |  | 
|  | /// Catch-all for a test we know `fxtest` has yet to include correct handling | 
|  | /// logic. This is not an okay problem, and will raise an error unless a | 
|  | /// silencing flag is passed. | 
|  | unsupported, | 
|  |  | 
|  | /// Non-component but on-device tests (an illegal and mostly legacy | 
|  | /// configuration). | 
|  | unsupportedDeviceTest, | 
|  | } | 
|  |  | 
|  | const Set<TestType> hostTestTypes = { | 
|  | TestType.command, | 
|  | TestType.host, | 
|  | }; | 
|  |  | 
|  | const Set<TestType> unsupportedTestTypes = { | 
|  | TestType.unsupportedDeviceTest, | 
|  | TestType.unsupported, | 
|  | }; | 
|  |  | 
|  | /// Container for all the string primitives required to execute a test. | 
|  | /// | 
|  | /// Includes every relevant command line argument, flag, and environment | 
|  | /// variable. | 
|  | class ExecutionHandle { | 
|  | /// Complete string passed to `fx` to execute the test. | 
|  | final String handle; | 
|  |  | 
|  | /// Flags to pass to test runner. | 
|  | final List<String> flags; | 
|  |  | 
|  | /// Name of the operating system which will execute this test. "linux" or "mac" | 
|  | /// designate the host, while "fuchsia" designates the target device. | 
|  | final String os; | 
|  |  | 
|  | /// Concrete representation of this class of test. | 
|  | final TestType testType; | 
|  |  | 
|  | /// Environment variables to pass to the spawned [Process] that will actually | 
|  | /// execute the test. | 
|  | final Map<String, String> environment; | 
|  |  | 
|  | ExecutionHandle(this.handle, this.os, | 
|  | {this.flags = const [], this.testType, this.environment}) | 
|  | : assert(flags != null); | 
|  | ExecutionHandle.command(this.handle, this.os, {this.environment = const {}}) | 
|  | : testType = TestType.command, | 
|  | flags = []; | 
|  | ExecutionHandle.component(this.handle, this.os, {this.environment = const {}}) | 
|  | : testType = TestType.component, | 
|  | flags = []; | 
|  | ExecutionHandle.e2e(this.handle, this.os, {this.environment = const {}}) | 
|  | : testType = TestType.e2e, | 
|  | flags = []; | 
|  | ExecutionHandle.suite(this.handle, this.os, | 
|  | {this.flags = const [], this.environment = const {}}) | 
|  | : testType = TestType.suite; | 
|  | ExecutionHandle.host(this.handle, this.os, {this.environment = const {}}) | 
|  | : testType = TestType.host, | 
|  | flags = []; | 
|  | ExecutionHandle.unsupportedDeviceTest(this.handle, | 
|  | {this.environment = const {}}) | 
|  | : os = 'fuchsia', | 
|  | flags = [], | 
|  | testType = TestType.unsupportedDeviceTest; | 
|  | const ExecutionHandle.unsupported() | 
|  | : handle = '', | 
|  | os = '', | 
|  | flags = const [], | 
|  | environment = const {}, | 
|  | testType = TestType.unsupported; | 
|  |  | 
|  | /// Produces the complete list of tokens required to invoke this test. | 
|  | /// | 
|  | /// This does not account for any extra tokens the user many require - here | 
|  | /// we are only considered with vanilla test invocations driven straight from | 
|  | /// the definition in the manifest. | 
|  | CommandTokens getInvocationTokens(List<String> runnerFlags) { | 
|  | if (testType == TestType.command) { | 
|  | return _getCommandTokens(); | 
|  | } else if (testType == TestType.component) { | 
|  | return _getComponentTokens(runnerFlags); | 
|  | } else if (testType == TestType.host) { | 
|  | return _getHostTokens(); | 
|  | } else if (testType == TestType.suite) { | 
|  | return _getSuiteTokens(runnerFlags); | 
|  | } else if (testType == TestType.e2e) { | 
|  | return _getEndToEndTokens(); | 
|  | } | 
|  | return CommandTokens.empty(); | 
|  | } | 
|  |  | 
|  | /// Handler for test definitions using the "command" keyword. | 
|  | /// | 
|  | /// Handles tests containing a key like so: | 
|  | /// ```json | 
|  | /// {"command": ["host_x64/some_binary", "--some-flags"]} | 
|  | /// ``` | 
|  | CommandTokens _getCommandTokens() { | 
|  | List<String> commandTokens = handle.split(' '); | 
|  |  | 
|  | // Currently, some entries in `tests.json` appear due to a bug, and as such, | 
|  | // simply with the command ["run", "..."]. We need to coerce that to its | 
|  | // correct syntax, but with a helpful warning. | 
|  | if (commandTokens.first == 'run') { | 
|  | return CommandTokens( | 
|  | ['fx', 'shell', ...commandTokens.sublist(1)], | 
|  | warning: | 
|  | 'Warning! Only host tests are expected to use the "command" syntax. ' | 
|  | 'The test [$commandTokens] did not comply with this expectation.', | 
|  | ); | 
|  | } | 
|  | return CommandTokens(commandTokens); | 
|  | } | 
|  |  | 
|  | /// Handler for `tests.json` entries containing the `packageUrl` key ending | 
|  | /// in ".cmx". | 
|  | CommandTokens _getComponentTokens(List<String> runnerFlags) { | 
|  | List<String> subCommand = ['shell', 'run-test-component'] + runnerFlags; | 
|  | return CommandTokens(['fx', ...subCommand, handle]); | 
|  | } | 
|  |  | 
|  | /// Handler for `tests.json` entries containing the `packageUrl` key ending | 
|  | /// in ".cm". | 
|  | CommandTokens _getSuiteTokens(List<String> runnerFlags) { | 
|  | List<String> subCommand = ['shell', 'run-test-suite'] + runnerFlags; | 
|  | return CommandTokens(['fx', ...subCommand, ...flags, handle]); | 
|  | } | 
|  |  | 
|  | /// Handler for `tests.json` entries containing the `path` key. | 
|  | CommandTokens _getHostTokens() { | 
|  | return CommandTokens([handle]); | 
|  | } | 
|  |  | 
|  | /// Assembles the full invocation command for tests with a device dimension, | 
|  | /// but which start on the host machine. | 
|  | CommandTokens _getEndToEndTokens() { | 
|  | return CommandTokens([handle]); | 
|  | } | 
|  | } |