summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/tests/test_streamed_download_reliability.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/tests/test_streamed_download_reliability.py')
-rw-r--r--packages/meshbay-hub/tests/test_streamed_download_reliability.py104
1 files changed, 57 insertions, 47 deletions
diff --git a/packages/meshbay-hub/tests/test_streamed_download_reliability.py b/packages/meshbay-hub/tests/test_streamed_download_reliability.py
index da745d0..bfd4a89 100644
--- a/packages/meshbay-hub/tests/test_streamed_download_reliability.py
+++ b/packages/meshbay-hub/tests/test_streamed_download_reliability.py
@@ -81,6 +81,10 @@ Object.defineProperty(globalThis, 'navigator', {
value: {
serviceWorker: {
get controller() { return controller; },
+ // What the document started with, which is the whole of the repair's
+ // evidence now. `getRegistration` is asked before anything registers.
+ getRegistration: async () => (PLAN.registeredAtLoad
+ ? {active: makeController()} : undefined),
register: async () => {
log.registers += 1;
if (PLAN.registerThrows) throw new Error('registration blocked');
@@ -118,6 +122,8 @@ Object.defineProperty(globalThis, 'navigator', {
globalThis.window = globalThis;
globalThis.isSecureContext = true;
+// Set before the module is imported, because it reads it at evaluation.
+controller = %(controlled)s ? makeController() : null;
// The self-test's repair reloads once and remembers it for the tab; both have
// to exist here or priming the worker throws instead of repairing.
const session = new Map();
@@ -160,7 +166,8 @@ const out = {};
def _run(tmp_path, body, *, control_after_ms=0, active=True,
serve="always", register_throws=False, control_budget_ms=800,
ready_settles=True, register_hangs=False,
- active_after_unregister=False, control_on_claim=False):
+ active_after_unregister=False, control_on_claim=False,
+ controlled_at_load=False, registered_at_load=False):
module = tmp_path / "downloads.mjs"
module.write_text(DOWNLOADS.read_text())
(tmp_path / "package.json").write_text('{"type":"module"}')
@@ -173,11 +180,13 @@ def _run(tmp_path, body, *, control_after_ms=0, active=True,
"registerHangs": register_hangs,
"activeAfterUnregister": active_after_unregister,
"controlOnClaim": control_on_claim,
+ "registeredAtLoad": registered_at_load,
}
script = tmp_path / "case.mjs"
script.write_text(
(PRELUDE % {"plan": json.dumps(plan), "module": module.as_posix(),
- "control": control_budget_ms})
+ "control": control_budget_ms,
+ "controlled": json.dumps(controlled_at_load)})
+ body
+ "\nout.log = log;\nconsole.log(JSON.stringify(out));\n")
proc = subprocess.run(["node", str(script)], capture_output=True, text=True,
@@ -398,68 +407,70 @@ if (target) await target.writable.close();
"discarding it did not get the page a worker it could stream to")
-# ── A page the worker cannot serve ──────────────────────────────────────────
+# ── A page loaded with the worker bypassed ──────────────────────────────────
-def test_a_page_the_worker_cannot_serve_reloads_itself_once(tmp_path):
- """Being controlled is not being servable, and the gap is a real failure.
- A document fetched by a hard reload — Ctrl+F5, Ctrl+Shift+R — is loaded with
- the service worker bypassed. It can be claimed afterwards, so `controller`
- comes back and every check in `_claimController` passes; but the navigations
- it starts keep missing the worker, and the hidden iframe a streamed download
- needs is a navigation. Every download then fails with "the worker did not
- answer" for the life of that page — on Firefox and Safari, the only path
- there is for a file too large to hold in memory.
+def test_a_hard_reloaded_page_reloads_itself_once(tmp_path):
+ """Uncontrolled at load while an active registration already exists is a
+ document fetched by a hard reload — Ctrl+F5, Ctrl+Shift+R — and nothing
+ else. Measured on Chrome at document start: a first visit has neither, an
+ ordinary reload has both, a hard reload has the registration and no
+ controller.
- Reported after an operator was told to hard-reload after each deployment:
- four downloads out of four worked on a freshly started browser, and the
- first attempt after a Ctrl+F5 failed, every time. An ordinary reload puts
- the document back under the worker, so priming does exactly that, once.
+ Such a page can still be claimed, so every control check passes; but the
+ navigations it starts keep missing the worker, and the hidden iframe a
+ streamed download needs is one. On Firefox and Safari that is the only way
+ to write a file too large to hold in memory. An ordinary reload undoes it.
"""
out = _run(tmp_path, """
M.primeServiceWorker();
- await new Promise((r) => setTimeout(r, 6000));
+ await new Promise((r) => setTimeout(r, 200));
out.reloads = log.reloads;
- """, serve="never")
- assert out["reloads"] == 1, (
- "a page that cannot be served by the worker was left that way")
+ """, controlled_at_load=False, registered_at_load=True)
+ assert out["reloads"] == 1
-def test_a_page_that_works_is_not_reloaded(tmp_path):
- """The self-test costs milliseconds when it passes, and must cost nothing
- else. Reloading a healthy page at boot would be a flicker on every visit."""
+def test_a_first_visit_is_not_a_bypass(tmp_path):
+ """Also uncontrolled at load, and perfectly healthy: the worker is being
+ installed right now and will claim the page in a moment. Reloading here
+ would be a flicker on everybody's first visit — and it was, taking the
+ group's WebRTC session down with it when it landed mid-connection."""
out = _run(tmp_path, """
M.primeServiceWorker();
- await new Promise((r) => setTimeout(r, 3000));
+ await new Promise((r) => setTimeout(r, 200));
out.reloads = log.reloads;
- """)
+ """, controlled_at_load=False, registered_at_load=False)
+ assert out["reloads"] == 0
+
+
+def test_a_controlled_page_does_not_reload(tmp_path):
+ """The ordinary case, which must cost nothing at all: no reload, and no
+ download spent asking. Chrome rations the downloads a page may start
+ without a user gesture to about three, and the first version of this check
+ asked its question by performing one — competing with the person's own
+ downloads for that budget."""
+ out = _run(tmp_path, """
+ M.primeServiceWorker();
+ await new Promise((r) => setTimeout(r, 200));
+ out.reloads = log.reloads;
+ out.navigations = log.navigations;
+ """, controlled_at_load=True, registered_at_load=True)
assert out["reloads"] == 0
+ assert out["navigations"] == 0, (
+ "priming performed a download; that budget belongs to the person")
def test_the_repair_happens_at_most_once(tmp_path):
"""The flag is in sessionStorage rather than a variable because the point is
- to survive the reload it triggers. If reloading does not help, the page
- stays broken and says so — it does not reload again, and again."""
+ to survive the reload it triggers, and because a page that is still bypassed
+ afterwards must stop rather than reload again, and again."""
out = _run(tmp_path, """
sessionStorage.setItem('meshbay.sw-repaired', '1');
M.primeServiceWorker();
- await new Promise((r) => setTimeout(r, 6000));
+ await new Promise((r) => setTimeout(r, 200));
out.reloads = log.reloads;
- """, serve="never")
- assert out["reloads"] == 0, "a page that had already been repaired reloaded again"
-
-
-def test_the_self_test_leaves_no_file_behind(tmp_path):
- """It opens a real download target to ask a real question, so it must also
- tear it down: a completed one would drop `meshbay-selftest.bin` into the
- download folder on every page load."""
- src = DOWNLOADS.read_text()
- fn = src[src.index("async function _canServeDownloads"):]
- fn = fn[:fn.index("\n}\n")]
- assert "writable.abort" in fn, (
- "the self-test's stream is never aborted, so the browser keeps what it "
- "was given")
- assert "frame.remove" in fn
+ """, controlled_at_load=False, registered_at_load=True)
+ assert out["reloads"] == 0
# ── The claim is asked for, not waited for ──────────────────────────────────
@@ -487,10 +498,9 @@ def test_an_uncontrolled_page_asks_at_once_rather_than_after_the_budget(tmp_path
"after the wait, not before it")
-def test_a_download_waits_for_the_self_test(tmp_path):
- """A click that lands while the check is still running must not race it.
- On a page that turns out to be unservable it would otherwise spend the full
- two attempts failing on a path that is about to be repaired."""
+def test_a_download_waits_for_priming(tmp_path):
+ """A click that lands while priming is still running must not race it: on a
+ page about to reload, the attempt would fail for nothing."""
out = _run(tmp_path, """
M.primeServiceWorker();
const t0 = Date.now();