summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorYuriy Andamasov <yuriy@vyos.io>2026-05-06 20:55:18 +0300
committerYuriy Andamasov <yuriy@vyos.io>2026-05-06 20:55:18 +0300
commit97d12b42d997627be6f33528ba2625bd0378de74 (patch)
treeafe2bc5b4426837530f2b4e0ab9840c81337a4c2 /tests
parent5d6fa52b8985f8068314aba26878a1d7d5cb84e5 (diff)
downloadvyos-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.py101
-rw-r--r--tests/test_swap_sources.py121
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()