diff options
| author | Yuriy Andamasov <yuriy@vyos.io> | 2026-05-06 20:55:18 +0300 |
|---|---|---|
| committer | Yuriy Andamasov <yuriy@vyos.io> | 2026-05-06 20:55:18 +0300 |
| commit | 97d12b42d997627be6f33528ba2625bd0378de74 (patch) | |
| tree | afe2bc5b4426837530f2b4e0ab9840c81337a4c2 /tests | |
| parent | 5d6fa52b8985f8068314aba26878a1d7d5cb84e5 (diff) | |
| download | vyos-documentation-97d12b42d997627be6f33528ba2625bd0378de74.tar.gz vyos-documentation-97d12b42d997627be6f33528ba2625bd0378de74.zip | |
feat: flip swap mechanism — Phase 2 (swap_sources.py rewrite)
Phase 2 of the MD-as-primary flip. Inverts swap_sources.py so it activates
RST overrides (rst-<stem>.rst → <stem>.rst, with the matching <stem>.md
excluded via _md_exclude.txt) for stems listed in docs/_rst_overrides.txt.
Changes:
- scripts/swap_sources.py: rewritten with inverted rename direction and
renamed runtime artifacts (_rst_override_state.json, _md_exclude.txt).
CLI flags --swap/--restore/--dry-run/--status kept for compatibility with
the Makefile and Read the Docs config.
- docs/conf.py: clean up the runtime-artifact references that Phase 1 left
pointing at the old _swap_state.json and _swap_exclude.txt names.
- scripts/import_myst.py and tests/test_import_myst.py deleted; obsolete
after the flip (MD is canonical, no separate import workflow needed).
- tests/test_swap_sources.py: rewritten for the new semantics. All 10 tests
pass under pytest.
Smoke-tested end-to-end on a real worktree page (quick-start): adding the
stem to _rst_overrides.txt, --dry-run, --swap, --status, --restore, all
behave correctly. State JSON has version 2 (bumped from 1 to surface the
incompatibility on rollback if old state lingers).
Phase 3 will verify Makefile, .readthedocs.yml, docs/_ext/vyos.py don't
reference any of the old names, then mark the PR ready-for-review.
Generated by robots https://vyos.io
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test_import_myst.py | 101 | ||||
| -rw-r--r-- | tests/test_swap_sources.py | 121 |
2 files changed, 64 insertions, 158 deletions
diff --git a/tests/test_import_myst.py b/tests/test_import_myst.py deleted file mode 100644 index 1d975b45..00000000 --- a/tests/test_import_myst.py +++ /dev/null @@ -1,101 +0,0 @@ -"""Tests for import_myst.py — run with: - cd tests && PYTHONPATH=../scripts python3 -m pytest test_import_myst.py -v -""" -import warnings -from pathlib import Path - -import pytest - - -# --------------------------------------------------------------------------- -# import_page tests (no git dependency) -# --------------------------------------------------------------------------- - -def test_import_single_page(tmp_path): - """Creates md-{name}.md with the given content.""" - from import_myst import import_page - - docs = tmp_path / "docs" - docs.mkdir() - content = b"# quick-start\nHello MyST\n" - - result = import_page("quick-start", content, docs, force=False) - - assert result is True - dest = docs / "md-quick-start.md" - assert dest.exists() - assert dest.read_bytes() == content - - -def test_import_skip_identical(tmp_path): - """Returns False and does not modify the file when content is identical.""" - from import_myst import import_page - - docs = tmp_path / "docs" - docs.mkdir() - content = b"# quick-start\nIdentical content\n" - dest = docs / "md-quick-start.md" - dest.write_bytes(content) - mtime_before = dest.stat().st_mtime_ns - - result = import_page("quick-start", content, docs, force=False) - - assert result is False - assert dest.read_bytes() == content - assert dest.stat().st_mtime_ns == mtime_before - - -def test_import_warn_different_without_force(tmp_path): - """Returns False and keeps old content when content differs and force=False.""" - from import_myst import import_page - - docs = tmp_path / "docs" - docs.mkdir() - old_content = b"# old content\n" - new_content = b"# new content\n" - dest = docs / "md-quick-start.md" - dest.write_bytes(old_content) - - with warnings.catch_warnings(record=True) as caught: - warnings.simplefilter("always") - result = import_page("quick-start", new_content, docs, force=False) - - assert result is False - assert dest.read_bytes() == old_content - assert len(caught) == 1 - assert "force" in str(caught[0].message).lower() - - -def test_import_overwrite_with_force(tmp_path): - """Returns True and writes new content when force=True.""" - from import_myst import import_page - - docs = tmp_path / "docs" - docs.mkdir() - old_content = b"# old content\n" - new_content = b"# new content\n" - dest = docs / "md-quick-start.md" - dest.write_bytes(old_content) - - result = import_page("quick-start", new_content, docs, force=True) - - assert result is True - assert dest.read_bytes() == new_content - - -def test_import_nested_path(tmp_path): - """Creates parent dirs and writes md-{name}.md in the correct nested location.""" - from import_myst import import_page - - docs = tmp_path / "docs" - docs.mkdir() - content = b"# zone\nFirewall zone docs\n" - - result = import_page("configuration/firewall/zone", content, docs, force=False) - - assert result is True - dest = docs / "configuration" / "firewall" / "md-zone.md" - assert dest.exists() - assert dest.read_bytes() == content - # Parent dirs were created - assert (docs / "configuration" / "firewall").is_dir() diff --git a/tests/test_swap_sources.py b/tests/test_swap_sources.py index 8576e056..7e9f68be 100644 --- a/tests/test_swap_sources.py +++ b/tests/test_swap_sources.py @@ -1,19 +1,25 @@ """Tests for swap_sources.py — run with: cd tests && PYTHONPATH=../scripts python -m pytest test_swap_sources.py -v + +In the inverted model MD is the canonical source for migrated pages and RST +under the ``rst-<stem>.rst`` prefix is a fallback used only for stems listed +in ``docs/_rst_overrides.txt``. ``do_swap`` activates the override (renames +``rst-<stem>.rst`` → ``<stem>.rst`` and excludes ``<stem>.md``); ``do_restore`` +undoes that. """ import json import os -import sys from pathlib import Path import pytest + # --------------------------------------------------------------------------- # Helper # --------------------------------------------------------------------------- def _setup_docs(tmp_path: Path, stems: list[str]) -> Path: - """Create a minimal docs/ tree with RST + md-prefixed MD files for each stem.""" + """Create a minimal docs/ tree with MD primary + rst-prefixed RST for each stem.""" docs = tmp_path / "docs" for stem in stems: p = Path(stem) @@ -21,22 +27,22 @@ def _setup_docs(tmp_path: Path, stems: list[str]) -> Path: parent = p.parent # may be "." for flat stems target_dir = docs / parent if str(parent) != "." else docs target_dir.mkdir(parents=True, exist_ok=True) - # RST file that would normally be the Sphinx source - (target_dir / f"{name}.rst").write_text(f".. _{name}:\n\nDummy RST for {stem}\n") - # md- prefixed MyST file waiting to be swapped in - (target_dir / f"md-{name}.md").write_text(f"# {name}\nDummy MyST for {stem}\n") + # MD file is the canonical source after the flip. + (target_dir / f"{name}.md").write_text(f"# {name}\nDummy MyST for {stem}\n") + # rst-prefixed RST file waiting to be activated as an override. + (target_dir / f"rst-{name}.rst").write_text(f".. _{name}:\n\nDummy RST for {stem}\n") return docs # --------------------------------------------------------------------------- -# parse_swap_list +# parse_override_list # --------------------------------------------------------------------------- -def test_parse_swap_list_basic(tmp_path): - from swap_sources import parse_swap_list +def test_parse_override_list_basic(tmp_path): + from swap_sources import parse_override_list - swap_txt = tmp_path / "_swap.txt" - swap_txt.write_text( + overrides_txt = tmp_path / "_rst_overrides.txt" + overrides_txt.write_text( "# comment\n" "\n" "configuration/firewall/zone\n" @@ -44,7 +50,7 @@ def test_parse_swap_list_basic(tmp_path): "# another comment\n" "installation/virtual/vmware\n" ) - stems = parse_swap_list(swap_txt) + stems = parse_override_list(overrides_txt) assert stems == [ "configuration/firewall/zone", "quick-start", @@ -52,15 +58,15 @@ def test_parse_swap_list_basic(tmp_path): ] -def test_parse_swap_list_empty(tmp_path): - from swap_sources import parse_swap_list +def test_parse_override_list_empty(tmp_path): + from swap_sources import parse_override_list - missing = tmp_path / "_swap.txt" - assert parse_swap_list(missing) == [] + missing = tmp_path / "_rst_overrides.txt" + assert parse_override_list(missing) == [] # --------------------------------------------------------------------------- -# do_swap +# do_swap (apply RST overrides) # --------------------------------------------------------------------------- def test_swap_renames_files(tmp_path): @@ -68,13 +74,13 @@ def test_swap_renames_files(tmp_path): stems = ["quick-start"] docs = _setup_docs(tmp_path, stems) - (tmp_path / "docs" / "_swap.txt").write_text("quick-start\n") + (docs / "_rst_overrides.txt").write_text("quick-start\n") do_swap(docs) - assert (docs / "quick-start.md").exists(), "md- file should be renamed to plain .md" - assert not (docs / "md-quick-start.md").exists(), "md- prefix file should be gone" - assert (docs / "quick-start.rst").exists(), "RST file should still exist" + assert (docs / "quick-start.rst").exists(), "rst- file should be renamed to plain .rst" + assert not (docs / "rst-quick-start.rst").exists(), "rst- prefix file should be gone" + assert (docs / "quick-start.md").exists(), "MD file should still exist (just excluded)" def test_swap_creates_state_file(tmp_path): @@ -82,22 +88,22 @@ def test_swap_creates_state_file(tmp_path): stems = ["quick-start"] docs = _setup_docs(tmp_path, stems) - (docs / "_swap.txt").write_text("quick-start\n") + (docs / "_rst_overrides.txt").write_text("quick-start\n") do_swap(docs) - state_file = docs / "_build" / "_swap_state.json" + state_file = docs / "_build" / "_rst_override_state.json" assert state_file.exists(), "state file should be created in _build/" state = json.loads(state_file.read_text()) - assert state["version"] == 1 - assert len(state["swaps"]) == 1 + assert state["version"] == 2 + assert len(state["overrides"]) == 1 - entry = state["swaps"][0] + entry = state["overrides"][0] assert entry["stem"] == "quick-start" - assert "md_from" in entry - assert "md_to" in entry - assert "rst_excluded" in entry + assert "rst_from" in entry + assert "rst_to" in entry + assert "md_excluded" in entry def test_swap_creates_exclude_file(tmp_path): @@ -105,15 +111,15 @@ def test_swap_creates_exclude_file(tmp_path): stems = ["quick-start"] docs = _setup_docs(tmp_path, stems) - (docs / "_swap.txt").write_text("quick-start\n") + (docs / "_rst_overrides.txt").write_text("quick-start\n") do_swap(docs) - exclude_file = docs / "_build" / "_swap_exclude.txt" + exclude_file = docs / "_build" / "_md_exclude.txt" assert exclude_file.exists(), "exclude file should be created in _build/" lines = [l.strip() for l in exclude_file.read_text().splitlines() if l.strip()] - assert "quick-start.rst" in lines + assert "quick-start.md" in lines # --------------------------------------------------------------------------- @@ -125,18 +131,19 @@ def test_restore_undoes_renames(tmp_path): stems = ["quick-start"] docs = _setup_docs(tmp_path, stems) - (docs / "_swap.txt").write_text("quick-start\n") + (docs / "_rst_overrides.txt").write_text("quick-start\n") do_swap(docs) - assert (docs / "quick-start.md").exists() + assert (docs / "quick-start.rst").exists() do_restore(docs) - assert (docs / "md-quick-start.md").exists(), "md- prefix file should be restored" - assert not (docs / "quick-start.md").exists(), "plain .md should be gone after restore" + assert (docs / "rst-quick-start.rst").exists(), "rst- prefix file should be restored" + assert not (docs / "quick-start.rst").exists(), "plain .rst should be gone after restore" + assert (docs / "quick-start.md").exists(), "MD file should remain untouched throughout" - state_file = docs / "_build" / "_swap_state.json" - exclude_file = docs / "_build" / "_swap_exclude.txt" + state_file = docs / "_build" / "_rst_override_state.json" + exclude_file = docs / "_build" / "_md_exclude.txt" assert not state_file.exists(), "state file should be deleted after restore" assert not exclude_file.exists(), "exclude file should be deleted after restore" @@ -159,20 +166,20 @@ def test_swap_fails_on_collision(tmp_path): stems = ["quick-start", "cli"] docs = _setup_docs(tmp_path, stems) - (docs / "_swap.txt").write_text("quick-start\ncli\n") + (docs / "_rst_overrides.txt").write_text("quick-start\ncli\n") - # Simulate a collision: unprefixed .md already exists for "cli" - (docs / "cli.md").write_text("# collision\n") + # Simulate a collision: unprefixed .rst already exists for "cli" + (docs / "cli.rst").write_text(".. _cli:\nCollision RST\n") with pytest.raises(RuntimeError, match="collision"): do_swap(docs) # Rollback: first stem's rename should be undone - assert (docs / "md-quick-start.md").exists(), "rollback should undo completed renames" - assert not (docs / "quick-start.md").exists(), "renamed file should not exist after rollback" + assert (docs / "rst-quick-start.rst").exists(), "rollback should undo completed renames" + assert not (docs / "quick-start.rst").exists(), "renamed file should not exist after rollback" # State file should NOT be written on failure - state_file = docs / "_build" / "_swap_state.json" + state_file = docs / "_build" / "_rst_override_state.json" assert not state_file.exists(), "no state file should be written on failure" @@ -186,7 +193,7 @@ def test_swap_rollback_on_rename_failure(tmp_path, monkeypatch): stems = ["quick-start", "cli"] docs = _setup_docs(tmp_path, stems) - (docs / "_swap.txt").write_text("quick-start\ncli\n") + (docs / "_rst_overrides.txt").write_text("quick-start\ncli\n") call_count = {"n": 0} real_rename = os.rename @@ -203,11 +210,11 @@ def test_swap_rollback_on_rename_failure(tmp_path, monkeypatch): do_swap(docs) # First rename (quick-start) should have been rolled back - assert (docs / "md-quick-start.md").exists(), "rollback should undo the first rename" - assert not (docs / "quick-start.md").exists(), "renamed file should not exist after rollback" + assert (docs / "rst-quick-start.rst").exists(), "rollback should undo the first rename" + assert not (docs / "quick-start.rst").exists(), "renamed file should not exist after rollback" # No state file should exist - assert not (docs / "_build" / "_swap_state.json").exists() + assert not (docs / "_build" / "_rst_override_state.json").exists() # --------------------------------------------------------------------------- @@ -219,20 +226,20 @@ def test_swap_nested_paths(tmp_path): stems = ["configuration/firewall/zone"] docs = _setup_docs(tmp_path, stems) - (docs / "_swap.txt").write_text("configuration/firewall/zone\n") + (docs / "_rst_overrides.txt").write_text("configuration/firewall/zone\n") do_swap(docs) - swapped = docs / "configuration" / "firewall" / "zone.md" - md_source = docs / "configuration" / "firewall" / "md-zone.md" - assert swapped.exists(), "nested md file should be renamed" - assert not md_source.exists() + activated = docs / "configuration" / "firewall" / "zone.rst" + rst_source = docs / "configuration" / "firewall" / "rst-zone.rst" + assert activated.exists(), "nested rst file should be renamed" + assert not rst_source.exists() - exclude_file = docs / "_build" / "_swap_exclude.txt" + exclude_file = docs / "_build" / "_md_exclude.txt" lines = [l.strip() for l in exclude_file.read_text().splitlines() if l.strip()] - assert "configuration/firewall/zone.rst" in lines + assert "configuration/firewall/zone.md" in lines do_restore(docs) - assert md_source.exists(), "nested md- file should be restored" - assert not swapped.exists() + assert rst_source.exists(), "nested rst- file should be restored" + assert not activated.exists() |
