Repository navigation
test(aot): share one program between three tests of entry-points-that-are-not-text.test.ts and compare embedded files by SHA-256 - #47541
Conversation
…re-not-text Three of the four tests built a program of their own with --aot and without: 8 builds, 8 new executables. They now read their lines from one program that lists the files it holds and requires tool.unknown. The file makes 4 builds and starts 4 executables, and the builds run at the same time. Each run compares stdout, stderr, the exit code and the signal. An embedded file is compared by its name, its size and its SHA-256. The require test checks that the answer is the path of the carried file.
|
Updated 6:49 AM PT - Oct 31st, 2026
⏳ @robobun, your commit 4dfcf21 is still building in
|
|
Status: ready for review. The file passes on all 11 lanes with the head commit (build 136077). Two tests are red in that build, and this PR touches neither. How the time was found. A preload that wraps Runs. How the assertions were checked. Eight changes to the new file, one at a time, each fail the tests that they must. For example, |
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Shared fixtures and executable harness test/aot/cli/entry-points-that-are-not-text.test.ts |
The tests use shared fixtures and cache builds by mode and entry points. The app helper checks successful execution and expected output. |
Entry-point embedding assertions test/aot/cli/entry-points-that-are-not-text.test.ts |
Tests compare embedded-file names, sizes, and hashes across build modes. The TypeScript case checks entry-point execution, embedding, and require resolution. |
Possibly related PRs
- oven-sh/bun#47296: Changes AOT root selection; this PR tests embedded names and
requirepaths with multiple entry points. - oven-sh/bun#47535: Shares AOT builds and executable launches for related test cases.
- oven-sh/bun#47463: Shares AOT builds and temporary-directory setup in another AOT test suite.
Suggested reviewers: jarred-sumner
Merge Risk: 
Minimal · up to 4dfcf
-
The tests reduce duplicate builds while retaining the checked embedding behavior. No merge-blocking issue was established; merge after normal checks pass.
Pre-merge checks: 
4
-
Full details: Title check
-
Explanation
The title names the main change: the test file now shares one program between three tests and compares embedded files by SHA-256. The changeset matches this. The title is a single line and specific. It is a bit long at 128 characters, but it is accurate and not vague.
Full details: Description check
-
Explanation
The description follows the repository template. It has a 'What does this PR do?' section that explains the problem, the fix, the background, and the downsides. It has a 'How did you verify your code works?' section that lists local timings, CI timings, assertion-failure checks, and other test runs. The main text is long, and most of the detail sits in a collapsed details block. The description is substantive and specific, so the check passes. The only gap is that macOS timing was not measured locally. The author states this openly and cites CI logs instead.
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
…e-not-text The program took the last part of a path for each embedded name too, so a name with a folder in front of it passed. It now removes only the hash from a name, and takes the last part only of the path that require answers. The names, stderr, the exit code and the signal of the shared executable are compared in one object, so a failure shows what was printed. The folder is made in beforeAll. A run with -t that selects no test of the file runs no afterAll, and it left the folder behind.
|
The four review notes, after 4dfcf21:
|
There was a problem hiding this comment.
Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.
LGTM — 4dfcf21 addresses the three threads from the earlier review (fixtures now created in beforeAll, embedded names printed without a directory strip, and app() asserts one combined {names, stderr, exitCode, signal} object), and the remaining inline comment is a nit. For weighing it: ../harness/shared-builds is imported by one file under test/aot/trimmed-is-whole, while every file in test/aot/cli uses ../harness/commands (slot/spawned/built) as this one does, and sharedBuilds takes a single entry and makes its folder at module load, so reusing it here would reopen the lazy-folder point.
Extended reasoning...
The PR rewrites one test file, test/aot/cli/entry-points-that-are-not-text.test.ts, so that three tests share two memoised bun build --compile executables (with and without --aot) instead of six, and compares embedded further entry points by name, size and SHA-256 plus stderr and signal; no production code, no security-sensitive surface, and no CODEOWNERS path is touched. I traced the embedded program's output against the expected ordered list on both the Windows and non-Windows branches, the hash-strip regex and the require-answer basename against /$bunfs/root/tool-<hash>.unknown, the slot usage (no nested slots, so no deadlock between the four concurrent spawns), and the beforeAll/afterAll pairing with Promise.allSettled so a failed build does not skip disposal. The second commit resolved all three prior inline threads from the code itself, the hunt ran dry, and the single surviving finding is a harness-reuse nit that the directory's own conventions argue against, which decided approve.
|
About the note on |
Behaviour change: none
Problem
test/aot/cli/entry-points-that-are-not-text.test.tstakes 45 s on darwin x64 (build 135961). Linux takes 3 s.Fix
--aotand without: 4 builds and 4 executables, all at the same time.bun bd test test/aot/cli/entry-points-that-are-not-text.test.tstakes 35 s, was 47 s. Release build, 2 CPUs: 1.5 s, was 2.8 s. macOS is not measured. Alsotest-files-self-skip,every-test-runs-in-ci.Background
bun build --compile a.ts b.binwrites a copy of Bun that starts ata.tsand holdsb.bin, a further entry point, as a file.require("./tool.unknown")answers. Each test reads its lines.--aot-separate-programs: only canary builds start its programs.Downsides
tool.unknownhas them too.build-carries-files-that-are-no-code.test.tscovers thatrequirewithout them.Notes
Where the time goes. Release build of 34cbc70, Linux x64. Each build ran alone, best of 3. CPU is user plus system time. The functions and the engine runs are from
--aot-report.--aot, the program and a further entry point that is no code--aot--aot tool.unknowntool.unknown, without--aot--aot--aot toolBun.spawnlists the child processes of the file. Before: 18. That is 8 builds, 8 starts of an executable,bun app.ts, and the probe oftest/aot/harness/compiler.ts. After: 10. That is 4 builds, 4 starts, and the same two.Which build became which.
--aot app.ts table.unknown,--aot app.ts linked.node,--aot app.ts(requires./tool.unknown)--aot app.ts table.unknown linked.nodeapp.ts table.unknown,app.ts linked.node,app.ts(requires./tool.unknown)app.ts table.unknown linked.node--aot tool.unknown--aot toolbun app.tsAll local times. Linux x64, 12 vCPUs, a shared VM. Main's file and this PR's file ran in turns. A time is the wall time of the command.
bun bd test <file>), 5 roundstaskset -c 0-3)taskset -c 0-1)taskset -c 0)bunofbun run build:releaseat 34cbc70, with the variables thatscripts/runner.node.tssets:BUN_GARBAGE_COLLECTOR_LEVEL=1,BUN_JSC_randomIntegrityAuditRate=1.0,BUN_RUNTIME_TRANSPILER_CACHE_PATH=0,BUN_FEATURE_FLAG_NO_ORPHANS=1.7 files that build many executables (2-wide)in build 135961). The row with 2 CPUs stands for that: 2.76 s here, 3.4 s on debian 13 x64 in that build.--aotbuild of the shared program takes 28 s alone, and each of the 4 builds writes 1.6 GB. The runs vary with the state of the disk.expect()calls: 17 before, 20 after.CI on main. Seconds of the file in build 135961, then in build 135905: darwin x64 45, 46. debian 13 x64-asan 21, 21. darwin aarch64 13, 1. windows 11 aarch64 5, 5. windows 2019 x64 4, 6. alpine x64 4, 4. ubuntu x64 4, 3. debian x64, debian aarch64, ubuntu aarch64 and alpine aarch64 3, 3.
macOS. Not measured: this machine is Linux x64. The numbers here are from the logs of CI.
darwin-x64-15.7.9-1, in a group of12 files that build many executables (4-wide). It took 44.99 s.run-parallel.tsreports40 builds: 159.0 s, 162.4 s of CPUand273 executables: 145.2 s, 13.2 s of CPU. The builds do not wait. The runs wait 132 s. That is 3.3 s for each new executable.darwin-x64-14.8.9-1: the file took 46.01 s, and273 executables: 150.5 s, 12.4 s of CPU.24 executables: 0.6 s, 0.6 s of CPU.darwin-aarch64-26.6.1-1, which waits too (347 executables: 134.5 s, 21.1 s of CPU). 0.98 s ondarwin-arm64-sourdough-tart-15-1in build 135905, which waits little (347 executables: 36.1 s, 19.7 s of CPU).CI times are not like for like. On main the file runs beside other files that build executables (
buildingFilesWidthinscripts/runner.node.ts). The runner puts a test file that a PR changes in front and runs it without them (modifiedSerialTests). So the time of the file in this PR's own build is the time of the file alone.Build 136064 ran the first commit and build 136077 ran the head. The file passed on every lane in both. One run each:
darwin-x64-14.8.9-1)darwin-x64-14.8.9-1)darwin-aarch64-26.6.1-1)darwin-arm64-baguette-tart-26-2)darwin-arm64-sourdough-tart-15-1)Assertions, before and after.
bun app.ts. Before:toMatchObjecton stdout and the exit code. After:toEqualon stdout, an empty stderr, exit code 0 and no signal.table.unknown 3000). After: its name, its size, and the SHA-256 of its bytes, against the bytes that the test wrote. The two files now differ (3000 and 2000 bytes), so one cannot pass for the other.blob.,table.unknown,tool.unknown, exact, withoutblob.on Windows. Another name, or a name twice, fails. A name is compared asBun.embeddedFileshas it, but for the hash, as before. So a folder in front of a name fails.required undefined, which any answer without a membernprints. After: the answer is a string whose last part istool.unknown, and the executable holdstool.unknownwith the size and the SHA-256 of the source text. An executable that reads the file as code printsran 42and fails.--aotand without: the lines of the two executables are compared, as before.The assertions fail when they must. Each line is one change to this PR's file, run with the release build:
table.unknownwritten with 3001 bytes: the first test fails, the others pass.store/blobwritten with the bytes oftable.unknown: the link test fails, the others pass.tool.unknownwritten with one byte more: therequiretest fails, the others pass.linked.nodeleft out of the entry points: the three tests of the shared program fail at the list of names.console.errorin the program: the three tests fail at stderr.ran 42printed by the program: the three tests fail at the list of names.store/blob.printed for the link: the three tests fail at the list of names.process.exitCode = 3in the program: the three tests fail. The failure shows the five names besideexitCode: 3.Seen in bun, not changed here. With
--aot, a further entry point that is no code makes the build compile much more of Bun's library.app.tsaloneapp.tsand a.tsfileapp.tsandtable.unknownconsole.log("x")aloneconsole.log("x")and a.tsfileconsole.log("x")andtable.unknown, a.txt, a.jsonor a.pngtable.unknown--explain=trimprints 240 lines forconsole.log("x")with a.tsfurther entry point, and 2098 lines withtable.unknown. The second list hasuses Bun serve.app.ts: 26 s of CPU alone, 48 s withtable.unknown.Other checks
BUN_JSC_validateExceptionChecks=1,BUN_JSC_dumpSimulatedThrows=1,BUN_DESTRUCT_VM_ON_EXIT=1, and theASAN_OPTIONSandLSAN_OPTIONSof the runner): 4 pass.bun test --parallel=3 --max-concurrency=2withimage-rejection,carrier-identity,extensionless-entry-pointsandentry-points-behind-links: 27 pass.--max-concurrency=1,AOT_PROGRAMS_JOBS=1, and one CPU: 4 pass. A build and the run of its executable take one slot oftest/aot/harness/commands.ts. A test holds no slot while it waits for a build.-t "not UTF-8"buildstoolonly.afterAllwaits for the builds that are under way, then removes the folder.-tthat selects no test of the file makes no folder. bun:test runs noafterAllin a file where a name filter leaves no test, so the folder is made inbeforeAll.test/aot/test-files-self-skip.test.tsandtest/aot/every-test-runs-in-ci.test.tspass.prettier --checkandoxlintreport nothing.tscreports nothing in the file.test/expected-durations.jsonandtest/parallel-allowlist.jsoncome from CI runs. They are not changed.Not done.
withoutDebugInformation()of the harness. On the Linux lanes the runner already hands this file a Bun without debug information, and the helper does nothing on macOS and Windows. Debug build with ASAN: the copy has 1.26 GB where the build has 1.60 GB, andbun bd testtakes 38.4 s without the helper and 37.5 s with it (medians of 4 rounds in turns). A localbun-profile: 2.26 s without, 1.88 s with (medians of 6).no test proof · iteration 0 · platform-specific test(s) that do not run on this machine, deferring to CI, which covers all platforms: test/aot/cli/entry-points-that-are-not-text.test.ts