Skip to content

fix: remove --forked from test commands to fix coverage measurement - #277

Draft
tofarr wants to merge 6 commits into
mainfrom
improve/test-coverage-26-to-40
Draft

fix: remove --forked from test commands to fix coverage measurement#277
tofarr wants to merge 6 commits into
mainfrom
improve/test-coverage-26-to-40

Conversation

@tofarr

@tofarr tofarr commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

HUMAN:

  • A human has tested these changes.

AGENT:


Why

pytest-forked runs each test in a forked child process that exits via os._exit() (line 79 of py/_process/forkedfunc.py), which bypasses coverage.py's atexit handlers. Every forked child's coverage data is silently discarded, producing wildly inaccurate coverage numbers:

  • Enterprise: 26% (with --forked) → 76% (without)
  • OSS: 27% (with --forked) → 74% (without)

This was reported as "about 35%" coverage. The actual coverage is 76% — the gap is entirely a measurement artifact.

The --forked flag was added in PR #15286 as part of the initial CI workflow creation (copy-pasted from the OSS command), not to fix a specific test-isolation bug. pytest-forked is also a deprecated package (removed from pytest core, maintained as a standalone plugin).

Summary

  • Removed --forked from both test jobs in .github/workflows/py-tests.yml (OSS + enterprise)
  • Removed --forked from the documented enterprise test command in AGENTS.md

How to Test

Run the enterprise test suite without --forked and confirm all tests pass with accurate coverage:

cd enterprise/enterprise
PYTHONPATH=".:$PYTHONPATH" poetry run pytest -n auto -p no:ddtrace -p no:ddtrace.pytest_bdd -p no:ddtrace.pytest_benchmark ./tests/unit --cov=server --cov-branch --cov-report=term

Expected: 3,069 passed, 6 skipped, 76% coverage.

Verified across 3 runs with -n auto (xdist parallelism) and 1 single-process run — all consistent, zero failures.

Type

  • Bug fix

Notes

  • The pytest-forked dependency (in pyproject.toml) is left in place as an unused dependency. Removing it requires lockfile regeneration and is out of scope for this fix.
  • Option B (keeping --forked with coverage concurrency fixes) was tested and ruled out: .coveragerc with concurrency = multiprocessing and COVERAGE_PROCESS_START both failed because os._exit() fundamentally cannot be worked around with config.
  • This affects both the OSS and enterprise test jobs. The same 27%→74% jump was confirmed on the OSS side.
  • If any test starts failing without --forked in the future, that indicates a real test-isolation bug (shared DB/session state leaking between tests) that --forked was masking. No such failures exist currently.

This PR was created by an AI agent (OpenHands) on behalf of Tim O'Farrell.


Enterprise server image for this PR:

ghcr.io/openhands/enterprise-server:sha-a8db948

tofarr and others added 6 commits August 28, 2026 14:42
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
The app-settings screen wraps everything in a <form action={formAction}>.
A nested <form> inside it is invalid HTML, so the inner form's submit
never fired and the POST to /api/v1/secrets did not happen. Replace
the nested form with a <div> and trigger the save via the button's
onClick, reading the textarea value via a ref.

Co-authored-by: openhands <openhands@all-hands.dev>
The app-settings component now uses useNavigate from react-router,
which requires a Router context. Wrap the test render with MemoryRouter
following the same pattern as agent-settings.test.tsx.

Co-authored-by: openhands <openhands@all-hands.dev>
pytest-forked runs each test in a forked child process that exits via
os._exit(), which bypasses coverage.py's atexit handlers. This silently
discards all coverage data from forked children, producing wildly
inaccurate numbers:

  Enterprise: 26% (with --forked) -> 76% (without)
  OSS:        27% (with --forked) -> 74% (without)

The flag was added in PR #15286 as part of the initial CI workflow
creation (copy-pasted from the OSS command), not to fix a specific
test-isolation bug. pytest-forked is also a deprecated package.

Attempts to fix coverage collection while keeping --forked (concurrency
config, COVERAGE_PROCESS_START) all failed because os._exit()
fundamentally cannot be worked around with config.

Full suite passes cleanly without --forked: 3069 passed, 0 failed,
verified across multiple runs with -n auto xdist parallelism.

Co-authored-by: openhands <openhands@all-hands.dev>
@github-actions github-actions Bot added the type: fix A bug fix label Aug 29, 2026
@github-actions

Copy link
Copy Markdown

Coverage report

This PR does not seem to contain any modification to coverable code.

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

Labels

type: fix A bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant