""" A group's index is never written to browser storage. `group_indexes` was an IndexedDB store holding a decrypted copy of every group's index — each file's name, path, size, hash and uploader — written on every index and every delta. The cross-group search of the time read it instead of dialling anything, which is what it was for. Search has dialled the nodes since 2026-08-28. That change removed the reader and kept the writers, so the browser went on building a cleartext file listing that nothing consulted, that no sign-out removed (the key database is a different one), and that grew with every group ever opened. **L7**, at rest. Showing a group's files while its node is unreachable is the only thing such a cache buys, and it is not wanted: a listing you cannot open is worse than an honest absence. So there is nothing left to read it with, and these tests keep it that way — a writer reintroduced without a reader would be invisible again, and the second time it would be invisible for the same reason as the first. """ import re from pathlib import Path STATIC = Path(__file__).resolve().parents[1] / "src" / "meshbay_hub" / "static" HUB_CLIENT = STATIC / "hub-client.js" APP = STATIC / "app.js" # The store name, read from the source rather than written down here: renaming it # must not quietly take these tests out of the picture. STORE = re.search(r"const IDB_STORE = '([^']+)';", HUB_CLIENT.read_text(encoding="utf-8")).group(1) def _functions(src: str) -> dict[str, str]: """Every top-level function in a module, by name.""" out = {} starts = [(m.start(), m.group(1)) for m in re.finditer(r"^(?:async )?function (\w+)\(", src, re.M)] for i, (at, name) in enumerate(starts): end = starts[i + 1][0] if i + 1 < len(starts) else len(src) out[name] = src[at:end] return out def test_only_the_purge_touches_the_old_store(): """ Creating it and emptying it, and nothing else. `openDB` still creates the store because dropping it needs a version bump, and a version bump is an upgrade another tab can block — which would take playlists down with it, since they share this database. An empty store costs nothing; the point is that nothing writes to it. """ fns = _functions(HUB_CLIENT.read_text(encoding="utf-8")) touching = sorted(n for n, body in fns.items() if "IDB_STORE" in body) assert touching == ["openDB", "purgeGroupIndexCache"], ( f"{touching} touch the {STORE!r} store; only creating and emptying it " "are allowed, and a write to it is a file listing kept on disk that " "nothing will ever read") def test_nothing_writes_a_group_index_to_the_store(): """Stated on the operation rather than on the callers, so a new one is caught.""" fns = _functions(HUB_CLIENT.read_text(encoding="utf-8")) purge = fns["purgeGroupIndexCache"] assert ".clear()" in purge for write in (".put(", ".add(", ".putAll("): assert write not in purge, f"the purge does a {write} — it must only clear" def test_no_module_carries_a_cache_writer_any_more(): """ The functions are gone, so the way this comes back is a new one. Any export of hub-client.js whose name is about caching an index is refused here rather than discovered months later with a store full of filenames. """ src = HUB_CLIENT.read_text(encoding="utf-8") for name in re.findall(r"^(?:async )?function (\w+)\(", src, re.M): assert not re.search(r"cache.*index|index.*cache", name, re.I) \ or name == "purgeGroupIndexCache", ( f"{name} looks like an index cache again — the store it would write " "to has no reader, and adding one was decided against") def test_the_purge_is_actually_called(): """ The defect being cleaned up was a function nobody called. A purge nobody calls is the same defect wearing the opposite hat: the data stays on every machine that already has it, and nothing says so. """ app = APP.read_text(encoding="utf-8") assert "purgeGroupIndexCache" in app, "app.js no longer imports the purge" call = re.search(r"purgeGroupIndexCache\(\)", app) assert call, "the purge is imported and never called" mount = app.index("const mount = () => {") assert "purgeOnce()" in app[mount:mount + 400], ( "the purge is no longer run at start-up, so a browser that still holds " "the old store keeps it")