Skip to content

Commit

Permalink
bump workflow versions
Browse files Browse the repository at this point in the history
Replace weak-napi with built in WeakRef
  • Loading branch information
rotu committed Jun 17, 2024
1 parent 46d129d commit cfa3117
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 201 deletions.
10 changes: 0 additions & 10 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,3 @@ tool similar to Cmake. GYP was originally created to generate native IDE project
files (Visual Studio, Xcode) for building Chromium.

The `.gyp` file is structured as a Python dictionary.

## Weak-napi

https://www.npmjs.com/package/weak-napi On certain rarer occasions, you run into
the need to be notified when a JavaScript object is going to be garbage
collected. This feature is exposed to V8's C++ API, but not to JavaScript.

That's where weak-napi comes in! This module exports the JS engine's GC tracking
functionality to JavaScript. This allows you to create weak references, and
optionally attach a callback function to any arbitrary JS object.
6 changes: 0 additions & 6 deletions test/package.json

This file was deleted.

81 changes: 0 additions & 81 deletions test/pnpm-lock.yaml

This file was deleted.

15 changes: 14 additions & 1 deletion test/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
{
"extends": "../tsconfig.json",
"include": ["**/*.ts"]
"include": [
"**/*.ts"
],
"ts-node": {
"files": true
},
"compilerOptions": {
"types": [
"mocha"
],
"lib": [
"ESNext"
]
}
}
40 changes: 40 additions & 0 deletions test/unit/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,43 @@ export async function captureEventsUntil(

return events
}

// REAL typings for global.gc per
// https://github.com/nodejs/node/blob/v20.0.0/deps/v8/src/extensions/gc-extension.cc
interface GCFunction {
(options: {
execution?: "sync"
flavor?: "regular" | "last-resort"
type?: "major-snapshot" | "major" | "minor"
filename?: string
}): void
(options: {
execution?: "async"
flavor?: "regular" | "last-resort"
type?: "major-snapshot" | "major" | "minor"
filename?: string
}): Promise<void>
(options: {
execution?: "async" | "sync"
flavor?: "regular" | "last-resort"
type?: "major-snapshot" | "major" | "minor"
filename?: string
}): void | Promise<void>
}

export function getGcOrSkipTest(test: Mocha.Context) {
if (process.env.SKIP_GC_TESTS) {
test.skip()
}

const gc = globalThis.gc as undefined | GCFunction
if (typeof gc !== "function") {
throw new Error(
"Garbage collection is not exposed. It may be enabled by the node --expose-gc flag. To skip GC tests, set the environment variable `SKIP_GC_TESTS`",
)
}
// https://github.com/nodejs/node/blob/v20.0.0/deps/v8/src/extensions/gc-extension.h
// per docs, we we're using use case 2 (Test that certain objects indeed are reclaimed)
const asyncMajorGc = () => gc({type: "major", execution: "async"})
return asyncMajorGc
}
57 changes: 16 additions & 41 deletions test/unit/socket-close-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import * as zmq from "../../src"

import {assert} from "chai"
import {testProtos, uniqAddress} from "./helpers"
import {testProtos, uniqAddress, getGcOrSkipTest} from "./helpers"
import {isFullError} from "../../src/errors"

for (const proto of testProtos("tcp", "ipc", "inproc")) {
Expand Down Expand Up @@ -107,75 +107,50 @@ for (const proto of testProtos("tcp", "ipc", "inproc")) {
})

it("should release reference to context", async function () {
if (process.env.SKIP_GC_TESTS === "true") {
this.skip()
}
if (global.gc === undefined) {
console.warn("gc is not exposed by the runtime")
this.skip()
}

const gc = getGcOrSkipTest(this)
this.slow(200)

const weak = require("weak-napi") as typeof import("weak-napi")
let weakRef: undefined | WeakRef<any>

let released = false
const task = async () => {
let context: zmq.Context | undefined = new zmq.Context()
const socket = new zmq.Dealer({context, linger: 0})
weakRef = new WeakRef(context)

weak(context, () => {
released = true
})
context = undefined

global.gc!()
socket.connect(await uniqAddress(proto))
await socket.send(Buffer.from("foo"))
socket.close()
}

await task()
global.gc()
await new Promise(resolve => {
setTimeout(resolve, 5)
})
assert.equal(released, true)
await gc()

assert.isDefined(weakRef)
assert.isUndefined(weakRef!.deref())
})
})

describe("in gc finalizer", function () {
it("should release reference to context", async function () {
if (process.env.SKIP_GC_TESTS === "true") {
this.skip()
}
if (global.gc === undefined) {
console.warn("gc is not exposed by the runtime")
const gc = getGcOrSkipTest(this)
if (process.env.SKIP_GC_FINALIZER_TESTS) {
this.skip()
}
this.slow(200)

const weak = require("weak-napi") as typeof import("weak-napi")

let released = false
let weakRef: undefined | WeakRef<any>
const task = async () => {
let context: zmq.Context | undefined = new zmq.Context()

const _dealer = new zmq.Dealer({context, linger: 0})

weak(context, () => {
released = true
})
context = undefined
global.gc!()
weakRef = new WeakRef(context)
}

await task()
global.gc()
await new Promise(resolve => {
setTimeout(resolve, 5)
})
assert.equal(released, true)
await gc()

assert.isDefined(weakRef)
assert.isUndefined(weakRef!.deref())
})
})
})
Expand Down
Loading

0 comments on commit cfa3117

Please sign in to comment.