|
| 1 | +# Porting Plan |
| 2 | + |
| 3 | +This document tracks the progress of porting tests from Node.js's test suite into the CTS. |
| 4 | +The source directories are [`test/js-native-api`](https://github.com/nodejs/node/tree/main/test/js-native-api) |
| 5 | +and [`test/node-api`](https://github.com/nodejs/node/tree/main/test/node-api) in the Node.js repository. |
| 6 | + |
| 7 | +## API Naming Convention |
| 8 | + |
| 9 | +Node-API uses two function prefixes that are sometimes confused: |
| 10 | + |
| 11 | +- **`napi_`** — the original prefix, retained for backwards compatibility |
| 12 | +- **`node_api_`** — the newer prefix, adopted after the project was renamed from "napi" to "Node API" |
| 13 | + |
| 14 | +The prefix alone does **not** indicate whether a function is Node.js-specific or runtime-agnostic. |
| 15 | +What matters is which header the function is declared in: |
| 16 | + |
| 17 | +- `js_native_api.h` — engine-agnostic APIs, available across all Node-API runtimes |
| 18 | +- `node_api.h` — runtime-specific APIs, providing features beyond pure JavaScript value operations. |
| 19 | + |
| 20 | +For example, `node_api_is_sharedarraybuffer` carries the newer `node_api_` prefix but is declared |
| 21 | +in `js_native_api.h` and is therefore engine-agnostic. |
| 22 | + |
| 23 | +## Difficulty Ratings |
| 24 | + |
| 25 | +Difficulty is assessed on two axes: |
| 26 | +- **Size/complexity** — total lines of C/C++ and JS across all source files |
| 27 | +- **Runtime-API dependence** — pure `js_native_api.h` is cheapest; Node.js extensions and direct |
| 28 | + libuv calls require harness work or Node-only scoping |
| 29 | + |
| 30 | +| Rating | Meaning | |
| 31 | +|---|---| |
| 32 | +| Easy | Small test, pure `js_native_api.h` or trivial runtime API, straightforward 1:1 port | |
| 33 | +| Medium | Moderate size or uses a Node.js extension API that the harness will need to abstract | |
| 34 | +| Hard | Large test and/or deep libuv/worker/SEA dependency; may need new harness primitives or Node-only scoping | |
| 35 | + |
| 36 | +## Engine-specific (`js-native-api`) |
| 37 | + |
| 38 | +Tests covering the engine-specific part of Node-API, defined in `js_native_api.h`. |
| 39 | + |
| 40 | +| Directory | Status | Difficulty | |
| 41 | +|---|---|---| |
| 42 | +| `2_function_arguments` | Ported | — | |
| 43 | +| `3_callbacks` | Not ported | Easy | |
| 44 | +| `4_object_factory` | Not ported | Easy | |
| 45 | +| `5_function_factory` | Not ported | Easy | |
| 46 | +| `6_object_wrap` | Not ported | Medium | |
| 47 | +| `7_factory_wrap` | Not ported | Easy | |
| 48 | +| `8_passing_wrapped` | Not ported | Easy | |
| 49 | +| `test_array` | Not ported | Easy | |
| 50 | +| `test_bigint` | Not ported | Easy | |
| 51 | +| `test_cannot_run_js` | Not ported | Medium | |
| 52 | +| `test_constructor` | Not ported | Medium | |
| 53 | +| `test_conversions` | Not ported | Medium | |
| 54 | +| `test_dataview` | Not ported | Easy | |
| 55 | +| `test_date` | Not ported | Easy | |
| 56 | +| `test_error` | Not ported | Medium | |
| 57 | +| `test_exception` | Not ported | Medium | |
| 58 | +| `test_finalizer` | Not ported | Medium | |
| 59 | +| `test_function` | Not ported | Medium | |
| 60 | +| `test_general` | Not ported | Hard | |
| 61 | +| `test_handle_scope` | Not ported | Easy | |
| 62 | +| `test_instance_data` | Not ported | Easy | |
| 63 | +| `test_new_target` | Not ported | Easy | |
| 64 | +| `test_number` | Not ported | Easy | |
| 65 | +| `test_object` | Not ported | Hard | |
| 66 | +| `test_promise` | Not ported | Easy | |
| 67 | +| `test_properties` | Not ported | Easy | |
| 68 | +| `test_reference` | Not ported | Medium | |
| 69 | +| `test_reference_double_free` | Not ported | Easy | |
| 70 | +| `test_sharedarraybuffer` | Not ported | Medium | |
| 71 | +| `test_string` | Not ported | Medium | |
| 72 | +| `test_symbol` | Not ported | Easy | |
| 73 | +| `test_typedarray` | Not ported | Medium | |
| 74 | + |
| 75 | +## Runtime-specific (`node-api`) |
| 76 | + |
| 77 | +Tests covering the runtime-specific part of Node-API, defined in `node_api.h`. |
| 78 | + |
| 79 | +| Directory | Status | Difficulty | |
| 80 | +|---|---|---| |
| 81 | +| `1_hello_world` | Not ported | Easy | |
| 82 | +| `test_async` | Not ported | Hard | |
| 83 | +| `test_async_cleanup_hook` | Not ported | Hard | |
| 84 | +| `test_async_context` | Not ported | Hard | |
| 85 | +| `test_buffer` | Not ported | Medium | |
| 86 | +| `test_callback_scope` | Not ported | Hard | |
| 87 | +| `test_cleanup_hook` | Not ported | Medium | |
| 88 | +| `test_env_teardown_gc` | Not ported | Easy | |
| 89 | +| `test_exception` | Not ported | Easy | |
| 90 | +| `test_fatal` | Not ported | Hard | |
| 91 | +| `test_fatal_exception` | Not ported | Easy | |
| 92 | +| `test_general` | Not ported | Medium | |
| 93 | +| `test_init_order` | Not ported | Medium | |
| 94 | +| `test_instance_data` | Not ported | Hard | |
| 95 | +| `test_make_callback` | Not ported | Hard | |
| 96 | +| `test_make_callback_recurse` | Not ported | Hard | |
| 97 | +| `test_null_init` | Not ported | Medium | |
| 98 | +| `test_reference_by_node_api_version` | Not ported | Medium | |
| 99 | +| `test_sea_addon` | Not ported | Hard | |
| 100 | +| `test_threadsafe_function` | Not ported | Hard | |
| 101 | +| `test_threadsafe_function_shutdown` | Not ported | Hard | |
| 102 | +| `test_uv_loop` | Not ported | Hard | |
| 103 | +| `test_uv_threadpool_size` | Not ported | Hard | |
| 104 | +| `test_worker_buffer_callback` | Not ported | Hard | |
| 105 | +| `test_worker_terminate` | Not ported | Hard | |
| 106 | +| `test_worker_terminate_finalization` | Not ported | Hard | |
| 107 | + |
| 108 | +## Special Considerations |
| 109 | + |
| 110 | +### `node_api_post_finalizer` (`6_object_wrap`, `test_finalizer`) |
| 111 | + |
| 112 | +Both tests call `node_api_post_finalizer` to defer JS-touching work out of the GC finalizer and |
| 113 | +onto the main thread. The function is declared in `js_native_api.h` but is gated behind |
| 114 | +`NAPI_EXPERIMENTAL`, so not all runtimes may implement it yet. The CTS harness will need a |
| 115 | +platform-agnostic post-finalizer primitive that implementors can map to their own |
| 116 | +deferred-callback mechanism, or the tests need to isolate the post-finalizer cases behind a |
| 117 | +runtime capability check. |
| 118 | + |
| 119 | +### `node_api_set_prototype` / `napi_get_prototype` (`test_general`, js-native-api) |
| 120 | + |
| 121 | +The general test suite mixes `js_native_api.h` assertions with calls to `node_api_set_prototype` |
| 122 | +(gated behind `NAPI_EXPERIMENTAL`) and `napi_get_prototype` (standard). The experimental function |
| 123 | +may not be implemented by all runtimes yet. The CTS port should split the affected test cases into |
| 124 | +a stable core and an experimental annex, or guard the `node_api_set_prototype` cases with a |
| 125 | +runtime capability check. |
| 126 | + |
| 127 | +### SharedArrayBuffer backing-store creation (`test_sharedarraybuffer`) |
| 128 | + |
| 129 | +`node_api_is_sharedarraybuffer` and `node_api_create_sharedarraybuffer` are both declared in |
| 130 | +`js_native_api.h` and are engine-agnostic. However, the test also exercises creating a |
| 131 | +SharedArrayBuffer from the C side via `node_api_create_sharedarraybuffer`, which allocates |
| 132 | +backing store memory. The CTS version will need a harness-provided factory (something like |
| 133 | +`create_shared_array_buffer(size)`) that each runtime can implement using its own path. |
| 134 | + |
| 135 | +### libuv dependency (multiple `node-api` tests) |
| 136 | + |
| 137 | +The following tests call into libuv directly — `napi_get_uv_event_loop`, `uv_thread_t`, |
| 138 | +`uv_mutex_t`, `uv_async_t`, `uv_check_t`, `uv_idle_t`, `uv_queue_work`, and related APIs: |
| 139 | + |
| 140 | +- `test_async`, `test_async_cleanup_hook`, `test_async_context` |
| 141 | +- `test_callback_scope` |
| 142 | +- `test_fatal` (uses `uv_thread_t` to test cross-thread fatal errors) |
| 143 | +- `test_instance_data` (async work + threadsafe functions + `uv_thread_t`) |
| 144 | +- `test_uv_loop`, `test_uv_threadpool_size` |
| 145 | + |
| 146 | +Porting options: |
| 147 | +1. **Node-only scope** — mark these tests as Node.js-only and skip on other runtimes. |
| 148 | +2. **Harness abstraction** — introduce a minimal platform-agnostic threading/async API in the |
| 149 | + harness (e.g., `cts_thread_create`, `cts_async_schedule`) that implementors back with their |
| 150 | + own event loop primitives (libuv, tokio, etc.). |
| 151 | + |
| 152 | +### Threadsafe functions (`test_threadsafe_function`, `test_threadsafe_function_shutdown`) |
| 153 | + |
| 154 | +`test_threadsafe_function` is the largest single test (~700 total lines across C and JS), covering |
| 155 | +blocking/non-blocking queue modes, queue-full handling, multiple concurrent threads, finalization |
| 156 | +ordering, uncaught exception propagation, and high-precision timing via `uv_hrtime`. The threading |
| 157 | +primitives are libuv-specific (same concern as the section above). Porting this test likely depends |
| 158 | +on resolving the libuv abstraction question first. |
| 159 | + |
| 160 | +### Worker threads (`test_worker_buffer_callback`, `test_worker_terminate`, `test_worker_terminate_finalization`) |
| 161 | + |
| 162 | +These three tests exercise addon behavior inside Node.js worker threads: buffer finalizer delivery |
| 163 | +in worker contexts, function-call behavior under pending exceptions during worker shutdown, and |
| 164 | +wrapped-object finalization on forced worker termination. Node.js worker threads have no direct |
| 165 | +equivalent in most other Node-API runtimes. These tests are likely Node.js-only and should be |
| 166 | +scoped accordingly. |
| 167 | + |
| 168 | +### SEA — Single Executable Applications (`test_sea_addon`) |
| 169 | + |
| 170 | +`test_sea_addon` verifies that a native addon can be loaded inside a Node.js Single Executable |
| 171 | +Application. SEA is a Node.js-specific packaging feature with no equivalent in other runtimes. |
| 172 | +This test should be excluded from the CTS scope or placed in a Node-only annex. |
| 173 | + |
| 174 | +### `napi_get_node_version` (`test_general`, node-api) |
| 175 | + |
| 176 | +`test_general` calls `napi_get_node_version`, which returns the Node.js major/minor/patch version. |
| 177 | +No equivalent exists in other runtimes. The CTS port should either omit that assertion or expose a |
| 178 | +harness helper (e.g., `cts_get_runtime_version`) that runtimes can optionally implement. |
| 179 | + |
| 180 | +### Legacy module registration (`test_null_init`) |
| 181 | + |
| 182 | +`test_null_init` exercises the deprecated `NAPI_MODULE` macro with a NULL init function, calling |
| 183 | +`napi_module_register` directly. Some newer runtimes that implement Node-API may not support this |
| 184 | +legacy registration path. If so, this test should be scoped as Node-only or skipped on runtimes |
| 185 | +that only support `NAPI_MODULE_INIT`. |
0 commit comments