mirror of
https://github.com/esphome/esphome.git
synced 2026-06-24 13:45:15 +00:00
[tests] Sandbox PlatformIO paths in test_writer to fix xdist race (#16619)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
This commit is contained in:
@@ -44,6 +44,42 @@ from esphome.writer import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def _isolate_platformio_paths(tmp_path_factory: pytest.TempPathFactory) -> Any:
|
||||||
|
"""Sandbox PlatformIO path lookups so tests never touch ~/.platformio.
|
||||||
|
|
||||||
|
`clean_all` and `clean_build` both query ProjectConfig for paths like
|
||||||
|
`cache_dir` and `core_dir` and `rmtree` anything that exists. By
|
||||||
|
default `core_dir` resolves to ~/.platformio, which is global state
|
||||||
|
shared across pytest-xdist workers — multiple workers can each pass
|
||||||
|
`is_dir()` and then race inside `shutil.rmtree`, producing
|
||||||
|
FileNotFoundError flakes (and trashing developers' local PIO state
|
||||||
|
when the suite is run outside CI).
|
||||||
|
|
||||||
|
14 of the 18 `clean_*` tests in this file invoke `clean_all` /
|
||||||
|
`clean_build` without installing their own ProjectConfig mock, so
|
||||||
|
making the fixture autouse is simpler than tagging each test
|
||||||
|
individually.
|
||||||
|
|
||||||
|
Patch ProjectConfig.get_instance to point every PIO dir at a unique
|
||||||
|
tmp directory that doesn't actually exist on disk — `is_dir()`
|
||||||
|
returns False, so the rmtree loop is skipped entirely. Tests that
|
||||||
|
want to verify the PIO-cleanup branch (e.g. test_clean_all,
|
||||||
|
test_clean_all_partial_exists) install their own inner patch which
|
||||||
|
stacks on top of this one and wins for the duration of their block.
|
||||||
|
"""
|
||||||
|
pio_root = tmp_path_factory.mktemp("isolated_pio") / "nonexistent"
|
||||||
|
mock_cfg = MagicMock()
|
||||||
|
mock_cfg.get.side_effect = lambda section, option: (
|
||||||
|
str(pio_root / option) if section == "platformio" else ""
|
||||||
|
)
|
||||||
|
with patch(
|
||||||
|
"platformio.project.config.ProjectConfig.get_instance",
|
||||||
|
return_value=mock_cfg,
|
||||||
|
):
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_copy_src_tree():
|
def mock_copy_src_tree():
|
||||||
"""Mock copy_src_tree to avoid side effects during tests."""
|
"""Mock copy_src_tree to avoid side effects during tests."""
|
||||||
|
|||||||
Reference in New Issue
Block a user