Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Pin `Path.home()` under unit tests via a session-scoped autouse conftest fixture, fixing 56 Windows runner failures on the new `windows-2025-vs2026` GitHub-hosted image where `USERPROFILE`/`HOMEDRIVE`+`HOMEPATH` are not seeded for pytest workers; also patch the `_check_and_notify_updates` import binding in the disabled-self-update test so it no longer races on the version-check cache. (#1270)
- `apm install` now works on macOS git 2.53.0 (Homebrew): bare-cache commands switch to `--git-dir` to satisfy the `safe.bareRepository=explicit` default; fetched SHAs are pinned as synthetic refs so `git clone --local --shared` no longer silently omits them. (#1268)
- Set the unit-test hermetic HOME at conftest import time so a single xdist worker on the `windows-2025-vs2026` runner can no longer race fixture setup and re-trigger the 53 `Path.home()` failures the session-scoped autouse fixture was supposed to prevent. (#1271)
- Override `Path.home()` itself in the root test conftest so the 46 remaining Windows `RuntimeError: Could not determine home directory` failures on xdist worker `gw2` cannot recur regardless of which conftest the worker imports first; per-test `monkeypatch.setenv("HOME", ...)` continues to work because the override consults env vars before falling back to the hermetic tmp dir. (#1272)

## [0.13.0] - 2026-05-11

Expand Down
67 changes: 61 additions & 6 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,74 @@
# Root conftest.py shared pytest configuration
# Root conftest.py -- shared pytest configuration
#
# Test directory structure:
# tests/unit/ Fast isolated unit tests (default CI scope)
# tests/integration/ E2E tests requiring network / external services
# tests/acceptance/ Acceptance criteria tests
# tests/benchmarks/ Performance benchmarks (excluded by default)
# tests/test_*.py Root-level tests (mixed unit/integration)
# tests/unit/ -- Fast isolated unit tests (default CI scope)
# tests/integration/ -- E2E tests requiring network / external services
# tests/acceptance/ -- Acceptance criteria tests
# tests/benchmarks/ -- Performance benchmarks (excluded by default)
# tests/test_*.py -- Root-level tests (mixed unit/integration)
#
# Quick reference:
# uv run pytest tests/unit tests/test_console.py -x # CI-equivalent fast run
# uv run pytest # Full suite
# uv run pytest -m benchmark # Benchmarks only
#
# Path.home() override (top of file, runs at conftest import time on every
# pytest-xdist worker): the windows-2025-vs2026 GitHub-hosted runner does not
# seed USERPROFILE / HOMEDRIVE / HOMEPATH for pytest-xdist worker subprocesses,
# so Path.home() raises RuntimeError. Earlier attempts patched only the env
# vars in tests/unit/conftest.py, but at least one xdist worker (gw2) still
# evaluated Path.home() before that conftest's import-time mutation took
# effect. Override Path.home() directly here -- the root conftest is loaded
# by every worker before any test in any test directory runs, so this is
# the earliest hook we have without writing a pytest plugin.

import os
import tempfile
from pathlib import Path

import pytest

_TMP_HOME = Path(tempfile.mkdtemp(prefix="apm-test-home-"))


def _ensure_home_env(home: Path) -> None:
home_str = str(home)
os.environ["HOME"] = home_str
if os.name == "nt":
os.environ["USERPROFILE"] = home_str
drive, _, tail = home_str.partition(":")
if tail:
os.environ["HOMEDRIVE"] = f"{drive}:"
os.environ["HOMEPATH"] = tail


_ensure_home_env(_TMP_HOME)


def _hermetic_home(_cls=Path) -> Path:
"""Resolve a home dir without ever raising.

Honors HOME / USERPROFILE / HOMEDRIVE+HOMEPATH so per-test
`monkeypatch.setenv("HOME", ...)` (or its Windows-trio equivalent)
keeps working. Falls back to a hermetic tmp dir only when the env
is empty -- which is the windows-2025-vs2026 xdist worker case.
"""
home = os.environ.get("HOME")
if not home and os.name == "nt":
home = os.environ.get("USERPROFILE")
Comment on lines +51 to +58
if not home:
drive = os.environ.get("HOMEDRIVE", "")
tail = os.environ.get("HOMEPATH", "")
if tail:
home = drive + tail
return Path(home) if home else _TMP_HOME


# Override Path.home() so any code path -- production or test -- that calls
# it during the test run gets the hermetic tmp dir, regardless of whether
# the runner subprocess inherited a usable HOME / USERPROFILE.
Path.home = classmethod(_hermetic_home) # type: ignore[method-assign]


@pytest.fixture(autouse=True, scope="session")
def _validate_primitive_coverage():
Expand Down
60 changes: 0 additions & 60 deletions tests/unit/conftest.py

This file was deleted.

33 changes: 33 additions & 0 deletions tests/unit/test_path_home_override.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""Regression trap for the root-conftest Path.home() override.

Locks in the contract that survives the windows-2025-vs2026 GitHub
runner: ``Path.home()`` MUST NOT raise even when every env var that
``ntpath.expanduser`` (Windows) or ``posixpath.expanduser`` (POSIX)
consults is unset. The earlier 56-failure / 53-failure / 46-failure
runs all tripped on a single xdist worker that hit
``RuntimeError: Could not determine home directory``.
"""

from __future__ import annotations

from pathlib import Path


def test_path_home_does_not_raise_with_cleared_env(monkeypatch):
"""Path.home() must return a usable Path even with HOME/USERPROFILE/etc cleared."""
for key in ("HOME", "USERPROFILE", "HOMEDRIVE", "HOMEPATH"):
monkeypatch.delenv(key, raising=False)

home = Path.home()

assert isinstance(home, Path)
assert str(home)


def test_path_home_honors_per_test_home_setenv(monkeypatch, tmp_path):
"""Per-test ``monkeypatch.setenv("HOME", ...)`` must still redirect Path.home()."""
target = tmp_path / "custom-home"
target.mkdir()
monkeypatch.setenv("HOME", str(target))

assert Path.home() == target
Loading