Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 24 additions & 9 deletions packages/mocactl/test/sbx-push.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
unlinkSync,
writeFileSync,
} from 'node:fs';
import { randomFillSync } from 'node:crypto';
import { tmpdir } from 'node:os';
import { dirname, join } from 'node:path';
import { gunzipSync } from 'node:zlib';
Expand Down Expand Up @@ -98,6 +99,19 @@ const pushed = async (r: string, o: Parameters<typeof localWorkspace>[0] = {}) =
return w;
};

/**
* Random bytes, which gzip cannot shrink -- the point being that a chunk stays at its uncompressed
* size, so the splitter has to split.
*
* `randomFillSync` into a pre-allocated Buffer, NOT
* `Buffer.from(Array.from({ length: n }, () => Math.floor(Math.random() * 256)))`: the array form
* builds an n-element JS array before the Buffer, which for the ~27 MiB this file generates costs
* about a second of CPU and a 27-million-element allocation, against ~3 ms here. A secondary
* saving -- the bulk of this test's time was a `toEqual` on two 12 MiB buffers, see below -- but
* worth having on the one test in this package carrying a 120 s timeout.
*/
const incompressible = (n: number): Buffer => randomFillSync(Buffer.allocUnsafe(n));

describe('the push list (SBX0 §6.2)', () => {
it('lists tracked files (even under an ignored dir) and untracked ones, never ignored ones or secrets', async () => {
const plan = await planPush(repo());
Expand Down Expand Up @@ -226,16 +240,10 @@ describe('the push list (SBX0 §6.2)', () => {
it('splits a large tree into several Execs, each under the stdin ceiling', async () => {
const r = repo();
for (let i = 0; i < 3; i++) {
writeFileSync(
join(r, `blob${i}.bin`),
Buffer.from(Array.from({ length: 5 << 20 }, () => Math.floor(Math.random() * 256))),
);
writeFileSync(join(r, `blob${i}.bin`), incompressible(5 << 20));
}
// One file just under the per-file limit, incompressible: its chunk is the largest possible.
writeFileSync(
join(r, 'big.bin'),
Buffer.from(Array.from({ length: MAX_FILE - 4096 }, () => Math.floor(Math.random() * 256))),
);
writeFileSync(join(r, 'big.bin'), incompressible(MAX_FILE - 4096));
const plan = await planPush(r);
expect(plan.chunks.length).toBeGreaterThan(2);
for (const c of plan.chunks) expect(c.length).toBeLessThanOrEqual(MAX_STDIN);
Expand All @@ -246,7 +254,14 @@ describe('the push list (SBX0 §6.2)', () => {
);
for (const s of sent) expect(s.stdin?.length ?? 0).toBeLessThanOrEqual(MAX_STDIN_BYTES);
expect(statSync(join(ws, 'blob2.bin')).size).toBe(5 << 20);
expect(readFileSync(join(ws, 'big.bin'))).toEqual(readFileSync(join(r, 'big.bin')));
// `Buffer.equals`, not `toEqual`: both assert byte-for-byte identity, but toEqual walks the
// two ~12 MiB buffers as structures, element by element, which measured 18.7 s against 0 ms
// here -- on its own more than enough to blow a CI budget. The `.length` check first so a
// failure still says something useful, since `equals` collapses to a bare true/false.
const pushed = readFileSync(join(ws, 'big.bin'));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: const pushed shadows the module-level pushed() helper (line 96), which every later test in this file calls. It's harmless here, but a rename (copy/got) avoids confusion. Optionally, give the assertion a message, e.g. expect(got.equals(original), 'pushed big.bin differs').toBe(true), so a failure says more than expected false to be true.

const original = readFileSync(join(r, 'big.bin'));
expect(pushed.length).toBe(original.length);
expect(pushed.equals(original)).toBe(true);
expect(await hasUnpulled(exec)).toBe(false);
}, 120_000);
});
Expand Down
Loading