Create a new end-to-end test

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:

  1. Prerequisites.
  2. Create a new test.
  3. Build the test.
  4. Start the emulator.
  5. Run the test.
  6. Edit the test.
  7. Update and run the test.

1. Prerequisites

This guide requires that you're familiar with the following tasks:

2. Create a new test

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:

  1. 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
    
  2. Create a new branch, for example:

    git checkout -b create_my_first_e2e_test
    
  3. Go to the //src/tests/end_to_end directory:

    cd src/tests/end_to_end
    
  4. Create a new test directory called my_e2e_test_example, which has a test directory:

    mkdir -p my_e2e_test_example/test
    
  5. Go to the new test directory:

    cd my_e2e_test_example
    
  6. 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
    
  7. 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.

  8. Save the file and exit the text editor.

  9. Use a text editor to create a new BUILD.gn file, for example:

    nano ./BUILD.gn
    
  10. 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.

  11. Save the file and exit the text editor.

  12. 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.

  13. 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.

3. Build the test

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.

  1. 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.

  2. 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.

4. Start the emulator

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.

  1. 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
    
  2. 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.
  3. Start the package server

    fx serve
    
  4. 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.
    
    1. 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.

  5. Run the fx set-device command and select fuchsia-emulator (the emulator's default device name) to be your device, for example:

5. Run the test

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!\""

6. Edit the test

Edit the my_new_e2e_test.dart file to implement your test case.

Use the following resources for writing new tests:

  • The developer guide{:.external} for writing Dart tests.
  • The source code of existing end-to-end tests, for example:
  • The source code of the sl4f end-to-end test, which tests various facades in SL4F. See these tests to understand how you may want to invoke some facades for testing certain features of a Fuchsia product, for example:

7. Update and run the test

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.