blob: 8b9bca1e6c6928189690aaa4c59b379aac5dc7b9 [file] [view]
# Machina runtime for Linux testing
This guide provides instructions for running and debugging Starnix tests against
a Linux environment using Machina.
Machina runs tests inside a Linux virtual machine, providing an isolated and
standardized environment using our target kernel version. Note that running
Machina requires an Intel-based CPU to execute, as well as Debian guest images
available locally. Googlers will have such images available by default, while
external developers will need to bring their own. External developers should
read the [Virtualization Get Started][virtualization-get-started] guide for more
information on how to build their own Debian images.
## Running existing Machina tests locally {#running-existing-machina-tests-locally}
### Environment setup {#environmental-setup}
1. Ensure you're using a high-performance, Intel-based machine with
virtualization capabilities. For Googlers, a specialist Cloudtop will provide
the ideal environment. If you're unsure what CPU your machine has, you can
use `lscpu` like so:
```posix-terminal {:.devsite-disable-click-to-copy}
lscpu | grep "Vendor ID"
Vendor ID: GenuineIntel
```
1. Set a product configuration which supports virtualization. Most products
will work, so long as the board is `x64`. Here's an example configuration:
```posix-terminal
fx set fuchsia.x64 --main-pb workbench_eng.x64
```
1. Add the `linux_vm_tests` target:
```posix-terminal
fx add-test //src/starnix/tests:linux_vm_tests
```
1. Bootstrap an emulator with the standard `fx build` and `ffx emu start`
workflows.
### Running tests {#running-tests}
The test suites are the same as the vanilla syscalls, but prefixed with
`linux_`. Here are some examples of common target inclusion:
- **Run the whole suite:**
```posix-terminal
fx test linux_syscalls_cpp_tests
```
- **Run individual tests:**
```posix-terminal
fx test linux_fcntl_test
```
- **Run on both Starnix and Linux:** Specify the base name of the test, which
will run all variants that your environment may be configured to run
(Starnix, Machina, Host):
```posix-terminal
fx test mount_test
```
## Debugging a failing Machina-based syscall test {#debugging-failing-tests}
### Understanding Logs {#understanding-logs}
The syscall tests are gTest suites, and output is piped through the test
framework. In other words, the output from the gTest invocation appears in
stdout on failing tests. You can view all gTest logs, regardless of outcome,
using the `--output` arg in your `fx test` invocation.
Logs related to the Machina runtime are output to the system log (`ffx log`),
and typically associated with an identifying tag. Currently, there is one
runtime being employed for all syscall tests, using the `linux_guest` tag. The
exception to this rule is system logs related to kernel-side virtualization, for
instance logs emitted by the Zircon hypervisor. These logs will not have a
guest-specific identifier associated with them.
The following documents the system logs associated with a typical flow.
1. **Initial guest bootstrap:**
In the following logs, you see the `starnix_test_runner` component
requesting a Machina guest with the `linux_guest` tag. The
`starnix_test_runner` logs two lines about its interaction request. The
third line is from the `interactive-debian-guest` component, which can be
thought of as the running Machina guest component. It receives the request
and starts bootstrapping. You can see all logs across the system are tagged
with an identifier (`linux_guest`). As logs indicate, the Machina guest is
bootstrapped lazily. This initial bootstrap typically takes **~60 seconds**
to become ready for interactions, but is only necessary for the very first
run.
```none {:.devsite-disable-click-to-copy}
[00043.071313][starnix_test_runner][linux_guest] INFO: Pushing data to guest (destination: /data/tests/deps/clone_exec_helper)
[00043.071321][starnix_test_runner][linux_guest] INFO: Interaction requested, lazily starting the guest instance.
[00046.686157][interactive-debian-guest][linux_guest] INFO: [interactive_debian_guest_impl.cc(110)] Start requested for an interactive Debian guest.
```
1. **Pushing test dependencies and binaries:**
Once the guest is bootstrapped, preliminary data begins to be pushed to the
guest. These are the required dependencies for syscall tests, followed by the
test binary itself:
```none {:.devsite-disable-click-to-copy}
[00439.934416][starnix_test_runner.cm][linux_guest,starnix_test_runner] INFO: Pushing data to guest (destination: /data/tests/deps/simple_ext4.img)
[00441.040568][starnix_test_runner.cm][linux_guest,starnix_test_runner] INFO: Successfully pushed data to guest (destination: /data/tests/deps/simple_ext4.img)
[00444.834216][starnix_test_runner.cm][linux_guest,starnix_test_runner] INFO: Pushing data to guest (destination: /starnix_linux_fuse_test_fuse_test_bin)
[00448.652779][starnix_test_runner.cm][linux_guest,starnix_test_runner] INFO: Successfully pushed data to guest (destination: /starnix_linux_fuse_test_fuse_test_bin)
```
1. **Test execution and processing:**
Once the environmental setup steps are done, you should see the execution
command issued. This is executing the gTest binary on the guest. Once again, the
output of this binary execution is piped into stdout on your terminal, as you
would expect from any other `fx test` invocation for a gTest suite. When
execution completes, the results file is copied back over to the host for
processing:
```none {:.devsite-disable-click-to-copy}
[00448.653126][starnix_test_runner.cm][linux_guest,starnix_test_runner] INFO: Executing command on guest: /starnix_linux_fuse_test_fuse_test_bin --gtest_output=json:/test_result-ccde95ca-acb3-4b84-af4d-f371b9582d20.json)
[00448.848658][starnix_test_runner.cm][linux_guest,starnix_test_runner] INFO: Command '/starnix_linux_fuse_test_fuse_test_bin --gtest_output=json:/test_result-ccde95ca-acb3-4b84-af4d-f371b9582d20.json'
...terminated with status Status(OK), return code 0
[00448.849066][starnix_test_runner.cm][linux_guest,starnix_test_runner] INFO: Fetching file from guest (remote_path: /test_result-ccde95ca-acb3-4b84-af4d-f371b9582d20.json)
```
### Understanding the Runtime {#understanding-runtime}
The Starnix test runner is responsible for orchestrating the tests, and can be
thought of as the glue between the Fuchsia test framework and the Machina
runtime. There are two key things to understand related to the runtime:
1. Syscall tests are identified in their CML by the `test_type: "syscall"`
program tag in the `[syscalls_cpp_test.cml][syscalls-cml]`.
1. The Starnix test runner looks for this tag when handling suite requests, and
branches the logic accordingly to handle these tests. The core handling
logic can be found in `[syscalls.rs][syscalls-rs]`, the main entry point
being `run_syscall_tests`.
While there is much more to the runtime than just these two points, maintaining
it all as documentation would be arduous. Hopefully these two core pieces of the
system will provide solid anchor points for your own investigation and
debugging.
## Advanced debugging {#advanced-debugging}
### Verbose Linux Kernel Logging {#verbose-logging}
If you suspect something is going wrong in the Linux kernel itself, you can
enable more verbose Linux kernel logging by setting the following GN argument:
```gn
redirect_guest_serial_logs = true
```
This funnels Linux kernel logs into the standard system output, meaning you can
see guest kernel logs emitted by `ffx log`. Logs are emitted under the `vmm`
component, and will be tagged with `(guest klog)` for clarity on the source. For
instance:
```text {:.devsite-disable-click-to-copy}
[00352.454169][vmm.cm][vmm] INFO: [vmm.cc(491)] (guest klog): [ 0.000000] Linux version 6.6.13-amd64 (debian-kernel@lists.debian.org) (gcc-13 (Debian 13.2.0-10) 13.2.0, GNU ld (GNU Binutils for Debian) 2.41.90.20240115) #1 SMP PREEMPT_DYNAMIC Debian 6.6.13-1 (2024-01-20)
```
In this log example, you see the `vmm` component emit a Linux kernel log line.
The `vmm` emitted this log at system uptime `00352.454169`. The `(guest klog)`
shows that the Linux kernel emitted their line at `[ 0.000000]`, or the zeroth
second of uptime from its perspective.
### Shelling into Machina {#shelling-into-machina}
You can access a fairly standard command line interface for the running Linux
guest. Note that test binaries and artifacts will **not** be present in the
images by default, as they are dynamically pushed by the test runner
scaffolding. See the following sections for more information on getting test
binaries and artifacts into the guest. Here are the steps to get access to this
shell:
1. Follow the
[Virtualization Get Started][virtualization-get-started]
guide, which shows you how to set up your local GN args to enable
virtualization tools.
1. Launch an emulator and connect to the shell:
```posix-terminal
fx shell
```
1. Launch the Debian guest:
```posix-terminal
guest launch debian
```
This drops you into the Debian shell.
Note that the shell behavior can be confusing:
- `exit` will **not** exit the guest shell.
- `CTRL+C` will **not** terminate a running program, but instead exit the
Debian shell back to Fuchsia.
As a tip, you can use `guest attach debian` to return into the shell if you
accidentally CTRL+C out of the Linux guest and into Fuchsia.
### Modifying Debian Images {#modifying-debian-images}
In some cases, you may wish to alter the default Debian images (e.g., to add
binaries or debug programs). Since there is no simple way to push artifacts
over, you must modify the images directly.
1. **Mount the image:** On your Linux host, install tools and mount the image:
```posix-terminal
sudo apt-get install libguestfs-tools
sudo mkdir /mnt/machina_guest_img
sudo guestmount -a prebuilt/virtualization/packages/debian_guest/images/x64/rootfs.qcow2 -m /dev/vda /mnt/machina_guest_img/
```
1. **Interact with the image:** You can now copy files to the mounted
directory. For example, to copy the mount test binary and dependencies:
```posix-terminal
sudo cp ./out/core.x64-balanced/linux_x64/linux_mount_test_bin /mnt/machina_guest_img/home/
sudo mkdir -p /mnt/machina_guest_img/home/data/tests/deps/
sudo cp src/starnix/tests/syscalls/cpp/data/* /mnt/machina_guest_img/home/data/tests/deps/
```
1. **Unmount the image:**
```posix-terminal
sudo guestunmount /mnt/machina_guest_img
```
After unmounting, the image will contain your changes. You can then shell into
the environment (as detailed above) and execute binaries as needed.
<!-- Reference links -->
[syscalls-cml]: /src/starnix/tests/syscalls/cpp/meta/syscalls_cpp_test.cml
[syscalls-rs]: /src/sys/test_runners/starnix/src/syscalls.rs
[virtualization-get-started]: /docs/development/virtualization/get_started.md