1313"""
1414Consumer tests: verify that downstream repos build successfully against this branch.
1515
16- Run all tests:
16+ Via Python (requires ide_support to have been run first):
17+ bazel run //:ide_support # once, to set up .venv_docs
1718 python -m pytest src/tests/test_consumer.py -s
18-
19- Filter by repo or override type (pytest -k):
2019 python -m pytest src/tests/test_consumer.py -k "score and local"
2120 python -m pytest src/tests/test_consumer.py -k "process_description"
22-
23- Use a temp dir instead of the persistent cache:
2421 python -m pytest src/tests/test_consumer.py --disable-cache
2522
2623Known non-passing tests are sometimes marked xfail and do not count as failures.
2724"""
2825
29- import atexit
30- import random
3126import re
3227import shutil
3328import subprocess
29+ import warnings
3430from dataclasses import dataclass
3531from pathlib import Path
3632
3733import pytest
38- from _pytest .config import Config
3934from pytest import TempPathFactory
40- from rich .console import Console
4135
4236from src .helper_lib import find_git_root , get_current_git_hash , get_github_base_url
4337
4640# ---------------------------------------------------------------------------
4741
4842CACHE_DIR = Path .home () / ".cache" / "docs_as_code_consumer_tests"
49- _log_fp = open ("consumer_test.log" , "a" , encoding = "utf-8" ) # noqa: SIM115
50- atexit .register (_log_fp .close )
51- _console = Console (file = _log_fp , force_terminal = False , width = 120 , color_system = None )
5243
5344# ---------------------------------------------------------------------------
5445# Data model
@@ -130,7 +121,7 @@ def _strip_score_docs_overrides(content: str) -> str:
130121 return "\n " .join (result ) + ("\n " if content .endswith ("\n " ) else "" )
131122
132123
133- _BAZEL_DEP_PATTERN = r' bazel_dep\(name = " score_docs_as_code" (?:, version = " [^"]+" )?\)'
124+ _BAZEL_DEP_PATTERN = r"""^ bazel_dep\(name = ["'] score_docs_as_code["'] (?:, version = ["'] [^"']+["'] )?\)"""
134125
135126
136127def _write_module_bazel (
@@ -155,20 +146,20 @@ def _write_module_bazel(
155146)"""
156147
157148 (repo_path / "MODULE.bazel" ).write_text (
158- re .sub (_BAZEL_DEP_PATTERN , replacement , base ), encoding = "utf-8"
149+ re .sub (_BAZEL_DEP_PATTERN , replacement , base , flags = re . MULTILINE ), encoding = "utf-8"
159150 )
160151
161152
162153# ---------------------------------------------------------------------------
163154# Repo helpers
164155# ---------------------------------------------------------------------------
165156
166- _cloned : set [str ] = set ()
157+ _cloned : set [Path ] = set ()
167158
168159
169160def _ensure_repo (repo_path : Path , git_url : str , use_cache : bool ) -> None :
170- """Clone or update a repo exactly once per session per repo name ."""
171- if repo_path . name in _cloned :
161+ """Clone or update a repo exactly once per session per path ."""
162+ if repo_path in _cloned :
172163 return
173164 if repo_path .exists ():
174165 if use_cache :
@@ -199,23 +190,25 @@ def _ensure_repo(repo_path: Path, git_url: str, use_cache: bool) -> None:
199190 capture_output = True ,
200191 cwd = repo_path .parent ,
201192 )
202- _cloned .add (repo_path . name )
193+ _cloned .add (repo_path )
203194
204195
205196def _cleanup_before_cmd (cwd : Path , cmd : str ) -> None :
197+ # ubproject.toml is created by :docs
206198 for p in cwd .glob ("*/ubproject.toml" ):
207199 p .unlink ()
200+
201+ # _build is created by :docs
208202 shutil .rmtree (cwd / "_build" , ignore_errors = True )
203+
204+ # for ide_support, also clear the venv and bazel cache to ensure a clean slate
209205 if cmd == "bazel run //:ide_support" :
210206 shutil .rmtree (cwd / ".venv_docs" , ignore_errors = True )
211- subprocess .run (["bazel" , "clean" , "--async" ], text = True , cwd = cwd )
207+ subprocess .run (["bazel" , "clean" , "--async" ], check = True , text = True , cwd = cwd )
212208
213209
214210def _run_bazel_cmd (cmd : str , repo_name : str , cwd : Path ) -> None :
215- """Stream a bazel command to the log file; fail on non-zero exit or warnings."""
216- _console .print (f"\n [cyan]{ '=' * 80 } [/cyan]" )
217- _console .print (f"[cornflower_blue]{ repo_name } : { cmd } [/cornflower_blue]" )
218-
211+ """Stream a bazel command to stdout; fail on non-zero exit, warn on WARNING lines."""
219212 process = subprocess .Popen (
220213 cmd .split (),
221214 stdout = subprocess .PIPE ,
@@ -226,16 +219,12 @@ def _run_bazel_cmd(cmd: str, repo_name: str, cwd: Path) -> None:
226219 )
227220
228221 assert process .stdout is not None
229- for line in iter ( process .stdout . readline , "" ) :
230- _console . print (line . rstrip () )
222+ for line in process .stdout :
223+ print (line , end = "" )
231224 if "WARNING" in line :
232- process .terminate ()
233- process .wait ()
234- pytest .fail (
235- f"Unexpected warning in { repo_name } `{ cmd } `: { line .strip ()} " ,
236- pytrace = False ,
237- )
225+ warnings .warn (f"{ repo_name } `{ cmd } `: { line .strip ()} " , stacklevel = 2 )
238226 process .stdout .close ()
227+
239228 rc = process .wait ()
240229 if rc != 0 :
241230 pytest .fail (
@@ -250,20 +239,20 @@ def _run_bazel_cmd(cmd: str, repo_name: str, cwd: Path) -> None:
250239
251240
252241@pytest .fixture (scope = "module" )
253- def sphinx_base_dir (tmp_path_factory : TempPathFactory , pytestconfig : Config ) -> Path :
242+ def repos_base_dir (tmp_path_factory : TempPathFactory , pytestconfig : pytest . Config ) -> Path :
254243 if pytestconfig .getoption ("--disable-cache" ):
255244 return tmp_path_factory .mktemp ("consumer_tests" )
256245 CACHE_DIR .mkdir (parents = True , exist_ok = True )
257246 return CACHE_DIR
258247
259248
260249@pytest .fixture (scope = "module" )
261- def consumer_env (sphinx_base_dir : Path ) -> tuple [str , str ]:
250+ def consumer_env (repos_base_dir : Path ) -> tuple [str , str ]:
262251 """Resolve git metadata and set up the local symlink used by local_path_override."""
263252 git_root = find_git_root ()
264253 assert git_root , "Git root not found"
265254
266- dest = sphinx_base_dir / "docs_as_code"
255+ dest = repos_base_dir / "docs_as_code"
267256 if dest .is_symlink ():
268257 dest .unlink ()
269258 elif dest .is_dir ():
@@ -279,7 +268,7 @@ def consumer_env(sphinx_base_dir: Path) -> tuple[str, str]:
279268
280269
281270def _check_remote_available () -> tuple [bool , str ]:
282- """Return (available, skip_reason ). Called once at module import."""
271+ """Return (available, reason ). Called once at module import."""
283272 git_root = find_git_root ()
284273 if git_root is None :
285274 return False , "git root not found"
@@ -329,12 +318,13 @@ def _make_params() -> list[pytest.param]: # type: ignore[type-arg]
329318 for override in ("local" , "remote" ):
330319 for cmd in repo .commands :
331320 marks = []
332- if override == "remote" and not _REMOTE_AVAILABLE :
333- marks .append (pytest .mark .skip (reason = _REMOTE_SKIP_REASON ))
334- if repo .name == "module_template" and random .choice ([True , False ]):
321+ if (
322+ repo .name == "module_template"
323+ and cmd == "bazel build //:needs_json"
324+ ):
335325 marks .append (
336326 pytest .mark .xfail (
337- reason = "module_template is currently broken" ,
327+ reason = "needs_json in module_template is currently broken" ,
338328 strict = False ,
339329 )
340330 )
@@ -355,14 +345,17 @@ def test_consumer_repo(
355345 repo : ConsumerRepo ,
356346 override_type : str ,
357347 cmd : str ,
358- sphinx_base_dir : Path ,
348+ repos_base_dir : Path ,
359349 consumer_env : tuple [str , str ],
360- pytestconfig : Config ,
350+ pytestconfig : pytest . Config ,
361351) -> None :
352+ if override_type == "remote" and not _REMOTE_AVAILABLE :
353+ pytest .fail (_REMOTE_SKIP_REASON , pytrace = False )
354+
362355 gh_url , current_hash = consumer_env
363356 use_cache = not bool (pytestconfig .getoption ("--disable-cache" ))
364357
365- repo_path = sphinx_base_dir / repo .name
358+ repo_path = repos_base_dir / repo .name
366359 _ensure_repo (repo_path , repo .git_url , use_cache )
367360 _write_module_bazel (repo_path , override_type , current_hash , gh_url )
368361 _cleanup_before_cmd (repo_path , cmd )
0 commit comments