blob: 80ca0c86c3f525cf2b7111e10c7bab78943c77af [file] [log] [blame] [view] [edit]
# User guide for fx test
This page provides best practices, examples, and reference materials
for using the `fx test` command for running tests in
a [Fuchsia source checkout setup][fuchsia-source-checkout]
(`fuchsia.git`).
## Basic usage
To get started, simply run `fx test`:
```posix-terminal
fx test
```
This will do several things:
1. Identify tests included in your current build.
1. Select a subset of included tests based on selection criteria.
1. Rebuild and republish those tests.
1. Check that an appropriate Fuchsia device exists to run tests on.
1. In parallel, start running tests on that device and provide status output.
1. Write a log file describing the operations that occurred.
If you did not include any tests in your build, `fx test` will exit.
Try `fx set core.x64`**`--with //src/diagnostics:tests`** on your
`fx set` command line to include some tests as an example.
For more details on the current status of `fx test`, see this
[`README`][fxtest-source] page.
## Basic concepts
`fx test` is a **Test Executor**, which means it ingests a list of
available tests and is responsible for scheduling and observing
their execution. The source of this data is
[`tests.json`](tests-json-format.md).
Each test listed in `tests.json` is a **Test Suite** which may each
contain any number of **Test Cases**. That is, a Test Suite is a
single binary or Fuchsia Component, and it contains Test Cases
which are defined in a way specific to each test framework (e.g.
C++ `TEST`, Rust `#[test]`, Python `unittest.TestCase`). Enumerating
and executing on-device Test Cases is the responsibility of the
[Test Runner
Framework][trf-docs].
### Basic test selection
`fx test` supports selecting individual Test Suites using command
line options. This allows you to include a large number of tests
in your build and then only execute a subset of those tests.
Any non-flag argument to `fx test` is a **selection** that is
fuzzy-matched against each test in the input:
```posix-terminal
fx test archivist --dry
```
Note: The examples in this section pass `--dry` to do a dry-run.
This will simply list selected tests without running them.
By default, the following fields are searched:
|Field|Description|
|---|---|
|name|The full name of the test. This is component URL for on-device tests and test binary path for host tests.|
|label|The build label for the test. For example, `//src/examples:my_test`.|
|component name|The name of the component manifest (excluding `.cm`) for on-device tests only.|
|package name|The name of the Fuchsia package for on-device tests only.|
You can select all tests below a directory in the source tree by
listing the prefix:
```posix-terminal
fx test //src/diagnostics/tests --dry
```
By default all of the above fields are matched, but you can select
specific fields using `--package` or `--component`:
```posix-terminal
fx test --package archivist_unittests --dry
```
By default, multiple selections on the command line implement an
inclusive-OR operation. Test selection supports composite AND
operations as follows:
```posix-terminal
fx test --package archivist --and unittests --dry
```
This command selects all tests where the package matches `archivist` and any field
matches `unittests`.
If you know the exact name of the test you want to execute, you may
use the `--exact` flag to select only that test:
```posix-terminal
fx test --exact fuchsia-pkg://fuchsia.com/archivist-tests#meta/archivist-unittests.cm --dry
```
If no tests match your selection, `fx test` will try to heuristically match
tests in your source checkout and suggest `fx set` arguments to include them:
```bash {:.devsite-disable-click-to-copy}
$ fx test driver-tests --dry
...
For `driver-tests`, did you mean any of the following?
driver_tools_tests (91.67% similar)
--with //src/devices/bin/driver_tools:driver_tools_tests
driver-runner-tests (90.96% similar)
--with //src/devices/bin/driver_manager:driver-runner-tests
driver-inspect-test (90.96% similar)
--with //src/devices/tests/driver-inspect-test:driver-inspect-test
```
You can then add the necessary packages to your build.
### Basic test output
`fx test` stores its output in log files for later analysis. You
can view a summary of this log file in text form using the
`-pr/--previous` argument. For example, to see test logs from the
previous run:
```bash {:.devsite-disable-click-to-copy}
$ fx test -pr log
previous-log-file.json.gz:
4 tests were run
[START first_test]
...
[END first_test]
```
For a full list of options for processing previous log files, run
`fx test -pr help`.
By default this command processes the most recent log stored in
your Fuchsia output directory, but you may pass `--logpath` to
choose a specific log.
This command is resilient to corrupt or incomplete log files,
so it should still work even if you terminate the `fx test` command
running the tests.
### Basic test debugging
`fx test` integrates with `zxdb` to provide a simple and easy way to debug your
test failures, without needing to recompile anything. Pass `--break-on-failure`
to your `fx test` invocation to automatically have test failures break into the
debugger:
```none {.devsite-disable-click-to-copy}
$ fx test --break-on-failure rust_crasher_test.cm
...
⚠️ zxdb caught test failure in rust_crasher_test.cm, type `frame` to get started.
14 LLVM_LIBC_FUNCTION(void, abort, ()) {
15 for (;;) {
▶ 16 CRASH_WITH_UNIQUE_BACKTRACE();
17 _zx_process_exit(ZX_TASK_RETCODE_EXCEPTION_KILL);
18 }
══════════════════════════
Invalid opcode exception
══════════════════════════
Process 1 (koid=107752) thread 1 (koid=107754)
Faulting instruction: 0x4159210ab797
🛑 process 1 __llvm_libc::__abort_impl__() • abort.cc:16
[zxdb] // Now you can debug why the test failed!
```
You can also use the `--breakpoint=<location>` option to set a breakpoint at a specific
location anywhere in your code. `<location>` takes standard zxdb breakpoint
syntax, typically a file and line number or a function name:
* `--breakpoint=my_file.rs:123` sets a breakpoint on line 123 of my_file.rs.
* `--breakpoint=some_function` sets a breakpoint on `some_function`.
Note that this option will cause your tests to run significantly slower, since
zxdb will need to load all of the symbols for your test to be able to install
the breakpoint. It is highly recommended to only use this option in addition to
`--test-filter`.
When you're finished debugging the test failure, you can type `quit`, `ctrl+d`,
or `detach *` to resume running your tests. Note, if there were multiple test
case failures, this will not pause to let you debug those tests as well. See
[debugging tests][zxdb-testing-docs] for details about how to debug multiple
test failures that occur in parallel.
## Configuration options
`fx test` is highly configurable, and a full list of options is
available at `fx test --help`.
This section describes how configuration options are specified and
what they mean. Configuration options are categorized as Utility,
Build, Test Selection, Execution, or Output Options. They may be
specified on the command line or in a configuration file.
### Configuration file
All arguments for `fx test` are set on the command line, but defaults may be set
per-user. If you place a file called `.fxtestrc` in your HOME directory, the arguments in that file will be the new defaults for future `fx test` invocations.
For example:
```
# ~/.fxtestrc
# Lines starting with "#" are comments and ignored.
# The below config roughly matches the behavior of the old Dart-based `fx test`.
# Default parallel to 1.
--parallel 1
# Disable status output.
--no-status
# Print output for tests taking longer than 2 seconds.
--slow 2
```
The above file overrides the defaults for `--parallel` and `--status`
flags, which normally default to `4` and `false` respectively. The new defaults
may still be overridden on the command line when invoking `fx test`.
### Utility options
Utility options change the overall behavior of `fx test`.
**`--dry`** performs a "dry-run." `fx test` will complete test selection, but
will then simply print the list of selected test suites rather than executing
any of them.
**`--list`** runs `fx test` in "list mode." Rather than executing
tests, this command lists all test *cases* within each test suite.
It outputs the appropriate command line to run each individual case.
Note that this does require access to a Fuchsia device or emulator
because cases are enumerated by Test Manager on device.
**`-pr/--prev/--previous COMMAND`** will process the log file from
a previous execution of `fx test`, and will print information
depending on the value of `COMMAND`. No new tests are executed.
This command respects `--logpath` to specify the log to read from.
The following `COMMAND`s are implemented:
- `log` prints the command line and output for each test recorded
in the log file.
- `path` prints the path to the most recent log file.
- `replay` will replay the previous run, using new display options.
The speed of the replay can be controlled using the --replay-speed
argument. Values > 1 speed up output, and values < 1 show the run
in slow motion.
- `help` prints a summary of available commands.
### Build options
`fx test` builds and updates selected tests by default. This is
useful when running `fx -i test`, which will detect changes to your
source directory and re-invoke `fx test` following each file
modification. Test rebuilding works as follows (with overrides listed inline).
- **All selected tests are rebuilt by calling `fx build <targets>`
for each `fx test` invocation.**
- Use `--[no-]build` to toggle this behavior.
- **If selected tests are in a specified package for your build
(specified using `fx set --with-test`), the `updates` package
is built and an OTA will be performed.**
- Use `--[no-]updateifinbase` to toggle this behavior.
- Warning: OTA will fail when targeting an emulator.
### Test selection options
The following options affect which tests are selected by `fx test` and how
selections are applied.
**`--host`** and **`--device`** select only host or device tests
respectively. This is a global setting and they cannot be combined.
**`--[no-]e2e`** controls whether to run end-to-end (E2E) tests.
E2E tests are not run by default because they have the potential
to put the device in an invalid state. **`--only-e2e`** implies
`--e2e`, and ensures that only E2E tests are selected.
**`--package`** (`-p`) and **`--component`** (`-c`) select within package or
component names respectively. Names preceded by neither select any test field.
Multiple selections may be changed by **`--and`** (`-a`). For example:
```posix-terminal
fx test --package foo -a --component bar //src/other --and --package my-tests
```
The above command line contains two selection clauses:
1. Package "foo" AND component "bar" (e.g. fuchsia-pkg://fuchsia.com/foo#meta/bar.cm).
1. Package "my-tests" AND //src/other.
Tests matching either of the above clauses are selected.
Test selections are fuzzy-matched using a Damerau-Levenshtein
distance of 3 by default (e.g. "my_tset" will match "my-test").
**`--fuzzy <N>`** can be used to override this value to `N`, where
0 means not to do fuzzy matching.
Suggestions are shown by default if no test matches a selection
clause. The number of suggestions (default 6) can be overridden using
**`--suggestions-count N`**, and suggestions can be disabled or enabled using
**`--[no-]show-suggestions`**.
### Execution options
Tests are executed in a specific way that maximizes throughput and
stability, but each element of this default may be overridden. Tests
are executed as follows (with overrides listed inline):
- **Each selected test is executed in the order they appear within `tests.json`**
- Use `--random` to randomize this execution order.
- **All selected tests are run, starting at the beginning of the ordered list above.**
- Use `--offset N` to skip `N` tests at the beginning of the list. Default is 0.
- Use `--limit N` to run at most `N` tests from the offset. Default is no limit.
- **At most 4 tests may run in parallel, such that at most one of
those tests is "non-hermetic" (as determined by `test-list.json`).**
- Use `--parallel N` to change this default. `--parallel 1` means to execute
each test serially.
- **Tests run until they terminate themselves.**
- Use `--timeout N` to wait at most `N` seconds per test.
- **Each test runs one time.**
- Use `--count N` to run each test `N` times.
- **If any execution of a test is failed, the rest of the repeats will be skipped.**
- Use `--no-fail-by-group` to continue running up to the limit specified
by `--count`.
- **All test cases are run from each test.**
- Use `--test-filter` to run only specifically named test cases.
- **Failed tests are recorded and execution continues with the next selected test.**
- Use `--fail` (`-f`) to terminate all tests following the first failure.
- **Tests that specify a maximum log level in `tests.json` will fail
if logs at a higher severity are seen.**
- Use `--[no-]restrict-logs` to toggle this behavior.
- **Tests components themselves choose the minimum log severity to emit.**
- Use `--min-severity-logs` to override this minimum for all test components.
- **Test components are run using the Merkle root hash from build
artifacts, which ensures that the latest version built was successfully
pushed to the target and is being run.**
- Use `--[no-]use-package-hash` to toggle this behavior.
- **Test cases that are disabled are not run.**
- Use `--also-run-disabled-tests` to run disabled test cases anyway.
- **Test output logs contain only the last segment of the component
moniker, so they are easier to visually inspect.**
- Use `--[no-]show-full-moniker-in-logs` to toggle this behavior.
- **Failing tests terminate following failure without waiting**
- Use `--break-on-failure` to catch failing tests with [zxdb][zxdb-docs].
- Use `--breakpoint=<location>` to install breakpoints at specific
[locations][#basic-test-debugging].
Note that using the `--breakpoint` option will significantly slow down your
tests. It is highly recommended to only use this option in conjunction with
`--test-filter`. `--break-on-failure` may be used with many tests with minimal
impact to performance.
- **Command line arguments to the test are completely controlled by test runners**
- Append `--` to your arguments to pass remaining arguments verbatim to the
test. For example: `fx test foo -- --argument_for_test`
will pass `--argument_for_test` to the test itself.
- **Host tests will inherit a limited set of environment variables
from the user's environment automatically**
- Use `--env` (`-e`) to add new `KEY=VALUE` environment variables
to tests. This flag may be specified multiple times.
- **If no package server is running, a temporary server will be started
for the duration of `fx test`'s execution**
- Use `--no-allow-temporary-package-server` to disable this behavior.
- If an existing package server is found, a temporary one will not be started.
### Output options
`fx test` is intended for developer use cases and includes a simple terminal UI
that displays the status of tests as they are executing. The default output
behavior is as follows (with overrides listed inline):
- **A status display is shown at the bottom of the terminal, and it
is automatically updated to show what operations are currently
executing.**
- Use `--[no-]status` to toggle status display.
- Use `--status-lines N` to change the number of status output lines.
- Use `--status-delay N` to change the refresh rate (default is
0.033 or approximately 30hz). If your terminal is slow you may
want to change this to 0.5 or 1.
- **Output is styled with ANSI terminal colors.**
- Use `--[no-]style` to toggle this behavior.
- Use `--simple` as shorthand for `--no-style --no-status`.
- **Test outputs are only shown for tests that fail.**
- Use `--output` (`-o`) to show all test output (combine with
`--parallel 1` to prevent interleaving).
- Use `--no-output` to hide output explicitly, such as to
override `--output` set in config.
- Use `--slow N` (`-s N`) to show output only for test suites
that take longer than `N` seconds to execute.
- **Logs are written to a timestamped `.json.gz` file under the build
directory specified by `fx status`.**
- Use `--[no-]log` to toggle logging entirely.
- Use `--logpath` to change the output path of the log.
- **Test artifacts are not streamed off of the device.**
- Use `--artifact-output-directory` (`--outdir`) to specify a directory where
artifacts may be streamed in the `ffx test` output format.
- **Debug printing is suppressed.**
- Use `--verbose` (`-v`) to print debug information to the console.
This data is *extremely* verbose, and is only useful to debug `fx
test` itself.
## Log Format
`fx test` is designed to support external tooling by representing every
user-visible output as an "event" which is logged to a file during execution.
Log files are compressed using gzip. Each line of the decompressed
file is a single JSON object representing one event. The event
schema is currently defined in [this][fxtest-python-event] Python
file.
When the format is stabilized, it will be possible to build interactive
viewers and converters to other formats (such as [Build Event
Protocol][build-event-protocol]{:.external}).
## Common issues
### fx test does not work with emacs
The emacs compilation window does not emulate an xterm-compatible terminal,
resulting in an error like below:
```bash {:.devsite-disable-click-to-copy}
in _make_progress_bar raise ValueError("Width must be at least 3")
```
To solve this problem, run `fx test` with the `--no-status` option to disable
the status bar.
### Escape sequences appear in fx test output
Your terminal may not support ANSI color codes, which `fx test` fails to detect.
Pass the `--no-style` option to `fx test` to disable color output or the
`--no-status` option to disable the updating status bar. Passing the
`--simple` option to `fx test` is equivalent to
`--no-style --no-status`.
### I don't know where my log file is
You can set the location of the log by passing `--logpath` to `fx test`, though
this is recommended only for non-interactive use.
By default, your logs are stored in your Fuchsia output directory as timestamped
files. Print the path to the previous logs using `fx test -pr path`.
### Printing the log file dumps garbage into my terminal
`fx test` logs are gzipped by default. Use the following command to pretty
print the most recent log to your terminal:
```bash
cat `fx test -pr path` | gunzip | jq -C | less -R
```
This command does the following:
- Find the most recent log path (`fx test -pr path`).
- Pipe the log to `gunzip` to decompress the log.
- Pipe the decompressed log to `jq` to pretty-print it with color output (`-C`).
- Pipe the color output to `less` configured to display color (`-R`).
For convenience, you can add an alias for this command in your `.bashrc` file:
```bash
alias testlog='cat `fx test -pr path` | gunzip | jq -C | less -R'
```
### Opting out of the new fx test command
The new `fx test` command is currently set to be the default.
To opt out of this setting, set the following environment variable:
```bash
export FUCHSIA_DISABLED_legacy_fxtest=0
```
<!-- Reference links -->
[fuchsia-source-checkout]: /docs/get-started/get_fuchsia_source.md
[build-event-protocol]: https://bazel.build/remote/bep
[fxtest-python-event]: https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/scripts/fxtest/python/event.py
[fxtest-source]: https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/scripts/fxtest/python
[trf-docs]: /docs/development/testing/components/test_runner_framework.md
[zxdb-docs]: /docs/development/debugger/commands.md
[zxdb-testing-docs]: /docs/development/debugger/tests.md