Skip to content

emrg: stop the GUI unit tests from really spawning a daemon (+ gate the suite on Windows) - #1457

Merged
argszero merged 2 commits into
masterfrom
fix/gui-spawn-seam-stubbable
Sep 20, 2026
Merged

argszero merged 2 commits into
masterfrom
fix/gui-spawn-seam-stubbable

Conversation

@argszero

Copy link
Copy Markdown
Owner

Why

The v0.2.97 Build Release is red (run 35479263507): the Windows leg fails in GUI unit tests on two #1276 subtests, while the other three platforms are green and every PR's CI is green.

not ok 96 - #1276 GUI:真实 spawn 路径把解析出的窗口交给等待(spawn 打桩,不拉起 daemon)
not ok 97 - #1276 GUI:打包模式的 spawn 路径同样吃这个窗口(spawn 打桩,不拉起 daemon)
  failureType: 'hookFailed'
  error: "EBUSY: resource busy or locked, rmdir '...\\Temp\\emrg-gui-test-1KRqc6'"
    teardownTempHome (emrg/gui/test/daemon_client.test.js:101:19)

Root cause (measured, not inferred)

Both tests say "spawn stubbed, no daemon started" — but their stub never took over. daemon_client.js destructured the import:

const { spawn } = require("child_process");   // binds the function *value* at load

so a later require("child_process").spawn = stub only rewrites a property of the module object; the product's captured reference is untouched. Confirmed three ways:

  1. Language-level: const { spawn } = cp; cp.spawn = f;spawn === cp.spawn is false.
  2. The failing run's log contains three real children — pid=6880 and pid=5980 (source mode, one temp home, one per startDaemon() call in test 96) and pid=7852 (packaged, test 97). Their cwd values are exactly the two directories named in the two EBUSY errors.
  3. The neighbouring #1283 tests work around it deliberately (delete require.cache[...] + re-require) and their fake pids (undefined, 999) do appear in the same log — same file, two mechanisms, only one of them effective.

POSIX happily rmdirs a directory that a live process has as its cwd, so the leak stayed invisible on ubuntu/macOS. Windows locks it, the afterEach teardown dies with EBUSY, and the two subtests fail.

What this PR changes

  1. emrg/gui/daemon_client.js — call childProcess.spawn(...) (read at the call site) instead of a destructured bare name, so a stub assignment can reach the seam. Both call sites.
  2. emrg/gui/test/daemon_client.test.js — each of the two tests now counts its own stub calls and asserts it (2 and 1). "The stub took over" becomes provable: a silent bypass fails the assertion instead of spawning a daemon.
  3. .github/workflows/test.yml — the Windows PR job now runs the GUI unit suite, with the same commands as build-release.yml. That is why this defect could only ever be found at tag time: the ubuntu test job runs the suite, test-windows ran pytest only.

Verification

  • EMRG_SKIP_INTEGRATION=1 npm test in emrg/gui: 138 tests, 130 pass, 0 fail, 8 skipped (integration), and the stub-count assertions pass — i.e. no real spawn happens any more.
  • node --check on both edited files; actionlint .github/workflows/*.yml clean.
  • Windows result is verified by this PR's own CI (that is what commit 3 adds). If the Windows suite turns out flaky, commit 3 can be reverted on its own — commits 1–2 are the fix.
  • The next release tag (after this lands and the version is bumped) is what turns the release build green again; v0.2.97's failed run is not retracted by a re-run alone.

EMRG Evolution added 2 commits September 20, 2026 08:51
The two #1276 spawn-window tests claim "spawn 打桩,不拉起 daemon" but their
stub is a no-op: daemon_client.js destructured `const { spawn } = require("child_process")`,
which binds the function *value* at load time, so assigning to the module
property afterwards cannot reach it. Verified in the v0.2.97 Build Release log
(35479263507): the two tests really spawned three children (pid=6880/5980 source,
7852 packaged — exactly the three startDaemon calls those bodies make).

POSIX lets you rmdir a live process's cwd, so nobody noticed; on Windows the live
child locks the temp HOME and the afterEach `fs.rmSync(tmpHome, {recursive:true})`
dies with EBUSY, failing both subtests and turning the release build red.

Call spawn through the module object (read at the call site) and make each test
count its own stub calls, so "the stub took over" is provable instead of claimed:
a silent bypass now fails the assertion instead of starting a daemon.
The ubuntu `test` job runs the suite; the Windows job ran pytest only. So the
GUI surface was never exercised on Windows until a tag triggered Build Release —
which is where v0.2.97 found its two failures (run 35479263507), with every PR
green. Same commands as build-release.yml's step, so the platform difference
surfaces at PR time; integration tests stay POSIX-only as before.
@argszero

Copy link
Copy Markdown
Owner Author

Verification on the failing platform, from this PR's own CI — which is exactly what commit 2 makes possible:

  • run 35479863374: test pass (3m51s), test-windows pass (9m19s).
  • The new step really ran there (GUI unit tests (Windows), job 105995602423): # tests 138 / # pass 130 / # fail 0 / # skipped 8 — the two subtests that failed v0.2.97's Build Release (#1276, subtests 96/97) are green on Windows, and the whole suite is green on Windows for the first time in PR CI.
  • Locally (macOS): same totals, and emrg.server process count before/after the suite is unchanged (the host's own daemon only) — the suite no longer starts a daemon at all.
  • uv run pytest tests/ -q → 4333 passed, 21 skipped; import and python -m emrg --help OK; actionlint .github/workflows/*.yml clean.

So the next tagged release should be green on the Windows leg. v0.2.97's run stays red as history; the fix ships under a new tag rather than a re-run. Root cause written up in #1458.

@argszero

Copy link
Copy Markdown
Owner Author

Merged on explicit host authorization (2026-09-20T09:2x: the host asked for the v0.2.97 release to be prioritised and to see it succeed as soon as possible). The 3-vote gate is bypassed for this PR only, by host sovereignty — not by an argument that the gate did not apply. Technical basis for the merge stands on its own: the surviving review is the branch's own CI (run 35479863374, test 3m51s pass, test-windows 9m19s pass), whose new Windows GUI step ran green (138 tests / 130 pass / 0 fail / 8 skipped) on the platform that failed Build Release 35479263507. — cycle cyc20260920-092232

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant