diff options
Diffstat (limited to 'packages/meshbay-hub/tests/test_downloads.py')
| -rw-r--r-- | packages/meshbay-hub/tests/test_downloads.py | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/packages/meshbay-hub/tests/test_downloads.py b/packages/meshbay-hub/tests/test_downloads.py index cd0cded..41d61bf 100644 --- a/packages/meshbay-hub/tests/test_downloads.py +++ b/packages/meshbay-hub/tests/test_downloads.py @@ -108,3 +108,59 @@ def test_the_open_action_reads_the_file_back(tmp_path): target = src[src.index("export async function openTarget"):] assert "getFile()" in target and "window.open(" in target assert "revokeObjectURL" in target, "the blob URL must not be leaked" + + +# ── Streaming to disk without the File System Access API ──────────────────── + +SW = STATIC / "sw.js" + + +def test_the_worker_only_answers_its_own_urls(): + """ + It is registered at the root scope, so it sees every request the page makes. + Anything that is not a download of ours has to fall through untouched — a + service worker that answers more than it should is a cache bug waiting to + happen. + """ + src = SW.read_text() + assert "startsWith(PREFIX)" in src + assert "self.location.origin" in src, "cross-origin requests must fall through" + # The API, not the word: the file explains in prose that it caches nothing. + for api in ("caches.open", "caches.match", "cache.put"): + assert api not in src, f"this worker must not cache anything ({api})" + + +def test_the_download_is_announced_as_an_attachment(): + src = SW.read_text() + assert "Content-Disposition" in src and "attachment" in src + assert "filename*=UTF-8''" in src, "a name with accents would be mangled" + assert "Content-Length" in src + + +def test_a_length_is_only_promised_when_it_is_known(tmp_path): + """ + An archive is assembled as it goes and is larger than the files in it. + Announcing the sum of their sizes would truncate the download at that mark. + """ + src = SW.read_text() + assert "if (entry.size > 0)" in src + + app = (STATIC / "app.js").read_text() + zip_call = app[app.index("const target = await _openDownloadTarget(suggested"):] + zip_call = zip_call[:zip_call.index(");") + 2] + assert zip_call.rstrip().endswith(", 0);"), ( + "the zip download announces a Content-Length it will not match") + + +def test_backpressure_is_real(tmp_path): + """ + The point of the service worker path is not holding the file. A stream that + is transferred gives `writer.write()` something to wait on; posting chunks + to a port would queue them in memory and look identical from here. + """ + src = DOWNLOADS.read_text() + fn = src[src.index("export async function openStreamedDownload"):] + assert "new TransformStream()" in fn + assert "[readable]" in fn, "the readable half must be transferred, not copied" + assert "writer.write(bytes)" in fn + assert "return null" in fn, "a browser that cannot transfer streams must say so" |