This guide provides instructions on how to create a new end-to-end test using the Dart test library{:.external} and SL4F.
The guide creates an end-to-end test that prints “Hello world!” in the log of a Fuchsia device. Once you verify that you can build and run this test from your machine, use the resources provided in this guide as reference to further develop the test.
To create a new end-to-end test, the steps are:
This guide requires that you're familiar with the following tasks:
An end-to-end test needs to have the following directory structure and files:
//src/tests/end_to_end/<your_test_directory> ├── test │ └── <test_source_code_files> ├── BUILD.gn ├── OWNERS ├── README.md ├── pubspec.yaml └── analysis_options.yaml
The instructions in this section create the minimum directory structure and files necessary to build and run an end-to-end test.
Do the following:
Go to your Fuchsia directory, for example:
Note: If your Fuchsia source code is not located in the ~/fuchsia
directory, replace ~/fuchsia
with your Fuchsia directory.
cd ~/fuchsia
Create a new branch, for example:
git checkout -b create_my_first_e2e_test
Go to the //src/tests/end_to_end
directory:
cd src/tests/end_to_end
Create a new test directory called my_e2e_test_example
, which has a test
directory:
mkdir -p my_e2e_test_example/test
Go to the new test directory:
cd my_e2e_test_example
Use a text editor to create a new my_new_e2e_test.dart
file in the test
directory, for example:
nano test/my_new_e2e_test.dart
Paste the following code to my_new_e2e_test.dart
:
import 'package:sl4f/sl4f.dart' as sl4f; import 'package:test/test.dart'; void main() { sl4f.Sl4f sl4fDriver; setUp(() async { sl4fDriver = sl4f.Sl4f.fromEnvironment(); await sl4fDriver.startServer(); }); tearDown(() async { await sl4fDriver.stopServer(); sl4fDriver.close(); }); test('tests hello world', () async { await sl4f.DeviceLog(sl4fDriver).info('Hello world!'); print('Printed "Hello world!" in the device\'s log.'); }, timeout: Timeout(Duration(minutes: 1))); }
The test()
function in this code prints Hello world!
in the device‘s log, then the test outputs the Printed "Hello world!" in the device's log.
message on the host machine’s screen.
Save the file and exit the text editor.
Use a text editor to create a new BUILD.gn
file, for example:
nano ./BUILD.gn
Paste the following code to BUILD.gn
:
import("//build/dart/test.gni") dart_test("my_new_e2e_test") { sources = [ "my_new_e2e_test.dart" ] deps = [ "//sdk/testing/sl4f/client", "//third_party/dart-pkg/pub/test", ] } group("test") { testonly = true deps = [ ":my_new_e2e_test($host_toolchain)" ] }
This BUILD.gn file defines the test target group to include my_new_e2e_test.
Save the file and exit the text editor.
Copy an existing analysis_options.yaml
file to your test directory, for example:
cp ../sl4f/analysis_options.yaml .
The Dart compiler uses this file to identify compile warnings.
Create empty pubspec.yaml
, OWNERS
, and README.md
files:
touch pubspec.yaml OWNERS README.md
Some text editors use the pubspec.yaml
file to recognize that this test is a Dart package. Provide the content of OWNERS
and README.md
files later when you contribue the test to the Fuchsia project.
Before you can run an end-to-end test, you first need to configure and build a Fuchsia image to include the test in the build artifacts:
Note: The examples in this guide use the workstation
product. End-to-end tests work with most products except core
.
Configure your Fuchsia image to include the my_e2e_test_example
test directory and the test
target group:
fx set workstation.qemu-x64 --with //src/tests/end_to_end/my_e2e_test_example:test
//src/tests/end_to_end/my_e2e_test_example
is the path to your new test directory. The test
target group, as defined in the BUILD.gn
file, includes my_new_e2e_test
.
Build your Fuchsia image:
fx build
When the fx build
command completes, your build artifacts now include the my_new_e2e_test
end-to-end test, which you can run from your host machine.
Start the emulator to run your Fuchsia image:
Note: The steps in this section assume that you don't have any terminals currently running FEMU or the fx serve
command.
Configure an IPv6 network for the emulator:
Note: This has to be completed once per machine.
sudo ip tuntap add dev qemu mode tap user $USER && sudo ip link set qemu up
Configure the upscript:
Note: If your machine is behind a firewall, you may need to apply some additional configuration to allow the emulator to access the network. This is typically accomplished by running an “upscript”, which sets up the interfaces and firewall access rules for the current process. If you‘re on a corporate network, check with your internal networking team to see if they have an existing upscript for you to use. If you’re not behind a firewall, there's still some configuration needed to enable tun/tap networking. The example upscript at {{ ‘’ }}FUCHSIA_ROOT{{ ‘’ }}/scripts/start-unsecure-internet.sh should work for the majority of non-corporate users.
ffx config set emu.upscript {{ '<var>' }}PATH_TO_UPSCRIPT{{ '</var>' }}
Replace the following:
PATH_TO_UPSCRIPT
: The path to a FEMU network setup script; for example, ~/fuchsia/scripts/start-unsecure-internet.sh
.Start the package server
fx serve
Start the emulator:
ffx emu start --net tap
When startup is complete, the emulator prints the following message and opens a shell prompt:
Logging to "{{ '<var>' }}$USER{{ '</var>' }}/.local/share/Fuchsia/ffx/emu/instances/fuchsia-emulator/emulator.log" Waiting for Fuchsia to start (up to 60 seconds)........Emulator is ready.
The --net
flag requires a value to indicate which kind of networking to implement. --net
has the following possible values:
tap
: Attaches a Tun/Tap interface.user
: Sets up mapped ports through SLiRP.none
: Disables networking.auto
: Checks the host system's capabilities and selects tap
if it is available or user
if a tap interface is unavailable. auto
is the default.auto
is the default if the flag is not specified on the command line. The upscript is automatically executed only if the user selects tap
mode.
If auto
is used, the launcher checks for a tap interface on the device. If it finds a tap interface, it uses tap
mode; otherwise it uses user
mode.
Run the fx set-device
command and select fuchsia-emulator
(the emulator's default device name) to be your device, for example:
In a new terminal, run the my_new_e2e_test
end-to-end test:
fx test --e2e my_new_e2e_test
This test prints the following output:
... 00:00 +0: my_new_e2e_test tests hello world Printed "Hello world!" in the device's log. 00:02 +1: All tests passed! ...
To scan the device logs for the Hello world!
string, run the following command:
ffx log --filter "Hello world!" dump
This command only prints the lines that contain Hello world!
from the device logs, for example:
[sl4f][][I] request id: String(""), name: "logging_facade.LogInfo", args: Object({"message": String("Hello world!")}) [sl4f][][I] Received synchronous request: Sender, MethodId { facade: "logging_facade", method: "LogInfo" }, Object({"message": String("Hello world!")}) [sl4f][][I] "\"Hello world!\""
Edit the my_new_e2e_test.dart
file to implement your test case.
Use the following resources for writing new tests:
After editing the test's source code, use the fx test --e2e
command to run the updated version of the test, for example:
fx test --e2e my_new_e2e_test
When this command detects any changes in the test's source code, the command automatically rebuilds the test prior to running the test.