feat(napi): pass the rest of async tests (#1792)
Pass the rest of async tests, including await the JavaScript Promise in the Rust side, and the worker_threads tests.
This commit is contained in:
parent
ca18bbdae0
commit
36581336c6
10 changed files with 80 additions and 106 deletions
3
.github/workflows/test-release.yaml
vendored
3
.github/workflows/test-release.yaml
vendored
|
@ -513,11 +513,12 @@ jobs:
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
yarn build
|
yarn build
|
||||||
yarn workspace @examples/napi build --target wasm32-wasi-preview1-threads
|
yarn workspace @examples/napi build --target wasm32-wasi-preview1-threads --release
|
||||||
- name: Test
|
- name: Test
|
||||||
run: yarn workspace @examples/napi test -s
|
run: yarn workspace @examples/napi test -s
|
||||||
env:
|
env:
|
||||||
WASI_TEST: 'true'
|
WASI_TEST: 'true'
|
||||||
|
NODE_OPTIONS: '--max-old-space-size=8192'
|
||||||
|
|
||||||
test-latest-bun:
|
test-latest-bun:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
|
@ -18,5 +18,8 @@ pub fn setup() {
|
||||||
println!("cargo:rustc-link-arg=--import-undefined");
|
println!("cargo:rustc-link-arg=--import-undefined");
|
||||||
println!("cargo:rustc-link-arg=--shared-memory");
|
println!("cargo:rustc-link-arg=--shared-memory");
|
||||||
println!("cargo:rustc-link-arg=--max-memory=2147483648");
|
println!("cargo:rustc-link-arg=--max-memory=2147483648");
|
||||||
|
// lld only allocates 1MiB for the WebAssembly stack, and the array that you're allocating on the stack is exactly 1MiB.
|
||||||
|
// 0x800000 bytes = 8MiB
|
||||||
|
println!("cargo:rustc-link-arg=-zstack-size=0x800000");
|
||||||
println!("cargo:rustc-link-arg=--no-check-features");
|
println!("cargo:rustc-link-arg=--no-check-features");
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ impl FromNapiValue for AbortSignal {
|
||||||
sys::napi_wrap(
|
sys::napi_wrap(
|
||||||
env,
|
env,
|
||||||
signal.0.value,
|
signal.0.value,
|
||||||
Box::into_raw(Box::new(abort_controller)) as *mut _,
|
Box::into_raw(Box::new(abort_controller)).cast(),
|
||||||
Some(async_task_abort_controller_finalize),
|
Some(async_task_abort_controller_finalize),
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
|
|
|
@ -144,7 +144,11 @@ pub fn execute_tokio_future<
|
||||||
spawn(inner);
|
spawn(inner);
|
||||||
|
|
||||||
#[cfg(target_os = "wasi")]
|
#[cfg(target_os = "wasi")]
|
||||||
|
{
|
||||||
|
std::thread::spawn(|| {
|
||||||
block_on(inner);
|
block_on(inner);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Ok(promise.0.value)
|
Ok(promise.0.value)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import ava from 'ava'
|
import test from 'ava'
|
||||||
|
|
||||||
const { Fib, Fib2, Fib3 } = (await import('../index.js')).default
|
const { Fib, Fib2, Fib3 } = (await import('../index.js')).default
|
||||||
|
|
||||||
const test = process.env.WASI_TEST ? ava.skip : ava
|
|
||||||
|
|
||||||
for (const [index, factory] of [
|
for (const [index, factory] of [
|
||||||
() => new Fib(),
|
() => new Fib(),
|
||||||
() => Fib2.create(0),
|
() => Fib2.create(0),
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import ava from 'ava'
|
import test from 'ava'
|
||||||
|
|
||||||
const { NotWritableClass } = (await import('../index.js')).default
|
const { NotWritableClass } = (await import('../index.js')).default
|
||||||
|
|
||||||
const test = process.env.WASI_TEST ? ava.skip : ava
|
|
||||||
|
|
||||||
test('Not Writable Class', (t) => {
|
test('Not Writable Class', (t) => {
|
||||||
const obj = new NotWritableClass('1')
|
const obj = new NotWritableClass('1')
|
||||||
t.throws(() => {
|
t.throws(() => {
|
||||||
|
|
|
@ -124,10 +124,6 @@ test('should validate Map', (t) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test.only('should validate promise', async (t) => {
|
test.only('should validate promise', async (t) => {
|
||||||
if (process.env.WASI_TEST) {
|
|
||||||
t.pass()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.is(
|
t.is(
|
||||||
await validatePromise(
|
await validatePromise(
|
||||||
new Promise((resolve) => {
|
new Promise((resolve) => {
|
||||||
|
|
|
@ -144,7 +144,6 @@ const {
|
||||||
} = (await import('../index.js')).default
|
} = (await import('../index.js')).default
|
||||||
|
|
||||||
const Napi4Test = Number(process.versions.napi) >= 4 ? test : test.skip
|
const Napi4Test = Number(process.versions.napi) >= 4 ? test : test.skip
|
||||||
const isWasiTest = !!process.env.WASI_TEST
|
|
||||||
|
|
||||||
test('export const', (t) => {
|
test('export const', (t) => {
|
||||||
t.is(DEFAULT_COST, 12)
|
t.is(DEFAULT_COST, 12)
|
||||||
|
@ -356,10 +355,6 @@ test('return function', (t) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
Napi4Test('callback function return Promise', async (t) => {
|
Napi4Test('callback function return Promise', async (t) => {
|
||||||
if (isWasiTest) {
|
|
||||||
t.pass()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const cbSpy = spy()
|
const cbSpy = spy()
|
||||||
await callbackReturnPromise<string>(() => '1', spy)
|
await callbackReturnPromise<string>(() => '1', spy)
|
||||||
t.is(cbSpy.callCount, 0)
|
t.is(cbSpy.callCount, 0)
|
||||||
|
@ -375,10 +370,6 @@ Napi4Test('callback function return Promise', async (t) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
Napi4Test('callback function return Promise and spawn', async (t) => {
|
Napi4Test('callback function return Promise and spawn', async (t) => {
|
||||||
if (isWasiTest) {
|
|
||||||
t.pass()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const finalReturn = await callbackReturnPromiseAndSpawn((input) =>
|
const finalReturn = await callbackReturnPromiseAndSpawn((input) =>
|
||||||
Promise.resolve(`${input} world`),
|
Promise.resolve(`${input} world`),
|
||||||
)
|
)
|
||||||
|
@ -597,7 +588,7 @@ test('create external TypedArray', (t) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('mutate TypedArray', (t) => {
|
test('mutate TypedArray', (t) => {
|
||||||
if (isWasiTest) {
|
if (process.env.WASI_TEST) {
|
||||||
t.pass()
|
t.pass()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -671,7 +662,7 @@ test('receive class reference in either', (t) => {
|
||||||
|
|
||||||
test('receive different class', (t) => {
|
test('receive different class', (t) => {
|
||||||
// TODO: fix the napi_unwrap error from the emnapi
|
// TODO: fix the napi_unwrap error from the emnapi
|
||||||
if (isWasiTest) {
|
if (process.env.WASI_TEST) {
|
||||||
t.pass()
|
t.pass()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -863,10 +854,6 @@ Napi4Test('throw error from thread safe function fatal mode', (t) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
Napi4Test('await Promise in rust', async (t) => {
|
Napi4Test('await Promise in rust', async (t) => {
|
||||||
if (isWasiTest) {
|
|
||||||
t.pass()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const fx = 20
|
const fx = 20
|
||||||
const result = await asyncPlus100(
|
const result = await asyncPlus100(
|
||||||
new Promise((resolve) => {
|
new Promise((resolve) => {
|
||||||
|
@ -877,10 +864,6 @@ Napi4Test('await Promise in rust', async (t) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
Napi4Test('Promise should reject raw error in rust', async (t) => {
|
Napi4Test('Promise should reject raw error in rust', async (t) => {
|
||||||
if (isWasiTest) {
|
|
||||||
t.pass()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const fxError = new Error('What is Happy Planet')
|
const fxError = new Error('What is Happy Planet')
|
||||||
const err = await t.throwsAsync(() => asyncPlus100(Promise.reject(fxError)))
|
const err = await t.throwsAsync(() => asyncPlus100(Promise.reject(fxError)))
|
||||||
t.is(err, fxError)
|
t.is(err, fxError)
|
||||||
|
@ -899,10 +882,6 @@ Napi4Test('call ThreadsafeFunction with callback', async (t) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
Napi4Test('async call ThreadsafeFunction', async (t) => {
|
Napi4Test('async call ThreadsafeFunction', async (t) => {
|
||||||
if (isWasiTest) {
|
|
||||||
t.pass()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
await t.notThrowsAsync(() =>
|
await t.notThrowsAsync(() =>
|
||||||
tsfnAsyncCall((err, arg1, arg2, arg3) => {
|
tsfnAsyncCall((err, arg1, arg2, arg3) => {
|
||||||
t.is(err, null)
|
t.is(err, null)
|
||||||
|
@ -915,10 +894,6 @@ Napi4Test('async call ThreadsafeFunction', async (t) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('Throw from ThreadsafeFunction JavaScript callback', async (t) => {
|
test('Throw from ThreadsafeFunction JavaScript callback', async (t) => {
|
||||||
if (isWasiTest) {
|
|
||||||
t.pass()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const errMsg = 'ThrowFromJavaScriptRawCallback'
|
const errMsg = 'ThrowFromJavaScriptRawCallback'
|
||||||
await t.throwsAsync(
|
await t.throwsAsync(
|
||||||
() =>
|
() =>
|
||||||
|
@ -968,10 +943,6 @@ Napi4Test('accept ThreadsafeFunction tuple args', async (t) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
Napi4Test('threadsafe function return Promise and await in Rust', async (t) => {
|
Napi4Test('threadsafe function return Promise and await in Rust', async (t) => {
|
||||||
if (isWasiTest) {
|
|
||||||
t.pass()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const value = await tsfnReturnPromise((err, value) => {
|
const value = await tsfnReturnPromise((err, value) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err
|
throw err
|
||||||
|
@ -1016,10 +987,6 @@ Napi4Test('object only from js', (t) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
Napi4Test('promise in either', async (t) => {
|
Napi4Test('promise in either', async (t) => {
|
||||||
if (isWasiTest) {
|
|
||||||
t.pass()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.is(await promiseInEither(1), false)
|
t.is(await promiseInEither(1), false)
|
||||||
t.is(await promiseInEither(20), true)
|
t.is(await promiseInEither(20), true)
|
||||||
t.is(await promiseInEither(Promise.resolve(1)), false)
|
t.is(await promiseInEither(Promise.resolve(1)), false)
|
||||||
|
@ -1073,7 +1040,7 @@ Napi9Test('create symbol for', (t) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
Napi9Test('get module file name', (t) => {
|
Napi9Test('get module file name', (t) => {
|
||||||
if (isWasiTest) {
|
if (process.env.WASI_TEST) {
|
||||||
t.pass()
|
t.pass()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,11 @@ const __dirname = join(fileURLToPath(import.meta.url), '..')
|
||||||
|
|
||||||
const t =
|
const t =
|
||||||
// aarch64-unknown-linux-gnu is extremely slow in CI, skip it or it will timeout
|
// aarch64-unknown-linux-gnu is extremely slow in CI, skip it or it will timeout
|
||||||
(process.arch === 'arm64' && process.platform === 'linux') ||
|
process.arch === 'arm64' && process.platform === 'linux' ? test.skip : test
|
||||||
process.env.WASI_TEST
|
|
||||||
? test.skip
|
|
||||||
: test
|
|
||||||
|
|
||||||
const concurrency =
|
const concurrency = process.env.WASI_TEST
|
||||||
process.platform === 'win32' ||
|
? 1
|
||||||
|
: process.platform === 'win32' ||
|
||||||
process.platform === 'darwin' ||
|
process.platform === 'darwin' ||
|
||||||
(process.platform === 'linux' && process.arch === 'x64')
|
(process.platform === 'linux' && process.arch === 'x64')
|
||||||
? 50
|
? 50
|
||||||
|
@ -26,7 +24,8 @@ t('should be able to require in worker thread', async (t) => {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
Array.from({ length: concurrency }).map(() => {
|
Array.from({ length: concurrency }).map(() => {
|
||||||
const w = new Worker(join(__dirname, 'worker.cjs'), {
|
const w = new Worker(join(__dirname, 'worker.cjs'), {
|
||||||
execArgv: [],
|
execArgv: ['--experimental-wasi-unstable-preview1'],
|
||||||
|
env: process.env,
|
||||||
})
|
})
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
w.postMessage({ type: 'require' })
|
w.postMessage({ type: 'require' })
|
||||||
|
@ -52,7 +51,8 @@ t('custom GC works on worker_threads', async (t) => {
|
||||||
Promise.all([
|
Promise.all([
|
||||||
new Promise<Worker>((resolve, reject) => {
|
new Promise<Worker>((resolve, reject) => {
|
||||||
const w = new Worker(join(__dirname, 'worker.cjs'), {
|
const w = new Worker(join(__dirname, 'worker.cjs'), {
|
||||||
execArgv: [],
|
execArgv: ['--experimental-wasi-unstable-preview1'],
|
||||||
|
env: process.env,
|
||||||
})
|
})
|
||||||
w.postMessage({
|
w.postMessage({
|
||||||
type: 'async:buffer',
|
type: 'async:buffer',
|
||||||
|
@ -93,7 +93,8 @@ t('should be able to new Class in worker thread concurrently', async (t) => {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
Array.from({ length: concurrency }).map(() => {
|
Array.from({ length: concurrency }).map(() => {
|
||||||
const w = new Worker(join(__dirname, 'worker.cjs'), {
|
const w = new Worker(join(__dirname, 'worker.cjs'), {
|
||||||
execArgv: [],
|
execArgv: ['--experimental-wasi-unstable-preview1'],
|
||||||
|
env: process.env,
|
||||||
})
|
})
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
w.postMessage({ type: 'constructor' })
|
w.postMessage({ type: 'constructor' })
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
const { parentPort } = require('worker_threads')
|
const { parentPort } = require('worker_threads')
|
||||||
|
|
||||||
const native = require('../index.node')
|
const isWasiTest = !!process.env.WASI_TEST
|
||||||
|
|
||||||
|
import('../index.js').then(({ default: native }) => {
|
||||||
parentPort.on('message', ({ type }) => {
|
parentPort.on('message', ({ type }) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'require':
|
case 'require':
|
||||||
|
@ -11,7 +12,7 @@ parentPort.on('message', ({ type }) => {
|
||||||
break
|
break
|
||||||
case 'async:buffer':
|
case 'async:buffer':
|
||||||
Promise.all(
|
Promise.all(
|
||||||
Array.from({ length: 100 }).map(() =>
|
Array.from({ length: isWasiTest ? 2 : 100 }).map(() =>
|
||||||
native.bufferPassThrough(Buffer.from([1, 2, 3])),
|
native.bufferPassThrough(Buffer.from([1, 2, 3])),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -24,7 +25,7 @@ parentPort.on('message', ({ type }) => {
|
||||||
break
|
break
|
||||||
case 'async:arraybuffer':
|
case 'async:arraybuffer':
|
||||||
Promise.all(
|
Promise.all(
|
||||||
Array.from({ length: 100 }).map(() =>
|
Array.from({ length: isWasiTest ? 2 : 100 }).map(() =>
|
||||||
native.arrayBufferPassThrough(Uint8Array.from([1, 2, 3])),
|
native.arrayBufferPassThrough(Uint8Array.from([1, 2, 3])),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -38,7 +39,7 @@ parentPort.on('message', ({ type }) => {
|
||||||
break
|
break
|
||||||
case 'constructor':
|
case 'constructor':
|
||||||
let ellie
|
let ellie
|
||||||
for (let i = 0; i < 10000; i++) {
|
for (let i = 0; i < (isWasiTest ? 10 : 10000); i++) {
|
||||||
ellie = new native.Animal(native.Kind.Cat, 'Ellie')
|
ellie = new native.Animal(native.Kind.Cat, 'Ellie')
|
||||||
}
|
}
|
||||||
parentPort.postMessage(ellie.name)
|
parentPort.postMessage(ellie.name)
|
||||||
|
@ -47,3 +48,8 @@ parentPort.on('message', ({ type }) => {
|
||||||
throw new TypeError(`Unknown message type: ${type}`)
|
throw new TypeError(`Unknown message type: ${type}`)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}).catch((e) => {
|
||||||
|
console.error(e)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue