-
Notifications
You must be signed in to change notification settings - Fork 568
Remove mocha exit flag #26664
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
alexvy86
wants to merge
35
commits into
microsoft:main
Choose a base branch
from
alexvy86:ralph-removes-mocha-exit
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Remove mocha exit flag #26664
Changes from 12 commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
5923ea3
fix(container-loader): dispose SerializedStateManager instances in te…
alexvy86 3731e73
fix(container-runtime): dispose ContainerRuntime instances in tests t…
alexvy86 00020af
fix(tree): remove --exit flag by properly disposing TestTreeProvider …
alexvy86 5257835
fix(local-server-tests): properly dispose LocalDeltaConnectionServer …
alexvy86 6661ee7
fix(fluid-telemetry,react): remove --exit flag by cleaning up Applica…
alexvy86 da562c9
fix(inventory-app): remove --exit flag by setting up JSDOM before Qui…
alexvy86 fadbe1e
fix(experimental): remove --exit flag from dds/tree and property-dds …
alexvy86 3dd5255
fix(dds): remove --exit flag from memory/benchmark test mocharcs
alexvy86 7b4ab5d
fix(test-end-to-end-tests): remove --exit flag by fixing LocalServerT…
alexvy86 fa80b89
fix: remove --exit flag from webflow, odsp-client, and snapshots pack…
alexvy86 63ff049
fix(experimental,e2e-tests): remove --exit flag from PropertyDDS and …
alexvy86 02b75e2
Merge remote-tracking branch 'upstream/main' into ralph-removes-mocha…
alexvy86 d906f29
Remove file
alexvy86 a6d6b67
Update investigation file
alexvy86 7d844b0
Formatting
alexvy86 387e188
fix(dds/tree,fluid-telemetry): fix lint errors in dispose and stopPol…
alexvy86 3d11ab7
fix(local-server-tests): fix timer leaks so tests exit without --exit…
alexvy86 a687f40
fix(property-dds): dispose containers in afterEach to prevent timer l…
alexvy86 8f4a2bd
fix(local-server-stress-tests): remove --exit flag as cleanup is alre…
alexvy86 b150f37
docs: update investigation notes with container disposal pattern
alexvy86 3eece80
fix(fluid-telemetry): clear heartbeat interval on container dispose t…
alexvy86 7d916d0
fix(react,fluid-static): fix timer leaks so tests exit without --exit…
alexvy86 2d8515b
docs: update investigation notes with react/fluid-static timer leak f…
alexvy86 fd01a03
More fixes
alexvy86 57bec76
fix(dds/tree,container-runtime): fix timer leaks from summarizer cont…
alexvy86 dcc90fc
fix(test/snapshots): fix timer leaks so tests exit without --exit flag
alexvy86 804a1cb
docs: update investigation notes for packages/test/snapshots (root ca…
alexvy86 498b329
Formatting
alexvy86 02bf0f0
Fix missing async
alexvy86 c79462d
fix(test-end-to-end-tests,container-loader,container-runtime): fix re…
alexvy86 bdb7f9e
Formatting
alexvy86 7f3979d
fix(mocha-test-setup,test-end-to-end-tests): fix timer/socket leaks s…
alexvy86 edd661f
docs: update investigation notes with root causes 16 (setTimeout patc…
alexvy86 83c1324
Fix build
alexvy86 e3c13ae
Fix build
alexvy86 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| # Investigation: Why mocha tests need --exit flag | ||
|
|
||
| ## Summary of Root Causes Found | ||
|
|
||
| ### Root Cause 1: SnapshotRefresher 24-hour timer (CONFIRMED via --detect-open-handles) | ||
| **Affected packages:** packages/loader/container-loader (and likely others) | ||
|
|
||
| `SnapshotRefresher` creates a 24-hour (86400000ms) `setTimeout` via the `Timer` class's | ||
| `setLongTimeout`. Tests create `SerializedStateManager` instances (which own a `SnapshotRefresher`) | ||
| without calling `.dispose()` after the test completes. The timer keeps the process alive. | ||
|
|
||
| **Location:** `packages/loader/container-loader/src/test/serializedStateManager.spec.ts` | ||
| **Fix:** Add `afterEach` cleanup to call `serializedStateManager.dispose()` for each test | ||
| that creates an instance with offline load enabled. | ||
|
|
||
| ### Root Cause 2: DeliLambda.readClientIdleTimer (CONFIRMED by code analysis) | ||
| **Affected packages:** Any package that uses TestTreeProvider.create() or TestObjectProvider | ||
| with a local server driver (e.g. packages/dds/tree, packages/test/local-server-tests, etc.) | ||
|
|
||
| `DeliLambda` creates a 60-second `setInterval` (readClientIdleTimer) when the local orderer | ||
| is set up. This timer is only cleared when `DeliLambda.close()` is called, which happens when | ||
| `LocalServerTestDriver.dispose()` is called. Tests that use `TestTreeProvider.create()` directly | ||
| (not through `describeCompat`) don't call `driver.dispose()` after tests. | ||
|
|
||
| `describeCompat` already handles this with `provider.driver.dispose?.()` in its `after` hook, | ||
| but calls it fire-and-forget (not awaited). This still causes a brief hang while the async | ||
| cleanup chain completes. | ||
|
|
||
| **Location:** packages/dds/tree/src/test/* (and others using TestTreeProvider) | ||
| **Fix:** Add proper cleanup for TestTreeProvider instances in tests | ||
|
|
||
| ### Root Cause 3: JSDOM (suspected) | ||
| **Affected packages:** packages/framework/react | ||
|
|
||
| JSDOM keeps the process alive through internal timers and window/document event handling. | ||
| Tests use `globalJsdom()` from the `global-jsdom` package. | ||
| **Status:** Not yet confirmed via diagnostics. | ||
|
|
||
| ### Root Cause 4: Other packages (unknown) | ||
| **Affected packages:** packages/runtime/container-runtime, and others | ||
|
|
||
| Likely similar to root cause 1 (SnapshotRefresher or similar timed objects), but not yet confirmed. | ||
|
|
||
| ## Packages affected | ||
| - packages/dds/tree (Root cause 2 - TestTreeProvider not disposed) | ||
| - packages/runtime/container-runtime (Root cause 4 - TBD) | ||
| - packages/loader/container-loader (Root cause 1 - SnapshotRefresher 24h timer - CONFIRMED) | ||
| - packages/service-clients/odsp-client (Root cause 2 - likely local server) | ||
| - packages/test/local-server-tests (Root cause 2 - local server) | ||
| - packages/test/snapshots (Root cause 4 - TBD) | ||
| - packages/framework/react (Root cause 3 - JSDOM) | ||
| - packages/framework/client-logger/fluid-telemetry (Root cause 4 - TBD) | ||
| - packages/test/test-end-to-end-tests/src/test (Root cause 2 - local server) | ||
| - examples/data-objects/table-document (Root cause 2 - uses describeCompat with local server) | ||
| - examples/data-objects/webflow (Root cause 4 - TBD) | ||
| - examples/data-objects/inventory-app (Root cause 4 - TBD) | ||
|
|
||
| ## Tasks | ||
|
|
||
| ### Done | ||
| - [x] Understand scope of the problem | ||
| - [x] Identify primary root cause (DeliLambda.readClientIdleTimer for local server packages) | ||
| - [x] Confirm secondary root cause (SnapshotRefresher 24h timer via diagnostics) | ||
|
|
||
| ### Done (continued) | ||
| - [x] Fix packages/loader/container-loader (serializedStateManager.spec.ts cleanup) | ||
| - Added `makeSsm()` factory helper + `instancesToDispose` tracking array at outer describe scope | ||
| - `afterEach` disposes all tracked instances, preventing 24h SnapshotRefresher timers from leaking | ||
| - Removed `config.exit = true` from `.mocharc.cjs` | ||
| - [x] Fix packages/runtime/container-runtime (3 spec files with ContainerRuntime not disposed) | ||
| - Root cause: GarbageCollector in ContainerRuntime creates MAX_INT32 timer on creation | ||
| - hardwareStats.spec.ts, runtimeLayerCompatValidation.spec.ts, containerRuntime.extensions.spec.ts | ||
| - Removed `config.exit = true` from `.mocharc.cjs` | ||
|
|
||
| - [x] Fix packages/dds/tree (TestTreeProvider disposal) | ||
| - Root cause: LoaderContainerTracker skips non-interactive (summarizer) containers, so the | ||
| summarizer container created by `createSummarizer()` was never disposed | ||
| - Fix 1: Change `state: "disabled"` to `state: "summaryOnRequest"` for `SummarizeType.onDemand` | ||
| to prevent SummaryManager from spawning auto-summarizer containers with GC timers | ||
| - Fix 2: Capture `summarizerContainer` from `createSummarizer()` and dispose it explicitly | ||
| in `TestTreeProvider.dispose()`, clearing its GC session expiry timer | ||
| - Fix 3: Add `afterEach` cleanup in sharedTree.spec.ts and testTreeProvider.spec.ts | ||
| - Fix 4: Add `provider.dispose()` in `getIIDCompressor()` in nodeIdentifier.spec.ts | ||
| - Removed `config.exit = true` from `.mocharc.cjs` | ||
|
|
||
| ### Todo | ||
| - [ ] Run diagnostics on packages/runtime/container-runtime | ||
| - [ ] Run diagnostics on packages/framework/react | ||
| - [ ] Fix remaining packages after root causes confirmed | ||
| - [ ] Remove --exit flag from fixed packages and verify tests pass | ||
|
|
||
| ## Key findings | ||
|
|
||
| 1. `packages/loader/container-loader/src/test/serializedStateManager.spec.ts`: | ||
| - Creates SerializedStateManager instances (with SnapshotRefresher) without disposing them | ||
| - The SnapshotRefresher's internal Timer (24h default) keeps the process alive | ||
| - Fix: Add afterEach/after cleanup to dispose each SerializedStateManager | ||
|
|
||
| 2. `packages/dds/tree/.mocharc.cjs` already has comment: | ||
| > "In this package, tests which use TestTreeProvider.create cause this issue" | ||
| - TestTreeProvider creates LocalServerTestDriver → LocalDeltaConnectionServer | ||
| - DeliLambda (inside the server) creates a 60s setInterval (readClientIdleTimer) | ||
| - Not cleared because driver.dispose() is never called after tests | ||
|
|
||
| 3. describeCompat already does driver.dispose() (line 182 in describeCompat.ts), | ||
| but fire-and-forget (not awaited), so it's still async. | ||
|
|
||
| ## Test diagnostic approach used | ||
| ```bash | ||
| # Create a script to trace timer creation and report on SIGTERM: | ||
| cat > /tmp/mocha_trace.js << 'EOF' | ||
| # (intercepts setTimeout/setInterval and logs on SIGTERM) | ||
| EOF | ||
|
|
||
| # Run tests and send SIGTERM after completion: | ||
| cd /workspaces/FluidFramework/packages/loader/container-loader | ||
| mocha --no-exit --require /tmp/mocha_trace.js "lib/test/loader.spec.js" & | ||
| PID=$! | ||
| sleep 5 | ||
| kill -TERM $PID | ||
| # Look at output for active timer stacks | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
examples/data-objects/inventory-app/src/test/globalSetup.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| /*! | ||
| * Copyright (c) Microsoft Corporation and contributors. All rights reserved. | ||
| * Licensed under the MIT License. | ||
| */ | ||
|
|
||
| import globalJsdom from "global-jsdom"; | ||
|
|
||
| // Set up JSDOM before any modules are loaded (Quill needs document at import time). | ||
| // @fluidframework/react imports Quill at ESM module-load time, so document must exist | ||
| // before the test file's static imports are resolved. | ||
| const cleanup = globalJsdom(); | ||
|
|
||
| // Remove JSDOM after imports are done, but before we run any tests. | ||
| // Tests which require JSDOM (e.g. the "dom tests" describe block) call globalJsdom() | ||
| // themselves to set up their own clean DOM. | ||
| before(() => { | ||
| cleanup(); | ||
| }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,7 +30,10 @@ async function getIIDCompressor(): Promise<IIdCompressor> { | |
| runtime: IFluidDataStoreRuntime; | ||
| } | ||
| ).runtime; | ||
| return runtime.idCompressor ?? fail("Expected IIdCompressor to be present in runtime"); | ||
| const compressor = | ||
| runtime.idCompressor ?? fail("Expected IIdCompressor to be present in runtime"); | ||
| provider.dispose(); | ||
| return compressor; | ||
|
Comment on lines
+33
to
+36
|
||
| } | ||
|
|
||
| describe("Node Identifier", () => { | ||
|
|
||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.