Skip to content

test: fix integration test coverage with single process - #7114

Open
wak327 wants to merge 1 commit into
canonical:mainfrom
wak327:test/fix-integration-coverage-single-process
Open

wak327 wants to merge 1 commit into
canonical:mainfrom
wak327:test/fix-integration-coverage-single-process

Conversation

@wak327

@wak327 wak327 commented Sep 29, 2026 •

Copy link
Copy Markdown

Proposed Commit Message

test: fix integration test coverage with single process

enable_coverage.py wraps the ExecStart=/usr line of each stage service
with `coverage run`. Since the single process optimization (#5489) the
stage services are shims whose ExecStart is `sh -c '... | nc ...'`, so
nothing got wrapped and coverage was silently no longer collected. On
releases whose packaging disables the optimization, the script instead
exits early because the network stage is still cloud-init.service.

Wrap whichever of cloud-init-main.service and the stage services run
cloud-init from /usr, and fail when none do, so that a future unit
change cannot silently disable coverage again.

Fixes GH-6769

Additional Context

Fixes #6769

The script has to handle two unit layouts:

  • Upstream (single process): cloud-init-main.service runs ExecStart=/usr/bin/cloud-init --all-stages, and the stage services are nc shims. The current script exits 0 without wrapping anything, so coverage is never collected.
  • Ubuntu 22.04/24.04 packaging (debian/patches/no-single-process.patch on ubuntu/jammy and ubuntu/noble): there is no cloud-init-main.service. Each stage service runs /usr/bin/cloud-init ... itself, and the network stage is cloud-init.service. The current script exits 1 because cloud-init-network.service does not exist, so the assertion in install_coverage() fails.

I checked the new script against unit files rendered from systemd/*.tmpl and against the no-single-process variants of them. It wraps only cloud-init-main.service in the first case and the four stage services in the second. With no matching unit, it fails. I also confirmed that a Type=notify unit whose ExecStart is wrapped in python -m coverage run --append still reaches READY and writes .coverage to its working directory (systemd-run --user --wait -p Type=notify ...). I have not run the full integration suite with coverage enabled because I don't have LXD available here.

enable_profile.py has the same problem, and _collect_profile() in tests/integration_tests/conftest.py still expects one stats file per stage. I'm happy to fix that in a follow-up so this PR stays focused on the reported issue.

Test Steps

CLOUD_INIT_INCLUDE_COVERAGE=true CLOUD_INIT_CLOUD_INIT_SOURCE=<path to cloud-init deb> \
  tox -e integration-tests -- tests/integration_tests/modules/test_write_files.py

/tmp/cloud_init_test_logs/last/html/index.html should now report coverage for cloudinit/. Repeat with CLOUD_INIT_OS_IMAGE=noble CLOUD_INIT_CLOUD_INIT_SOURCE=NONE for the no-single-process layout.

Merge type

  • Squash merge using "Proposed Commit Message"
  • Rebase and merge unique commits. Requires commit messages per-commit each referencing the pull request number (#<PR_NUM>)

@wak327
wak327 marked this pull request as draft September 30, 2026 01:41
@wak327
wak327 marked this pull request as ready for review September 30, 2026 01:41
enable_coverage.py wraps the ExecStart=/usr line of each stage service
with `coverage run`. Since the single process optimization (canonical#5489) the
stage services are shims whose ExecStart is `sh -c '... | nc ...'`, so
nothing got wrapped and coverage was silently no longer collected. On
releases whose packaging disables the optimization, the script instead
exits early because the network stage is still cloud-init.service.

Wrap whichever of cloud-init-main.service and the stage services run
cloud-init from /usr, and fail when none do, so that a future unit
change cannot silently disable coverage again.

Fixes canonicalGH-6769
@wak327
wak327 force-pushed the test/fix-integration-coverage-single-process branch from 27a65dd to 301af0e Compare September 30, 2026 20:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

code coverage breakage

1 participant