diff --git a/test/node-api/test_async_cleanup_hook/binding.c b/test/node-api/test_async_cleanup_hook/binding.c index 4e88479574fb01..8ffd45af6085cb 100644 --- a/test/node-api/test_async_cleanup_hook/binding.c +++ b/test/node-api/test_async_cleanup_hook/binding.c @@ -4,6 +4,7 @@ #include #include "../../js-native-api/common.h" +static int cleanup_hook_count = 0; static void MustNotCall(napi_async_cleanup_hook_handle hook, void* arg) { assert(0); } @@ -21,6 +22,7 @@ static struct AsyncData* CreateAsyncData() { } static void AfterCleanupHookTwo(uv_handle_t* handle) { + cleanup_hook_count++; struct AsyncData* data = (struct AsyncData*) handle->data; napi_status status = napi_remove_async_cleanup_hook(data->handle); assert(status == napi_ok); @@ -28,10 +30,12 @@ static void AfterCleanupHookTwo(uv_handle_t* handle) { } static void AfterCleanupHookOne(uv_async_t* async) { + cleanup_hook_count++; uv_close((uv_handle_t*) async, AfterCleanupHookTwo); } static void AsyncCleanupHook(napi_async_cleanup_hook_handle handle, void* arg) { + cleanup_hook_count++; struct AsyncData* data = (struct AsyncData*) arg; uv_loop_t* loop; napi_status status = napi_get_uv_event_loop(data->env, &loop); @@ -44,7 +48,31 @@ static void AsyncCleanupHook(napi_async_cleanup_hook_handle handle, void* arg) { uv_async_send(&data->async); } +static void ObjectFinalizer(napi_env env, void* data, void* hint) { + // AsyncCleanupHook and its subsequent callbacks are called twice. + assert(cleanup_hook_count == 6); + + napi_ref* ref = data; + NODE_API_CALL_RETURN_VOID(env, napi_delete_reference(env, *ref)); + free(ref); +} + +static void CreateObjectWrap(napi_env env) { + napi_value js_obj; + napi_ref* ref = malloc(sizeof(*ref)); + NODE_API_CALL_RETURN_VOID(env, napi_create_object(env, &js_obj)); + NODE_API_CALL_RETURN_VOID( + env, napi_wrap(env, js_obj, ref, ObjectFinalizer, NULL, ref)); + // create a strong reference so that the finalizer is called at shutdown. + NODE_API_CALL_RETURN_VOID(env, napi_reference_ref(env, *ref, NULL)); +} + static napi_value Init(napi_env env, napi_value exports) { + // Reinitialize the static variable to be compatible with musl libc. + cleanup_hook_count = 0; + // Create object wrap before cleanup hooks. + CreateObjectWrap(env); + { struct AsyncData* data = CreateAsyncData(); data->env = env; @@ -64,6 +92,9 @@ static napi_value Init(napi_env env, napi_value exports) { napi_remove_async_cleanup_hook(must_not_call_handle); } + // Create object wrap after cleanup hooks. + CreateObjectWrap(env); + return NULL; } diff --git a/test/node-api/test_cleanup_hook/binding.c b/test/node-api/test_cleanup_hook/binding.c index 3e0ddfe9e3c59b..4dd7b3f5f2684e 100644 --- a/test/node-api/test_cleanup_hook/binding.c +++ b/test/node-api/test_cleanup_hook/binding.c @@ -1,19 +1,48 @@ +#include +#include +#include "../../js-native-api/common.h" #include "node_api.h" #include "uv.h" -#include "../../js-native-api/common.h" +static int cleanup_hook_count = 0; static void cleanup(void* arg) { + cleanup_hook_count++; printf("cleanup(%d)\n", *(int*)(arg)); } static int secret = 42; static int wrong_secret = 17; +static void ObjectFinalizer(napi_env env, void* data, void* hint) { + // cleanup is called once. + assert(cleanup_hook_count == 1); + + napi_ref* ref = data; + NODE_API_CALL_RETURN_VOID(env, napi_delete_reference(env, *ref)); + free(ref); +} + +static void CreateObjectWrap(napi_env env) { + napi_value js_obj; + napi_ref* ref = malloc(sizeof(*ref)); + NODE_API_CALL_RETURN_VOID(env, napi_create_object(env, &js_obj)); + NODE_API_CALL_RETURN_VOID( + env, napi_wrap(env, js_obj, ref, ObjectFinalizer, NULL, ref)); + // create a strong reference so that the finalizer is called at shutdown. + NODE_API_CALL_RETURN_VOID(env, napi_reference_ref(env, *ref, NULL)); +} + static napi_value Init(napi_env env, napi_value exports) { + // Create object wrap before cleanup hooks. + CreateObjectWrap(env); + napi_add_env_cleanup_hook(env, cleanup, &wrong_secret); napi_add_env_cleanup_hook(env, cleanup, &secret); napi_remove_env_cleanup_hook(env, cleanup, &wrong_secret); + // Create object wrap after cleanup hooks. + CreateObjectWrap(env); + return NULL; } diff --git a/test/node-api/test_cleanup_hook/test.js b/test/node-api/test_cleanup_hook/test.js index 354f4449045c17..300551ce678be1 100644 --- a/test/node-api/test_cleanup_hook/test.js +++ b/test/node-api/test_cleanup_hook/test.js @@ -6,7 +6,8 @@ const child_process = require('child_process'); if (process.argv[2] === 'child') { require(`./build/${common.buildType}/binding`); } else { - const { stdout } = + const { stdout, status, signal } = child_process.spawnSync(process.execPath, [__filename, 'child']); + assert.strictEqual(status, 0, `process exited with status(${status}) and signal(${signal})`); assert.strictEqual(stdout.toString().trim(), 'cleanup(42)'); }