netemul-sandbox is essentially a service provider. Tests that use it directly create sandboxes, managed realms, networks, and endpoints by calling
fuchsia.netemul FIDL methods.
Sandbox tests can be written in any FIDL-supported language, though all current tests are written in Rust and use the Rust client library (see documentation) to interact with the
fuchsia.netemul FIDL APIs. Many tests also use the
netstack_testing_common library which contains useful helpers for setting up network realms and virtual networks and interacting with their constituent components (in particular the netstack).
Refer to this example test (see the component manifest and test source) that uses the Netemul Sandbox to create two hermetic test realms containing Netstack2 components, both connected to the same virtual network over virtual interfaces. The test also uses the
RealmUdpSocket trait to create UDP sockets with each hermetic netstack and bind each of them to an address assigned to its respective virtual interface. The test then exercises the netstack‘s socket API by sending a UDP packet from the client to the server and verifying it’s sent and received properly.
netemul-sandbox itself is the core realm-management service provider, and it implements
fuchsia.netemul/ManagedRealm. The sandbox is built on top of Realm Builder, an integration testing library that supports dynamic construction of component topologies at runtime.
Here’s a (simplified) illustration of the component topology of an integration test that uses the Netemul Sandbox (the components with a white background are non-executable, meaning they don't have a runnable program; they exist for organizational/routing purposes):
As you can see, the test realms are created inside a component collection, which is managed by Realm Builder. Capabilities are routed internally between components in the test realm, and can also be connected to dynamically from the test (for example, the test could exercise
fuchsia.posix.socket/Provider exposed by the netstack to test sockets).
As you can see in the component diagram above, the
netemul-sandbox component uses the
network-context component to provide access to the
network-context provides the ability to configure virtual networks.
netemul-runner is a test runner™️ in the sense of the Component Framework and Test Runner Framework—a component runner serves the
fuchsia.component.runner/ComponentRunner protocol so that the Component Manager can start the component, and a test runner implements
fuchsia.test/Suite on behalf of the test component, so that the Test Manager can run the tests on behalf of a user-facing tool like
netemul-runner implements the
fuchsia.test/Suite protocol by first configuring the Netemul environment in which the inner test component should run, then proxying
fuchsia.test/Suite requests to that component. This allows the runner to delegate the job of actually running the components in the test to the Component Framework, and delegate running the test and evaluating its results to the respective test runner.
program section, the manifest for a Netemul Runner test is largely an ordinary component manifest; child components and capability routing are declared statically. There are, however, some things about a Netemul Runner test that are different from a typical test component:
A Netemul Runner test effectively requires two components: the component that actually contains the test suite (sometimes called the test driver), and a non-executable parent component (sometimes called the test root) that specifies the network environment in which the test should be run and includes the test driver along with any other components in the integration test as child components. A developer invoking the test will actually run (e.g. with
ffx test) the root component, which specifies
"netemul_test_runner" as its
runner (typically by including the default shard in its manifest). The test driver looks like an ordinary test component, but expects to be run in the network environment declared by the test root.
The virtual network and netstacks in the test are configured in the
program section of the test root’s manifest. Following is the schema of the
program expected by the Netemul Runner (fields are required unless specifically noted to be optional). You can also look at the definition of this schema where it's defined in the source code of the Netemul Runner here.
|Array of ||Virtual networks to be configured.|
|Array of ||Netstack components to be configured; each netstack should be available in the test root’s namespace at |
|(optional) Array of String||Names of child components to be eagerly started once test network configuration is complete.|
Network: a virtual broadcast domain backed by netemul.
|String||The name of the network (must be unique).|
|Array of ||Endpoints to be created and attached to this network.|
Endpoint: a virtual network endpoint backed by netemul.
|String||The name of the endpoint (must be unique across all networks).|
|(optional) String||MAC address of the virtual endpoint. If not set, will be generated randomly using the endpoint's name as a seed.|
|(optional) Number||MTU of the virtual endpoint. If not set, defaults to 1500.|
|(optional) Boolean||Whether to bring the link up during network setup. If not set, defaults to |
Netstack: a configurable netstack component.
|String||The name of the netstack (must be unique).|
|Array of ||Interfaces to be installed in the netstack.|
Interface: an endpoint that has been installed in a netstack.
|String||The name of the interface to be installed. Must match an endpoint declared on a network.|
|Array of String||Static IP addresses to be assigned to the interface. Corresponding local subnet routes will also be added to the netstack’s routing table.|
|(optional) Boolean||Whether to disable automatic generation and assignment of link-local IPv6 addresses for the interface. If not set, defaults to false.|
|(optional) String||IP address of the default gateway. If not set, no default route is configured.|
|(optional) Boolean||Whether to enable IPv4 forwarding on the interface. If not set, defaults to false.|
|(optional) Boolean||Whether to enable IPv6 forwarding on the interface. If not set, defaults to false.|
useclauses required in test root component manifest
The test root component must
fuchsia.test/Suite from the test driver, so that the Netemul Runner can proxy it, and it also is required to
fuchsia.netemul/ConfigurableNetstack protocol for each of the netstacks to be configured in the test. Each netstack
use clause must set the
path field to
name is the name of the netstack as specified under
program. See the example test linked below for an example.
Refer to this example test that uses the Netemul Runner to run a client and server that are connected over a virtual network. (In particular, see the component manifest for the test root and the source for the test driver and server. Each netstack is configured with a network interface and a static IP address. Additionally, the server component is configured with eager startup, meaning the Netemul Runner will actively start it once test setup is complete, so it can bind to its statically assigned IP address and listen for incoming connections.
In addition to the
server, and corresponding netstacks, this test includes a
sync-manager, which allows the components to synchronize test execution (see below).
As mentioned above, the Netemul Runner is mainly a high-level orchestrator that configures the network environment in which the test will run and acts as liaison between the Test Manager and the test driver, while delegating most of the functionality of the runner to other components:
This makes the Netemul Runner’s component topology rather simple; it is a component that exposes the
netemul_test_runner capability and has a
netemul-sandbox as a child component, for use in creating network environments. The rest of the relevant components (the test driver, the
configurable-netstack, etc.) are part of the actual test.
The configurable netstack is a support component used in Netemul Runner tests that is essentially a test-friendly wrapper around the netstack’s administrative FIDL APIs. It serves the
fuchsia.netemul/ConfigurableNetstack protocol, which provides a single method to create an interface by installing a device in the netstack, and configure it with, for example, static IP addresses.
The primary utility of the configurable netstack is in providing a stable interface between the Netemul Runner and the netstack. Netemul Runner tests use
fuchsia.netemul/ConfigurableNetstack, which makes it available in its namespace; the runner accesses it from there in order to configure the requested interfaces. The runner could theoretically call all the netstack protocols directly, but this would mean that as those APIs change, all existing Netemul Runner tests would have to be updated along with the calling code in the Netemul Runner. The configurable netstack provides a stable API behind which we can encapsulate any netstack-specific management APIs.
sync-manager is a support component used to synchronize components running in a Netemul Runner test “out-of-band”, i.e. without direct communication over FIDL APIs or the network. For example, in this test, the client uses the
sync-manager to wait until the server is accepting connections before attempting to connect to the server, because attempts to connect before the server has had a chance to bind to its assigned IP addresses would fail. To synchronize, the server joins the bus once it’s bound, and the client waits for the server to join before starting connection attempts.
The Netemul Runner previously supported running a virtualized guest as part of an integration test. One use case for this was to verify interoperability between Fuchsia’s networking stack and that of other operating systems. This is not currently supported, but there is a proposed design to support it (without using the runner itself) if we have a need for it: https://fxbug.dev/87587.