From e72e24f129ea59e10c477baa9f629d2ba78abfc2 Mon Sep 17 00:00:00 2001 From: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com> Date: Sun, 9 Oct 2022 06:23:05 +0800 Subject: [PATCH 1/5] fix --- CHANGELOG.md | 1 + .../src/__tests__/collectHandles.test.js | 12 +++++++ packages/jest-core/src/collectHandles.ts | 31 +++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8db5b756640b..27d5afbd2221 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - `[jest-reporters]` Revert: Transform file paths into hyperlinks ([#13399](https://github.com/facebook/jest/pull/13399)) - `[@jest/types]` Infer type of `each` table correctly when the table is a tuple or array ([#13381](https://github.com/facebook/jest/pull/13381)) - `[@jest/types]` Rework typings to allow the `*ReturnedWith` matchers to be called with no argument ([#13385](https://github.com/facebook/jest/pull/13385)) +- `[jest-core]` Fix `detectOpenHandles` false positives for some special objects such as `TLSWRAP`. ([#13414](https://github.com/facebook/jest/pull/13414)) ### Chore & Maintenance diff --git a/packages/jest-core/src/__tests__/collectHandles.test.js b/packages/jest-core/src/__tests__/collectHandles.test.js index 229ccb9a2c7a..2455149f4526 100644 --- a/packages/jest-core/src/__tests__/collectHandles.test.js +++ b/packages/jest-core/src/__tests__/collectHandles.test.js @@ -10,6 +10,7 @@ import * as crypto from 'crypto'; import {promises as dns} from 'dns'; import http from 'http'; import {PerformanceObserver} from 'perf_hooks'; +import {TLSSocket} from 'tls'; import zlib from 'zlib'; import collectHandles from '../collectHandles'; @@ -134,4 +135,15 @@ describe('collectHandles', () => { expect.objectContaining({message: 'TCPSERVERWRAP'}), ); }); + + it('should collect handles for some special objects such as `TLSWRAP`', async () => { + const handleCollector = collectHandles(); + + const socket = new TLSSocket(); + socket.destroy(); + + const openHandles = await handleCollector(); + + expect(openHandles).toHaveLength(0); + }); }); diff --git a/packages/jest-core/src/collectHandles.ts b/packages/jest-core/src/collectHandles.ts index 5e69fd920e71..2cc5f7c76b7e 100644 --- a/packages/jest-core/src/collectHandles.ts +++ b/packages/jest-core/src/collectHandles.ts @@ -8,6 +8,8 @@ /* eslint-disable local/ban-types-eventually */ import * as asyncHooks from 'async_hooks'; +import * as v8 from 'v8'; +import * as vm from 'vm'; import {promisify} from 'util'; import stripAnsi = require('strip-ansi'); import type {Config} from '@jest/types'; @@ -45,6 +47,27 @@ const hasWeakRef = typeof WeakRef === 'function'; const asyncSleep = promisify(setTimeout); +let gcFunc: typeof global.gc | undefined; +function runGC() { + if (!gcFunc) { + if (typeof global.gc === 'function') { + gcFunc = global.gc; + } else { + v8.setFlagsFromString('--expose-gc'); + gcFunc = vm.runInNewContext('gc'); + v8.setFlagsFromString('--no-expose-gc'); + if (!gcFunc) { + console.warn( + 'Cannot find `global.gc` function. Please run node with `--expose-gc`', + ); + gcFunc = () => {}; + } + } + } + + gcFunc(); +} + // Inspired by https://github.com/mafintosh/why-is-node-running/blob/master/index.js // Extracted as we want to format the result ourselves export default function collectHandles(): HandleCollectionResult { @@ -125,6 +148,14 @@ export default function collectHandles(): HandleCollectionResult { // callback, we will not yet have seen the resource be destroyed here. await asyncSleep(100); + if (activeHandles.size !== 0) { + // For some special objects such as `TLSWRAP`. + // Ref: https://github.com/facebook/jest/issues/11665 + runGC(); + + await asyncSleep(0); + } + hook.disable(); // Get errors for every async resource still referenced at this moment From c3982c331271894b2d2f7fcdc0d5d9ffbad5beca Mon Sep 17 00:00:00 2001 From: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com> Date: Sun, 9 Oct 2022 06:32:13 +0800 Subject: [PATCH 2/5] lint --- packages/jest-core/src/collectHandles.ts | 25 +++++++++++------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/packages/jest-core/src/collectHandles.ts b/packages/jest-core/src/collectHandles.ts index 2cc5f7c76b7e..7a9b2cd7ecd8 100644 --- a/packages/jest-core/src/collectHandles.ts +++ b/packages/jest-core/src/collectHandles.ts @@ -8,9 +8,9 @@ /* eslint-disable local/ban-types-eventually */ import * as asyncHooks from 'async_hooks'; +import {promisify} from 'util'; import * as v8 from 'v8'; import * as vm from 'vm'; -import {promisify} from 'util'; import stripAnsi = require('strip-ansi'); import type {Config} from '@jest/types'; import {formatExecError} from 'jest-message-util'; @@ -47,21 +47,18 @@ const hasWeakRef = typeof WeakRef === 'function'; const asyncSleep = promisify(setTimeout); -let gcFunc: typeof global.gc | undefined; +let gcFunc: Function | undefined = (globalThis as any).gc; function runGC() { if (!gcFunc) { - if (typeof global.gc === 'function') { - gcFunc = global.gc; - } else { - v8.setFlagsFromString('--expose-gc'); - gcFunc = vm.runInNewContext('gc'); - v8.setFlagsFromString('--no-expose-gc'); - if (!gcFunc) { - console.warn( - 'Cannot find `global.gc` function. Please run node with `--expose-gc`', - ); - gcFunc = () => {}; - } + v8.setFlagsFromString('--expose-gc'); + gcFunc = vm.runInNewContext('gc'); + v8.setFlagsFromString('--no-expose-gc'); + if (!gcFunc) { + console.warn( + 'Cannot find `global.gc` function. Please run node with `--expose-gc`', + ); + // eslint-disable-next-line @typescript-eslint/no-empty-function + gcFunc = () => {}; } } From bfe94ca318f844ed1393d40986444295818502d2 Mon Sep 17 00:00:00 2001 From: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com> Date: Sun, 9 Oct 2022 15:16:59 +0800 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: Simen Bekkhus --- packages/jest-core/src/collectHandles.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/jest-core/src/collectHandles.ts b/packages/jest-core/src/collectHandles.ts index 7a9b2cd7ecd8..ffa72b1883a2 100644 --- a/packages/jest-core/src/collectHandles.ts +++ b/packages/jest-core/src/collectHandles.ts @@ -47,7 +47,7 @@ const hasWeakRef = typeof WeakRef === 'function'; const asyncSleep = promisify(setTimeout); -let gcFunc: Function | undefined = (globalThis as any).gc; +let gcFunc: (() => void) | undefined = (globalThis as any).gc; function runGC() { if (!gcFunc) { v8.setFlagsFromString('--expose-gc'); @@ -145,7 +145,7 @@ export default function collectHandles(): HandleCollectionResult { // callback, we will not yet have seen the resource be destroyed here. await asyncSleep(100); - if (activeHandles.size !== 0) { + if (activeHandles.size > 0) { // For some special objects such as `TLSWRAP`. // Ref: https://github.com/facebook/jest/issues/11665 runGC(); From 434d522606d4f37cc0ec1ce8797a41beb70a4997 Mon Sep 17 00:00:00 2001 From: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com> Date: Sun, 9 Oct 2022 16:32:19 +0800 Subject: [PATCH 4/5] review --- CHANGELOG.md | 2 +- packages/jest-core/src/__tests__/collectHandles.test.js | 2 +- packages/jest-core/src/collectHandles.ts | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27d5afbd2221..e060e80db633 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,12 +9,12 @@ ### Fixes +- `[jest-core]` Fix `detectOpenHandles` false positives for some special objects such as `TLSWRAP`. ([#13414](https://github.com/facebook/jest/pull/13414)) - `[babel-plugin-jest-hoist]` Ignore `TSTypeQuery` when checking for hoisted references ([#13367](https://github.com/facebook/jest/pull/13367)) - `[jest-mock]` Fix mocking of getters and setters on classes ([#13398](https://github.com/facebook/jest/pull/13398)) - `[jest-reporters]` Revert: Transform file paths into hyperlinks ([#13399](https://github.com/facebook/jest/pull/13399)) - `[@jest/types]` Infer type of `each` table correctly when the table is a tuple or array ([#13381](https://github.com/facebook/jest/pull/13381)) - `[@jest/types]` Rework typings to allow the `*ReturnedWith` matchers to be called with no argument ([#13385](https://github.com/facebook/jest/pull/13385)) -- `[jest-core]` Fix `detectOpenHandles` false positives for some special objects such as `TLSWRAP`. ([#13414](https://github.com/facebook/jest/pull/13414)) ### Chore & Maintenance diff --git a/packages/jest-core/src/__tests__/collectHandles.test.js b/packages/jest-core/src/__tests__/collectHandles.test.js index 2455149f4526..db56aeff2184 100644 --- a/packages/jest-core/src/__tests__/collectHandles.test.js +++ b/packages/jest-core/src/__tests__/collectHandles.test.js @@ -136,7 +136,7 @@ describe('collectHandles', () => { ); }); - it('should collect handles for some special objects such as `TLSWRAP`', async () => { + it('should not be false positives for some special objects such as `TLSWRAP`', async () => { const handleCollector = collectHandles(); const socket = new TLSSocket(); diff --git a/packages/jest-core/src/collectHandles.ts b/packages/jest-core/src/collectHandles.ts index ffa72b1883a2..f5e79eafed9e 100644 --- a/packages/jest-core/src/collectHandles.ts +++ b/packages/jest-core/src/collectHandles.ts @@ -54,11 +54,9 @@ function runGC() { gcFunc = vm.runInNewContext('gc'); v8.setFlagsFromString('--no-expose-gc'); if (!gcFunc) { - console.warn( - 'Cannot find `global.gc` function. Please run node with `--expose-gc`', + throw new Error( + 'Cannot find `global.gc` function. Please run node with `--expose-gc` and report this issue in jest repo.', ); - // eslint-disable-next-line @typescript-eslint/no-empty-function - gcFunc = () => {}; } } From b33c610d2af3739e2343771c9832c3902600e98b Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sun, 9 Oct 2022 17:27:47 +0200 Subject: [PATCH 5/5] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e060e80db633..102e9f3337b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,8 @@ ### Fixes -- `[jest-core]` Fix `detectOpenHandles` false positives for some special objects such as `TLSWRAP`. ([#13414](https://github.com/facebook/jest/pull/13414)) - `[babel-plugin-jest-hoist]` Ignore `TSTypeQuery` when checking for hoisted references ([#13367](https://github.com/facebook/jest/pull/13367)) +- `[jest-core]` Fix `detectOpenHandles` false positives for some special objects such as `TLSWRAP`. ([#13414](https://github.com/facebook/jest/pull/13414)) - `[jest-mock]` Fix mocking of getters and setters on classes ([#13398](https://github.com/facebook/jest/pull/13398)) - `[jest-reporters]` Revert: Transform file paths into hyperlinks ([#13399](https://github.com/facebook/jest/pull/13399)) - `[@jest/types]` Infer type of `each` table correctly when the table is a tuple or array ([#13381](https://github.com/facebook/jest/pull/13381))