Skip to content

Commit eec8736

Browse files
authored
chore(dev): allow explicit test worker budgets and document pinned installs (#921)
1 parent ef38865 commit eec8736

4 files changed

Lines changed: 74 additions & 10 deletions

File tree

‎CONTRIBUTING.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ bun run check
7070
bun run test
7171
```
7272

73+
The Node and UI runners default to at most four concurrent test files. On a
74+
machine with at least eight available CPUs, `OPENPI_TEST_WORKERS=8 bun run test`
75+
uses eight workers. For a memory-constrained run, set it to one or two.
76+
Windows process-isolated tests always run one file at a time.
77+
7378
Green automation only proves the code, type, and test contracts. When a change touches the runtime or the UI, also complete the matching smoke in a real, `/reload`ed Pi:
7479

7580
- Tool or lifecycle changes: actually trigger the success, failure, and termination paths in normal tool mode;

‎extensions/subagents/docs/effect-v4-notes.md‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@
1616
1717
## Install
1818

19-
```bash
20-
npm install effect@beta @effect/platform-node@beta
21-
```
19+
Use the repository root `package.json` and lockfile for the current Effect versions.
20+
Install the pinned development dependencies from the repository root with
21+
`bun install --frozen-lockfile`. The examples below retain their historical beta.98
22+
verification; they are not an instruction to install that version.
2223

2324
Big structural facts:
2425

25-
- **One version number for everything.** All ecosystem packages release together at
26-
`4.0.0-beta.N`. `@effect/platform-node` must match `effect` exactly.
26+
- **Use the repository's tested version cohort.** The root manifest pins Effect packages
27+
together to avoid prerelease dependency drift during packed npm installs; see
28+
[issue #533](https://github.com/openpi-dev/openpi/issues/533).
2729
- **`@effect/platform` is gone — merged into core `effect`.** `FileSystem`, `Path`,
2830
`PlatformError`, `Terminal`, `Stdio` are now top-level `effect` modules.
2931
`@effect/platform-node` remains as the Node *implementation* package.

‎scripts/run-tests.mjs‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,21 @@ if (nodeTests.length === 0 || vitestTests.length === 0) {
3232

3333
// Process and jsdom fixtures both need headroom. Bound file-level overlap
3434
// instead of letting cold loaders and DOM work compete for every core.
35-
const concurrency = Math.max(1, Math.min(4, availableParallelism() - 1));
35+
const availableWorkers = availableParallelism();
36+
const requestedWorkers = process.env.OPENPI_TEST_WORKERS;
37+
const concurrency =
38+
requestedWorkers === undefined
39+
? Math.max(1, Math.min(4, availableWorkers - 1))
40+
: Number(requestedWorkers);
41+
if (
42+
!Number.isInteger(concurrency) ||
43+
concurrency < 1 ||
44+
concurrency > availableWorkers
45+
) {
46+
throw new Error(
47+
`OPENPI_TEST_WORKERS must be an integer between 1 and ${availableWorkers}.`,
48+
);
49+
}
3650

3751
function runNodeTests(files, options = []) {
3852
if (files.length === 0) return 0;

‎tests/scripts/run-tests.test.ts‎

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
rmSync,
88
writeFileSync,
99
} from "node:fs";
10-
import { tmpdir } from "node:os";
10+
import { availableParallelism, tmpdir } from "node:os";
1111
import { join, resolve } from "node:path";
1212
import test from "node:test";
1313

@@ -59,7 +59,9 @@ function fixture() {
5959
assert.equal(process.argv[2], "run");
6060
const args = process.argv.slice(3);
6161
const workers = Number(args.find((arg) => arg.startsWith("--maxWorkers="))?.split("=")[1]);
62-
assert.ok(Number.isInteger(workers) && workers >= 1 && workers <= 4);
62+
assert.ok(Number.isInteger(workers) && workers >= 1);
63+
if (process.env.EXPECT_WORKERS) assert.equal(workers, Number(process.env.EXPECT_WORKERS));
64+
else assert.ok(workers <= 4);
6365
const files = args.filter((arg) => !arg.startsWith("--"));
6466
assert.equal(files.length, 1);
6567
assert.ok(files[0].endsWith("sample.spec.ts"));
@@ -69,8 +71,17 @@ function fixture() {
6971
);
7072
return {
7173
root,
72-
run(args: string[] = [], failSuite = "") {
73-
const env: NodeJS.ProcessEnv = { ...process.env, FAIL_SUITE: failSuite };
74+
run(
75+
args: string[] = [],
76+
failSuite = "",
77+
overrides: NodeJS.ProcessEnv = {},
78+
) {
79+
const env: NodeJS.ProcessEnv = {
80+
...process.env,
81+
FAIL_SUITE: failSuite,
82+
};
83+
delete env.OPENPI_TEST_WORKERS;
84+
Object.assign(env, overrides);
7485
// Start a fresh test runner rather than inheriting this test worker context.
7586
delete env.NODE_TEST_CONTEXT;
7687
return spawnSync(process.execPath, ["scripts/run-tests.mjs", ...args], {
@@ -210,3 +221,35 @@ test("invalid selection and empty discovery fail before running a partial suite"
210221
runner.dispose();
211222
}
212223
});
224+
225+
test("local worker override is validated before running tests", () => {
226+
const runner = fixture();
227+
try {
228+
const workers = String(Math.min(5, availableParallelism()));
229+
const valid = runner.run(["ui"], "", {
230+
OPENPI_TEST_WORKERS: workers,
231+
EXPECT_WORKERS: workers,
232+
});
233+
assert.equal(valid.status, 0, valid.stderr || valid.stdout);
234+
const node = runner.run(["node"], "", { OPENPI_TEST_WORKERS: "1" });
235+
assert.equal(node.status, 0, node.stderr || node.stdout);
236+
for (const value of [
237+
"0",
238+
"-1",
239+
"1.5",
240+
"2junk",
241+
"",
242+
"9007199254740992",
243+
String(availableParallelism() + 1),
244+
]) {
245+
const invalid = runner.run([], "", {
246+
OPENPI_TEST_WORKERS: value,
247+
});
248+
assert.notEqual(invalid.status, 0);
249+
assert.match(invalid.stderr, /OPENPI_TEST_WORKERS must be an integer/);
250+
assert.equal(invalid.stdout.includes("marker"), false);
251+
}
252+
} finally {
253+
runner.dispose();
254+
}
255+
});

0 commit comments

Comments
 (0)