personal memory agent
0

Configure Feed

Select the types of activity you want to include in your feed.

solstone / tests / test_tmpdir_fallback.py
5.6 kB 205 lines
1# SPDX-License-Identifier: AGPL-3.0-only 2# Copyright (c) 2026 sol pbc 3"""Canary tests for the root conftest TMPDIR fallback prelude.""" 4 5from __future__ import annotations 6 7import os 8import subprocess 9import sys 10from pathlib import Path 11 12import pytest 13 14pytest_plugins = ["pytester"] 15 16_ROOT_CONFTEST = Path(__file__).resolve().parent.parent / "conftest.py" 17_NOTICE = ( 18 "solstone: pytest invoked without TMPDIR export; routing tmp dirs to " 19 "/var/tmp. Prefer 'make test' to set TMPDIR at the shell level.\n" 20) 21 22 23def _install_root_conftest(pytester: pytest.Pytester) -> None: 24 pytester.makepyfile(conftest=_ROOT_CONFTEST.read_text(encoding="utf-8")) 25 26 27def _run_nested( 28 pytester: pytest.Pytester, 29 env_overrides: dict[str, str | None] | None = None, 30) -> subprocess.CompletedProcess[str]: 31 basetemp = pytester.path / "basetemp" 32 env = os.environ.copy() 33 env.pop("TMPDIR", None) 34 env.pop("_SOLSTONE_TMPDIR_FALLBACK_NOTIFIED", None) 35 env.pop("_SOLSTONE_TMPDIR_FALLBACK_TARGET", None) 36 if env_overrides: 37 for key, value in env_overrides.items(): 38 if value is None: 39 env.pop(key, None) 40 else: 41 env[key] = value 42 return subprocess.run( 43 [ 44 sys.executable, 45 "-m", 46 "pytest", 47 "-q", 48 "-p", 49 "no:cacheprovider", 50 "--basetemp", 51 str(basetemp), 52 ], 53 cwd=pytester.path, 54 env=env, 55 capture_output=True, 56 text=True, 57 check=False, 58 ) 59 60 61def test_prelude_redirects_to_var_tmp(pytester: pytest.Pytester) -> None: 62 _install_root_conftest(pytester) 63 pytester.makepyfile( 64 test_tmpdir=""" 65 import os 66 import tempfile 67 68 def test_redirects_to_var_tmp(): 69 assert tempfile.gettempdir() == "/var/tmp" 70 assert os.environ["TMPDIR"] == "/var/tmp" 71 """ 72 ) 73 74 result = _run_nested(pytester) 75 76 assert result.returncode == 0, result.stderr + result.stdout 77 assert "1 passed" in result.stdout 78 79 80def test_notice_present_when_tmpdir_unset(pytester: pytest.Pytester) -> None: 81 _install_root_conftest(pytester) 82 pytester.makepyfile( 83 test_notice=""" 84 def test_noop(): 85 assert True 86 """ 87 ) 88 89 result = _run_nested(pytester) 90 combined = result.stderr + result.stdout 91 92 assert result.returncode == 0, combined 93 assert _NOTICE in combined 94 95 96def test_notice_absent_when_tmpdir_already_set(pytester: pytest.Pytester) -> None: 97 _install_root_conftest(pytester) 98 pytester.makepyfile( 99 test_notice=""" 100 import os 101 import tempfile 102 103 def test_uses_existing_tmpdir(): 104 assert tempfile.gettempdir() == "/tmp" 105 assert os.environ["TMPDIR"] == "/tmp" 106 """ 107 ) 108 109 result = _run_nested(pytester, {"TMPDIR": "/tmp"}) 110 combined = result.stderr + result.stdout 111 112 assert result.returncode == 0, combined 113 assert "solstone: pytest invoked without TMPDIR" not in combined 114 115 116def test_notice_single_fire_across_workers(pytester: pytest.Pytester) -> None: 117 _install_root_conftest(pytester) 118 pytester.makepyfile( 119 test_notice=""" 120 def test_noop(): 121 assert True 122 """ 123 ) 124 125 first = _run_nested(pytester) 126 second = _run_nested(pytester, {"_SOLSTONE_TMPDIR_FALLBACK_NOTIFIED": "1"}) 127 combined = first.stderr + first.stdout + second.stderr + second.stdout 128 129 assert first.returncode == 0, combined 130 assert second.returncode == 0, combined 131 assert combined.count(_NOTICE) == 1 132 133 134def test_unwritable_target_degrades_visibly( 135 pytester: pytest.Pytester, tmp_path: Path 136) -> None: 137 _install_root_conftest(pytester) 138 pytester.makepyfile( 139 test_notice=""" 140 import os 141 142 def test_tmpdir_stays_unset(): 143 assert os.environ.get("TMPDIR") is None 144 """ 145 ) 146 blocked = tmp_path / "blocked" 147 blocked.mkdir() 148 os.chmod(blocked, 0) 149 150 try: 151 result = _run_nested( 152 pytester, {"_SOLSTONE_TMPDIR_FALLBACK_TARGET": str(blocked)} 153 ) 154 finally: 155 os.chmod(blocked, 0o700) 156 157 combined = result.stderr + result.stdout 158 notice = ( 159 "solstone: pytest invoked without TMPDIR export and fallback target " 160 f"{blocked} is not writable; leaving TMPDIR unset.\n" 161 ) 162 163 assert result.returncode == 0, combined 164 assert notice in combined 165 assert "routing tmp dirs to" not in combined 166 167 168def test_subprocess_pytest_lands_in_var_tmp(pytester: pytest.Pytester) -> None: 169 _install_root_conftest(pytester) 170 test_path = pytester.makepyfile( 171 test_subprocess=""" 172 import os 173 import tempfile 174 175 def test_redirects_in_fresh_subprocess(): 176 assert tempfile.gettempdir() == "/var/tmp" 177 assert os.environ["TMPDIR"] == "/var/tmp" 178 """ 179 ) 180 env = os.environ.copy() 181 env.pop("TMPDIR", None) 182 env.pop("_SOLSTONE_TMPDIR_FALLBACK_NOTIFIED", None) 183 env.pop("_SOLSTONE_TMPDIR_FALLBACK_TARGET", None) 184 185 result = subprocess.run( 186 [ 187 sys.executable, 188 "-m", 189 "pytest", 190 "-q", 191 "-p", 192 "no:cacheprovider", 193 "--basetemp", 194 str(pytester.path / "basetemp"), 195 str(test_path), 196 ], 197 cwd=pytester.path, 198 env=env, 199 capture_output=True, 200 text=True, 201 check=False, 202 ) 203 204 assert result.returncode == 0, result.stderr + result.stdout 205 assert "1 passed" in result.stdout