This library implements helpers for writing e2e tests for ffx subtools.
It includes:
- A testing fixture to reduce setup boilerplate
- A hermetic execution environment for ffx (via
ffx_isolate
) - Low-level emulator spawning utilities (for flash and OTA testing)
And is planned to include:
- Matchers for ffx command output (b/293217132)
ffx emu
integration by merging withffx_e2e_emu
(b/295230484)
Usage
Subtool e2e tests typically live in src/developer/ffx/tests
. This is akin to
ffx self-test
but using rustc_test
to execute tests instead of a subtool.
In BUILD.gn
:
import("//build/host.gni")
import("//build/rust/rustc_binary.gni")
if (is_host) {
rustc_test("ffx_<something>_test") {
testonly = true
edition = "2021"
source_root = "src/tests.rs"
sources = [ "src/tests.rs" ]
deps = [
"//src/developer/ffx/testing:ffx_testing",
"//src/lib/fuchsia",
"//src/lib/testing/fixture",
]
# If using ffx_testing::Emu: Only one emulator can be spawned at a time.
# These lower level emulators use TAP networking, which is required for IPv6
# support.
# args = [ "--test-threads=1" ]
}
}
In src/tests.rs
:
use ffx_testing::{base_fixture, TestContext};
use fixture::fixture;
// base_fixture sets up the test environment this test
#[fixture(base_fixture)]
#[fuchsia::test]
async fn my_test(ctx: TestContext) {
let _daemon = ctx.isolate().start_daemon().await.unwrap();
let output = ctx.isolate().ffx(&["daemon", "echo"]).await.expect("daemon echo");
assert!(output.status.success());
}
Low Level Emulators
A low-level emulator can be brought up with Emu::start
. It can be controlled
via serial and talked to by ffx. For a test that uses the emulator, see
ffx_target_test.
/!\ This emulator is brought up with an empty disk /!\
This is by design. To e2e test with a fuchsia image use the ffx_e2e_emu
library under //src/developer/ffx/lib/e2e_emu
.
use ffx_testing::Emu;
let emu = Emu::start(&ctx);
// NOTE: If using serial, make sure to drain or close the serial stream when no longer in use.
// Failure to do so will result in QEMU halting.
{
let serial = emu.serial().await;
// ...
}
// Dropping or letting the emu go out of scope cleans up the emulator.