Files
vnctalk-prosody/tests/test_08_image_patches.py
Stefan-Sanger ca082d39fd fix: complete M1 — re-add run_as_root, fix stale patch tests, document manual tasks
Three changes to complete the repo-level work for Milestone 1 (0.11.6 →
0.12.6) plus a howto for the remaining manual/external tasks:

1. config/prosody.cfg.lua.template: re-add run_as_root = true. Production
   and the compose harness run as root (startup.sh writes into root-owned
   /etc/prosody/). Without it, mod_posix calls prosody.shutdown() during
   startup, which deactivates c2s (port 5222) before the shutdown itself
   errors out (prosody.main_thread is nil during module init), leaving
   Prosody running without c2s.

2. tests/test_08_image_patches.py: replace 3 stale patch-marker entries
   that checked for patches M1 intentionally dropped (moduleapi,
   mod_admin_telnet, muc.lib dumpTable) with markers that verify their
   config-based replacements (console_interfaces, http_interfaces) and
   the storagemanager.open() rewrite in mod_vnc_muc_fcm.lua.

3. upgrade-plan.md: update M1 status to reflect the post-M1 fixes
   (run_as_root, default_storage, stale tests), mark manual steps (DB
   migration, telnet console regression, external testsuite) with
   cross-references to m1-manual-tasks.md, and correct 0.12.5 → 0.12.6
   throughout.

4. m1-manual-tasks.md: new file documenting the three manual tasks that
   require external infrastructure — DB schema migration (one-way, with
   rehearse-on-copy procedure), telnet console regression test (0.12
   reimplemented the console on mod_admin_shell), and external testsuite
   run against a dev deployment.

Verified: compose-harness testsuite — 80 passed, 5 skipped, 1 pre-existing
failure (test_vcard_fallback: mod_vnc_vcard_fallback not enabled in config,
unrelated to M1).

Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
2026-07-15 17:58:02 +02:00

109 lines
4.0 KiB
Python

"""Patch-application CI test.
The Dockerfile builder stage applies every `patches/*.patch` to the upstream
Prosody source with `patch -p1 --fuzz=0` before `make install`. A patch that
fails to apply aborts the build, but a accidentally-dropped patch file or a
config-based replacement that was forgotten would leave the upstream file
unpatched while the build still succeeds. These tests exec into the running
prosody container and grep each patched upstream file (or rendered config)
for the VNCtalk-specific marker, catching that regression without a live
connection.
Requires the compose stack to be up:
docker compose up -d --build postgres mocks prosody
If `docker compose exec prosody` is not available, the whole module is skipped.
"""
import os
import shutil
import subprocess
import pytest
REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
# (test id, path inside the container, grep marker)
#
# Patches dropped at M1 and their replacements:
# - moduleapi.patch → mod_vnc_muc_fcm*.lua now call storagemanager.open()
# - mod_admin_telnet.patch → console_interfaces = { "*" } in the config
# - portmanager.patch → http_interfaces = { "*", "::" } in the config
# - muc.lib dumpTable → removed (debug helper, no replacement)
PATCH_MARKERS = [
("mod_mam_has_vnc_rest_message",
"/usr/local/lib/prosody/modules/mod_mam/mod_mam.lua",
"vnc-rest-message"),
("vnc_muc_fcm_uses_storagemanager",
"/usr/local/lib/prosody/modules/mod_vnc_muc_fcm.lua",
"storagemanager.open"),
("register_lib_has_vnc_muc_kick",
"/usr/local/lib/prosody/modules/muc/register.lib.lua",
"vnc-muc-kick"),
("config_has_console_interfaces",
"/etc/prosody/prosody.cfg.lua",
"console_interfaces"),
("config_has_http_interfaces",
"/etc/prosody/prosody.cfg.lua",
"http_interfaces"),
("portmanager_uses_network_default_read_size",
"/usr/local/lib/prosody/core/portmanager.lua",
"network_default_read_size"),
("mod_carbons_has_vnc_rest_hook",
"/usr/local/lib/prosody/modules/mod_carbons.lua",
"vnc-rest-message"),
("hidden_lib_present",
"/usr/local/lib/prosody/modules/muc/hidden.lib.lua",
"muc_room_allow_public"),
("mod_muc_unique_has_handle_iq_tobare",
"/usr/local/lib/prosody/modules/mod_muc_unique.lua",
"handle_iq_tobare"),
]
def _compose_available():
if not shutil.which("docker"):
return False
try:
res = subprocess.run(
["docker", "compose", "ps", "--services", "--filter", "status=running"],
cwd=REPO_ROOT, capture_output=True, text=True, timeout=20,
)
except (subprocess.SubprocessError, OSError):
return False
if res.returncode != 0:
return False
return "prosody" in res.stdout.split()
def _exec_grep(path, marker):
"""Return the grep match count (int) inside the prosody container, or -1."""
if not _compose_available():
return -1
# grep -Fc prints the match count (fixed-string match, so regex
# metacharacters in markers like '*' are treated literally).
res = subprocess.run(
["docker", "compose", "exec", "-T", "prosody",
"sh", "-c", f"grep -Fc -- {repr(marker)} {path}"],
cwd=REPO_ROOT, capture_output=True, text=True, timeout=30,
)
out = res.stdout.strip()
if res.returncode == 0 and out.isdigit():
return int(out)
return 0
@pytest.fixture(scope="module", autouse=True)
def require_compose():
if not _compose_available():
pytest.skip("compose stack not running (run: docker compose up -d prosody)", allow_module_level=True)
@pytest.mark.parametrize("test_id, path, marker", PATCH_MARKERS, ids=[m[0] for m in PATCH_MARKERS])
def test_patch_applied(test_id, path, marker):
count = _exec_grep(path, marker)
if count < 0:
pytest.skip("compose stack not available")
assert count > 0, (
f"Patch marker {marker!r} not found in {path} (grep count={count}). "
f"The patch or config replacement for '{test_id}' is missing or wrong."
)