Let debug_code hold back the terminated event - #122
Conversation
`terminated` means the debuggee has ended, and a client that hears it ends the debug session and disconnects. Sending it after every chunk of debugged code makes a session usable exactly once. TestItemControllers debugs a test item's `@testsnippet` setups and then its body as separate `debug_code` calls on one session, so the event sent after the setup tore the session down before the body ran, and breakpoints in the body were never hit — julia-testitems/TestItemRunner.jl#107. `debug_code(...; notify_termination=false)` suppresses the event for a chunk that is not the last one. The default is unchanged, so a single call behaves exactly as before. The test drives a real session over a loopback socket with a minimal DAP client that completes the handshake and records the events it is sent, which is what makes "once per session, not once per chunk" observable at all.
Julia 1.0 has no precompile cache locking, and on Windows a `.ji` that another process holds open cannot be replaced. This package had exactly one test item, so one test process started and nothing raced; adding the debug session tests makes several start together, all loading JuliaInterpreter, and whichever loses dies with "Cannot write cache file". Nothing in the package can fix that, so CI now runs the test items one at a time — they take seconds each, so it costs nothing. Requires julia-testitems/testitem-workflow#8, which forwards `max-workers` to `julia-run-testitems`; the action has always accepted it, the workflow just never passed one through. The README documented only the four-positional form of `debug_code`, and the README is what people actually read, so it now covers `notify_termination` too.
|
Two follow-ups pushed. The Windows + Julia 1.0.5 failure is not the new feature or the new test's logic — it is a precompile-cache race. The item that errored is the pre-existing Julia 1.0 has no precompile cache locking, and on Windows a CI now runs the test items one at a time. That needs julia-testitems/testitem-workflow#8, which forwards Also added Audit result, since you asked for one: the change is compatible with every consumer of DebugAdapter.jl.
Ordering for the vendored copies: julia-vscode consumes DebugAdapter as a git submodule and picks this up on the next bump with no source change. But TestItemControllers, JuliaSessionControllers and julia-vscode's nested TIC copy vendor it as a git subtree pinned to a release tag, currently v3.1.0, and Worth knowing separately: julia-vscode currently ships two different DebugAdapter versions side by side — 3.1.1-DEV via the submodule for REPL/notebook/launch debugging, and 3.1.0 via the TIC subtree for test-item debugging. |
A test item with `setup=[...]` debugs its snippets and then its own body, as separate `debug_code` calls on one debug session. `debug_code` sends a `terminated` event when the code it was given finishes, and a client takes that as "the debuggee has ended" and disconnects — so the session was already gone by the time the test item's body ran, and no breakpoint in the item was ever hit. Breakpoints inside the snippet worked, which is what made the symptom confusing. Snippets now pass `notify_termination=false`, so only the item's own body reports termination. Requires DebugAdapter 3.2, which adds the keyword argument (julia-vscode/DebugAdapter.jl#122), to be released and vendored first. Closes julia-testitems/TestItemRunner.jl#107
The Windows + Julia 1.0 failure was not this package's to fix. TestItemControllers nominates one test process to activate the environment and holds the others back until it reports, so that the test environment is precompiled exactly once — but on Julia 1.0 to 1.8 activation built nothing, because those TestEnv variants stop at `Pkg.activate` and only 1.9 and later finish with `Pkg._auto_precompile`. Every process therefore reached its first `using` at the same time, with no cache file locking in Base before 1.10 to protect them. julia-testitems/TestItemControllers.jl#66 closes that, so capping the workers here is unnecessary.
|
Correction: my earlier diagnosis was wrong, and the David pointed out that TestItemControllers does serialize precompilation for old Julia, and he was right. The controller nominates one test process to activate the environment and parks the rest in What I missed is that whether that window actually builds anything depends on the vendored TestEnv shim. The Fixed properly in julia-testitems/TestItemControllers.jl#66, which precompiles the test environment inside the window the gate already serializes. Verified on Julia 1.0 with a fixture whose only test item is So this PR needs no workflow change of its own — but it stays red until #66 ships through a TestItemControllers release and the |
Upstream half of julia-testitems/TestItemRunner.jl#107 — "Debugger does not stop at breakpoint of a testitem when using setup". TestItemControllers will use this once a release is out and the vendored copy is updated.
terminatedmeans the debuggee has ended, and a client that hears it ends the debug session and disconnects. The session loop sends it after every:debugcommand, which makes a session usable exactly once.TestItemControllers debugs a test item's
@testsnippetsetups and then its body as separatedebug_codecalls on one session. The event sent after the setup tore the session down before the body ran, so breakpoints inside the snippet worked and breakpoints in the test item itself were never hit — exactly what the issue reports.I confirmed the mechanism before writing the fix: two
debug_codecalls on one session produce twoterminatedevents.debug_code(...; notify_termination=false)suppresses the event for a chunk that is not the last one. The default is unchanged, so every existing caller behaves exactly as before.The test drives a real
DebugSessionover a loopback socket with a minimal DAP client that completes the handshake and records the events it is sent — that is what makes "once per session, not once per chunk" observable. It fails when the fix is removed.Version bumped to
3.2.0-DEVsince this adds a keyword argument.🤖 Generated with Claude Code