Files
chemenu/tools/chemenu/tests/conftest.py
T
torben f63a72cb24
CI / verify (push) Successful in 42s
Release / release (push) Successful in 37s
fix: raw_dir-Fixture kappt config.ROOT, private Fixture-Namen ersetzt (2.1.1)
Files changed:
- CHANGES.md
- VERSION
- tools/chemenu/tests/conftest.py
- tools/chemenu/tests/test_corpus_diff.py
- tools/chemenu/tests/test_index_build.py
- tools/chemenu/tests/test_kb_collections.py
- tools/chemenu/tests/test_lint.py
- tools/chemenu/tests/test_migrate_cmd.py
- tools/chemenu/tests/test_new_page.py
- tools/chemenu/tests/test_page_ops.py
- tools/chemenu/tests/test_provenance.py
- tools/chemenu/tests/test_search.py
- tools/chemenu/tests/test_touch.py
2026-09-01 17:03:51 +02:00

194 lines
8.0 KiB
Python

import os
from pathlib import Path
import pytest
from chemenu import config
from chemenu.frontmatter_io import write_page
# Environment the tool reads for its own behaviour. Cleared for every test, so
# that a test which needs one sets it itself and the rest run against the
# tool's own defaults. `WIKI_TRACE_DIR` is deliberately absent: it is not a
# leak but the redirect `isolated_trace_dir` installs one fixture below.
_WIKITOOL_ENV = (
"WIKI_AUTHOR",
"WIKI_TRACE",
"WIKI_TRACE_CONTENT",
"WIKI_TRACE_MAX_CONTENT",
"WIKITOOL_SESSION_ID",
"WIKITOOL_UPDATE_URL",
"WIKITOOL_UPDATE_TOKEN",
)
# Environment git reads for identity or for where its repo lives. A stray
# `GIT_DIR` would point every fixture repo at the developer's checkout; the
# identity variables outrank `git config user.name`, which is the value
# `config.default_author()` is supposed to be reading.
_GIT_ENV = (
"GIT_DIR",
"GIT_WORK_TREE",
"GIT_AUTHOR_NAME",
"GIT_AUTHOR_EMAIL",
"GIT_COMMITTER_NAME",
"GIT_COMMITTER_EMAIL",
"EMAIL",
)
@pytest.fixture(autouse=True)
def hermetic_environment(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
"""Cut every test off from the machine it runs on.
The suite was green for months while silently depending on whoever ran it:
`config.default_author()` shells out to `git config user.name` and got an
answer from the *global* git configuration of the developer's account. The
first CI run that reached pytest had none, and two tests fell over
(Gitea #8); two more of the same kind were written afterwards, by someone
who had read that issue. Neither round was a mistake anyone could have seen
locally - which is the argument for closing the hole here rather than
fixing each case.
So: `HOME` points into `tmp_path`, git's global and system configuration
are `/dev/null`, and the tool's own environment is cleared. A test that
needs an identity now has to establish one - `WIKI_AUTHOR`, or a local
`git config user.name` in its own fixture repo - and one that does not gets
the same empty machine everywhere, CI included.
Returns the fake `HOME`, for the rare test that wants to put something in it.
"""
home = tmp_path / "home"
home.mkdir()
monkeypatch.setenv("HOME", str(home))
monkeypatch.setenv("XDG_CONFIG_HOME", str(home / ".config"))
# Both are read even when unset in the environment; pointing them at
# /dev/null is git's own documented way to say "there is no such file".
monkeypatch.setenv("GIT_CONFIG_GLOBAL", os.devnull)
monkeypatch.setenv("GIT_CONFIG_SYSTEM", os.devnull)
for name in (*_WIKITOOL_ENV, *_GIT_ENV):
monkeypatch.delenv(name, raising=False)
return home
@pytest.fixture(autouse=True)
def isolated_trace_dir(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, hermetic_environment: Path
) -> Path:
"""Send every test's telemetry into its own tmp_path.
The emitter is wired into `cli.main()` and into both gates, so any test that
exercises those paths writes a trace. Without this the suite appends to the
real `reports/telemetry/` - which is exactly what it did for one run before
this fixture existed.
Depends on `hermetic_environment` for the ordering, not for a value: that
fixture clears `WIKI_TRACE`, so it has to run first for the redirect
installed here to survive with tracing still enabled. Tracing is never
turned off suite-wide - two telemetry tests assert that a trace is written.
"""
trace_dir = tmp_path / "telemetry"
monkeypatch.setenv("WIKI_TRACE_DIR", str(trace_dir))
return trace_dir
@pytest.fixture
def raw_dir(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
"""A small fake raw/ tree sitting next to the kb_dir fixture (same
tmp_path), for provenance-coverage tests. One file is deliberately left
uncovered by any source page.
`config.ROOT` is repointed at `tmp_path` for the same reason
`hermetic_environment` clears the environment: a `raw/...` path in a
fixture page is resolved against the *repository* root by the code under
test (`provenance.legacy_source_pages`, for one), so without this the
fixture builds a raw tree that the code never looks at and answers from
the developer's own `raw/` instead.
That was not theoretical. `test_legacy_source_pages_flags_url_and_directory`
passed for months only because this checkout happened to have a
`raw/documents/` directory; the run that emptied it turned the test red in
CI while it stayed green locally, because git does not track empty
directories and the local one survived. Same shape as Gitea #8, closed the
same way - in the fixture, not in the one test that happened to trip.
"""
monkeypatch.setattr(config, "ROOT", tmp_path)
raw = tmp_path / "raw"
(raw / "notes").mkdir(parents=True)
(raw / "notes" / "Aurora.md").write_text("# Aurora raw notes\n", encoding="utf-8")
(raw / "notes" / "Uningested.md").write_text("# Not yet ingested anywhere\n", encoding="utf-8")
return raw
@pytest.fixture
def kb_dir(tmp_path: Path) -> Path:
"""A minimal fixture kb/ with the standard collection layout, populated
with a handful of pages covering entities/concepts/sources/comparisons.
Every collection carries a COLLECTION.md, both because that is what makes it
a collection and because the scanner must prove it skips them at a depth the
kb-root meta files never reach."""
kb = tmp_path / "kb"
for sub in ("entities/projects", "entities/systems", "entities/tools",
"entities/technologies", "entities/people",
"concepts", "sources", "comparisons"):
(kb / sub).mkdir(parents=True)
for collection in ("entities", "concepts", "sources", "comparisons"):
(kb / collection / "COLLECTION.md").write_text(
f"# kb/{collection}/ - Collection Contract\n", encoding="utf-8"
)
write_page(
kb / "entities/systems/aurora.md",
{
"type": "types/entity.md", "entity_type": "system",
"tags": ["server"], "created": "2026-07-31", "modified": "2026-07-31",
"related": ["Borealis"], "sources": [], "confidence": 0.9,
"summary": "Server hosting DocStore with ZFS storage",
},
"\n# aurora\n\n## Description\n\nHosts things.\n\n## Relationships\n\n- **Related to:** [[Borealis]]\n\n## See Also\n\n- [[Borealis]]\n",
)
write_page(
kb / "entities/systems/Borealis.md",
{
"type": "types/entity.md", "entity_type": "system",
"tags": ["workstation"], "created": "2026-08-02", "modified": "2026-08-02",
"related": ["aurora"], "sources": [], "confidence": 0.9,
},
"\n# Borealis\n\n## Description\n\nA workstation.\n\n## Relationships\n\n- **Related to:** [[aurora]]\n",
)
write_page(
kb / "entities/tools/gdeploy.md",
{
"type": "types/entity.md", "entity_type": "tool",
"tags": [], "created": "2026-07-25", "modified": "2026-07-25",
"related": [], "sources": [], "confidence": 0.8,
},
"\n# gdeploy\n\n## Description\n\nDeploy tool.\n",
)
write_page(
kb / "concepts/Modbus.md",
{
"type": "types/concept.md", "concept_type": "protocol",
"tags": [], "created": "2026-07-25", "modified": "2026-07-25",
"related": [], "sources": [], "confidence": 0.7,
},
"\n# Modbus\n\n## Definition\n\nIndustrial protocol.\n",
)
write_page(
kb / "sources/Source - Aurora.md",
{
"type": "types/source.md", "source_type": "notes", "author": "Torben",
"source": "raw/notes/Aurora.md", "date": "2026-08-02",
"tags": [], "entities": ["aurora"], "concepts": [],
},
"\n# Source: Aurora\n\n## Summary\n\nNotes.\n",
)
(kb / "index.md").write_text(
"# Wiki Index\n\n[[aurora]] [[Borealis]] [[gdeploy]] [[Modbus]] [[Source - Aurora]]\n",
encoding="utf-8",
)
(kb / "log.md").write_text("# Wiki Log\n", encoding="utf-8")
return kb