aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/tests/test_mnp_1_0_node_compat.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/tests/test_mnp_1_0_node_compat.py')
-rw-r--r--packages/meshbay-hub/tests/test_mnp_1_0_node_compat.py144
1 files changed, 0 insertions, 144 deletions
diff --git a/packages/meshbay-hub/tests/test_mnp_1_0_node_compat.py b/packages/meshbay-hub/tests/test_mnp_1_0_node_compat.py
deleted file mode 100644
index b15018b..0000000
--- a/packages/meshbay-hub/tests/test_mnp_1_0_node_compat.py
+++ /dev/null
@@ -1,144 +0,0 @@
-"""
-The page ships before the nodes do.
-
-The SPA is served by the hub, so deploying the hub puts this version of the
-client in front of *every* node, including the ones still running MNP 1.0. That
-window is not a corner case — it is the normal state for as long as it takes an
-operator to update, and for a node someone else runs it may be indefinite.
-
-The failure mode is specific and quiet: a node logs an unknown message type and
-sends **nothing back**, so a control that speaks MNP 1.1 to it produces a
-thirty-second wait ending in a timeout, with nothing on screen to say the node
-simply cannot do this. Three of them were like that before these tests:
-
-* The shared-directories toggles, eject and plug have no older equivalent at
- all.
-* The per-app folder pickers spoke `app_directories`, where a 1.0 node
- understands `video_root` / `audio_root` / `photo_roots`.
-
-Source-reading, like the other SPA guards. What it cannot check is that the
-degraded path is pleasant; what it does check is that each of the three exists.
-"""
-
-import re
-from pathlib import Path
-
-import pytest
-
-STATIC = Path(__file__).resolve().parents[1] / "src" / "meshbay_hub" / "static"
-TRANSPORT = STATIC / "transport.js"
-FILES_APP = STATIC / "files-app.js"
-GROUP_PAGE = STATIC / "group-page.js"
-GROUP_SETTINGS = STATIC / "group-settings.js"
-
-pytestmark = pytest.mark.skipif(not TRANSPORT.exists(),
- reason="SPA sources unavailable")
-
-
-def _component(source: str, name: str) -> str:
- start = source.index(f"\nfunction {name}(")
- end = source.find("\nfunction ", start + 1)
- return source[start:end if end != -1 else len(source)]
-
-
-# ── Knowing which node you are talking to ───────────────────────────────────
-
-def test_the_client_keeps_the_version_it_checked():
- """
- `_checkNodeVersion` parsed the node's version and threw it away, so nothing
- downstream could ask. Refusing to connect is not the only thing a version
- is good for.
- """
- source = TRANSPORT.read_text(encoding="utf-8")
- assert "this._nodeVersion = String(reply.v" in source
- assert "get supportsAppOps()" in source
-
-
-def test_the_capability_reads_the_version_rather_than_guessing():
- """
- Inferring it from whether some field happens to be present is how two
- unrelated things end up coupled — the flag would flip because a payload
- changed shape for another reason entirely.
- """
- source = TRANSPORT.read_text(encoding="utf-8")
- getter = source[source.index("get supportsAppOps()"):]
- getter = getter[:getter.index("\n }") + 4]
- assert "_nodeVersion" in getter
- assert "1" in getter, "no version comparison in the capability check"
-
-
-# ── The three degraded paths ────────────────────────────────────────────────
-
-def test_app_directories_fall_back_to_the_three_older_messages():
- """
- Videos, Music and Photos each had their own message before the generic op,
- and those still work — so an operator on an un-upgraded node keeps the
- ability they had rather than being handed a control that times out.
- """
- source = TRANSPORT.read_text(encoding="utf-8")
- legacy = source[source.index("async setAppDirectoriesLegacy("):]
- legacy = legacy[:legacy.index("\n async ", 1)]
- for call in ("setPhotoRoots", "setVideoRoot", "setAudioRoot"):
- assert call in legacy, f"{call} is not reachable on the older path"
-
- panel = _component(GROUP_SETTINGS.read_text(encoding="utf-8"),
- "GroupSettingsPanel")
- assert "transport.supportsAppOps" in panel, (
- "the settings page sends the 1.1 message unconditionally")
-
-
-def test_the_older_path_refuses_what_it_cannot_carry():
- """
- `video_root` and `audio_root` hold one folder. Sending several would store
- the first and drop the rest silently, which is worse than refusing — the
- operator would see a saved setting that is not what they chose.
- """
- source = TRANSPORT.read_text(encoding="utf-8")
- legacy = source[source.index("async setAppDirectoriesLegacy("):]
- legacy = legacy[:legacy.index("\n async ", 1)]
- assert "clean.length > 1" in legacy
- assert "throw new Error" in legacy
-
-
-def test_root_management_is_read_only_against_an_older_node():
- """
- Unlike the app directories, `writable`, `removable`, eject and plug have no
- older equivalent to route to. The controls are shown without being
- offered, with the reason, rather than accepting a click that goes nowhere.
- """
- panel = _component(GROUP_SETTINGS.read_text(encoding="utf-8"),
- "GroupSettingsPanel")
- table_call = panel[panel.index("<${SharedDirectoriesTable}"):]
- table_call = table_call[:table_call.index("/>")]
- assert "readOnly=" in table_call
- assert "nodeSupportsAppOps" in table_call
- assert "settings_node.roots_node_too_old" in panel, (
- "nothing says why the controls are inert")
-
-
-def test_chat_settings_are_hidden_rather_than_routed():
- """
- Chat's directory and link-preview switch are new in 1.1 with nothing
- before them, so there is no older message to fall back to.
- """
- panel = _component(GROUP_SETTINGS.read_text(encoding="utf-8"),
- "GroupSettingsPanel")
- assert "settings_node.app_node_too_old" in panel
-
-
-# ── Reading an older node's handshake ───────────────────────────────────────
-
-def test_the_ack_is_read_in_both_shapes(app=None):
- """
- A 1.0 ack has `video_root` and no `video_directories`, and no
- `chat_link_preview` at all. Reading a missing plural as "nothing
- configured" empties a working Videos tab; reading a missing switch as off
- silently changes what a group's chat does.
- """
- page = GROUP_PAGE.read_text(encoding="utf-8")
- block = page[page.index("setAppDirectories({"):]
- block = block[:block.index("setNodeSupportsAppOps")]
- for legacy in ("ack.video_root", "ack.audio_root", "ack.photo_roots"):
- assert legacy in block, f"{legacy} is not read as a fallback"
- assert "ack.chat_link_preview !== false" in page, (
- "an absent link-preview switch must read as on, not off")