Cover per-language debugger launch flows in extension E2E - #19133
Cover per-language debugger launch flows in extension E2E#19133Adam Ratzman (adamint) wants to merge 58 commits into
Conversation
…18957) The issue asked for E2E coverage that proves the per-language debugger launch flows in the VS Code extension actually stop on a source breakpoint inside the running resource, not only that the extension advertises a debugger. This adds the harness for that end to end and lands one language (Node) so the extension has a real proof to run in CI while the rest of the matrix comes later. The Node shard registers a `builder.AddNodeApp("e2e-node", ...)` fixture in the shared AppHost, opens the AppHost under Aspire's own debug session, starts the resource with `aspire resource ... start`, sets a breakpoint by marker comment inside the fixture's `app.js`, and asserts the stopped stack frame is inside `app.js`. It also asserts the resource session is a distinct js-debug session from the AppHost session, and that stopping debugging tears down the debuggee and the child process it spawns, not only the process js-debug launched. All three assertions run through a single control-channel command (`proveResourceDebugging`) so the proof runs in the extension host rather than being reconstructed from adapter events across the RPC boundary. The Node resource fixture is only wired for the `resource-debugger` shard: both the `Aspire.Hosting.JavaScript` PackageReference in the shared AppHost `.csproj` and the `AddNodeApp` registration are gated by `includeNodeResourceFixture = shardName === 'resource-debugger'`, and the `ASPIRE_EXTENSION_E2E_NODE_APP_SCRIPT` env var is only set on that shard. Every other shard still asserts on the same resource tree it does today. The runner now also calls `assertShardExecutedTests` after ExTester exits, so a shard that runs to completion without executing any test - or that silently skips its only proof - fails instead of reporting an empty success. Not covered by this PR, on purpose: Python, Go, Rust, MAUI, and Azure Functions. Those debuggers ship in marketplace extensions (`ms-python.debugpy`, `golang.go`, `vadimcn.vscode-lldb`, `ms-dotnettools.dotnet-maui`, `ms-azuretools.vscode-azurefunctions`), and the E2E runner does not install marketplace extensions into the E2E VS Code instance. Adding them needs an extension-install step in `run-e2e.js` plus each language's language-specific fixture (a Python venv, a Go module, and so on) - a bigger change that should not gate the Node proof. The harness (`proveResourceDebugging` command, `assertShardExecutedTests`, per-shard fixture gating, `getNodeAppBreakpointLine` marker approach, process-tree teardown assertions) is written to be reused for those languages; each subsequent language is expected to be a new shard plus a fixture, not a new extension of the proof itself. Along the way I removed the `proveMauiResourceDebugging` alias. The comment claimed it was "kept so an out-of-repo caller keeps working", but `AspireExtensionE2EControlCommand` is an internal test-only bridge with no such caller. Keeping two proof names for the same code path made the tests read like there is still MAUI-specific behavior when there isn't. I also fixed a couple of small real bugs while I was in the code: - `browser.ts` was building `pwa-<browser>` from whatever string the AppHost handed over. `firefox` would flow through and fail deep inside VS Code with an opaque "Configured debug type is not supported" once the session was already starting. The extension now allowlists `msedge` and `chrome` (the two browsers js-debug actually contributes) and fails at configuration time with a localized message that names the browser and the supported set. - `browser.ts` also forwarded `web_root` unconditionally. The hosting side defaults it to an empty string when the resource has no web root, and js-debug treats an empty `webRoot` as a real path when resolving source maps. It is now only forwarded when the AppHost supplied one. - `AspireDebugSession.stopDebugging()` used to stop the AppHost session before the resource sessions. A resource that was suspended on a breakpoint would keep the AppHost shutdown blocked until its debugger cascaded a stop, which sometimes outran the extension's internal wait. Resource sessions are now stopped first, then the AppHost session, then the synthetic Aspire parent. The existing unit test was updated to assert the new order. Compile, lint, `compile-e2e`, and the full unit suite (`corepack yarn unit-test`) all pass. Full E2E (`test:e2e`) is not runnable in this environment because it downloads VS Code and takes far too long under current load; the E2E specs compile. Refs microsoft#18957 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: ab3b19ec-aa39-4336-bdfb-db7c5b699341
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 19133Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 19133" |
There was a problem hiding this comment.
Pull request overview
Adds real VS Code extension E2E coverage for Node resource debugging and strengthens debugger lifecycle handling.
Changes:
- Adds breakpoint, session-isolation, and process-tree teardown E2E proofs.
- Adds shard validation and Node-only fixture provisioning.
- Improves browser validation, diagnostics, localization structure, and debug-session shutdown ordering.
Show a summary per file
| File | Description |
|---|---|
.github/workflows/extension-e2e-tests.yml |
Runs the debugger shard on Linux and Windows. |
.gitignore |
Ignores E2E logs. |
extension/CONTRIBUTING.md |
Documents the new shard. |
extension/scripts/e2e-shard-results.js |
Rejects empty or skipped proof runs. |
extension/scripts/run-e2e.js |
Creates and runs the Node fixture. |
extension/src/debugger/AspireDebugSession.ts |
Stops resource sessions before AppHost. |
extension/src/debugger/languages/azureFunctions.ts |
Extracts session display labels. |
extension/src/debugger/languages/browser.ts |
Validates browser adapters and web roots. |
extension/src/loc/strings.ts |
Adds debugger-related strings. |
extension/src/test-e2e/helpers/fixtures.ts |
Adds breakpoint and process helpers. |
extension/src/test-e2e/helpers/paths.ts |
Resolves the Node fixture path. |
extension/src/test-e2e/resourceDebugger.e2e.test.ts |
Proves Node debugging end to end. |
extension/src/test/aspireDebugSession.test.ts |
Verifies debugger shutdown ordering. |
extension/src/test/azureFunctionsDebugger.test.ts |
Covers Azure Functions adapter behavior. |
extension/src/test/browserDebugger.test.ts |
Covers browser adapter validation. |
extension/src/test/e2eLaunchProfile.test.ts |
Updates fixture source assertions. |
extension/src/test/e2eShardMatrix.test.ts |
Verifies CI shard coverage. |
extension/src/test/e2eShardResults.test.ts |
Tests shard-result validation. |
extension/src/test/javascriptRuntime.test.ts |
Expands JavaScript runtime coverage. |
extension/src/test/processDiagnostics.test.ts |
Tests process parsing and formatting. |
extension/src/test/resourceDebugProof.test.ts |
Tests proof-request normalization. |
extension/src/testing/e2eStateFileBridge.ts |
Implements the language-neutral proof. |
extension/src/testing/processDiagnostics.ts |
Adds process diagnostic helpers. |
extension/src/types/extensionApi.ts |
Defines the generalized proof command. |
Review details
Suppressed comments (2)
extension/src/testing/e2eStateFileBridge.ts:900
- This “head” is global across every tracked debug session. The AppHost sessions start first, so their first 20 output events can fill the array before the resource prints its PID lines;
readReportedPidcan then lose those lines once they also fall out of the tail ring buffer. Keep the first events per session (or specifically for the resource session) instead.
// The first lines a debuggee writes identify it (for example the pid it reports), so the
// head is kept separately from the ring buffer that holds the most recent lines.
if (outputHeadEvents.length < 20) {
outputHeadEvents.push(outputEvent);
extension/src/testing/e2eStateFileBridge.ts:1106
- This wait uses a global, capped ring buffer as its completion signal. Output from the AppHost can satisfy it without the resource producing anything, while once the buffer reaches 200 entries its length never increases and the wait always times out. Track a monotonic output count scoped to
session.idinstead.
const outputEventsBefore = outputEvents.length;
await session.customRequest('continue', { threadId });
await waitForE2eValue(
'the resumed resource process to produce output',
timeoutMs,
() => outputEvents.length > outputEventsBefore ? true : undefined);
- Files reviewed: 23/24 changed files
- Comments generated: 4
- Review effort level: Balanced
Four review comments, all of them right.
Correlate the breakpoint-removal acknowledgement (e2eStateFileBridge.ts).
`resumeDebuggeeAfterBreakpoint` accepted the next `setBreakpoints` response
from any tracked adapter. A proof has the synthetic Aspire parent, the AppHost
session, and the resource session alive at once, all tracked by the `'*'`
tracker, so another session's response could let the continue through before
the resource's adapter had dropped the breakpoint - and the debuggee would
re-suspend on the next iteration. Requests now carry their `seq` and responses
their `request_seq`, the removal request is matched by session id and source
path, and the acknowledgement must be the successful response to that exact
request. VS Code assigns `seq` in `AbstractDebugAdapter.internalSend` before
`$sendDAMessage` invokes `onWillReceiveMessage`, so the sequence number is
always present on the captured request. `findBreakpointRemovalRequest` and
`isBreakpointRemovalAcknowledged` are exported and unit tested.
Two bugs in the same function came along with it. The post-continue liveness
check compared `outputEvents.length` against a snapshot, but that array is a
ring buffer capped at 200, so once it filled, its length stopped growing and
the wait could never be satisfied; a monotonic counter replaces it. And a
re-suspend on the resumed session is now reported by name instead of surfacing
as a 60s output timeout.
Fix the `process` event comments (e2eStateFileBridge.ts,
resourceDebugger.e2e.test.ts). The bridge claimed js-debug emits the DAP
`process` event once the debuggee launches; the E2E spec claimed the opposite
and parsed pids out of stdout. The spec was right. js-debug only calls
`dap().process(...)` from `src/vsDebugServer.ts` and
`src/flatSessionLauncher.ts` - its standalone DAP server entry points, where it
repurposes the event to rename the session - and it never populates
`systemProcessId` anywhere. Inside VS Code it sends no `process` event at all.
The comments now say that, explain that the event is still captured because
`coreclr` and `debugpy` do send it, and note that with `outputCapture: 'std'`
js-debug pipes the debuggee's stdio from the launching parent session while the
stop is reported by the child session - which is why the output-based signals
are not filtered by the stopped session's id.
Localize the Azure Functions debug-session names (strings.ts). They are
user-visible session names but were plain template strings, so they were never
extracted. They use `vscode.l10n.t` now, like the adjacent browser labels.
Registered in `package.nls.json` with `unsupportedBrowserDebugTarget`, which the
previous commit added to `strings.ts` without registering, and the base XLF is
regenerated with `yarn localize`.
Close the browser allowlist bypass (browser.ts). `browserDebugTypesByName` was
an object literal, so `WithBrowserDebugger("toString")` - the hosting API takes
an arbitrary string - resolved through `Object.prototype` and assigned a
function to `debugConfiguration.type`. It is a `Map` now, which has no inherited
keys, with unit tests for `toString`, `constructor`, `__proto__`,
`hasOwnProperty` and `valueOf`.
`compile-tests`, `compile-e2e`, `lint` and the unit suite (1490 passing) are
clean. `AppHost discovery > workspace project fallback checks projects beyond
bounded file-search batch` times out intermittently on this machine; it does so
on the unmodified branch too, and it is unrelated to these files.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Review details
Suppressed comments (3)
extension/src/debugger/AspireDebugSession.ts:138
Promise.allrejects as soon as one resource stop fails, so another resource stop can still be in flight when the AppHost is stopped. That reintroduces the shutdown ordering problem this change is intended to fix for multi-resource sessions. Wait for every stop attempt to settle, retain the first failure, and only then stop the AppHost/parent.
await Promise.all(resourceDebugSessions.map(session => session.stopSession()));
extension/src/test-e2e/resourceDebugger.e2e.test.ts:168
- The fallback to all sessions is chosen only when the stopped session emitted no output at all. If that child session emits any js-debug diagnostic while the PID markers remain on the launching parent session (the split documented above), its nonempty output hides the valid parent markers and this test fails. Search the stopped-session output for the marker first, then fall back to all captured output only when that search has no match.
const stoppedSessionEvents = events.filter(event => event.sessionId === proof.resourceDebugSession?.id);
const output = (stoppedSessionEvents.length > 0 ? stoppedSessionEvents : events).map(event => event.output).join('');
const matches = [...output.matchAll(new RegExp(`${marker}=(\\d+)`, 'g'))];
extension/src/test-e2e/resourceDebugger.e2e.test.ts:141
- The control-channel deadline is 360 seconds, but the handler deliberately gives startup, resource start, and breakpoint phases independent budgets of 180 + 180 + 240 seconds (plus up to 60 seconds to resume). A successful slow startup can therefore exhaust this outer deadline long before the breakpoint phase's advertised budget, leaving the proof running after the test reports a timeout. Make the outer command and Mocha test timeouts cover the sum of the independent phase caps, or use one shared deadline consistently.
}, { timeoutMs: proofTimeoutMs + 60000 });
- Files reviewed: 25/26 changed files
- Comments generated: 0 new
- Review effort level: Balanced
The branch conflicted with main, so GitHub could not build refs/pull/19133/merge and no `pull_request` workflow had ever been scheduled for the PR - `ci.yml` had zero runs on this branch while sibling PRs were running normally. Merging is what unblocks CI. microsoft#19001 landed the Azure Functions HTTPS launch path, which touches the same four places this branch does. - `.github/workflows/extension-e2e-tests.yml` and `extension/CONTRIBUTING.md`: both shards kept. The resource-debugger prose no longer lists Azure Functions among the languages whose debugger is not installed into the E2E VS Code instance, because that shard now installs it. - `extension/scripts/run-e2e.js`: the AppHost fixture emits both opt-in resources. `writeAzureFunctionsProject` runs before `writeAppHostProject` as on main, `writeNodeAppFixture` after it, and the csproj template carries both the `Aspire.Hosting.JavaScript` and `Aspire.Hosting.Azure.Functions` references. - `extension/src/debugger/languages/azureFunctions.ts`: union of both import sets. `AzureFunctionsLaunchConfiguration` is dropped from the value import because the merged body only narrows through `isAzureFunctionsLaunchConfiguration`. - `extension/src/test/azureFunctionsDebugger.test.ts`: an add/add conflict. Took main's suite, which is the far larger one, and re-added this branch's metadata coverage - adapter identity, session naming from the project file, project resolution, and the two rejection paths - as a second suite, since main covers none of it and the naming tests are what pin the localized `azureFunctionsDisplayName` / `azureFunctionsLabel` strings. The missing-extension test needed a real change rather than a straight port: main now builds the project before it resolves the extension, so the unported test failed on `spawn dotnet ENOENT` instead of reaching the lookup. It stubs `DotNetService` the way the neighbouring tests do. - `extension/loc/xlf/aspire-vscode.xlf`: regenerated with `yarn localize` from the merged `package.nls.json` instead of hand-merging generated XML. `compile-tests`, `compile-e2e`, `lint` and the unit suite (1511 passing, 0 failing) are clean on the merge result. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Review details
Suppressed comments (3)
extension/src/debugger/AspireDebugSession.ts:152
Promise.allrejects as soon as one resource stop fails, so this method can begin stopping the AppHost while other resource-stop promises are still pending. That breaks the ordering this change is intended to guarantee and can leave the AppHost shutdown blocked on one of those resources. Await all resource stops withallSettled, then propagate the first failure after the AppHost and parent have been stopped.
let resourceStopError: unknown;
try {
const resourceDebugSessions = this._resourceDebugSessions.filter(session => session.id !== this._appHostDebugSession?.id);
await Promise.all(resourceDebugSessions.map(session => session.stopSession()));
extension/src/test-e2e/resourceDebugger.e2e.test.ts:141
- The control-channel wait is only 360 seconds, but the handler can legitimately consume 180 seconds for AppHost startup + 180 seconds for resource start + 240 seconds for the breakpoint, plus another 60 seconds when resuming for the teardown proof. Under load this caller abandons a still-valid proof after six minutes, and the 600-second Mocha timeout is also shorter than the 660-second handler budget. Align the outer and suite timeouts with the sum of the independent phase budgets, or change the handler to use one shared deadline.
timeoutMs: proofTimeoutMs,
expectedResourceDebugSessionType: 'pwa-node',
stopDebuggingOnCompletion: options.stopDebuggingOnCompletion,
}, { timeoutMs: proofTimeoutMs + 60000 });
extension/src/test-e2e/resourceDebugger.e2e.test.ts:168
- The fallback is selected based on whether the stopped child session emitted any output, not whether it emitted this PID marker. js-debug sends the fixture's captured stdout from the launching parent session, while the stopped child can still emit its own diagnostics; one such diagnostic makes this code discard the parent events and falsely report the PID as missing. Only prefer the stopped-session stream when that stream actually contains a marker match.
const events = [...proof.outputHead, ...proof.outputSample];
const stoppedSessionEvents = events.filter(event => event.sessionId === proof.resourceDebugSession?.id);
const output = (stoppedSessionEvents.length > 0 ? stoppedSessionEvents : events).map(event => event.output).join('');
const matches = [...output.matchAll(new RegExp(`${marker}=(\\d+)`, 'g'))];
- Files reviewed: 25/26 changed files
- Comments generated: 0 new
- Review effort level: Balanced
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Reverts the `false &&` guard added in microsoft#18547 and restores the two run_extension_e2e skip-checks in the aggregate gate. The job has been dark since 2026-06-29. microsoft#18547 disabled it because the Windows debug-dashboard shard was consistently failing, but it linked microsoft#18412 as the tracker -- and that issue had already been closed as completed on 2026-06-26 by the *previous* re-enable (microsoft#18464). So there is currently no open issue tracking the disable, and nothing surfaces that the shards do not run. This change is a probe: CI on this PR exercises the shards against current main so we can see empirically whether debug-dashboard still fails, rather than inferring it from a six-week-old report. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 487b899d-d79d-4349-a84b-a026861bde7f
Four fixes to the VS Code resource debugger, extracted from microsoft#19133 so they are not gated on an E2E harness. `WithBrowserDebugger(browser)` takes an arbitrary string and `browser.ts` forwarded it as `pwa-<value>`. js-debug only contributes `pwa-chrome` and `pwa-msedge`, so anything else failed inside VS Code with "Configured debug type is not supported" after the session had already started - no resource name, no indication of which browsers do work. Unknown values now fail up front with the supported list. The allowlist is a `Map` rather than an object literal because the key is caller-supplied: a literal inherits `Object.prototype`, so a resource named `toString` or `__proto__` would resolve to an inherited member and assign a function to `debugConfiguration.type`. The hosting side sends `web_root: ""` when a browser resource has no web root, and js-debug treats an empty `webRoot` as a real path when it resolves source maps. Only forward a value the AppHost actually configured. `stopDebugging()` stopped the AppHost first and left resource debug sessions to `dispose()`. A resource running under a debugger can hold the AppHost shutdown open until its own session exits, so the AppHost stop waited on a process whose debugger had not been told to stop yet. Resource sessions now stop first, and a failure there is rethrown only after the AppHost and the synthetic Aspire parent have been stopped, so one bad adapter cannot strand the rest. The Azure Functions debug-session names were plain template strings, so they were never extracted for localization despite being user-visible session names. They use `vscode.l10n.t` now, like the adjacent browser labels. Adds `browserDebugger.test.ts`, extends the `stopDebugging` ordering test, and adds a metadata suite to `azureFunctionsDebugger.test.ts` that pins the localized names. 1473 unit tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…mint/issue-18957-resource-debug-e2e
The product fixes and the generic shard/matrix coverage check that were
developed alongside this proof do not depend on the E2E harness, and the
`extension_e2e_tests` job is currently disabled on main, so shipping them here
would block user-visible fixes behind a job that cannot run. They now ship
separately:
- browser debug targets, empty `webRoot`, and `stopDebugging()` resource
ordering, with their unit tests
- the spec-to-matrix set difference check, which is a unit test and therefore
runs on every PR regardless of the E2E guard
What remains here is the resource debugger spec, the E2E control channel and
fixtures it needs, and the two matrix rows that run it.
`e2eShardMatrix.test.ts` keeps only the assertion that this shard is scheduled
on both platforms. The `assert.ok(runner.includes('<source line>'))` assertions
that were in it are dropped: they matched literal source text of `run-e2e.js`
without exercising it, so they broke on any refactor while proving nothing.
`assertShardExecutedTests` is behaviourally covered by `e2eShardResults.test.ts`.
This branch merges the E2E re-enable change so the shard is stacked on top of
it. `microsoft/aspire` has no branch to point the PR base at, so the dependency
is expressed by the merge rather than by the PR base.
Note that the process tree teardown test depends on the `stopDebugging()`
ordering fix that now ships in the product fixes PR.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Review details
Suppressed comments (4)
extension/src/test-e2e/resourceDebugger.e2e.test.ts:168
- The fallback is selected based on whether the stopped session emitted any output, not whether that output contains the PID marker. js-debug normally sends the fixture's stdout on its launching parent session, so one unrelated output event from the stopped child makes this search ignore the parent PID and fail. Search the stopped-session stream first, then fall back to all events only when that stream contains no marker.
const stoppedSessionEvents = events.filter(event => event.sessionId === proof.resourceDebugSession?.id);
const output = (stoppedSessionEvents.length > 0 ? stoppedSessionEvents : events).map(event => event.output).join('');
extension/src/test-e2e/resourceDebugger.e2e.test.ts:141
- The command can legitimately spend up to 180s starting the AppHost, 180s starting the resource, and 240s waiting for the breakpoint (600s total), but this caller gives the control bridge only 360s. A slow proof can therefore time out in the test while it is still running in the serialized extension-host control channel, leaving teardown commands queued behind it. Either use one shared deadline in the handler or raise both this timeout and the Mocha timeout to cover the sum of the phase budgets plus teardown.
}, { timeoutMs: proofTimeoutMs + 60000 });
extension/src/test-e2e/helpers/fixtures.ts:694
- If the diagnostic
ps/PowerShell command fails, times out, or returns invalid JSON,getProcessSnapshotthrows here and replaces the primary process-exit timeout with an inspection error. Process inspection is best-effort diagnostics, so preserve the timeout and append the inspection failure instead of masking it.
throw new Error(`Timed out after ${timeoutMs}ms waiting for ${description} (pid ${pid}) to exit. Last observed process: ${formatProcessSnapshot(getProcessSnapshot(pid), pid)}.`);
extension/src/test-e2e/resourceDebugger.e2e.test.ts:95
- The PR description and testing section still claim browser allowlisting/webRoot fixes, resource-before-AppHost stop ordering, and Browser/Azure Functions/AspireDebugSession test additions, but the current 18-file diff contains none of those files. The current
browser.tsstill buildspwa-${browser}and always assignswebRoot, whileAspireDebugSession.stopDebugging()still stops the AppHost first. Please either restore those changes and tests or update the PR description/testing claims to match this revision.
await executeE2eControlCommand({ name: 'stopDebugging' }, { waitFor: 'started' });
- Files reviewed: 17/18 changed files
- Comments generated: 0 new
- Review effort level: Balanced
…xes' into adamint/issue-18957-resource-debug-e2e
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3253974d-4f18-486f-863c-281a607656d4
There was a problem hiding this comment.
Review details
Suppressed comments (2)
extension/src/test-e2e/resourceDebugger.e2e.test.ts:160
- This committed comment narrates branch/PR dependency history (
this PR declares as a prerequisite) rather than the current behavior. Keep the resource-before-AppHost shutdown rationale, but remove the PR-history wording so the comment remains accurate after merge.
// The teardown this asserts on depends on the resource stop ordering fixed in
// https://github.com/microsoft/aspire/pull/19145, which this PR declares as a prerequisite:
// stopping while a resource is suspended on a breakpoint has to stop the resource session
// before the AppHost or the debuggee and its children are left running.
extension/src/testing/e2eStateFileBridge.ts:804
stopDebuggingOnCompletion !== falsesilently treats every malformed JSON value (for example, the string"false") astrue. This command comes from an untyped control file, and the normalizer validates the other request fields at runtime; reject a defined non-boolean before applying the default so a malformed teardown proof cannot stop the debuggee and invalidate the process-tree assertion.
stopDebuggingOnCompletion: command.stopDebuggingOnCompletion !== false,
- Files reviewed: 18/18 changed files
- Comments generated: 0 new
- Review effort level: Balanced
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Resolve the E2E runner, fixture, workflow, and launch-profile test conflicts while preserving the resource debugger proof and adopting the current advisory runner flow. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Review details
Suppressed comments (1)
extension/src/test-e2e/resourceDebugger.e2e.test.ts:77
- The teardown uses the same deadline as the test body. If any phase consumes the remaining budget,
getRemainingE2eDeadlineMsrejects immediately for every cleanup, so the 30-second Mocha slack runs the hook but never startsstopDebugging, breakpoint cleanup, or AppHost cleanup. Reserve a separate bounded cleanup deadline (and include it in the Mocha timeout), rather than reusing an already-expired operation deadline.
() => runResourceDebuggerPhase(
'resource debugger teardown stop control',
resourceDebuggerDeadline,
resourceDebuggerPhaseTimeoutMs.stopDebuggingControl,
timeoutMs => executeE2eControlCommand({ name: 'stopDebugging' }, { timeoutMs })),
- Files reviewed: 17/17 changed files
- Comments generated: 0 new
- Review effort level: Balanced
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Review details
Suppressed comments (2)
extension/src/test-e2e/resourceDebugger.e2e.test.ts:77
- If a test consumes the shared 900-second deadline, every teardown callback reaches
getRemainingE2eDeadlineMswith an expired deadline and throws before invokingstopDebugging, breakpoint cleanup, or AppHost cleanup. The advertised 30-second Mocha teardown slack therefore cannot perform cleanup, leaving live sessions/processes to contaminate subsequent tests. Reserve a bounded cleanup budget within the overall timeout or use a separate bounded teardown deadline.
() => runResourceDebuggerPhase(
'resource debugger teardown stop control',
resourceDebuggerDeadline,
resourceDebuggerPhaseTimeoutMs.stopDebuggingControl,
timeoutMs => executeE2eControlCommand({ name: 'stopDebugging' }, { timeoutMs })),
extension/src/testing/resourceDebugOutput.ts:33
- The fallback combines output from every debug session into one byte stream. DAP events from the Aspire parent, AppHost, and js-debug sessions can interleave, so a PID marker split across two events can either be broken by another session's output or completed with digits from the wrong session. Reassemble output independently per
sessionIdbefore matching the marker.
function findPidMatches(events: readonly DebugAdapterOutputEvent[], marker: string): RegExpMatchArray[] {
const output = events.map(event => event.output).join('');
return [...output.matchAll(new RegExp(`${marker}=(\\d+)`, 'g'))];
- Files reviewed: 17/17 changed files
- Comments generated: 0 new
- Review effort level: Balanced
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| await runE2eTeardown([ | ||
| () => runResourceDebuggerPhase( | ||
| 'resource debugger teardown stop control', | ||
| resourceDebuggerDeadline, |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Review details
Suppressed comments (2)
extension/CONTRIBUTING.md:125
- This documented command still uses the runner’s 40-minute default, while the new shard is explicitly budgeted for up to 54 minutes and CI raises its process timeout to 60 minutes. A slow/failing local run will therefore be killed before the shard’s bounded proof and teardown complete. Include the same 3600000 ms override in the command.
ASPIRE_EXTENSION_E2E_SHARD=resource-debugger ASPIRE_EXTENSION_E2E_SPEC=out/test-e2e/test-e2e/resourceDebugger.e2e.test.js ASPIRE_EXTENSION_E2E_CLI_PATH=/path/to/aspire corepack yarn test:e2e
.github/workflows/extension-e2e-tests.yml:275
- The new 60-minute ExTester timeout is nested inside the existing 75-minute job timeout, which starts before checkout, dependency setup, CLI extraction, compilation, restore, VSIX installation, and VS Code setup. Consequently these rows do not actually reserve the stated 15 minutes for post-timeout cleanup and diagnostics; if setup consumes 15 minutes, GitHub cancels the job before
runWithProcessTreeTimeoutcan fire and the upload steps run. Increase the job-level timeout (preferably via a per-row override) to cover setup + 60 minutes + diagnostics.
runTestsTimeoutMs: 3600000
- Files reviewed: 16/17 changed files
- Comments generated: 0 new
- Review effort level: Balanced
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Description
Adds an end-to-end proof that Aspire launches a Node resource under its real language debugger, stops on a source breakpoint, and tears down the complete debuggee process tree.
resource-debuggerE2E shards using VS Code's built-in js-debug adapter.Thenablecannot outlive the test.Other language adapters remain separate follow-up work because the E2E VS Code instance does not install Marketplace extensions.
Refs #18957
Dependencies
This PR stays draft until both dependencies land. The branch can then be rebased and the hosted resource-debugger shards can run against the final combined workflow.
Validation
Checklist