testBigPushesTravelCompressed
A big push goes compressed to a server that says it takes compressed bodies (and small requests, and those before it has said so, as they are); a compressed body is held to the server's size limit unpacked.
import { tempDir, withChildren } from "#codebase/tcmts/cli/test/e2e/harness"; import { codebase, startServer } from "#codebase/tcmts/cli/test/e2e/sync"; import assert from "node:assert/strict"; import { spawn } from "node:child_process"; import fs from "node:fs"; import path from "node:path"; import { DatabaseSync } from "node:sqlite"; import { gzipSync } from "node:zlib"; export const testBigPushesTravelCompressed = () => withChildren(async (keep) => { const root = tempDir("sync gzip"); const server = codebase(root, "server"); fs.rmSync(path.join(server.dir, "scratch.ts")); const url = await startServer(keep, server.dir, "tok"); const call = (route: string, body: BodyInit, headers: Record<string, string> = {}) => fetch(`${url}/${route}`, { method: "POST", headers: { authorization: "Bearer tok", ...headers }, body, }); const gzip = (text: string) => new Uint8Array(gzipSync(text)); const plain = await call("missing", JSON.stringify({ components: ["abc"] })); assert.match(plain.headers.get("accept-encoding") ?? "", /gzip/, "it says it takes gzip"); const zipped = await call("missing", gzip(JSON.stringify({ components: ["abc"] })), { "content-encoding": "gzip", }); assert.deepEqual(await zipped.json(), { missing: ["abc"] }); // 100 MB of nothing packs into a small body; unpacked, it's over the limit const bomb = await call("missing", gzip(`{"components": []${" ".repeat(100 * 1024 * 1024)}}`), { "content-encoding": "gzip", }); assert.equal(bomb.status, 413); assert.equal((await call("missing", "{}", { "content-encoding": "br" })).status, 415); // a push through a proxy that notes how each request came const proxy = keep( spawn(process.execPath, [ "-e", `const http = require("node:http"); http.createServer((req, res) => { console.log(req.url + " " + (req.headers["content-encoding"] ?? "identity")); req.pipe(http.request(new URL(req.url, ${JSON.stringify(url)}), { method: req.method, headers: req.headers }, (r) => { res.writeHead(r.statusCode, r.headers); r.pipe(res); })); }).listen(0, "127.0.0.1", function () { console.log("port " + this.address().port); });`, ]), ); let seen = ""; proxy.stdout!.setEncoding("utf8").on("data", (d: string) => (seen += d)); const port = await new Promise<string>((resolve) => { const check = () => { const m = /port (\d+)/.exec(seen); if (m) resolve(m[1]!); else setTimeout(check, 20); }; check(); }); const a = codebase(root, "a"); a.scratch( Array.from( { length: 40 }, (_, i) => `export const text${i} = ${JSON.stringify(`${i} `.repeat(1000))};\n`, ).join("") + "export const twice = (s: string): string => s + s;\n", ); a.tcm("add"); a.tcm("remote", "add", "origin", `http://127.0.0.1:${port}`, "--token", "tok"); assert.match(a.tcm("push"), /sent 41 definition\(s\)/); // (the push ran synchronously: what the proxy wrote meanwhile is read now) await new Promise((r) => setTimeout(r, 300)); assert.match(seen, /^\/whoami identity$/m, "before the server says it takes gzip"); assert.match(seen, /^\/put gzip$/m, "definitions, compressed"); assert.match(seen, /^\/set-branch identity$/m, "a small body as it is"); assert.match(server.tcm("ls"), /text39/); // sent lean (the IR's head, no shape), kept whole: the server's IR is what the source gives const names = (await (await call("branch", JSON.stringify({ name: "main" }))).json()).branch .names as { path: string; hash: string }[]; const text7 = names.find((n) => n.path === "text7")!.hash; const [kept] = (await (await call("get", JSON.stringify({ hashes: [text7] }))).json()).records; assert.ok(kept.ir.includes(JSON.stringify("7 ".repeat(1000))), "its IR, whole"); // sent without a type shape, it has one: worked out for what the branch names const twice = names.find((n) => n.path === "twice")!.hash; // (read from the database: the server, another process, keeps what it read) const shapeOf = () => { const db = new DatabaseSync(path.join(server.dir, ".tcm", "codebase.sqlite"), { readOnly: true, }); try { return db.prepare("SELECT value FROM metadata WHERE hash = ? AND key = 'shape'").get(twice); } finally { db.close(); } }; assert.ok(shapeOf(), "worked out as the server's branch came to name it"); assert.match(server.tcm("find", ":(s: string) => string"), /twice/); })