Skip to content

Enable multiprocess coverage tracking with coverage.process_startup()#1122

Closed
Copilot wants to merge 6 commits intomasterfrom
copilot/add-coverage-for-subprocess
Closed

Enable multiprocess coverage tracking with coverage.process_startup()#1122
Copilot wants to merge 6 commits intomasterfrom
copilot/add-coverage-for-subprocess

Conversation

Copy link

Copilot AI commented Feb 17, 2026

Coverage metrics were missing code executed in child processes. OpenWPM spawns worker processes (BrowserManager, StorageController) using the multiprocess library that were not being tracked.

Problem

OpenWPM uses the multiprocess library (a fork of stdlib multiprocessing) for worker processes. Standard coverage configuration approaches don't work because:

  • patch = ["subprocess"] only instruments subprocess.Popen/os.system(), which OpenWPM doesn't use for workers
  • concurrency = ["multiprocessing"] monkeypatches stdlib multiprocessing, not the multiprocess fork

Solution

Implemented manual coverage initialization in child processes using coverage.process_startup():

Changes Made

  1. Modified openwpm/utilities/multiprocess_utils.py:

    • Added coverage.process_startup() call at the beginning of Process.run()
    • Guarded by COVERAGE_PROCESS_START environment variable check so it only activates during test runs
    • Handles ImportError gracefully when coverage isn't installed
  2. Modified openwpm/browser_manager.py:

    • Changed to import Process from openwpm.utilities.multiprocess_utils wrapper instead of directly from multiprocess library
    • Added coverage.process_startup() directly in BrowserManager.run() since it overrides the parent's run() method without calling super().run(), which would bypass the wrapper's coverage initialization
    • Ensures BrowserManager gets both coverage instrumentation and exception logging
  3. Added pytest fixture in test/conftest.py:

    • Created session-scoped autouse fixture enable_subprocess_coverage()
    • Sets COVERAGE_PROCESS_START to point to pyproject.toml when tests run under coverage
    • Only activates when coverage is actually being measured
  4. Configuration in pyproject.toml:

    • Kept existing concurrency = ["multiprocessing"], parallel = true, and sigterm = true
    • Removed irrelevant patch = ["subprocess"]

This enables proper coverage collection across all multiprocess worker processes during test runs, following the approach documented in coverage.py's subprocess measurement guide. Both process patterns are now covered:

  • StorageController: Uses Process wrapper with target function, gets coverage from wrapper's run()
  • BrowserManager: Overrides run() method, gets coverage from its own run() implementation
Original prompt

This section details on the original issue you should resolve

<issue_title>Code coverage should cover all processes</issue_title>
<issue_description>Try adding
tool.coverage.run
Patch= ["subprocess"] and see if this improves our coverage
https://pytest-cov.readthedocs.io/en/latest/subprocess-support.html
</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Co-authored-by: vringar <13276717+vringar@users.noreply.github.com>
Copilot AI changed the title [WIP] Add code coverage for subprocess functions Enable subprocess coverage tracking Feb 17, 2026
Copilot AI requested a review from vringar February 17, 2026 22:45
Copy link
Contributor

@vringar vringar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot read the documentation linked in the original issue. Use the patch key. Try again

Co-authored-by: vringar <13276717+vringar@users.noreply.github.com>
Copy link
Author

Copilot AI commented Feb 17, 2026

@copilot read the documentation linked in the original issue. Use the patch key. Try again

Updated to use patch = ["subprocess"] instead of adding subprocess to concurrency list. Commit fd5524d

Copilot AI requested a review from vringar February 17, 2026 23:46
@vringar
Copy link
Contributor

vringar commented Feb 19, 2026

@copilot The current approach (patch = ["subprocess"]) doesn't solve the problem. Here's why:

The core issue: OpenWPM's worker processes (BrowserManager, StorageController) use the third-party multiprocess library (not stdlib multiprocessing). multiprocess is a complete fork with its own class hierarchy (multiprocess.process.BaseProcess vs multiprocessing.process.BaseProcess).

  • patch = ["subprocess"] only instruments subprocess.Popen / os.system(). BrowserManager doesn't use those — it extends multiprocess.Process.
  • concurrency = ["multiprocessing"] monkeypatches stdlib multiprocessing.process.BaseProcess, which never touches the multiprocess fork.

What you need to do instead:

Use coverage.process_startup() to manually start coverage inside each child process. Here's the plan:

  1. Modify openwpm/utilities/multiprocess_utils.py: In the Process wrapper class's run() method, call coverage.process_startup() at the very beginning, before mp.Process.run(self). Guard it behind a check for the COVERAGE_PROCESS_START environment variable so it only activates during test runs. See https://coverage.readthedocs.io/en/latest/subprocess.html#configuring-python-for-sub-process-measurement

  2. Fix BrowserManager: openwpm/browser_manager.py:644 imports Process directly from multiprocess instead of from openwpm.utilities.multiprocess_utils. Change it to use the wrapper from multiprocess_utils (which already wraps multiprocess.Process), so it also gets the coverage hook. Alternatively, add the same coverage.process_startup() call at the top of BrowserManager.run().

  3. Add a pytest fixture in test/conftest.py: Create a session-scoped autouse fixture that sets COVERAGE_PROCESS_START to point to pyproject.toml (the coverage config file) when tests are run with coverage. Something like:

@pytest.fixture(scope="session", autouse=True)
def enable_subprocess_coverage():
    """Enable coverage collection in child processes when running under coverage."""
    try:
        import coverage
        # Only set this if we're actually measuring coverage
        if coverage.Coverage.current() is not None:
            os.environ["COVERAGE_PROCESS_START"] = str(
                Path(__file__).parent.parent / "pyproject.toml"
            )
    except ImportError:
        pass
  1. Keep the existing config: parallel = true and sigterm = true are correct and needed. Remove patch = ["subprocess"] as it's not relevant. Keep concurrency = ["multiprocessing"].

The key files to modify:

  • openwpm/utilities/multiprocess_utils.py — add coverage startup to Process.run()
  • openwpm/browser_manager.py — either use the wrapper Process or add coverage startup to BrowserManager.run()
  • test/conftest.py — add the fixture to set COVERAGE_PROCESS_START
  • pyproject.toml — remove patch = ["subprocess"]

@vringar
Copy link
Contributor

vringar commented Feb 19, 2026

@copilot One more thing: before implementing the above, investigate whether BrowserManager (in openwpm/browser_manager.py:644) could simply extend openwpm.utilities.multiprocess_utils.Process instead of importing Process directly from multiprocess. The wrapper class already exists and is used by StorageControllerHandle (see openwpm/storage/storage_controller.py:15). If BrowserManager can use it too, you'd only need to add the coverage.process_startup() call in one place (multiprocess_utils.Process.run()) instead of two.

Check if there's anything in BrowserManager that would prevent this (e.g., it overrides run() itself, or relies on specific multiprocess.Process behavior that the wrapper might interfere with).

Copilot AI and others added 2 commits February 19, 2026 19:29
Co-authored-by: vringar <13276717+vringar@users.noreply.github.com>
Co-authored-by: vringar <13276717+vringar@users.noreply.github.com>
Copy link
Author

Copilot AI commented Feb 19, 2026

@copilot The current approach (patch = ["subprocess"]) doesn't solve the problem. Here's why:

The core issue: OpenWPM's worker processes (BrowserManager, StorageController) use the third-pa...

Implemented all the requested changes:

  1. ✅ Added coverage.process_startup() to Process.run() in multiprocess_utils.py (guarded by COVERAGE_PROCESS_START check)
  2. ✅ Fixed BrowserManager to import Process from multiprocess_utils wrapper instead of direct multiprocess import
  3. ✅ Added pytest fixture in test/conftest.py to set COVERAGE_PROCESS_START when running under coverage
  4. ✅ Removed patch = ["subprocess"] from pyproject.toml, kept parallel = true and sigterm = true

Changes in commits af38303 and 6794f17

Copilot AI changed the title Enable subprocess coverage tracking Enable multiprocess coverage tracking with coverage.process_startup() Feb 19, 2026
Co-authored-by: vringar <13276717+vringar@users.noreply.github.com>
Copy link
Author

Copilot AI commented Feb 19, 2026

@copilot One more thing: before implementing the above, investigate whether BrowserManager (in openwpm/browser_manager.py:644) could simply extend openwpm.utilities.multiprocess_utils.Process in...

Investigated the issue. BrowserManager already extends the Process wrapper from multiprocess_utils (changed in commit af38303), but it overrides run() without calling super().run(), which bypasses the coverage initialization in the wrapper.

Added coverage.process_startup() directly to BrowserManager.run() at line 731 to ensure coverage is collected. Both process types now have coverage instrumentation:

  • StorageController: Uses Process wrapper via target function, gets coverage from wrapper's run()
  • BrowserManager: Overrides run(), gets coverage from its own run() method

Commit 74a8843

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 should cover all processes

2 participants

Comments