Skip to content

tests: add VM backend dimension + small test fixes - #6149

Open
JamesC1305 wants to merge 9 commits into
firecracker-microvm:mainfrom
JamesC1305:tests/add-vm-backend
Open

tests: add VM backend dimension + small test fixes#6149
JamesC1305 wants to merge 9 commits into
firecracker-microvm:mainfrom
JamesC1305:tests/add-vm-backend

Conversation

@JamesC1305

Copy link
Copy Markdown
Contributor

Changes

Major changes:

  • Introduce new dimension to test suite's uvm fixture, vm_backend
  • Introduce GuestKernel wrapper and replace guest_kernel fixture's raw path parameterisation with GuestKernel object

Small changes / fixes:

  • Utilise lifecycle fixture shadowing, i.e., if all tests in a module use a common setup, we can override uvm_configured locally, which the booted/restored uvm fixtures then consume for that module
  • Convert lifecycle from stringly-typed to enum
  • Decouple network tests from KVM thread layout (previously assumed that first free CPU was num_vcpus + 2)
  • Move huge page config into it's own file, mirroring how other utilities are setup

Reason

Introduce the VM backend dimension to abstract away KVM-specific behaviour from the microvm. Anything KVM specific is handled by methods on the backend.

The new GuestKernel dataclass provides richer access to information about the guest kernel, and allows selection between direct-boot and EFI images.

License Acceptance

By submitting this pull request, I confirm that my contribution is made under
the terms of the Apache 2.0 license. For more information on following Developer
Certificate of Origin and signing off your commits, please check
CONTRIBUTING.md.

PR Checklist

  • I have read and understand CONTRIBUTING.md.
  • I have run tools/devtool checkbuild --all to verify that the PR passes
    build checks on all supported architectures.
  • I have run tools/devtool checkstyle to verify that the PR passes the
    automated style checks.
  • I have described what is done in these changes, why they are needed, and
    how they are solving the problem in a clear and encompassing way.
  • I have updated any relevant documentation (both in code and in the docs)
    in the PR.
  • I have mentioned all user-facing changes in CHANGELOG.md.
  • If a specific issue led to this PR, this PR closes the issue.
  • When making API changes, I have followed the
    Runbook for Firecracker API changes.
  • I have tested all new and changed functionalities in unit tests and/or
    integration tests.
  • I have linked an issue to every new TODO.

  • This functionality cannot be added in rust-vmm.

Move the body of Microvm.basic_config into a standalone
kvm_basic_config helper, alongside the has_kvm probe. Microvm still
carries its inline copy until the vm_backend dimension lands and
rewires it to delegate.

This prepares for the vm_backend dimension, so its commit contains only
new logic rather than relocated KVM code.

Signed-off-by: James Curtis <jxcurtis@amazon.co.uk>
Introduce GuestKernel as the logical guest kernel artifact. It parses
the canonical vmlinux-<version>[-no-acpi] artifact name into version
and ACPI metadata and locates the matching EFI-loadable boot image
(bzImage on x86_64; on aarch64 the Image boots both ways).

The guest_kernel fixture and pytest properties derive kernel identity
from the logical artifact instead of re-parsing file names; the fixture
still yields the vmlinux path and the reported identity is unchanged.

This prepares the vm_backend dimension, whose backends resolve a
GuestKernel to the concrete image they can boot.

Signed-off-by: James Curtis <jxcurtis@amazon.co.uk>
HugePagesConfig describes the supported huge-page modes and is shared
by the test framework and its tests. Move it from framework.microvm to
a dedicated utils_hugepages module, following the utils_<topic>
convention, and update its import sites.

Pure move: no functional change.

Signed-off-by: James Curtis <jxcurtis@amazon.co.uk>
The kernel catalogues already carry logical GuestKernel artifacts, but
the fixture still yields the bare vmlinux path, so consumers keep
re-deriving kernel identity from the file name. Yield the GuestKernel
itself; consumers read its parsed fields, and the few that still want
the path read its vmlinux field.

MicroVMFactory.build takes the GuestKernel directly, stores it as
vm.guest_kernel, and boots its vmlinux, so the parsed identity reaches
the VM rather than being re-derived from the file name later. Accepting
a path and coercing it inside build would put that parsing back; instead
the two path callers (tools/sandbox.py, tools/test-popular-containers)
convert at their boundary, where a bad name fails against the file the
user actually named. pin_guest_kernel now takes a catalogue or
pytest.param; every callsite already passed one.

Consumers that treated the fixture value as a path now read what they
mean: the GDB target names the vmlinux, snapshot artifact directories
key on the stable pytest_id, the MSR baseline lookup reads the parsed
version, and the fcmetrics guest_kernel dimension reads the object's
metric_id.

Microvm.kernel_file becomes a property derived from guest_kernel rather
than a second copy of the same answer stored by build(). Snapshot meta
records that concrete image, so restore recovers the logical kernel it
came from: guest_kernel is then the single source of truth for both
built and restored VMs, and the path-derived metric fallbacks go away.
A restored VM now emits the same guest_kernel dimension as a built one
("linux-6.1", previously the patch-level "linux-6.1.168"). A snapshot
naming an artifact the catalogue cannot parse now fails with that value
named rather than degrading the dimension silently; only the out-of-tree
nonci artifact flows can produce one.

Signed-off-by: James Curtis <jxcurtis@amazon.co.uk>
The network throughput test recomputed the first free CPU as
`vcpus_count + 2`, duplicating pin_threads' internal thread layout.
Move pin_threads() out of the network_microvm fixture into the tests so
test_network_tcp_throughput can consume pin_threads' documented return
value instead, and assert against it in the iperf helper.

Signed-off-by: James Curtis <jxcurtis@amazon.co.uk>
Add a VmBackend field to the Microvm class. Microvm delegates
basic_config to the backend-specific helper introduced by the previous
commits and asks the backend to perform any required preparation before
starting. Microvm owns the shared InstanceStart, state validation, and
SSH readiness sequence. Route CPU-template application through
backend-owned basic_config so backend-specific machine configuration
stays behind that interface.

Add the vm_backend fixture as a dimension of the uvm fixtures. Tests
using it multiply over the backends the host can run. Backend discovery
may return an empty set so backend-independent pytest targets can
collect without KVM. After test selection, fail cleanly if any
selected test requires a VM backend and none is available.

MicroVMFactory now takes its backend explicitly; custom-factory
callsites pass the fixture through or stay on KVM.

The kernel_file property now resolves through the backend interface;
KVM continues to boot the guest kernel's vmlinux.

Signed-off-by: James Curtis <jxcurtis@amazon.co.uk>
Replace the stringly-typed uvm_lifecycle with a VmLifecycle str-enum.
Keep pytest IDs and dynamic fixture names unchanged by using enum values
explicitly, and update the A/B fixture to compare enum members.

This makes the dimension states explicit without changing the generated
test matrix.

Signed-off-by: James Curtis <jxcurtis@amazon.co.uk>
Report host backend capabilities in the pytest header: /dev/kvm
existence, access and mode. Backend selection failures are then
diagnosable from the pytest/CI log alone.

Signed-off-by: James Curtis <jxcurtis@amazon.co.uk>
Modules that need customisation between lifecycle stages - e.g. an extra
device or a file pushed into the guest - previously reimplemented the
whole spawn/basic_config/add_net_iface/start sequence locally. Document
same-name stage shadowing (including decoration via same-name
chaining) as a supported extension point in the fixture-system comment
block, and adopt it:

- test_rng.py: replace the local boot/restore constructors, the
  uvm_ctor parametrization, the rate_limiter fixture and the private
  uvm_any with two stage overrides: uvm_configured mirrors the conftest
  stage but spawns at INFO log level (preserving b755a67, "test: set
  log level to INFO for test_rng"), and uvm_booted configures the
  entropy device before boot.
- test_sysgenid.py, test_vmclock.py: decorate uvm_booted via
  same-name chaining to scp the guest test binary, deleting the local
  boot fixtures.
- test_fips.py: override uvm_configured to supply the command line
  parameters to the guest kernel, rather than maintaining an additional
  uvm_with_fips fixture.

Collected test variants are unchanged across all touched modules.

Signed-off-by: James Curtis <jxcurtis@amazon.co.uk>
@JamesC1305 JamesC1305 added the Status: Awaiting review Indicates that a pull request is ready to be reviewed label Aug 24, 2026
@codecov

codecov Bot commented Aug 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.98%. Comparing base (81b38b9) to head (cfc6a40).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6149   +/-   ##
=======================================
  Coverage   82.98%   82.98%           
=======================================
  Files         277      277           
  Lines       30885    30885           
=======================================
  Hits        25630    25630           
  Misses       5255     5255           
Flag Coverage Δ
5.10-m5n.metal 83.24% <ø> (-0.01%) ⬇️
5.10-m6a.metal 82.61% <ø> (-0.01%) ⬇️
5.10-m6g.metal 80.05% <ø> (-0.01%) ⬇️
5.10-m6i.metal 83.24% <ø> (-0.01%) ⬇️
5.10-m7a.metal-48xl 82.61% <ø> (ø)
5.10-m7g.metal 80.05% <ø> (ø)
5.10-m7i.metal-24xl 83.22% <ø> (-0.02%) ⬇️
5.10-m7i.metal-48xl 83.23% <ø> (ø)
5.10-m8g.metal-24xl 80.05% <ø> (-0.01%) ⬇️
5.10-m8g.metal-48xl 80.05% <ø> (ø)
5.10-m8i.metal-48xl 83.22% <ø> (-0.01%) ⬇️
5.10-m8i.metal-96xl 83.23% <ø> (+<0.01%) ⬆️
6.1-m5n.metal ?
6.1-m6a.metal ?
6.1-m6g.metal ?
6.1-m6i.metal ?
6.1-m7a.metal-48xl ?
6.1-m7g.metal ?
6.1-m7i.metal-24xl ?
6.1-m7i.metal-48xl ?
6.1-m8g.metal-24xl ?
6.1-m8g.metal-48xl ?
6.1-m8i.metal-48xl ?
6.1-m8i.metal-96xl ?
6.18-m5n.metal 83.27% <ø> (+<0.01%) ⬆️
6.18-m6a.metal 82.63% <ø> (-0.01%) ⬇️
6.18-m6g.metal 80.05% <ø> (ø)
6.18-m6i.metal 83.27% <ø> (-0.01%) ⬇️
6.18-m7a.metal-48xl 82.62% <ø> (-0.01%) ⬇️
6.18-m7g.metal 80.05% <ø> (ø)
6.18-m7i.metal-24xl 83.29% <ø> (+<0.01%) ⬆️
6.18-m7i.metal-48xl 83.29% <ø> (-0.01%) ⬇️
6.18-m8g.metal-24xl 80.05% <ø> (-0.01%) ⬇️
6.18-m8g.metal-48xl 80.05% <ø> (ø)
6.18-m8i.metal-48xl 83.29% <ø> (-0.01%) ⬇️
6.18-m8i.metal-96xl 83.29% <ø> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Status: Awaiting review Indicates that a pull request is ready to be reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants