From e97c65fd1ebea687c882cd58b14306af9998676a Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Fri, 23 Aug 2024 19:06:35 -0700 Subject: [PATCH] Add 59 more node tests + copy node test fixtures (#13495) --- .gitattributes | 3 + .vscode/settings.json | 3 + test/js/node/test/.gitignore | 10 + test/js/node/test/common/arraystream.js | 23 + test/js/node/test/common/assertSnapshot.js | 97 + test/js/node/test/common/benchmark.js | 43 + test/js/node/test/common/child_process.js | 146 + test/js/node/test/common/countdown.js | 28 + test/js/node/test/common/cpu-prof.js | 50 + test/js/node/test/common/crypto.js | 132 + test/js/node/test/common/debugger.js | 183 + test/js/node/test/common/dns.js | 341 ++ test/js/node/test/common/duplexpair.js | 48 + test/js/node/test/common/fixtures.js | 59 + test/js/node/test/common/fixtures.mjs | 17 + test/js/node/test/common/gc.js | 127 + test/js/node/test/common/globals.js | 146 + test/js/node/test/common/heap.js | 249 ++ test/js/node/test/common/hijackstdio.js | 32 + test/js/node/test/common/http2.js | 148 + test/js/node/test/common/index.js | 1156 ++++++ test/js/node/test/common/index.mjs | 110 + test/js/node/test/common/inspector-helper.js | 537 +++ test/js/node/test/common/internet.js | 58 + test/js/node/test/common/measure-memory.js | 57 + test/js/node/test/common/ongc.js | 32 + test/js/node/test/common/package.json | 3 + test/js/node/test/common/prof.js | 67 + test/js/node/test/common/report.js | 339 ++ test/js/node/test/common/require-as.js | 27 + test/js/node/test/common/sea.js | 133 + test/js/node/test/common/shared-lib-util.js | 50 + test/js/node/test/common/snapshot.js | 65 + test/js/node/test/common/tick.js | 13 + test/js/node/test/common/tls.js | 176 + test/js/node/test/common/tmpdir.js | 1 - test/js/node/test/common/udppair.js | 101 + test/js/node/test/common/v8.js | 70 + test/js/node/test/common/wasi.js | 43 + test/js/node/test/common/wpt.js | 980 +++++ .../fixtures/.empty-hidden-repl-history-file} | 0 .../test/fixtures/.empty-repl-history-file | 0 test/js/node/test/fixtures/.node_repl_history | 2 + .../node/test/fixtures/0-dns/0-dns-cert.pem | 19 + .../js/node/test/fixtures/0-dns/0-dns-key.pem | 27 + .../node/test/fixtures/0-dns/0-dns-rsapub.der | Bin 0 -> 270 bytes test/js/node/test/fixtures/0-dns/README.md | 28 + .../node/test/fixtures/0-dns/create-cert.js | 75 + test/js/node/test/fixtures/0-dns/package.json | 16 + test/js/node/test/fixtures/GH-1899-output.js | 23 + test/js/node/test/fixtures/GH-7131/a.js | 5 + test/js/node/test/fixtures/GH-7131/b.js | 2 + test/js/node/test/fixtures/GH-892-request.js | 50 + test/js/node/test/fixtures/a.js | 46 + test/js/node/test/fixtures/aead-vectors.js | 703 ++++ test/js/node/test/fixtures/altdocs.md | 2 + test/js/node/test/fixtures/apilinks/buffer.js | 12 + .../node/test/fixtures/apilinks/buffer.json | 4 + test/js/node/test/fixtures/apilinks/class.js | 12 + .../js/node/test/fixtures/apilinks/class.json | 5 + .../js/node/test/fixtures/apilinks/exports.js | 13 + .../node/test/fixtures/apilinks/exports.json | 6 + test/js/node/test/fixtures/apilinks/mod.js | 11 + test/js/node/test/fixtures/apilinks/mod.json | 3 + .../node/test/fixtures/apilinks/prototype.js | 13 + .../test/fixtures/apilinks/prototype.json | 5 + .../js/node/test/fixtures/apilinks/reverse.js | 13 + .../node/test/fixtures/apilinks/reverse.json | 5 + test/js/node/test/fixtures/apilinks/root.js | 10 + test/js/node/test/fixtures/apilinks/root.json | 2 + .../node/test/fixtures/assert-first-line.js | 2 + .../js/node/test/fixtures/assert-long-line.js | 1 + test/js/node/test/fixtures/async-error.js | 27 + test/js/node/test/fixtures/b/c.js | 49 + test/js/node/test/fixtures/b/d.js | 33 + test/js/node/test/fixtures/b/package/index.js | 23 + test/js/node/test/fixtures/baz.js | 1 + .../node/test/fixtures/catch-stdout-error.js | 38 + .../fixtures/child-process-echo-options.js | 1 + .../child-process-message-and-exit.js | 3 + .../test/fixtures/child-process-persistent.js | 1 + .../test/fixtures/child-process-spawn-node.js | 11 + .../child-process-stay-alive-forever.js | 3 + .../child_process_should_emit_error.js | 29 + test/js/node/test/fixtures/cjs-module-wrap.js | 10 + .../node/test/fixtures/cjs-module-wrapper.js | 23 + .../test/fixtures/cluster-preload-test.js | 7 + test/js/node/test/fixtures/cluster-preload.js | 12 + .../test/fixtures/clustered-server/app.js | 36 + .../node/test/fixtures/console/2100bytes.js | 68 + .../test/fixtures/console/2100bytes.snapshot | 42 + test/js/node/test/fixtures/console/console.js | 5 + .../test/fixtures/console/console.snapshot | 9 + .../console/console_low_stack_space.js | 34 + .../console/console_low_stack_space.snapshot | 1 + .../test/fixtures/console/force_colors.js | 5 + .../fixtures/console/force_colors.snapshot | 1 + .../node/test/fixtures/console/hello_world.js | 25 + .../fixtures/console/hello_world.snapshot | 1 + .../test/fixtures/console/stack_overflow.js | 37 + .../fixtures/console/stack_overflow.snapshot | 8 + .../test/fixtures/copy/kitchen-sink/README.md | 1 + .../fixtures/copy/kitchen-sink/a/b/README2.md | 1 + .../fixtures/copy/kitchen-sink/a/b/index.js | 3 + .../fixtures/copy/kitchen-sink/a/c/README2.md | 1 + .../copy/kitchen-sink/a/c/d/README3.md | 1 + .../fixtures/copy/kitchen-sink/a/c/d/index.js | 3 + .../fixtures/copy/kitchen-sink/a/c/index.js | 3 + .../fixtures/copy/kitchen-sink/a/index.js | 3 + .../test/fixtures/copy/kitchen-sink/index.js | 3 + test/js/node/test/fixtures/crash.wasm | Bin 0 -> 36 bytes test/js/node/test/fixtures/crypto/aes_cbc.js | 144 + test/js/node/test/fixtures/crypto/aes_ctr.js | 99 + test/js/node/test/fixtures/crypto/aes_gcm.js | 134 + test/js/node/test/fixtures/crypto/ecdsa.js | 113 + test/js/node/test/fixtures/crypto/eddsa.js | 51 + test/js/node/test/fixtures/crypto/hmac.js | 52 + test/js/node/test/fixtures/crypto/rsa.js | 330 ++ test/js/node/test/fixtures/crypto/rsa_pkcs.js | 138 + test/js/node/test/fixtures/crypto/rsa_pss.js | 149 + .../node/test/fixtures/cycles/folder/foo.js | 26 + test/js/node/test/fixtures/cycles/root.js | 30 + .../js/node/test/fixtures/cycles/warning-a.js | 1 + .../js/node/test/fixtures/cycles/warning-b.js | 3 + .../cycles/warning-esm-half-transpiled-a.js | 1 + .../cycles/warning-esm-half-transpiled-b.js | 2 + .../cycles/warning-esm-transpiled-a.js | 2 + .../cycles/warning-esm-transpiled-b.js | 1 + .../cycles/warning-moduleexports-a.js | 2 + .../cycles/warning-moduleexports-b.js | 1 + .../cycles/warning-moduleexports-class-a.js | 11 + .../cycles/warning-moduleexports-class-b.js | 1 + .../cycles/warning-skip-proxy-traps-a.js | 17 + .../cycles/warning-skip-proxy-traps-b.js | 10 + .../test/fixtures/debugger-repeat-last.js | 7 + .../debugger-util-regression-fixture.js | 4 + test/js/node/test/fixtures/debugger/alive.js | 5 + .../node/test/fixtures/debugger/backtrace.js | 30 + test/js/node/test/fixtures/debugger/break.js | 16 + .../node/test/fixtures/debugger/cjs/index.js | 5 + .../node/test/fixtures/debugger/cjs/other.js | 3 + test/js/node/test/fixtures/debugger/empty.js | 0 .../node/test/fixtures/debugger/exceptions.js | 10 + .../test/fixtures/debugger/three-lines.js | 3 + .../test/fixtures/debugger/twenty-lines.js | 20 + .../node/test/fixtures/debugger/use-strict.js | 2 + test/js/node/test/fixtures/define-global.js | 1 + .../fixtures/deprecated-userland-class.js | 15 + .../fixtures/deprecated-userland-function.js | 6 + .../fixtures/deprecated-userland-subclass.js | 19 + test/js/node/test/fixtures/deprecated.js | 7 + test/js/node/test/fixtures/destroy-stdin.js | 1 + .../test/fixtures/disable-warning-worker.js | 4 + test/js/node/test/fixtures/disable-warning.js | 15 + test/js/node/test/fixtures/doc_inc_1.md | 3 + test/js/node/test/fixtures/doc_inc_2.md | 3 + .../doc_with_backticks_in_headings.md | 13 + test/js/node/test/fixtures/doc_with_yaml.md | 34 + .../document_with_cjs_and_esm_code_snippet.md | 11 + .../document_with_esm_and_cjs_code_snippet.md | 11 + .../node/test/fixtures/document_with_links.md | 20 + .../fixtures/document_with_special_heading.md | 4 + .../node/test/fixtures/dotenv/basic-valid.env | 1 + .../fixtures/dotenv/eof-without-value.env | 2 + .../node/test/fixtures/dotenv/multiline.env | 7 + .../test/fixtures/dotenv/node-options.env | 6 + .../test/fixtures/dotenv/uv-threadpool.env | 1 + test/js/node/test/fixtures/dotenv/valid.env | 66 + .../js/node/test/fixtures/echo-close-check.js | 40 + test/js/node/test/fixtures/echo.js | 31 + test/js/node/test/fixtures/elipses.txt | 1 + test/js/node/test/fixtures/empty-with-bom.txt | 1 + test/js/node/test/fixtures/empty.cjs | 0 test/js/node/test/fixtures/empty.js | 0 test/js/node/test/fixtures/empty.json | 1 + test/js/node/test/fixtures/empty.txt | 0 test/js/node/test/fixtures/emptyframe.http2 | Bin 0 -> 4233 bytes .../fixtures/errors/async_error_eval_cjs.js | 39 + .../errors/async_error_eval_cjs.snapshot | 7 + .../fixtures/errors/async_error_eval_esm.js | 41 + .../errors/async_error_eval_esm.snapshot | 7 + .../errors/async_error_microtask_main.js | 13 + .../async_error_microtask_main.snapshot | 6 + .../errors/async_error_nexttick_main.js | 13 + .../errors/async_error_nexttick_main.snapshot | 7 + .../fixtures/errors/async_error_sync_esm.mjs | 12 + .../errors/async_error_sync_esm.snapshot | 6 + .../fixtures/errors/async_error_sync_main.js | 13 + .../errors/async_error_sync_main.snapshot | 6 + .../test/fixtures/errors/core_line_numbers.js | 13 + .../errors/core_line_numbers.snapshot | 10 + .../errors/error_aggregateTwoErrors.js | 15 + .../errors/error_aggregateTwoErrors.snapshot | 20 + .../node/test/fixtures/errors/error_exit.js | 32 + .../test/fixtures/errors/error_exit.snapshot | 18 + .../test/fixtures/errors/error_with_nul.js | 12 + .../fixtures/errors/error_with_nul.snapshot | Bin 0 -> 174 bytes .../events_unhandled_error_common_trace.js | 22 + ...ents_unhandled_error_common_trace.snapshot | 12 + .../errors/events_unhandled_error_nexttick.js | 9 + .../events_unhandled_error_nexttick.snapshot | 10 + .../errors/events_unhandled_error_sameline.js | 6 + .../events_unhandled_error_sameline.snapshot | 10 + .../errors/events_unhandled_error_subclass.js | 7 + .../events_unhandled_error_subclass.snapshot | 10 + .../node/test/fixtures/errors/force_colors.js | 1 + .../fixtures/errors/force_colors.snapshot | 15 + .../errors/if-error-has-good-stack.js | 24 + .../errors/if-error-has-good-stack.snapshot | 25 + .../errors/promise_always_throw_unhandled.js | 16 + .../promise_always_throw_unhandled.snapshot | 17 + .../promise_unhandled_warn_with_error.js | 8 + ...promise_unhandled_warn_with_error.snapshot | 11 + .../test-no-extra-info-on-fatal-exception.js | 7 + ...-no-extra-info-on-fatal-exception.snapshot | 6 + .../fixtures/errors/throw_custom_error.js | 27 + .../errors/throw_custom_error.snapshot | 7 + .../errors/throw_error_with_getter_throw.js | 10 + .../throw_error_with_getter_throw.snapshot | 8 + .../errors/throw_in_line_with_tabs.js | 34 + .../errors/throw_in_line_with_tabs.snapshot | 8 + .../test/fixtures/errors/throw_non_error.js | 27 + .../fixtures/errors/throw_non_error.snapshot | 7 + .../node/test/fixtures/errors/throw_null.js | 26 + .../test/fixtures/errors/throw_null.snapshot | 8 + .../test/fixtures/errors/throw_undefined.js | 26 + .../fixtures/errors/throw_undefined.snapshot | 8 + .../test/fixtures/errors/timeout_throw.js | 28 + .../fixtures/errors/timeout_throw.snapshot | 10 + .../undefined_reference_in_new_context.js | 31 + ...ndefined_reference_in_new_context.snapshot | 13 + .../unhandled_promise_trace_warnings.js | 5 + .../unhandled_promise_trace_warnings.snapshot | 29 + .../assertionless-json-import.mjs | 24 + .../builtin-named-exports-loader.mjs | 59 + .../builtin-named-exports.mjs | 17 + .../es-module-loaders/byop-dummy-loader.mjs | 30 + .../es-module-loaders/example-loader.mjs | 46 + .../hook-resolve-type-loader.mjs | 25 + .../es-module-loaders/hook-resolve-type.mjs | 18 + .../es-module-loaders/hooks-custom.mjs | 109 + .../hooks-initialize-port.mjs | 16 + .../es-module-loaders/hooks-initialize.mjs | 7 + .../es-module-loaders/hooks-input.mjs | 90 + .../es-module-loaders/http-loader.mjs | 22 + .../fixtures/es-module-loaders/js-as-esm.js | 1 + .../fixtures/es-module-loaders/loader-dep.js | 1 + .../es-module-loaders/loader-edge-cases.mjs | 13 + .../loader-invalid-format.mjs | 20 + .../es-module-loaders/loader-invalid-url.mjs | 10 + .../loader-load-bad-next-context.mjs | 3 + .../loader-load-bad-next-url.mjs | 3 + .../loader-load-dynamic-import.mjs | 14 + .../loader-load-foo-or-42.mjs | 19 + .../loader-load-impersonating-next-url.mjs | 3 + .../loader-load-incomplete.mjs | 14 + .../loader-load-next-modified.mjs | 11 + .../loader-load-null-return.mjs | 3 + .../loader-load-passing-modified-context.mjs | 6 + .../loader-load-passthru.mjs | 14 + ...loader-load-receiving-modified-context.mjs | 7 + .../es-module-loaders/loader-log-args.mjs | 31 + .../es-module-loaders/loader-resolve-42.mjs | 17 + .../loader-resolve-bad-next-context.mjs | 3 + .../loader-resolve-bad-next-specifier.mjs | 3 + .../loader-resolve-dynamic-import.mjs | 14 + .../es-module-loaders/loader-resolve-foo.mjs | 15 + .../loader-resolve-incomplete.mjs | 13 + .../loader-resolve-multiple-next-calls.mjs | 9 + .../loader-resolve-next-modified.mjs | 19 + .../loader-resolve-null-return.mjs | 3 + ...oader-resolve-passing-modified-context.mjs | 6 + .../loader-resolve-passthru.mjs | 14 + ...der-resolve-receiving-modified-context.mjs | 7 + .../loader-resolve-shortcircuit.mjs | 14 + .../loader-resolve-strip-xxx.mjs | 10 + .../loader-resolve-strip-yyy.mjs | 7 + .../es-module-loaders/loader-shared-dep.mjs | 11 + ...oader-this-value-inside-hook-functions.mjs | 21 + .../loader-unknown-builtin-module.mjs | 7 + .../loader-with-custom-condition.mjs | 16 + .../es-module-loaders/loader-with-dep.mjs | 11 + .../loader-with-too-many-args.mjs | 7 + .../missing-dynamic-instantiate-hook.mjs | 17 + .../es-module-loaders/mock-loader.mjs | 133 + .../test/fixtures/es-module-loaders/mock.mjs | 70 + .../module-named-exports.mjs | 2 + .../import.meta.never-resolve.mjs | 5 + .../never-settling-resolve-step/loader.mjs | 10 + .../never-load.cjs | 7 + .../never-load.mjs | 5 + .../never-resolve.cjs | 7 + .../never-resolve.mjs | 5 + .../never-settling-resolve-step/race.cjs | 7 + .../never-settling-resolve-step/race.mjs | 7 + .../not-found-assert-loader.mjs | 16 + .../es-module-loaders/preset-cjs-source.mjs | 21 + .../es-module-loaders/register-loader.cjs | 4 + .../es-module-loaders/register-loader.mjs | 4 + .../register-programmatically-loader-load.mjs | 4 + ...gister-programmatically-loader-resolve.mjs | 3 + .../es-module-loaders/string-sources.mjs | 43 + .../es-module-loaders/syntax-error.mjs | 2 + ...enable-load-hook-rejected-no-arguments.mjs | 10 + .../thenable-load-hook-rejected.mjs | 10 + .../es-module-loaders/thenable-load-hook.mjs | 10 + .../es-module-loaders/throw-undefined.mjs | 3 + .../es-module-require-cache/counter.js | 2 + .../fixtures/es-module-require-cache/echo.cjs | 1 + .../es-module-require-cache/preload.js | 1 + .../fixtures/es-module-specifiers/index.mjs | 11 + .../es-module-specifiers/package.json | 1 + .../node/test/fixtures/es-module-url/empty.js | 0 .../test/fixtures/es-module-url/native.mjs | 2 + .../es-modules/builtin-imports-case.mjs | 5 + .../es-modules/cjs-esm-esm-cycle/a.mjs | 1 + .../es-modules/cjs-esm-esm-cycle/b.mjs | 2 + .../es-modules/cjs-esm-esm-cycle/c.cjs | 1 + .../test/fixtures/es-modules/cjs-esm-esm.js | 1 + .../node/test/fixtures/es-modules/cjs-esm.js | 1 + .../es-modules/cjs-exports-invalid.mjs | 1 + .../test/fixtures/es-modules/cjs-exports.mjs | 36 + .../test/fixtures/es-modules/cjs-file.cjs | 1 + test/js/node/test/fixtures/es-modules/cjs.js | 5 + .../es-modules/conditional-exports.js | 1 + .../es-modules/conditional-exports.mjs | 1 + .../test/fixtures/es-modules/data-import.mjs | 2 + test/js/node/test/fixtures/es-modules/dep1.js | 1 + test/js/node/test/fixtures/es-modules/dep2.js | 1 + .../deprecated-folders-ignore/main.js | 1 + .../deprecated-folders-ignore/package.json | 3 + .../es-modules/dynamic-import/import.cjs | 2 + .../es-modules/dynamic-import/import.mjs | 2 + .../fixtures/es-modules/es-note-error-1.cjs | 1 + .../fixtures/es-modules/es-note-error-1.mjs | 1 + .../fixtures/es-modules/es-note-error-2.cjs | 1 + .../fixtures/es-modules/es-note-error-2.mjs | 1 + .../fixtures/es-modules/es-note-error-3.cjs | 1 + .../fixtures/es-modules/es-note-error-3.mjs | 1 + .../fixtures/es-modules/es-note-error-4.cjs | 1 + .../fixtures/es-modules/es-note-error-4.mjs | 1 + .../es-note-promiserej-import-2.cjs | 1 + .../es-note-unexpected-export-1.cjs | 2 + .../es-note-unexpected-export-2.cjs | 4 + .../es-note-unexpected-import-1.cjs | 1 + .../es-note-unexpected-import-3.cjs | 1 + .../es-note-unexpected-import-4.cjs | 1 + .../es-note-unexpected-import-5.cjs | 1 + .../es-modules/esm-cjs-esm-cycle/a.mjs | 3 + .../es-modules/esm-cjs-esm-cycle/b.cjs | 3 + .../esm-cjs-esm-cycle/require-a.cjs | 1 + .../esm-cjs-esm-cycle/require-b.cjs | 1 + .../es-modules/esm-cjs-esm-esm-cycle/a.mjs | 1 + .../es-modules/esm-cjs-esm-esm-cycle/b.cjs | 1 + .../es-modules/esm-cjs-esm-esm-cycle/c.mjs | 1 + .../es-modules/esm-esm-cjs-esm-cycle/a.mjs | 15 + .../es-modules/esm-esm-cjs-esm-cycle/b.mjs | 3 + .../es-modules/esm-esm-cjs-esm-cycle/c.mjs | 5 + .../es-modules/esm-esm-cjs-esm-cycle/d.mjs | 3 + .../esm-esm-cjs-esm-esm-cycle/a.mjs | 1 + .../esm-esm-cjs-esm-esm-cycle/b.mjs | 1 + .../esm-esm-cjs-esm-esm-cycle/c.cjs | 1 + .../esm-esm-cjs-esm-esm-cycle/z.mjs | 1 + .../es-modules/esm-snapshot-mutator.js | 4 + .../test/fixtures/es-modules/esm-snapshot.js | 2 + .../es-modules/esm-top-level-await.mjs | 7 + .../export-name-code-injection.wasm | Bin 0 -> 98 bytes .../es-modules/export-name-syntax-error.wasm | Bin 0 -> 37 bytes .../fixtures/es-modules/exports-both/load.cjs | 1 + .../test/fixtures/es-modules/exports-cases.js | 9 + .../fixtures/es-modules/exports-cases2.js | 29 + .../fixtures/es-modules/exports-cases3.js | 25 + .../exports-import-default/load.cjs | 1 + .../es-modules/exports-import-only/load.cjs | 2 + .../es-modules/exports-require-only/load.cjs | 1 + .../js/node/test/fixtures/es-modules/file.ext | 3 + .../test/fixtures/es-modules/file.unknown | 0 .../folder%25with percentage#/index.js | 1 + .../test/fixtures/es-modules/import-esm.mjs | 3 + .../es-modules/import-invalid-ext.mjs | 1 + .../es-modules/import-invalid-pjson.mjs | 1 + .../es-modules/import-json-named-export.mjs | 1 + .../test/fixtures/es-modules/import-name.wasm | Bin 0 -> 237 bytes .../es-modules/import-process-exit.mjs | 1 + .../es-modules/import-resolve-exports.mjs | 4 + .../test/fixtures/es-modules/imported-esm.mjs | 1 + .../fixtures/es-modules/imports-loose.mjs | 1 + .../fixtures/es-modules/imports-noext.mjs | 1 + .../test/fixtures/es-modules/invalid-cjs.js | 1 + .../es-modules/invalid-posix-host.mjs | 1 + .../es-modules/json-cache/another.cjs | 7 + .../fixtures/es-modules/json-cache/mod.cjs | 7 + .../fixtures/es-modules/json-cache/test.json | 5 + .../test/fixtures/es-modules/json-modules.mjs | 1 + .../legacy-main-resolver/index-js/index.js | 1 + .../index-json/index.json | 1 + .../index-node/index.node | 0 .../js/node/test/fixtures/es-modules/loop.mjs | 15 + .../js/node/test/fixtures/es-modules/loose.js | 3 + .../node/test/fixtures/es-modules/message.mjs | 1 + .../test/fixtures/es-modules/mjs-file.mjs | 1 + .../module-counter-by-type/index.js | 3 + .../module-counter-by-type/package.json | 4 + .../fixtures/es-modules/network-import.mjs | 1 + test/js/node/test/fixtures/es-modules/noext | 1 + .../node/test/fixtures/es-modules/noext-esm | 2 + .../node/test/fixtures/es-modules/noext-wasm | Bin 0 -> 136 bytes .../bare-import-double.mjs | 1 + .../bare-import-single.mjs | 1 + .../package-cjs-named-error/double-quote.mjs | 1 + .../escaped-single-quote.mjs | 1 + .../package-cjs-named-error/fail.cjs | 4 + .../package-cjs-named-error/json-hack.mjs | 1 + .../package-cjs-named-error/json-hack/fail.js | 3 + .../json-hack/package.json | 3 + .../package-cjs-named-error/multi-line.mjs | 4 + .../package-cjs-named-error/oh'no.cjs | 3 + .../package-cjs-named-error/package.json | 5 + .../renamed-import.mjs | 1 + .../package-cjs-named-error/single-quote.mjs | 1 + .../package-default-extension/index.cjs | 1 + .../package-default-extension/index.mjs | 1 + .../package-ends-node_modules/index.js | 3 + .../package-ends-node_modules/package.json | 3 + .../echo-require-cache.js | 1 + .../package-type-commonjs/imports-esm.js | 1 + .../package-type-commonjs/imports-esm.mjs | 1 + .../es-modules/package-type-commonjs/index.js | 3 + .../package-type-commonjs/module.js | 2 + .../package-type-commonjs/package.json | 4 + .../es-modules/package-type-module/cjs.js | 1 + .../es-modules/package-type-module/esm.js | 1 + .../package-type-module/extension.unknown | 1 + .../package-type-module/imports-commonjs.cjs | 1 + .../package-type-module/imports-commonjs.mjs | 1 + .../package-type-module/imports-noext.mjs | 1 + .../imports-unknownext.mjs | 1 + .../es-modules/package-type-module/index.js | 4 + .../nested-default-type/module.js | 1 + .../nested-default-type/package.json | 1 + .../es-modules/package-type-module/noext-esm | 2 + .../es-modules/package-type-module/noext-wasm | Bin 0 -> 136 bytes .../package-type-module/package.json | 4 + .../package-type-module/wasm-dep.mjs | 15 + .../es-modules/package-without-pjson/index.js | 7 + .../commonjs-wrapper-variables.js | 6 + .../package-without-type/commonjs.js | 2 + .../package-without-type/detected-as-esm.js | 2 + .../es-modules/package-without-type/file#1.js | 1 + .../package-without-type/imports-commonjs.cjs | 1 + .../package-without-type/imports-commonjs.mjs | 1 + .../package-without-type/imports-esm.js | 1 + .../package-without-type/imports-esm.mjs | 1 + .../package-without-type/imports-noext-cjs.js | 1 + .../imports-noext-cjs.mjs | 1 + .../package-without-type/imports-noext-esm.js | 1 + .../imports-noext-esm.mjs | 1 + .../es-modules/package-without-type/index.js | 3 + .../es-modules/package-without-type/module.js | 2 + .../es-modules/package-without-type/noext-cjs | 2 + .../es-modules/package-without-type/noext-esm | 3 + .../package-without-type/package.json | 3 + .../es-modules/pattern-trailing-slash.mjs | 1 + .../es-modules/pjson-invalid/package.json | 1 + .../fixtures/es-modules/pjson-main/main.mjs | 1 + .../es-modules/pjson-main/package.json | 3 + .../es-modules/pkgimports/importbranch.js | 2 + .../es-modules/pkgimports/importer.js | 4 + .../es-modules/pkgimports/package.json | 34 + .../es-modules/pkgimports/requirebranch.js | 2 + .../pkgimports/sub/internal/test.js | 3 + .../fixtures/es-modules/pkgimports/sub/x.js | 2 + .../fixtures/es-modules/pkgimports/test.js | 1 + .../node/test/fixtures/es-modules/print-3.mjs | 1 + .../test/fixtures/es-modules/process-exit.mjs | 2 + .../fixtures/es-modules/reference-error.mjs | 3 + .../es-modules/require-and-import/load.cjs | 2 + .../es-modules/require-and-import/load.mjs | 2 + .../test/fixtures/es-modules/require-cjs.mjs | 5 + .../es-modules/require-reference-error.cjs | 2 + .../es-modules/require-syntax-error.cjs | 2 + .../es-modules/require-throw-error.cjs | 2 + .../test/fixtures/es-modules/required-cjs.js | 3 + .../node/test/fixtures/es-modules/runmain.mjs | 7 + .../self-deprecated-folders/main.js | 2 + .../self-deprecated-folders/package.json | 11 + .../es-modules/should-not-be-resolved.mjs | 1 + .../node/test/fixtures/es-modules/simple.wasm | Bin 0 -> 136 bytes .../test/fixtures/es-modules/stateful.mjs | 5 + .../node/test/fixtures/es-modules/symlink.mjs | 1 + .../test/fixtures/es-modules/syntax-error.mjs | 1 + .../fixtures/es-modules/test-esm-comma,.mjs | 1 + .../test-esm-double-encoding-native%20.mjs | 6 + .../test/fixtures/es-modules/test-esm-ok.mjs | 2 + .../test/fixtures/es-modules/throw-error.mjs | 1 + .../node/test/fixtures/es-modules/tla/a.mjs | 7 + .../node/test/fixtures/es-modules/tla/b.mjs | 3 + .../node/test/fixtures/es-modules/tla/c.mjs | 3 + .../node/test/fixtures/es-modules/tla/d.mjs | 6 + .../fixtures/es-modules/tla/execution.mjs | 3 + .../test/fixtures/es-modules/tla/order.mjs | 1 + .../test/fixtures/es-modules/tla/parent.mjs | 9 + .../fixtures/es-modules/tla/process-exit.mjs | 1 + .../es-modules/tla/rejected-withexitcode.mjs | 2 + .../test/fixtures/es-modules/tla/rejected.mjs | 1 + .../es-modules/tla/require-execution.js | 1 + .../test/fixtures/es-modules/tla/resolved.mjs | 1 + .../unresolved-with-worker-process-exit.mjs | 8 + .../tla/unresolved-withexitcode.mjs | 2 + .../fixtures/es-modules/tla/unresolved.mjs | 1 + .../test/fixtures/es-modules/wasm-dep.mjs | 13 + .../test/fixtures/es-modules/wasm-modules.mjs | 2 + test/js/node/test/fixtures/exit.js | 22 + test/js/node/test/fixtures/experimental.json | 3 + .../fixtures/exports-function-with-param.js | 1 + .../test/fixtures/external-repl-module.js | 3 + test/js/node/test/fixtures/failcounter.js | 2 + test/js/node/test/fixtures/failmustcall1.js | 3 + test/js/node/test/fixtures/failmustcall2.js | 3 + .../test/fixtures/file-to-read-with-bom.txt | 3 + .../fixtures/file-to-read-without-bom.txt | 3 + test/js/node/test/fixtures/fixture.ini | 19 + test/js/node/test/fixtures/foo | 2 + test/js/node/test/fixtures/gc.js | 9 + test/js/node/test/fixtures/global/plain.js | 25 + .../node/test/fixtures/google_ssl_hello.bin | Bin 0 -> 517 bytes test/js/node/test/fixtures/guess-hash-seed.js | 165 + .../test/fixtures/icu-punycode-toascii.json | 149 + .../fixtures/inspector-global-function.mjs | 17 + .../dep.js | 1 + .../main.js | 1 + test/js/node/test/fixtures/inspector-open.js | 14 + .../test/fixtures/internal-modules/index.js | 1 + .../node/test/fixtures/intrinsic-mutation.js | 10 + test/js/node/test/fixtures/invalid.json | 5 + test/js/node/test/fixtures/is-object.js | 2 + test/js/node/test/fixtures/ispreloading.js | 2 + .../module-stub.json | 1 + .../module-stub/index.js | 22 + .../one-trailing-slash/two/three.js | 22 + .../module-stub/one/two/three.js | 22 + .../module-stub/package.json | 7 + .../js/node/test/fixtures/keys/.gitattributes | 4 + ...56_signature_signedby_rsa_private_b.sha256 | Bin 0 -> 256 bytes test/js/node/test/fixtures/keys/Makefile | 813 ++++ .../node/test/fixtures/keys/agent1-cert.pem | 23 + .../js/node/test/fixtures/keys/agent1-csr.pem | 18 + .../js/node/test/fixtures/keys/agent1-key.pem | 27 + test/js/node/test/fixtures/keys/agent1.cnf | 26 + test/js/node/test/fixtures/keys/agent1.pfx | Bin 0 -> 3573 bytes .../node/test/fixtures/keys/agent10-cert.pem | 41 + .../node/test/fixtures/keys/agent10-csr.pem | 18 + .../node/test/fixtures/keys/agent10-key.pem | 27 + test/js/node/test/fixtures/keys/agent10.cnf | 17 + test/js/node/test/fixtures/keys/agent10.pfx | Bin 0 -> 4317 bytes .../node/test/fixtures/keys/agent11-cert.pem | 8 + .../node/test/fixtures/keys/agent11-key.pem | 9 + .../node/test/fixtures/keys/agent2-cert.pem | 21 + .../js/node/test/fixtures/keys/agent2-csr.pem | 18 + .../js/node/test/fixtures/keys/agent2-key.pem | 27 + test/js/node/test/fixtures/keys/agent2.cnf | 19 + .../node/test/fixtures/keys/agent3-cert.pem | 18 + .../js/node/test/fixtures/keys/agent3-csr.pem | 18 + .../js/node/test/fixtures/keys/agent3-key.pem | 27 + test/js/node/test/fixtures/keys/agent3.cnf | 19 + .../node/test/fixtures/keys/agent4-cert.pem | 19 + .../js/node/test/fixtures/keys/agent4-csr.pem | 18 + .../js/node/test/fixtures/keys/agent4-key.pem | 27 + test/js/node/test/fixtures/keys/agent4.cnf | 21 + .../node/test/fixtures/keys/agent5-cert.pem | 19 + .../js/node/test/fixtures/keys/agent5-csr.pem | 18 + .../js/node/test/fixtures/keys/agent5-key.pem | 27 + test/js/node/test/fixtures/keys/agent5.cnf | 21 + .../node/test/fixtures/keys/agent6-cert.pem | 43 + .../js/node/test/fixtures/keys/agent6-csr.pem | 18 + .../js/node/test/fixtures/keys/agent6-key.pem | 27 + test/js/node/test/fixtures/keys/agent6.cnf | 18 + test/js/node/test/fixtures/keys/agent6.pfx | Bin 0 -> 4429 bytes .../node/test/fixtures/keys/agent7-cert.pem | 19 + .../js/node/test/fixtures/keys/agent7-csr.pem | 17 + .../js/node/test/fixtures/keys/agent7-key.pem | 27 + test/js/node/test/fixtures/keys/agent7.cnf | 17 + .../node/test/fixtures/keys/agent8-cert.pem | 20 + .../js/node/test/fixtures/keys/agent8-csr.pem | 17 + .../js/node/test/fixtures/keys/agent8-key.pem | 27 + test/js/node/test/fixtures/keys/agent8.cnf | 17 + .../node/test/fixtures/keys/agent9-cert.pem | 20 + .../js/node/test/fixtures/keys/agent9-csr.pem | 17 + .../js/node/test/fixtures/keys/agent9-key.pem | 27 + test/js/node/test/fixtures/keys/agent9.cnf | 17 + test/js/node/test/fixtures/keys/ca1-cert.pem | 22 + test/js/node/test/fixtures/keys/ca1-cert.srl | 1 + test/js/node/test/fixtures/keys/ca1-key.pem | 30 + test/js/node/test/fixtures/keys/ca1.cnf | 23 + test/js/node/test/fixtures/keys/ca2-cert.pem | 16 + test/js/node/test/fixtures/keys/ca2-cert.srl | 1 + test/js/node/test/fixtures/keys/ca2-crl.pem | 10 + .../node/test/fixtures/keys/ca2-database.txt | 2 + .../test/fixtures/keys/ca2-database.txt.attr | 1 + .../fixtures/keys/ca2-database.txt.attr.old | 1 + .../test/fixtures/keys/ca2-database.txt.old | 1 + test/js/node/test/fixtures/keys/ca2-key.pem | 18 + test/js/node/test/fixtures/keys/ca2-serial | 1 + test/js/node/test/fixtures/keys/ca2.cnf | 33 + test/js/node/test/fixtures/keys/ca3-cert.pem | 22 + test/js/node/test/fixtures/keys/ca3-cert.srl | 1 + test/js/node/test/fixtures/keys/ca3-csr.pem | 18 + test/js/node/test/fixtures/keys/ca3-key.pem | 27 + test/js/node/test/fixtures/keys/ca3.cnf | 23 + test/js/node/test/fixtures/keys/ca4-cert.pem | 19 + test/js/node/test/fixtures/keys/ca4-cert.srl | 1 + test/js/node/test/fixtures/keys/ca4-csr.pem | 18 + test/js/node/test/fixtures/keys/ca4-key.pem | 27 + test/js/node/test/fixtures/keys/ca4.cnf | 23 + test/js/node/test/fixtures/keys/ca5-cert.pem | 14 + test/js/node/test/fixtures/keys/ca5-cert.srl | 1 + test/js/node/test/fixtures/keys/ca5-csr.pem | 10 + test/js/node/test/fixtures/keys/ca5-key.pem | 8 + test/js/node/test/fixtures/keys/ca5.cnf | 35 + test/js/node/test/fixtures/keys/ca6-cert.pem | 14 + test/js/node/test/fixtures/keys/ca6-cert.srl | 1 + test/js/node/test/fixtures/keys/ca6-csr.pem | 10 + test/js/node/test/fixtures/keys/ca6-key.pem | 8 + test/js/node/test/fixtures/keys/ca6.cnf | 22 + .../test/fixtures/keys/cert-without-key.pfx | Bin 0 -> 1483 bytes test/js/node/test/fixtures/keys/dh1024.pem | 5 + test/js/node/test/fixtures/keys/dh2048.pem | 8 + test/js/node/test/fixtures/keys/dh512.pem | 4 + test/js/node/test/fixtures/keys/dherror.pem | 5 + test/js/node/test/fixtures/keys/dns-cert1.cnf | Bin 0 -> 565 bytes test/js/node/test/fixtures/keys/dsa1025.pem | 9 + .../js/node/test/fixtures/keys/dsa_params.pem | 14 + .../node/test/fixtures/keys/dsa_private.pem | 20 + .../test/fixtures/keys/dsa_private_1025.pem | 12 + .../fixtures/keys/dsa_private_encrypted.pem | 23 + .../keys/dsa_private_encrypted_1025.pem | 12 + .../test/fixtures/keys/dsa_private_pkcs8.pem | 15 + .../js/node/test/fixtures/keys/dsa_public.pem | 20 + .../test/fixtures/keys/dsa_public_1025.pem | 12 + test/js/node/test/fixtures/keys/ec-cert.pem | 13 + test/js/node/test/fixtures/keys/ec-csr.pem | 9 + test/js/node/test/fixtures/keys/ec-key.pem | 8 + test/js/node/test/fixtures/keys/ec.cnf | 17 + test/js/node/test/fixtures/keys/ec.pfx | Bin 0 -> 1022 bytes test/js/node/test/fixtures/keys/ec10-cert.pem | 27 + test/js/node/test/fixtures/keys/ec10-csr.pem | 10 + test/js/node/test/fixtures/keys/ec10-key.pem | 8 + test/js/node/test/fixtures/keys/ec10.pfx | Bin 0 -> 2198 bytes .../test/fixtures/keys/ec_p256_private.pem | 5 + .../test/fixtures/keys/ec_p256_public.pem | 4 + .../test/fixtures/keys/ec_p384_private.pem | 6 + .../test/fixtures/keys/ec_p384_public.pem | 5 + .../test/fixtures/keys/ec_p521_private.pem | 8 + .../test/fixtures/keys/ec_p521_public.pem | 6 + .../fixtures/keys/ec_secp256k1_private.pem | 5 + .../fixtures/keys/ec_secp256k1_public.pem | 4 + .../test/fixtures/keys/ed25519_private.pem | 3 + .../test/fixtures/keys/ed25519_public.pem | 3 + .../node/test/fixtures/keys/ed448_private.pem | 4 + .../node/test/fixtures/keys/ed448_public.pem | 4 + .../fixtures/keys/fake-cnnic-root-cert.pem | 18 + .../fixtures/keys/fake-cnnic-root-cert.srl | 1 + .../fixtures/keys/fake-cnnic-root-key.pem | 27 + .../test/fixtures/keys/fake-cnnic-root.cnf | 19 + .../fixtures/keys/fake-startcom-root-cert.pem | 22 + .../keys/fake-startcom-root-database.txt | 4 + .../keys/fake-startcom-root-database.txt.attr | 1 + .../fake-startcom-root-database.txt.attr.old | 1 + .../keys/fake-startcom-root-database.txt.old | 3 + .../fake-startcom-root-issued-certs/01.pem | 20 + .../fake-startcom-root-issued-certs/02.pem | 20 + .../fake-startcom-root-issued-certs/03.pem | 20 + .../fake-startcom-root-issued-certs/04.pem | 20 + .../fixtures/keys/fake-startcom-root-key.pem | 27 + .../fixtures/keys/fake-startcom-root-serial | 1 + .../keys/fake-startcom-root-serial.old | 1 + .../test/fixtures/keys/fake-startcom-root.cnf | 46 + .../incorrect_san_correct_subject-cert.pem | 11 + .../incorrect_san_correct_subject-key.pem | 5 + .../irrelevant_san_correct_subject-cert.pem | 11 + .../irrelevant_san_correct_subject-key.pem | 5 + test/js/node/test/fixtures/keys/rsa_ca.crt | 24 + test/js/node/test/fixtures/keys/rsa_cert.cnf | 22 + test/js/node/test/fixtures/keys/rsa_cert.crt | 24 + test/js/node/test/fixtures/keys/rsa_cert.pfx | Bin 0 -> 2629 bytes .../test/fixtures/keys/rsa_cert_foafssl_b.cnf | 28 + .../test/fixtures/keys/rsa_cert_foafssl_b.crt | 24 + .../fixtures/keys/rsa_cert_foafssl_b.exponent | 1 + .../fixtures/keys/rsa_cert_foafssl_b.modulus | 1 + .../node/test/fixtures/keys/rsa_private.pem | 27 + .../test/fixtures/keys/rsa_private_2048.pem | 27 + .../test/fixtures/keys/rsa_private_4096.pem | 51 + .../node/test/fixtures/keys/rsa_private_b.pem | 27 + .../fixtures/keys/rsa_private_encrypted.pem | 30 + .../test/fixtures/keys/rsa_private_pkcs8.pem | 28 + .../fixtures/keys/rsa_private_pkcs8_bad.pem | 28 + .../fixtures/keys/rsa_pss_private_2048.pem | 28 + .../rsa_pss_private_2048_sha1_sha1_20.pem | 28 + .../rsa_pss_private_2048_sha256_sha256_16.pem | 29 + .../rsa_pss_private_2048_sha512_sha256_20.pem | 29 + .../fixtures/keys/rsa_pss_public_2048.pem | 9 + .../keys/rsa_pss_public_2048_sha1_sha1_20.pem | 9 + .../rsa_pss_public_2048_sha256_sha256_16.pem | 10 + .../rsa_pss_public_2048_sha512_sha256_20.pem | 10 + .../js/node/test/fixtures/keys/rsa_public.pem | 9 + .../test/fixtures/keys/rsa_public_2048.pem | 9 + .../test/fixtures/keys/rsa_public_4096.pem | 14 + .../node/test/fixtures/keys/rsa_public_b.pem | 9 + ...c_sha1_signature_signedby_rsa_private.sha1 | 2 + ..._signature_signedby_rsa_private_pkcs8.sha1 | 2 + .../node/test/fixtures/keys/rsa_spkac.spkac | 1 + .../fixtures/keys/rsa_spkac_invalid.spkac | 1 + .../keys/selfsigned-no-keycertsign/README.md | 2 + .../keys/selfsigned-no-keycertsign/cert.conf | 17 + .../keys/selfsigned-no-keycertsign/cert.pem | 19 + .../https_renew_cert.sh | 13 + .../keys/selfsigned-no-keycertsign/key.pem | 27 + .../test/fixtures/keys/x25519_private.pem | 3 + .../node/test/fixtures/keys/x25519_public.pem | 3 + .../node/test/fixtures/keys/x448_private.pem | 4 + .../node/test/fixtures/keys/x448_public.pem | 4 + .../node/test/fixtures/klass-with-fields.js | 18 + test/js/node/test/fixtures/leakedGlobal.js | 5 + .../node/test/fixtures/linux-perf-logger.js | 17 + test/js/node/test/fixtures/linux-perf.js | 17 + test/js/node/test/fixtures/loop.js | 10 + .../fixtures/macos-app-sandbox/Info.plist | 24 + .../node_sandboxed.entitlements | 8 + .../test/fixtures/mime-whatwg-generated.js | 3533 +++++++++++++++++ test/js/node/test/fixtures/mime-whatwg.js | 392 ++ .../module-extension-over-directory/inner.js | 1 + .../inner/package.json | 3 + .../test/fixtures/module-load-order/file1 | 1 + .../test/fixtures/module-load-order/file1.js | 22 + .../fixtures/module-load-order/file1.node | 1 + .../test/fixtures/module-load-order/file1.reg | 1 + .../fixtures/module-load-order/file1.reg2 | 1 + .../test/fixtures/module-load-order/file2.js | 22 + .../fixtures/module-load-order/file2.node | 1 + .../test/fixtures/module-load-order/file2.reg | 1 + .../fixtures/module-load-order/file2.reg2 | 1 + .../fixtures/module-load-order/file2/index.js | 22 + .../module-load-order/file2/index.node | 1 + .../module-load-order/file2/index.reg | 1 + .../module-load-order/file2/index.reg2 | 1 + .../fixtures/module-load-order/file3.node | 1 + .../test/fixtures/module-load-order/file3.reg | 1 + .../fixtures/module-load-order/file3.reg2 | 1 + .../fixtures/module-load-order/file3/index.js | 22 + .../module-load-order/file3/index.node | 1 + .../module-load-order/file3/index.reg | 1 + .../module-load-order/file3/index.reg2 | 1 + .../test/fixtures/module-load-order/file4.reg | 1 + .../fixtures/module-load-order/file4.reg2 | 1 + .../fixtures/module-load-order/file4/index.js | 22 + .../module-load-order/file4/index.node | 1 + .../module-load-order/file4/index.reg | 1 + .../module-load-order/file4/index.reg2 | 1 + .../fixtures/module-load-order/file5.reg2 | 1 + .../fixtures/module-load-order/file5/index.js | 22 + .../module-load-order/file5/index.node | 1 + .../module-load-order/file5/index.reg | 1 + .../module-load-order/file5/index.reg2 | 1 + .../fixtures/module-load-order/file6/index.js | 22 + .../module-load-order/file6/index.node | 1 + .../module-load-order/file6/index.reg | 1 + .../module-load-order/file6/index.reg2 | 1 + .../module-load-order/file7/index.node | 1 + .../module-load-order/file7/index.reg | 1 + .../module-load-order/file7/index.reg2 | 1 + .../module-load-order/file8/index.reg | 1 + .../module-load-order/file8/index.reg2 | 1 + .../module-load-order/file9/index.reg2 | 1 + .../test/fixtures/module-loading-error.node | 1 + .../test/fixtures/module-mocking/basic-cjs.js | 5 + .../module-mocking/basic-esm-mock.mjs | 1 + .../fixtures/module-mocking/basic-esm.mjs | 1 + .../fixtures/module-require-symlink/foo.js | 2 + .../module-require-symlink/symlinked.js | 12 + .../fixtures/module-require/child/index.js | 2 + .../module-require/not-found/trailingSlash.js | 1 + .../fixtures/module-require/parent/index.js | 5 + .../module-require/relative/dot-slash.js | 1 + .../fixtures/module-require/relative/dot.js | 1 + .../fixtures/module-require/relative/index.js | 1 + .../test/fixtures/monkey-patch-run-main.js | 8 + .../test/fixtures/nested-index/one/hello.js | 23 + .../test/fixtures/nested-index/one/index.js | 22 + .../node/test/fixtures/nested-index/three.js | 20 + .../test/fixtures/nested-index/three/index.js | 20 + .../test/fixtures/nested-index/two/hello.js | 23 + .../test/fixtures/nested-index/two/index.js | 22 + .../test/fixtures/net-fd-passing-receiver.js | 53 + test/js/node/test/fixtures/no-wrapper.js | 1 + test/js/node/test/fixtures/not-main-module.js | 24 + .../old-repl-history-file-faulty.json | 1 + .../fixtures/old-repl-history-file-obj.json | 4 + .../test/fixtures/openssl3-conf/base_only.cnf | 12 + .../fixtures/openssl3-conf/default_only.cnf | 11 + .../openssl3-conf/legacy_provider_enabled.cnf | 15 + .../legacy_provider_inactive.cnf | 15 + .../test/fixtures/openssl_fips_disabled.cnf | 12 + .../test/fixtures/openssl_fips_enabled.cnf | 12 + .../test/fixtures/order_of_end_tags_5873.md | 6 + test/js/node/test/fixtures/out-of-bound.wasm | Bin 0 -> 58 bytes test/js/node/test/fixtures/outside.txt | 2 + .../overwrite-config-preload-module.js | 6 + .../fixtures/package-main-enoent/package.json | 4 + .../test/fixtures/package-main-enoent/test.js | 8 + .../test/fixtures/packages/index/index.js | 1 + .../test/fixtures/packages/index/package.json | 1 + .../packages/is-dir/package.json/.placeholder | 0 .../main-index/package-main-module/index.js | 22 + .../fixtures/packages/main-index/package.json | 3 + .../packages/main/package-main-module.js | 22 + .../test/fixtures/packages/main/package.json | 3 + .../missing-main-no-index/package.json | 4 + .../packages/missing-main-no-index/stray.js | 2 + .../fixtures/packages/missing-main/index.js | 22 + .../packages/missing-main/package.json | 4 + .../packages/unparseable/package.json | 3 + .../parent-process-nonpersistent-fork.js | 12 + .../fixtures/parent-process-nonpersistent.js | 13 + test/js/node/test/fixtures/path-resolve.js | 4 + test/js/node/test/fixtures/path.js | 29 + .../permission/deny/protected-file.md | 3 + .../deny/protected-folder/protected-file.md | 3 + .../fixtures/permission/deny/regular-file.md | 0 .../node/test/fixtures/permission/fs-read.js | 399 ++ .../permission/fs-symlink-target-write.js | 79 + .../test/fixtures/permission/fs-symlink.js | 93 + .../test/fixtures/permission/fs-traversal.js | 138 + .../test/fixtures/permission/fs-wildcard.js | 80 + .../node/test/fixtures/permission/fs-write.js | 465 +++ .../test/fixtures/permission/inspector-brk.js | 1 + .../test/fixtures/permission/loader/index.js | 3 + .../fixtures/permission/processbinding.js | 28 + test/js/node/test/fixtures/person-large.jpg | Bin 0 -> 139837 bytes test/js/node/test/fixtures/person.jpg | Bin 0 -> 45658 bytes test/js/node/test/fixtures/person.jpg.br | Bin 0 -> 45173 bytes test/js/node/test/fixtures/person.jpg.gz | Bin 0 -> 45429 bytes test/js/node/test/fixtures/pkgexports.mjs | 12 + .../test/fixtures/postject-copy/package.json | 15 + test/js/node/test/fixtures/print A.js | 1 + test/js/node/test/fixtures/print-10-lines.js | 24 + .../test/fixtures/print-chars-from-buffer.js | 31 + test/js/node/test/fixtures/print-chars.js | 26 + test/js/node/test/fixtures/print-delayed.js | 3 + .../node/test/fixtures/print-error-message.js | 1 + .../fixtures/print-intrinsic-mutation-name.js | 2 + test/js/node/test/fixtures/printA.js | 1 + test/js/node/test/fixtures/printB.js | 1 + test/js/node/test/fixtures/printC.js | 1 + .../test/fixtures/process-exit-code-cases.js | 136 + test/js/node/test/fixtures/pss-vectors.json | 89 + .../node/test/fixtures/readfile_pipe_test.txt | 5 + test/js/node/test/fixtures/recursive-a.cjs | 6 + test/js/node/test/fixtures/recursive-b.cjs | 3 + test/js/node/test/fixtures/recvfd.js | 77 + .../test/fixtures/registerExt.hello.world | 1 + test/js/node/test/fixtures/registerExt.test | 1 + test/js/node/test/fixtures/registerExt2.test | 1 + test/js/node/test/fixtures/report-oom.js | 13 + .../node/test/fixtures/require-bin/bin/req.js | 1 + .../node/test/fixtures/require-bin/lib/req.js | 1 + .../test/fixtures/require-bin/package.json | 4 + .../test/fixtures/require-empty-main/index.js | 2 + .../fixtures/require-empty-main/package.json | 1 + test/js/node/test/fixtures/require-resolve.js | 109 + .../resolve-paths/default/verify-paths.js | 21 + .../test/fixtures/rsa-oaep-test-vectors.js | 30 + .../test/fixtures/run-script/package.json | 15 + .../run-script/sub-directory/.gitkeep | 0 test/js/node/test/fixtures/sample.png | Bin 0 -> 9416 bytes test/js/node/test/fixtures/sample_document.md | 8 + test/js/node/test/fixtures/sea.js | 60 + .../node/test/fixtures/sea/get-asset-raw.js | 31 + test/js/node/test/fixtures/sea/get-asset.js | 102 + .../test/fixtures/self_ref_module/index.js | 4 + .../fixtures/self_ref_module/package.json | 13 + test/js/node/test/fixtures/semicolon.js | 22 + test/js/node/test/fixtures/shared-memory.wasm | Bin 0 -> 26 bytes test/js/node/test/fixtures/should_exit.js | 28 + test/js/node/test/fixtures/simple.wasm | Bin 0 -> 41 bytes .../node/test/fixtures/spawn_closed_stdio.py | 8 + .../node/test/fixtures/syntax/bad_syntax.js | 1 + .../node/test/fixtures/syntax/bad_syntax.mjs | 1 + .../fixtures/syntax/bad_syntax_shebang.js | 2 + .../node/test/fixtures/syntax/good_syntax.js | 1 + .../node/test/fixtures/syntax/good_syntax.mjs | 3 + .../fixtures/syntax/good_syntax_shebang.js | 2 + .../fixtures/syntax/illegal_if_not_wrapped.js | 3 + .../fixtures/test-error-first-line-offset.js | 1 + .../test/fixtures/test-fs-readfile-error.js | 22 + .../fixtures/test-fs-stat-sync-overflow.js | 7 + .../test/fixtures/test-init-index/index.js | 25 + .../node/test/fixtures/test-init-native/fs.js | 28 + .../home-pkg-in-both/.node_libraries/foo.js | 1 + .../home-pkg-in-both/.node_modules/foo.js | 1 + .../.node_libraries/foo.js | 1 + .../.node_modules/foo.js | 1 + .../local-pkg/test.js | 2 + .../node_path/foo.js | 1 + .../test-repl-tab-completion/.hiddenfiles | 1 + .../test-repl-tab-completion/hellorandom.txt | 1 + .../test-repl-tab-completion/helloworld.js | 1 + .../test-resolution-inspect-brk-main.ext | 0 .../test-resolution-inspect-brk-resolver.js | 4 + test/js/node/test/fixtures/throws_error.js | 22 + test/js/node/test/fixtures/throws_error1.js | 22 + test/js/node/test/fixtures/throws_error2.js | 23 + test/js/node/test/fixtures/throws_error3.js | 24 + test/js/node/test/fixtures/throws_error4.js | 41 + test/js/node/test/fixtures/throws_error5.js | 1 + test/js/node/test/fixtures/throws_error6.js | 1 + test/js/node/test/fixtures/throws_error7.js | 5 + test/js/node/test/fixtures/tls-connect.js | 108 + .../node/test/fixtures/tls-session-ticket.txt | 23 + test/js/node/test/fixtures/tz-version.txt | 1 + .../uncaught-exceptions/callbackify1.js | 15 + .../uncaught-exceptions/callbackify2.js | 22 + .../fixtures/uncaught-exceptions/domain.js | 12 + .../fixtures/uncaught-exceptions/global.js | 2 + .../uncaught-exceptions/parse-error-mod.js | 2 + .../uncaught-exceptions/parse-error.js | 2 + .../fixtures/uncaught-exceptions/timeout.js | 3 + .../uncaught-exceptions/uncaught-monitor1.js | 10 + .../uncaught-exceptions/uncaught-monitor2.js | 11 + test/js/node/test/fixtures/url-idna.js | 215 + .../js/node/test/fixtures/url-searchparams.js | 77 + .../fixtures/url-setter-tests-additional.js | 237 ++ .../test/fixtures/url-tests-additional.js | 36 + .../test/fixtures/utf8-bom-shebang-shebang.js | 3 + test/js/node/test/fixtures/utf8-bom.js | 1 + test/js/node/test/fixtures/utf8-bom.json | 1 + .../js/node/test/fixtures/utf8-shebang-bom.js | 2 + test/js/node/test/fixtures/utf8_test_text.txt | 1 + test/js/node/test/fixtures/v8/v8_warning.js | 19 + .../node/test/fixtures/v8/v8_warning.snapshot | 2 + .../vm/vm_caught_custom_runtime_error.js | 18 + .../vm_caught_custom_runtime_error.snapshot | 3 + .../fixtures/vm/vm_display_runtime_error.js | 38 + .../vm/vm_display_runtime_error.snapshot | 21 + .../fixtures/vm/vm_display_syntax_error.js | 38 + .../vm/vm_display_syntax_error.snapshot | 21 + .../vm/vm_dont_display_runtime_error.js | 46 + .../vm/vm_dont_display_runtime_error.snapshot | 13 + .../vm/vm_dont_display_syntax_error.js | 46 + .../vm/vm_dont_display_syntax_error.snapshot | 13 + test/js/node/test/fixtures/warnings.js | 3 + test/js/node/test/fixtures/wasi-preview-1.js | 48 + test/js/node/test/fixtures/wasi/input.txt | 1 + test/js/node/test/fixtures/wasi/input2.txt | 1 + test/js/node/test/fixtures/wasi/notadir | 0 .../test/fixtures/wasi/subdir/input_link.txt | 1 + .../test/fixtures/wasi/subdir/outside.txt | 1 + .../node/test/fixtures/watch-mode/inspect.js | 2 + .../watch-mode/inspect_with_signal.js | 2 + test/js/node/test/fixtures/watch-mode/ipc.js | 12 + test/js/node/test/fixtures/worker-data.cjs | 3 + test/js/node/test/fixtures/worker-data.mjs | 3 + .../js/node/test/fixtures/worker-from-argv.js | 3 + test/js/node/test/fixtures/worker-name.js | 17 + test/js/node/test/fixtures/worker-preload.js | 9 + test/js/node/test/fixtures/worker-script.mjs | 3 + test/js/node/test/fixtures/worker-script.ts | 0 .../test/fixtures/workload/allocation-exit.js | 17 + .../fixtures/workload/allocation-sigint.js | 17 + .../workload/allocation-worker-argv.js | 11 + .../fixtures/workload/allocation-worker.js | 5 + .../node/test/fixtures/workload/allocation.js | 16 + .../js/node/test/fixtures/workload/bounded.js | 22 + .../test/fixtures/workload/fibonacci-exit.js | 7 + .../fixtures/workload/fibonacci-sigint.js | 7 + .../workload/fibonacci-worker-argv.js | 11 + .../fixtures/workload/fibonacci-worker.js | 5 + .../node/test/fixtures/workload/fibonacci.js | 8 + .../workload/grow-and-set-near-heap-limit.js | 9 + .../grow-worker-and-set-near-heap-limit.js | 15 + .../test/fixtures/workload/grow-worker.js | 14 + test/js/node/test/fixtures/workload/grow.js | 12 + test/js/node/test/fixtures/x.txt | 1 + test/js/node/test/fixtures/x1024.txt | 1 + .../test/fixtures/x509-escaping/.gitignore | 2 + .../fixtures/x509-escaping/alt-0-cert.pem | 29 + .../fixtures/x509-escaping/alt-1-cert.pem | 28 + .../fixtures/x509-escaping/alt-10-cert.pem | 28 + .../fixtures/x509-escaping/alt-11-cert.pem | 28 + .../fixtures/x509-escaping/alt-12-cert.pem | 28 + .../fixtures/x509-escaping/alt-13-cert.pem | 28 + .../fixtures/x509-escaping/alt-14-cert.pem | 29 + .../fixtures/x509-escaping/alt-15-cert.pem | 29 + .../fixtures/x509-escaping/alt-16-cert.pem | 29 + .../fixtures/x509-escaping/alt-17-cert.pem | 29 + .../fixtures/x509-escaping/alt-18-cert.pem | 29 + .../fixtures/x509-escaping/alt-19-cert.pem | 29 + .../fixtures/x509-escaping/alt-2-cert.pem | 28 + .../fixtures/x509-escaping/alt-20-cert.pem | 29 + .../fixtures/x509-escaping/alt-21-cert.pem | 29 + .../fixtures/x509-escaping/alt-22-cert.pem | 28 + .../fixtures/x509-escaping/alt-23-cert.pem | 28 + .../fixtures/x509-escaping/alt-24-cert.pem | 28 + .../fixtures/x509-escaping/alt-25-cert.pem | 29 + .../fixtures/x509-escaping/alt-26-cert.pem | 29 + .../fixtures/x509-escaping/alt-27-cert.pem | 28 + .../fixtures/x509-escaping/alt-28-cert.pem | 28 + .../fixtures/x509-escaping/alt-29-cert.pem | 28 + .../fixtures/x509-escaping/alt-3-cert.pem | 28 + .../fixtures/x509-escaping/alt-30-cert.pem | 28 + .../fixtures/x509-escaping/alt-4-cert.pem | 28 + .../fixtures/x509-escaping/alt-5-cert.pem | 29 + .../fixtures/x509-escaping/alt-6-cert.pem | 28 + .../fixtures/x509-escaping/alt-7-cert.pem | 28 + .../fixtures/x509-escaping/alt-8-cert.pem | 28 + .../fixtures/x509-escaping/alt-9-cert.pem | 28 + .../fixtures/x509-escaping/create-certs.js | 643 +++ .../x509-escaping/google/intermediate.pem | 11 + .../fixtures/x509-escaping/google/key.pem | 5 + .../fixtures/x509-escaping/google/leaf0.pem | 10 + .../fixtures/x509-escaping/google/leaf1.pem | 10 + .../fixtures/x509-escaping/google/leaf2.pem | 10 + .../fixtures/x509-escaping/google/leaf3.pem | 10 + .../fixtures/x509-escaping/google/leaf4.pem | 10 + .../fixtures/x509-escaping/google/root.pem | 9 + .../fixtures/x509-escaping/info-0-cert.pem | 30 + .../fixtures/x509-escaping/info-1-cert.pem | 31 + .../fixtures/x509-escaping/info-2-cert.pem | 29 + .../fixtures/x509-escaping/info-3-cert.pem | 30 + .../fixtures/x509-escaping/info-4-cert.pem | 29 + .../test/fixtures/x509-escaping/package.json | 12 + .../fixtures/x509-escaping/server-key.pem | 52 + .../fixtures/x509-escaping/subj-0-cert.pem | 28 + .../fixtures/x509-escaping/subj-1-cert.pem | 28 + .../fixtures/x509-escaping/subj-2-cert.pem | 28 + .../fixtures/x509-escaping/subj-3-cert.pem | 28 + .../fixtures/x509-escaping/subj-4-cert.pem | 28 + .../fixtures/x509-escaping/subj-5-cert.pem | 28 + .../fixtures/x509-escaping/subj-6-cert.pem | 28 + .../fixtures/x509-escaping/subj-7-cert.pem | 28 + .../fixtures/x509-escaping/subj-8-cert.pem | 28 + .../fixtures/x509-escaping/subj-9-cert.pem | 28 + test/js/node/test/parallel/.gitignore | 24 + .../assert-esm-cjs-message-verify.test.js | 54 + .../buffer-failed-alloc-typed-arrays.test.js | 2 +- .../parallel/child-process-exec-env.test.js | 50 + .../child-process-exec-timeout-kill.test.js | 59 + ...ecfile-promisified-abortcontroller.test.js | 57 + .../child-process-fork-abort-signal.test.js | 115 + .../parallel/child-process-fork-args.test.js | 88 + .../parallel/child-process-fork-close.test.js | 68 + .../child-process-fork-detached.test.js | 31 + ...en-async-encrypted-private-key-der.test.js | 54 + ...ygen-async-explicit-elliptic-curve.test.js | 50 + ...-keygen-async-named-elliptic-curve.test.js | 51 + .../crypto-keygen-missing-oid.test.js | 55 + .../test/parallel/crypto-keygen-sync.test.js | 50 + .../fs-promises-readfile-empty.test.js | 27 + .../parallel/fs-read-stream-fd-leak.test.js | 66 + .../test/parallel/heap-prof-exec-argv.test.js | 43 + .../http-get-pipeline-problem.test.js | 98 + .../http-url.parse-https.request.test.js | 81 + .../js/node/test/parallel/https-agent.test.js | 106 + .../test/parallel/https-byteswritten.test.js | 58 + .../node/test/parallel/https-foafssl.test.js | 114 + .../parallel/https-socket-options.test.js | 102 + test/js/node/test/parallel/jest.config.js | 2 + .../module-main-extension-lookup.test.js | 23 + ...mily-attempt-timeout-default-value.test.js | 13 + .../process-chdir-errormessage.test.js | 26 + .../quic-internal-endpoint-options.test.js | 192 + .../test/parallel/require-empty-main.test.js | 31 + .../parallel/require-extensions-main.test.js | 15 + .../test/parallel/signal-unregister.test.js | 27 + .../test/parallel/stream-preprocess.test.js | 68 + .../test/parallel/tls-add-context.test.js | 93 + .../node/test/parallel/tls-ca-concat.test.js | 39 + .../test/parallel/tls-client-abort.test.js | 57 + .../test/parallel/tls-fast-writing.test.js | 97 + .../parallel/tls-net-socket-keepalive.test.js | 80 + .../tls-peer-certificate-multi-keys.test.js | 87 + .../tls-startcom-wosign-whitelist.test.js | 82 + .../test/parallel/tls-ticket-cluster.test.js | 153 + ...tls-transport-destroy-after-own-gc.test.js | 39 + .../test/parallel/tls-zero-clear-in.test.js | 81 + ...wg-url-custom-searchparams-entries.test.js | 62 + ...wg-url-custom-searchparams-foreach.test.js | 21 + ...hatwg-url-custom-searchparams-keys.test.js | 66 + ...rl-custom-searchparams-stringifier.test.js | 30 + ...twg-url-custom-searchparams-values.test.js | 52 + .../whatwg-url-custom-searchparams.test.js | 191 + .../parallel/worker-cjs-workerdata.test.js | 21 + .../test/parallel/worker-esmodule.test.js | 20 + .../parallel/worker-mjs-workerdata.test.js | 22 + ...-terminate-http2-respond-with-file.test.js | 51 + 1094 files changed, 29809 insertions(+), 2 deletions(-) create mode 100644 test/js/node/test/.gitignore create mode 100644 test/js/node/test/common/arraystream.js create mode 100644 test/js/node/test/common/assertSnapshot.js create mode 100644 test/js/node/test/common/benchmark.js create mode 100644 test/js/node/test/common/child_process.js create mode 100644 test/js/node/test/common/countdown.js create mode 100644 test/js/node/test/common/cpu-prof.js create mode 100644 test/js/node/test/common/crypto.js create mode 100644 test/js/node/test/common/debugger.js create mode 100644 test/js/node/test/common/dns.js create mode 100644 test/js/node/test/common/duplexpair.js create mode 100644 test/js/node/test/common/fixtures.js create mode 100644 test/js/node/test/common/fixtures.mjs create mode 100644 test/js/node/test/common/gc.js create mode 100644 test/js/node/test/common/globals.js create mode 100644 test/js/node/test/common/heap.js create mode 100644 test/js/node/test/common/hijackstdio.js create mode 100644 test/js/node/test/common/http2.js create mode 100644 test/js/node/test/common/index.js create mode 100644 test/js/node/test/common/index.mjs create mode 100644 test/js/node/test/common/inspector-helper.js create mode 100644 test/js/node/test/common/internet.js create mode 100644 test/js/node/test/common/measure-memory.js create mode 100644 test/js/node/test/common/ongc.js create mode 100644 test/js/node/test/common/package.json create mode 100644 test/js/node/test/common/prof.js create mode 100644 test/js/node/test/common/report.js create mode 100644 test/js/node/test/common/require-as.js create mode 100644 test/js/node/test/common/sea.js create mode 100644 test/js/node/test/common/shared-lib-util.js create mode 100644 test/js/node/test/common/snapshot.js create mode 100644 test/js/node/test/common/tick.js create mode 100644 test/js/node/test/common/tls.js create mode 100644 test/js/node/test/common/udppair.js create mode 100644 test/js/node/test/common/v8.js create mode 100644 test/js/node/test/common/wasi.js create mode 100644 test/js/node/test/common/wpt.js rename test/js/node/{fs/test.txt => test/fixtures/.empty-hidden-repl-history-file} (100%) create mode 100644 test/js/node/test/fixtures/.empty-repl-history-file create mode 100644 test/js/node/test/fixtures/.node_repl_history create mode 100644 test/js/node/test/fixtures/0-dns/0-dns-cert.pem create mode 100644 test/js/node/test/fixtures/0-dns/0-dns-key.pem create mode 100644 test/js/node/test/fixtures/0-dns/0-dns-rsapub.der create mode 100644 test/js/node/test/fixtures/0-dns/README.md create mode 100644 test/js/node/test/fixtures/0-dns/create-cert.js create mode 100644 test/js/node/test/fixtures/0-dns/package.json create mode 100644 test/js/node/test/fixtures/GH-1899-output.js create mode 100644 test/js/node/test/fixtures/GH-7131/a.js create mode 100644 test/js/node/test/fixtures/GH-7131/b.js create mode 100644 test/js/node/test/fixtures/GH-892-request.js create mode 100644 test/js/node/test/fixtures/a.js create mode 100644 test/js/node/test/fixtures/aead-vectors.js create mode 100644 test/js/node/test/fixtures/altdocs.md create mode 100644 test/js/node/test/fixtures/apilinks/buffer.js create mode 100644 test/js/node/test/fixtures/apilinks/buffer.json create mode 100644 test/js/node/test/fixtures/apilinks/class.js create mode 100644 test/js/node/test/fixtures/apilinks/class.json create mode 100644 test/js/node/test/fixtures/apilinks/exports.js create mode 100644 test/js/node/test/fixtures/apilinks/exports.json create mode 100644 test/js/node/test/fixtures/apilinks/mod.js create mode 100644 test/js/node/test/fixtures/apilinks/mod.json create mode 100644 test/js/node/test/fixtures/apilinks/prototype.js create mode 100644 test/js/node/test/fixtures/apilinks/prototype.json create mode 100644 test/js/node/test/fixtures/apilinks/reverse.js create mode 100644 test/js/node/test/fixtures/apilinks/reverse.json create mode 100644 test/js/node/test/fixtures/apilinks/root.js create mode 100644 test/js/node/test/fixtures/apilinks/root.json create mode 100644 test/js/node/test/fixtures/assert-first-line.js create mode 100644 test/js/node/test/fixtures/assert-long-line.js create mode 100644 test/js/node/test/fixtures/async-error.js create mode 100644 test/js/node/test/fixtures/b/c.js create mode 100644 test/js/node/test/fixtures/b/d.js create mode 100644 test/js/node/test/fixtures/b/package/index.js create mode 100644 test/js/node/test/fixtures/baz.js create mode 100644 test/js/node/test/fixtures/catch-stdout-error.js create mode 100644 test/js/node/test/fixtures/child-process-echo-options.js create mode 100644 test/js/node/test/fixtures/child-process-message-and-exit.js create mode 100644 test/js/node/test/fixtures/child-process-persistent.js create mode 100644 test/js/node/test/fixtures/child-process-spawn-node.js create mode 100644 test/js/node/test/fixtures/child-process-stay-alive-forever.js create mode 100644 test/js/node/test/fixtures/child_process_should_emit_error.js create mode 100644 test/js/node/test/fixtures/cjs-module-wrap.js create mode 100644 test/js/node/test/fixtures/cjs-module-wrapper.js create mode 100644 test/js/node/test/fixtures/cluster-preload-test.js create mode 100644 test/js/node/test/fixtures/cluster-preload.js create mode 100644 test/js/node/test/fixtures/clustered-server/app.js create mode 100644 test/js/node/test/fixtures/console/2100bytes.js create mode 100644 test/js/node/test/fixtures/console/2100bytes.snapshot create mode 100644 test/js/node/test/fixtures/console/console.js create mode 100644 test/js/node/test/fixtures/console/console.snapshot create mode 100644 test/js/node/test/fixtures/console/console_low_stack_space.js create mode 100644 test/js/node/test/fixtures/console/console_low_stack_space.snapshot create mode 100644 test/js/node/test/fixtures/console/force_colors.js create mode 100644 test/js/node/test/fixtures/console/force_colors.snapshot create mode 100644 test/js/node/test/fixtures/console/hello_world.js create mode 100644 test/js/node/test/fixtures/console/hello_world.snapshot create mode 100644 test/js/node/test/fixtures/console/stack_overflow.js create mode 100644 test/js/node/test/fixtures/console/stack_overflow.snapshot create mode 100644 test/js/node/test/fixtures/copy/kitchen-sink/README.md create mode 100644 test/js/node/test/fixtures/copy/kitchen-sink/a/b/README2.md create mode 100644 test/js/node/test/fixtures/copy/kitchen-sink/a/b/index.js create mode 100644 test/js/node/test/fixtures/copy/kitchen-sink/a/c/README2.md create mode 100644 test/js/node/test/fixtures/copy/kitchen-sink/a/c/d/README3.md create mode 100644 test/js/node/test/fixtures/copy/kitchen-sink/a/c/d/index.js create mode 100644 test/js/node/test/fixtures/copy/kitchen-sink/a/c/index.js create mode 100644 test/js/node/test/fixtures/copy/kitchen-sink/a/index.js create mode 100644 test/js/node/test/fixtures/copy/kitchen-sink/index.js create mode 100644 test/js/node/test/fixtures/crash.wasm create mode 100644 test/js/node/test/fixtures/crypto/aes_cbc.js create mode 100644 test/js/node/test/fixtures/crypto/aes_ctr.js create mode 100644 test/js/node/test/fixtures/crypto/aes_gcm.js create mode 100644 test/js/node/test/fixtures/crypto/ecdsa.js create mode 100644 test/js/node/test/fixtures/crypto/eddsa.js create mode 100644 test/js/node/test/fixtures/crypto/hmac.js create mode 100644 test/js/node/test/fixtures/crypto/rsa.js create mode 100644 test/js/node/test/fixtures/crypto/rsa_pkcs.js create mode 100644 test/js/node/test/fixtures/crypto/rsa_pss.js create mode 100644 test/js/node/test/fixtures/cycles/folder/foo.js create mode 100644 test/js/node/test/fixtures/cycles/root.js create mode 100644 test/js/node/test/fixtures/cycles/warning-a.js create mode 100644 test/js/node/test/fixtures/cycles/warning-b.js create mode 100644 test/js/node/test/fixtures/cycles/warning-esm-half-transpiled-a.js create mode 100644 test/js/node/test/fixtures/cycles/warning-esm-half-transpiled-b.js create mode 100644 test/js/node/test/fixtures/cycles/warning-esm-transpiled-a.js create mode 100644 test/js/node/test/fixtures/cycles/warning-esm-transpiled-b.js create mode 100644 test/js/node/test/fixtures/cycles/warning-moduleexports-a.js create mode 100644 test/js/node/test/fixtures/cycles/warning-moduleexports-b.js create mode 100644 test/js/node/test/fixtures/cycles/warning-moduleexports-class-a.js create mode 100644 test/js/node/test/fixtures/cycles/warning-moduleexports-class-b.js create mode 100644 test/js/node/test/fixtures/cycles/warning-skip-proxy-traps-a.js create mode 100644 test/js/node/test/fixtures/cycles/warning-skip-proxy-traps-b.js create mode 100644 test/js/node/test/fixtures/debugger-repeat-last.js create mode 100644 test/js/node/test/fixtures/debugger-util-regression-fixture.js create mode 100644 test/js/node/test/fixtures/debugger/alive.js create mode 100644 test/js/node/test/fixtures/debugger/backtrace.js create mode 100644 test/js/node/test/fixtures/debugger/break.js create mode 100644 test/js/node/test/fixtures/debugger/cjs/index.js create mode 100644 test/js/node/test/fixtures/debugger/cjs/other.js create mode 100644 test/js/node/test/fixtures/debugger/empty.js create mode 100644 test/js/node/test/fixtures/debugger/exceptions.js create mode 100644 test/js/node/test/fixtures/debugger/three-lines.js create mode 100644 test/js/node/test/fixtures/debugger/twenty-lines.js create mode 100644 test/js/node/test/fixtures/debugger/use-strict.js create mode 100644 test/js/node/test/fixtures/define-global.js create mode 100644 test/js/node/test/fixtures/deprecated-userland-class.js create mode 100644 test/js/node/test/fixtures/deprecated-userland-function.js create mode 100644 test/js/node/test/fixtures/deprecated-userland-subclass.js create mode 100644 test/js/node/test/fixtures/deprecated.js create mode 100644 test/js/node/test/fixtures/destroy-stdin.js create mode 100644 test/js/node/test/fixtures/disable-warning-worker.js create mode 100644 test/js/node/test/fixtures/disable-warning.js create mode 100644 test/js/node/test/fixtures/doc_inc_1.md create mode 100644 test/js/node/test/fixtures/doc_inc_2.md create mode 100644 test/js/node/test/fixtures/doc_with_backticks_in_headings.md create mode 100644 test/js/node/test/fixtures/doc_with_yaml.md create mode 100644 test/js/node/test/fixtures/document_with_cjs_and_esm_code_snippet.md create mode 100644 test/js/node/test/fixtures/document_with_esm_and_cjs_code_snippet.md create mode 100644 test/js/node/test/fixtures/document_with_links.md create mode 100644 test/js/node/test/fixtures/document_with_special_heading.md create mode 100644 test/js/node/test/fixtures/dotenv/basic-valid.env create mode 100644 test/js/node/test/fixtures/dotenv/eof-without-value.env create mode 100644 test/js/node/test/fixtures/dotenv/multiline.env create mode 100644 test/js/node/test/fixtures/dotenv/node-options.env create mode 100644 test/js/node/test/fixtures/dotenv/uv-threadpool.env create mode 100644 test/js/node/test/fixtures/dotenv/valid.env create mode 100644 test/js/node/test/fixtures/echo-close-check.js create mode 100644 test/js/node/test/fixtures/echo.js create mode 100644 test/js/node/test/fixtures/elipses.txt create mode 100644 test/js/node/test/fixtures/empty-with-bom.txt create mode 100644 test/js/node/test/fixtures/empty.cjs create mode 100644 test/js/node/test/fixtures/empty.js create mode 100644 test/js/node/test/fixtures/empty.json create mode 100644 test/js/node/test/fixtures/empty.txt create mode 100644 test/js/node/test/fixtures/emptyframe.http2 create mode 100644 test/js/node/test/fixtures/errors/async_error_eval_cjs.js create mode 100644 test/js/node/test/fixtures/errors/async_error_eval_cjs.snapshot create mode 100644 test/js/node/test/fixtures/errors/async_error_eval_esm.js create mode 100644 test/js/node/test/fixtures/errors/async_error_eval_esm.snapshot create mode 100644 test/js/node/test/fixtures/errors/async_error_microtask_main.js create mode 100644 test/js/node/test/fixtures/errors/async_error_microtask_main.snapshot create mode 100644 test/js/node/test/fixtures/errors/async_error_nexttick_main.js create mode 100644 test/js/node/test/fixtures/errors/async_error_nexttick_main.snapshot create mode 100644 test/js/node/test/fixtures/errors/async_error_sync_esm.mjs create mode 100644 test/js/node/test/fixtures/errors/async_error_sync_esm.snapshot create mode 100644 test/js/node/test/fixtures/errors/async_error_sync_main.js create mode 100644 test/js/node/test/fixtures/errors/async_error_sync_main.snapshot create mode 100644 test/js/node/test/fixtures/errors/core_line_numbers.js create mode 100644 test/js/node/test/fixtures/errors/core_line_numbers.snapshot create mode 100644 test/js/node/test/fixtures/errors/error_aggregateTwoErrors.js create mode 100644 test/js/node/test/fixtures/errors/error_aggregateTwoErrors.snapshot create mode 100644 test/js/node/test/fixtures/errors/error_exit.js create mode 100644 test/js/node/test/fixtures/errors/error_exit.snapshot create mode 100644 test/js/node/test/fixtures/errors/error_with_nul.js create mode 100644 test/js/node/test/fixtures/errors/error_with_nul.snapshot create mode 100644 test/js/node/test/fixtures/errors/events_unhandled_error_common_trace.js create mode 100644 test/js/node/test/fixtures/errors/events_unhandled_error_common_trace.snapshot create mode 100644 test/js/node/test/fixtures/errors/events_unhandled_error_nexttick.js create mode 100644 test/js/node/test/fixtures/errors/events_unhandled_error_nexttick.snapshot create mode 100644 test/js/node/test/fixtures/errors/events_unhandled_error_sameline.js create mode 100644 test/js/node/test/fixtures/errors/events_unhandled_error_sameline.snapshot create mode 100644 test/js/node/test/fixtures/errors/events_unhandled_error_subclass.js create mode 100644 test/js/node/test/fixtures/errors/events_unhandled_error_subclass.snapshot create mode 100644 test/js/node/test/fixtures/errors/force_colors.js create mode 100644 test/js/node/test/fixtures/errors/force_colors.snapshot create mode 100644 test/js/node/test/fixtures/errors/if-error-has-good-stack.js create mode 100644 test/js/node/test/fixtures/errors/if-error-has-good-stack.snapshot create mode 100644 test/js/node/test/fixtures/errors/promise_always_throw_unhandled.js create mode 100644 test/js/node/test/fixtures/errors/promise_always_throw_unhandled.snapshot create mode 100644 test/js/node/test/fixtures/errors/promise_unhandled_warn_with_error.js create mode 100644 test/js/node/test/fixtures/errors/promise_unhandled_warn_with_error.snapshot create mode 100644 test/js/node/test/fixtures/errors/test-no-extra-info-on-fatal-exception.js create mode 100644 test/js/node/test/fixtures/errors/test-no-extra-info-on-fatal-exception.snapshot create mode 100644 test/js/node/test/fixtures/errors/throw_custom_error.js create mode 100644 test/js/node/test/fixtures/errors/throw_custom_error.snapshot create mode 100644 test/js/node/test/fixtures/errors/throw_error_with_getter_throw.js create mode 100644 test/js/node/test/fixtures/errors/throw_error_with_getter_throw.snapshot create mode 100644 test/js/node/test/fixtures/errors/throw_in_line_with_tabs.js create mode 100644 test/js/node/test/fixtures/errors/throw_in_line_with_tabs.snapshot create mode 100644 test/js/node/test/fixtures/errors/throw_non_error.js create mode 100644 test/js/node/test/fixtures/errors/throw_non_error.snapshot create mode 100644 test/js/node/test/fixtures/errors/throw_null.js create mode 100644 test/js/node/test/fixtures/errors/throw_null.snapshot create mode 100644 test/js/node/test/fixtures/errors/throw_undefined.js create mode 100644 test/js/node/test/fixtures/errors/throw_undefined.snapshot create mode 100644 test/js/node/test/fixtures/errors/timeout_throw.js create mode 100644 test/js/node/test/fixtures/errors/timeout_throw.snapshot create mode 100644 test/js/node/test/fixtures/errors/undefined_reference_in_new_context.js create mode 100644 test/js/node/test/fixtures/errors/undefined_reference_in_new_context.snapshot create mode 100644 test/js/node/test/fixtures/errors/unhandled_promise_trace_warnings.js create mode 100644 test/js/node/test/fixtures/errors/unhandled_promise_trace_warnings.snapshot create mode 100644 test/js/node/test/fixtures/es-module-loaders/assertionless-json-import.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/builtin-named-exports.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/byop-dummy-loader.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/example-loader.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/hook-resolve-type-loader.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/hook-resolve-type.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/hooks-custom.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/hooks-initialize-port.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/hooks-initialize.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/hooks-input.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/http-loader.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/js-as-esm.js create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-dep.js create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-edge-cases.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-invalid-format.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-invalid-url.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-load-bad-next-context.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-load-bad-next-url.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-load-dynamic-import.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-load-foo-or-42.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-load-impersonating-next-url.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-load-incomplete.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-load-next-modified.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-load-null-return.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-load-passing-modified-context.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-load-passthru.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-load-receiving-modified-context.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-log-args.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-resolve-42.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-resolve-bad-next-context.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-resolve-bad-next-specifier.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-resolve-dynamic-import.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-resolve-foo.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-resolve-incomplete.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-resolve-multiple-next-calls.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-resolve-next-modified.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-resolve-null-return.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-resolve-passing-modified-context.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-resolve-passthru.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-resolve-receiving-modified-context.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-resolve-shortcircuit.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-resolve-strip-xxx.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-resolve-strip-yyy.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-shared-dep.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-this-value-inside-hook-functions.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-with-custom-condition.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-with-dep.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/loader-with-too-many-args.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/missing-dynamic-instantiate-hook.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/mock-loader.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/mock.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/module-named-exports.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/never-settling-resolve-step/import.meta.never-resolve.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/never-settling-resolve-step/loader.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/never-settling-resolve-step/never-load.cjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/never-settling-resolve-step/never-load.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/never-settling-resolve-step/never-resolve.cjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/never-settling-resolve-step/never-resolve.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/never-settling-resolve-step/race.cjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/never-settling-resolve-step/race.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/not-found-assert-loader.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/preset-cjs-source.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/register-loader.cjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/register-loader.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/register-programmatically-loader-load.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/register-programmatically-loader-resolve.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/string-sources.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/syntax-error.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/thenable-load-hook-rejected-no-arguments.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/thenable-load-hook-rejected.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/thenable-load-hook.mjs create mode 100644 test/js/node/test/fixtures/es-module-loaders/throw-undefined.mjs create mode 100644 test/js/node/test/fixtures/es-module-require-cache/counter.js create mode 100644 test/js/node/test/fixtures/es-module-require-cache/echo.cjs create mode 100644 test/js/node/test/fixtures/es-module-require-cache/preload.js create mode 100644 test/js/node/test/fixtures/es-module-specifiers/index.mjs create mode 100644 test/js/node/test/fixtures/es-module-specifiers/package.json create mode 100644 test/js/node/test/fixtures/es-module-url/empty.js create mode 100644 test/js/node/test/fixtures/es-module-url/native.mjs create mode 100644 test/js/node/test/fixtures/es-modules/builtin-imports-case.mjs create mode 100644 test/js/node/test/fixtures/es-modules/cjs-esm-esm-cycle/a.mjs create mode 100644 test/js/node/test/fixtures/es-modules/cjs-esm-esm-cycle/b.mjs create mode 100644 test/js/node/test/fixtures/es-modules/cjs-esm-esm-cycle/c.cjs create mode 100644 test/js/node/test/fixtures/es-modules/cjs-esm-esm.js create mode 100644 test/js/node/test/fixtures/es-modules/cjs-esm.js create mode 100644 test/js/node/test/fixtures/es-modules/cjs-exports-invalid.mjs create mode 100644 test/js/node/test/fixtures/es-modules/cjs-exports.mjs create mode 100644 test/js/node/test/fixtures/es-modules/cjs-file.cjs create mode 100644 test/js/node/test/fixtures/es-modules/cjs.js create mode 100644 test/js/node/test/fixtures/es-modules/conditional-exports.js create mode 100644 test/js/node/test/fixtures/es-modules/conditional-exports.mjs create mode 100644 test/js/node/test/fixtures/es-modules/data-import.mjs create mode 100644 test/js/node/test/fixtures/es-modules/dep1.js create mode 100644 test/js/node/test/fixtures/es-modules/dep2.js create mode 100644 test/js/node/test/fixtures/es-modules/deprecated-folders-ignore/main.js create mode 100644 test/js/node/test/fixtures/es-modules/deprecated-folders-ignore/package.json create mode 100644 test/js/node/test/fixtures/es-modules/dynamic-import/import.cjs create mode 100644 test/js/node/test/fixtures/es-modules/dynamic-import/import.mjs create mode 100644 test/js/node/test/fixtures/es-modules/es-note-error-1.cjs create mode 100644 test/js/node/test/fixtures/es-modules/es-note-error-1.mjs create mode 100644 test/js/node/test/fixtures/es-modules/es-note-error-2.cjs create mode 100644 test/js/node/test/fixtures/es-modules/es-note-error-2.mjs create mode 100644 test/js/node/test/fixtures/es-modules/es-note-error-3.cjs create mode 100644 test/js/node/test/fixtures/es-modules/es-note-error-3.mjs create mode 100644 test/js/node/test/fixtures/es-modules/es-note-error-4.cjs create mode 100644 test/js/node/test/fixtures/es-modules/es-note-error-4.mjs create mode 100644 test/js/node/test/fixtures/es-modules/es-note-promiserej-import-2.cjs create mode 100644 test/js/node/test/fixtures/es-modules/es-note-unexpected-export-1.cjs create mode 100644 test/js/node/test/fixtures/es-modules/es-note-unexpected-export-2.cjs create mode 100644 test/js/node/test/fixtures/es-modules/es-note-unexpected-import-1.cjs create mode 100644 test/js/node/test/fixtures/es-modules/es-note-unexpected-import-3.cjs create mode 100644 test/js/node/test/fixtures/es-modules/es-note-unexpected-import-4.cjs create mode 100644 test/js/node/test/fixtures/es-modules/es-note-unexpected-import-5.cjs create mode 100644 test/js/node/test/fixtures/es-modules/esm-cjs-esm-cycle/a.mjs create mode 100644 test/js/node/test/fixtures/es-modules/esm-cjs-esm-cycle/b.cjs create mode 100644 test/js/node/test/fixtures/es-modules/esm-cjs-esm-cycle/require-a.cjs create mode 100644 test/js/node/test/fixtures/es-modules/esm-cjs-esm-cycle/require-b.cjs create mode 100644 test/js/node/test/fixtures/es-modules/esm-cjs-esm-esm-cycle/a.mjs create mode 100644 test/js/node/test/fixtures/es-modules/esm-cjs-esm-esm-cycle/b.cjs create mode 100644 test/js/node/test/fixtures/es-modules/esm-cjs-esm-esm-cycle/c.mjs create mode 100644 test/js/node/test/fixtures/es-modules/esm-esm-cjs-esm-cycle/a.mjs create mode 100644 test/js/node/test/fixtures/es-modules/esm-esm-cjs-esm-cycle/b.mjs create mode 100644 test/js/node/test/fixtures/es-modules/esm-esm-cjs-esm-cycle/c.mjs create mode 100644 test/js/node/test/fixtures/es-modules/esm-esm-cjs-esm-cycle/d.mjs create mode 100644 test/js/node/test/fixtures/es-modules/esm-esm-cjs-esm-esm-cycle/a.mjs create mode 100644 test/js/node/test/fixtures/es-modules/esm-esm-cjs-esm-esm-cycle/b.mjs create mode 100644 test/js/node/test/fixtures/es-modules/esm-esm-cjs-esm-esm-cycle/c.cjs create mode 100644 test/js/node/test/fixtures/es-modules/esm-esm-cjs-esm-esm-cycle/z.mjs create mode 100644 test/js/node/test/fixtures/es-modules/esm-snapshot-mutator.js create mode 100644 test/js/node/test/fixtures/es-modules/esm-snapshot.js create mode 100644 test/js/node/test/fixtures/es-modules/esm-top-level-await.mjs create mode 100644 test/js/node/test/fixtures/es-modules/export-name-code-injection.wasm create mode 100644 test/js/node/test/fixtures/es-modules/export-name-syntax-error.wasm create mode 100644 test/js/node/test/fixtures/es-modules/exports-both/load.cjs create mode 100644 test/js/node/test/fixtures/es-modules/exports-cases.js create mode 100644 test/js/node/test/fixtures/es-modules/exports-cases2.js create mode 100644 test/js/node/test/fixtures/es-modules/exports-cases3.js create mode 100644 test/js/node/test/fixtures/es-modules/exports-import-default/load.cjs create mode 100644 test/js/node/test/fixtures/es-modules/exports-import-only/load.cjs create mode 100644 test/js/node/test/fixtures/es-modules/exports-require-only/load.cjs create mode 100644 test/js/node/test/fixtures/es-modules/file.ext create mode 100644 test/js/node/test/fixtures/es-modules/file.unknown create mode 100644 test/js/node/test/fixtures/es-modules/folder%25with percentage#/index.js create mode 100644 test/js/node/test/fixtures/es-modules/import-esm.mjs create mode 100644 test/js/node/test/fixtures/es-modules/import-invalid-ext.mjs create mode 100644 test/js/node/test/fixtures/es-modules/import-invalid-pjson.mjs create mode 100644 test/js/node/test/fixtures/es-modules/import-json-named-export.mjs create mode 100644 test/js/node/test/fixtures/es-modules/import-name.wasm create mode 100644 test/js/node/test/fixtures/es-modules/import-process-exit.mjs create mode 100644 test/js/node/test/fixtures/es-modules/import-resolve-exports.mjs create mode 100644 test/js/node/test/fixtures/es-modules/imported-esm.mjs create mode 100644 test/js/node/test/fixtures/es-modules/imports-loose.mjs create mode 100644 test/js/node/test/fixtures/es-modules/imports-noext.mjs create mode 100644 test/js/node/test/fixtures/es-modules/invalid-cjs.js create mode 100644 test/js/node/test/fixtures/es-modules/invalid-posix-host.mjs create mode 100644 test/js/node/test/fixtures/es-modules/json-cache/another.cjs create mode 100644 test/js/node/test/fixtures/es-modules/json-cache/mod.cjs create mode 100644 test/js/node/test/fixtures/es-modules/json-cache/test.json create mode 100644 test/js/node/test/fixtures/es-modules/json-modules.mjs create mode 100644 test/js/node/test/fixtures/es-modules/legacy-main-resolver/index-js/index.js create mode 100644 test/js/node/test/fixtures/es-modules/legacy-main-resolver/index-json/index.json create mode 100644 test/js/node/test/fixtures/es-modules/legacy-main-resolver/index-node/index.node create mode 100644 test/js/node/test/fixtures/es-modules/loop.mjs create mode 100644 test/js/node/test/fixtures/es-modules/loose.js create mode 100644 test/js/node/test/fixtures/es-modules/message.mjs create mode 100644 test/js/node/test/fixtures/es-modules/mjs-file.mjs create mode 100644 test/js/node/test/fixtures/es-modules/module-counter-by-type/index.js create mode 100644 test/js/node/test/fixtures/es-modules/module-counter-by-type/package.json create mode 100644 test/js/node/test/fixtures/es-modules/network-import.mjs create mode 100644 test/js/node/test/fixtures/es-modules/noext create mode 100644 test/js/node/test/fixtures/es-modules/noext-esm create mode 100644 test/js/node/test/fixtures/es-modules/noext-wasm create mode 100644 test/js/node/test/fixtures/es-modules/package-cjs-named-error/bare-import-double.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-cjs-named-error/bare-import-single.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-cjs-named-error/double-quote.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-cjs-named-error/escaped-single-quote.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-cjs-named-error/fail.cjs create mode 100644 test/js/node/test/fixtures/es-modules/package-cjs-named-error/json-hack.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-cjs-named-error/json-hack/fail.js create mode 100644 test/js/node/test/fixtures/es-modules/package-cjs-named-error/json-hack/package.json create mode 100644 test/js/node/test/fixtures/es-modules/package-cjs-named-error/multi-line.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-cjs-named-error/oh'no.cjs create mode 100644 test/js/node/test/fixtures/es-modules/package-cjs-named-error/package.json create mode 100644 test/js/node/test/fixtures/es-modules/package-cjs-named-error/renamed-import.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-cjs-named-error/single-quote.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-default-extension/index.cjs create mode 100644 test/js/node/test/fixtures/es-modules/package-default-extension/index.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-ends-node_modules/index.js create mode 100644 test/js/node/test/fixtures/es-modules/package-ends-node_modules/package.json create mode 100644 test/js/node/test/fixtures/es-modules/package-type-commonjs/echo-require-cache.js create mode 100644 test/js/node/test/fixtures/es-modules/package-type-commonjs/imports-esm.js create mode 100644 test/js/node/test/fixtures/es-modules/package-type-commonjs/imports-esm.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-type-commonjs/index.js create mode 100644 test/js/node/test/fixtures/es-modules/package-type-commonjs/module.js create mode 100644 test/js/node/test/fixtures/es-modules/package-type-commonjs/package.json create mode 100644 test/js/node/test/fixtures/es-modules/package-type-module/cjs.js create mode 100644 test/js/node/test/fixtures/es-modules/package-type-module/esm.js create mode 100644 test/js/node/test/fixtures/es-modules/package-type-module/extension.unknown create mode 100644 test/js/node/test/fixtures/es-modules/package-type-module/imports-commonjs.cjs create mode 100644 test/js/node/test/fixtures/es-modules/package-type-module/imports-commonjs.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-type-module/imports-noext.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-type-module/imports-unknownext.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-type-module/index.js create mode 100644 test/js/node/test/fixtures/es-modules/package-type-module/nested-default-type/module.js create mode 100644 test/js/node/test/fixtures/es-modules/package-type-module/nested-default-type/package.json create mode 100644 test/js/node/test/fixtures/es-modules/package-type-module/noext-esm create mode 100644 test/js/node/test/fixtures/es-modules/package-type-module/noext-wasm create mode 100644 test/js/node/test/fixtures/es-modules/package-type-module/package.json create mode 100644 test/js/node/test/fixtures/es-modules/package-type-module/wasm-dep.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-without-pjson/index.js create mode 100644 test/js/node/test/fixtures/es-modules/package-without-type/commonjs-wrapper-variables.js create mode 100644 test/js/node/test/fixtures/es-modules/package-without-type/commonjs.js create mode 100644 test/js/node/test/fixtures/es-modules/package-without-type/detected-as-esm.js create mode 100644 test/js/node/test/fixtures/es-modules/package-without-type/file#1.js create mode 100644 test/js/node/test/fixtures/es-modules/package-without-type/imports-commonjs.cjs create mode 100644 test/js/node/test/fixtures/es-modules/package-without-type/imports-commonjs.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-without-type/imports-esm.js create mode 100644 test/js/node/test/fixtures/es-modules/package-without-type/imports-esm.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-without-type/imports-noext-cjs.js create mode 100644 test/js/node/test/fixtures/es-modules/package-without-type/imports-noext-cjs.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-without-type/imports-noext-esm.js create mode 100644 test/js/node/test/fixtures/es-modules/package-without-type/imports-noext-esm.mjs create mode 100644 test/js/node/test/fixtures/es-modules/package-without-type/index.js create mode 100644 test/js/node/test/fixtures/es-modules/package-without-type/module.js create mode 100644 test/js/node/test/fixtures/es-modules/package-without-type/noext-cjs create mode 100644 test/js/node/test/fixtures/es-modules/package-without-type/noext-esm create mode 100644 test/js/node/test/fixtures/es-modules/package-without-type/package.json create mode 100644 test/js/node/test/fixtures/es-modules/pattern-trailing-slash.mjs create mode 100644 test/js/node/test/fixtures/es-modules/pjson-invalid/package.json create mode 100644 test/js/node/test/fixtures/es-modules/pjson-main/main.mjs create mode 100644 test/js/node/test/fixtures/es-modules/pjson-main/package.json create mode 100644 test/js/node/test/fixtures/es-modules/pkgimports/importbranch.js create mode 100644 test/js/node/test/fixtures/es-modules/pkgimports/importer.js create mode 100644 test/js/node/test/fixtures/es-modules/pkgimports/package.json create mode 100644 test/js/node/test/fixtures/es-modules/pkgimports/requirebranch.js create mode 100644 test/js/node/test/fixtures/es-modules/pkgimports/sub/internal/test.js create mode 100644 test/js/node/test/fixtures/es-modules/pkgimports/sub/x.js create mode 100644 test/js/node/test/fixtures/es-modules/pkgimports/test.js create mode 100644 test/js/node/test/fixtures/es-modules/print-3.mjs create mode 100644 test/js/node/test/fixtures/es-modules/process-exit.mjs create mode 100644 test/js/node/test/fixtures/es-modules/reference-error.mjs create mode 100644 test/js/node/test/fixtures/es-modules/require-and-import/load.cjs create mode 100644 test/js/node/test/fixtures/es-modules/require-and-import/load.mjs create mode 100644 test/js/node/test/fixtures/es-modules/require-cjs.mjs create mode 100644 test/js/node/test/fixtures/es-modules/require-reference-error.cjs create mode 100644 test/js/node/test/fixtures/es-modules/require-syntax-error.cjs create mode 100644 test/js/node/test/fixtures/es-modules/require-throw-error.cjs create mode 100644 test/js/node/test/fixtures/es-modules/required-cjs.js create mode 100644 test/js/node/test/fixtures/es-modules/runmain.mjs create mode 100644 test/js/node/test/fixtures/es-modules/self-deprecated-folders/main.js create mode 100644 test/js/node/test/fixtures/es-modules/self-deprecated-folders/package.json create mode 100644 test/js/node/test/fixtures/es-modules/should-not-be-resolved.mjs create mode 100644 test/js/node/test/fixtures/es-modules/simple.wasm create mode 100644 test/js/node/test/fixtures/es-modules/stateful.mjs create mode 100644 test/js/node/test/fixtures/es-modules/symlink.mjs create mode 100644 test/js/node/test/fixtures/es-modules/syntax-error.mjs create mode 100644 test/js/node/test/fixtures/es-modules/test-esm-comma,.mjs create mode 100644 test/js/node/test/fixtures/es-modules/test-esm-double-encoding-native%20.mjs create mode 100644 test/js/node/test/fixtures/es-modules/test-esm-ok.mjs create mode 100644 test/js/node/test/fixtures/es-modules/throw-error.mjs create mode 100644 test/js/node/test/fixtures/es-modules/tla/a.mjs create mode 100644 test/js/node/test/fixtures/es-modules/tla/b.mjs create mode 100644 test/js/node/test/fixtures/es-modules/tla/c.mjs create mode 100644 test/js/node/test/fixtures/es-modules/tla/d.mjs create mode 100644 test/js/node/test/fixtures/es-modules/tla/execution.mjs create mode 100644 test/js/node/test/fixtures/es-modules/tla/order.mjs create mode 100644 test/js/node/test/fixtures/es-modules/tla/parent.mjs create mode 100644 test/js/node/test/fixtures/es-modules/tla/process-exit.mjs create mode 100644 test/js/node/test/fixtures/es-modules/tla/rejected-withexitcode.mjs create mode 100644 test/js/node/test/fixtures/es-modules/tla/rejected.mjs create mode 100644 test/js/node/test/fixtures/es-modules/tla/require-execution.js create mode 100644 test/js/node/test/fixtures/es-modules/tla/resolved.mjs create mode 100644 test/js/node/test/fixtures/es-modules/tla/unresolved-with-worker-process-exit.mjs create mode 100644 test/js/node/test/fixtures/es-modules/tla/unresolved-withexitcode.mjs create mode 100644 test/js/node/test/fixtures/es-modules/tla/unresolved.mjs create mode 100644 test/js/node/test/fixtures/es-modules/wasm-dep.mjs create mode 100644 test/js/node/test/fixtures/es-modules/wasm-modules.mjs create mode 100644 test/js/node/test/fixtures/exit.js create mode 100644 test/js/node/test/fixtures/experimental.json create mode 100644 test/js/node/test/fixtures/exports-function-with-param.js create mode 100644 test/js/node/test/fixtures/external-repl-module.js create mode 100644 test/js/node/test/fixtures/failcounter.js create mode 100644 test/js/node/test/fixtures/failmustcall1.js create mode 100644 test/js/node/test/fixtures/failmustcall2.js create mode 100644 test/js/node/test/fixtures/file-to-read-with-bom.txt create mode 100644 test/js/node/test/fixtures/file-to-read-without-bom.txt create mode 100644 test/js/node/test/fixtures/fixture.ini create mode 100644 test/js/node/test/fixtures/foo create mode 100644 test/js/node/test/fixtures/gc.js create mode 100644 test/js/node/test/fixtures/global/plain.js create mode 100644 test/js/node/test/fixtures/google_ssl_hello.bin create mode 100644 test/js/node/test/fixtures/guess-hash-seed.js create mode 100644 test/js/node/test/fixtures/icu-punycode-toascii.json create mode 100644 test/js/node/test/fixtures/inspector-global-function.mjs create mode 100644 test/js/node/test/fixtures/inspector-instrumentation-breakpoint/dep.js create mode 100644 test/js/node/test/fixtures/inspector-instrumentation-breakpoint/main.js create mode 100644 test/js/node/test/fixtures/inspector-open.js create mode 100644 test/js/node/test/fixtures/internal-modules/index.js create mode 100644 test/js/node/test/fixtures/intrinsic-mutation.js create mode 100644 test/js/node/test/fixtures/invalid.json create mode 100644 test/js/node/test/fixtures/is-object.js create mode 100644 test/js/node/test/fixtures/ispreloading.js create mode 100644 test/js/node/test/fixtures/json-with-directory-name-module/module-stub.json create mode 100644 test/js/node/test/fixtures/json-with-directory-name-module/module-stub/index.js create mode 100644 test/js/node/test/fixtures/json-with-directory-name-module/module-stub/one-trailing-slash/two/three.js create mode 100644 test/js/node/test/fixtures/json-with-directory-name-module/module-stub/one/two/three.js create mode 100644 test/js/node/test/fixtures/json-with-directory-name-module/module-stub/package.json create mode 100644 test/js/node/test/fixtures/keys/.gitattributes create mode 100644 test/js/node/test/fixtures/keys/I_AM_THE_WALRUS_sha256_signature_signedby_rsa_private_b.sha256 create mode 100644 test/js/node/test/fixtures/keys/Makefile create mode 100644 test/js/node/test/fixtures/keys/agent1-cert.pem create mode 100644 test/js/node/test/fixtures/keys/agent1-csr.pem create mode 100644 test/js/node/test/fixtures/keys/agent1-key.pem create mode 100644 test/js/node/test/fixtures/keys/agent1.cnf create mode 100644 test/js/node/test/fixtures/keys/agent1.pfx create mode 100644 test/js/node/test/fixtures/keys/agent10-cert.pem create mode 100644 test/js/node/test/fixtures/keys/agent10-csr.pem create mode 100644 test/js/node/test/fixtures/keys/agent10-key.pem create mode 100644 test/js/node/test/fixtures/keys/agent10.cnf create mode 100644 test/js/node/test/fixtures/keys/agent10.pfx create mode 100644 test/js/node/test/fixtures/keys/agent11-cert.pem create mode 100644 test/js/node/test/fixtures/keys/agent11-key.pem create mode 100644 test/js/node/test/fixtures/keys/agent2-cert.pem create mode 100644 test/js/node/test/fixtures/keys/agent2-csr.pem create mode 100644 test/js/node/test/fixtures/keys/agent2-key.pem create mode 100644 test/js/node/test/fixtures/keys/agent2.cnf create mode 100644 test/js/node/test/fixtures/keys/agent3-cert.pem create mode 100644 test/js/node/test/fixtures/keys/agent3-csr.pem create mode 100644 test/js/node/test/fixtures/keys/agent3-key.pem create mode 100644 test/js/node/test/fixtures/keys/agent3.cnf create mode 100644 test/js/node/test/fixtures/keys/agent4-cert.pem create mode 100644 test/js/node/test/fixtures/keys/agent4-csr.pem create mode 100644 test/js/node/test/fixtures/keys/agent4-key.pem create mode 100644 test/js/node/test/fixtures/keys/agent4.cnf create mode 100644 test/js/node/test/fixtures/keys/agent5-cert.pem create mode 100644 test/js/node/test/fixtures/keys/agent5-csr.pem create mode 100644 test/js/node/test/fixtures/keys/agent5-key.pem create mode 100644 test/js/node/test/fixtures/keys/agent5.cnf create mode 100644 test/js/node/test/fixtures/keys/agent6-cert.pem create mode 100644 test/js/node/test/fixtures/keys/agent6-csr.pem create mode 100644 test/js/node/test/fixtures/keys/agent6-key.pem create mode 100644 test/js/node/test/fixtures/keys/agent6.cnf create mode 100644 test/js/node/test/fixtures/keys/agent6.pfx create mode 100644 test/js/node/test/fixtures/keys/agent7-cert.pem create mode 100644 test/js/node/test/fixtures/keys/agent7-csr.pem create mode 100644 test/js/node/test/fixtures/keys/agent7-key.pem create mode 100644 test/js/node/test/fixtures/keys/agent7.cnf create mode 100644 test/js/node/test/fixtures/keys/agent8-cert.pem create mode 100644 test/js/node/test/fixtures/keys/agent8-csr.pem create mode 100644 test/js/node/test/fixtures/keys/agent8-key.pem create mode 100644 test/js/node/test/fixtures/keys/agent8.cnf create mode 100644 test/js/node/test/fixtures/keys/agent9-cert.pem create mode 100644 test/js/node/test/fixtures/keys/agent9-csr.pem create mode 100644 test/js/node/test/fixtures/keys/agent9-key.pem create mode 100644 test/js/node/test/fixtures/keys/agent9.cnf create mode 100644 test/js/node/test/fixtures/keys/ca1-cert.pem create mode 100644 test/js/node/test/fixtures/keys/ca1-cert.srl create mode 100644 test/js/node/test/fixtures/keys/ca1-key.pem create mode 100644 test/js/node/test/fixtures/keys/ca1.cnf create mode 100644 test/js/node/test/fixtures/keys/ca2-cert.pem create mode 100644 test/js/node/test/fixtures/keys/ca2-cert.srl create mode 100644 test/js/node/test/fixtures/keys/ca2-crl.pem create mode 100644 test/js/node/test/fixtures/keys/ca2-database.txt create mode 100644 test/js/node/test/fixtures/keys/ca2-database.txt.attr create mode 100644 test/js/node/test/fixtures/keys/ca2-database.txt.attr.old create mode 100644 test/js/node/test/fixtures/keys/ca2-database.txt.old create mode 100644 test/js/node/test/fixtures/keys/ca2-key.pem create mode 100644 test/js/node/test/fixtures/keys/ca2-serial create mode 100644 test/js/node/test/fixtures/keys/ca2.cnf create mode 100644 test/js/node/test/fixtures/keys/ca3-cert.pem create mode 100644 test/js/node/test/fixtures/keys/ca3-cert.srl create mode 100644 test/js/node/test/fixtures/keys/ca3-csr.pem create mode 100644 test/js/node/test/fixtures/keys/ca3-key.pem create mode 100644 test/js/node/test/fixtures/keys/ca3.cnf create mode 100644 test/js/node/test/fixtures/keys/ca4-cert.pem create mode 100644 test/js/node/test/fixtures/keys/ca4-cert.srl create mode 100644 test/js/node/test/fixtures/keys/ca4-csr.pem create mode 100644 test/js/node/test/fixtures/keys/ca4-key.pem create mode 100644 test/js/node/test/fixtures/keys/ca4.cnf create mode 100644 test/js/node/test/fixtures/keys/ca5-cert.pem create mode 100644 test/js/node/test/fixtures/keys/ca5-cert.srl create mode 100644 test/js/node/test/fixtures/keys/ca5-csr.pem create mode 100644 test/js/node/test/fixtures/keys/ca5-key.pem create mode 100644 test/js/node/test/fixtures/keys/ca5.cnf create mode 100644 test/js/node/test/fixtures/keys/ca6-cert.pem create mode 100644 test/js/node/test/fixtures/keys/ca6-cert.srl create mode 100644 test/js/node/test/fixtures/keys/ca6-csr.pem create mode 100644 test/js/node/test/fixtures/keys/ca6-key.pem create mode 100644 test/js/node/test/fixtures/keys/ca6.cnf create mode 100644 test/js/node/test/fixtures/keys/cert-without-key.pfx create mode 100644 test/js/node/test/fixtures/keys/dh1024.pem create mode 100644 test/js/node/test/fixtures/keys/dh2048.pem create mode 100644 test/js/node/test/fixtures/keys/dh512.pem create mode 100644 test/js/node/test/fixtures/keys/dherror.pem create mode 100644 test/js/node/test/fixtures/keys/dns-cert1.cnf create mode 100644 test/js/node/test/fixtures/keys/dsa1025.pem create mode 100644 test/js/node/test/fixtures/keys/dsa_params.pem create mode 100644 test/js/node/test/fixtures/keys/dsa_private.pem create mode 100644 test/js/node/test/fixtures/keys/dsa_private_1025.pem create mode 100644 test/js/node/test/fixtures/keys/dsa_private_encrypted.pem create mode 100644 test/js/node/test/fixtures/keys/dsa_private_encrypted_1025.pem create mode 100644 test/js/node/test/fixtures/keys/dsa_private_pkcs8.pem create mode 100644 test/js/node/test/fixtures/keys/dsa_public.pem create mode 100644 test/js/node/test/fixtures/keys/dsa_public_1025.pem create mode 100644 test/js/node/test/fixtures/keys/ec-cert.pem create mode 100644 test/js/node/test/fixtures/keys/ec-csr.pem create mode 100644 test/js/node/test/fixtures/keys/ec-key.pem create mode 100644 test/js/node/test/fixtures/keys/ec.cnf create mode 100644 test/js/node/test/fixtures/keys/ec.pfx create mode 100644 test/js/node/test/fixtures/keys/ec10-cert.pem create mode 100644 test/js/node/test/fixtures/keys/ec10-csr.pem create mode 100644 test/js/node/test/fixtures/keys/ec10-key.pem create mode 100644 test/js/node/test/fixtures/keys/ec10.pfx create mode 100644 test/js/node/test/fixtures/keys/ec_p256_private.pem create mode 100644 test/js/node/test/fixtures/keys/ec_p256_public.pem create mode 100644 test/js/node/test/fixtures/keys/ec_p384_private.pem create mode 100644 test/js/node/test/fixtures/keys/ec_p384_public.pem create mode 100644 test/js/node/test/fixtures/keys/ec_p521_private.pem create mode 100644 test/js/node/test/fixtures/keys/ec_p521_public.pem create mode 100644 test/js/node/test/fixtures/keys/ec_secp256k1_private.pem create mode 100644 test/js/node/test/fixtures/keys/ec_secp256k1_public.pem create mode 100644 test/js/node/test/fixtures/keys/ed25519_private.pem create mode 100644 test/js/node/test/fixtures/keys/ed25519_public.pem create mode 100644 test/js/node/test/fixtures/keys/ed448_private.pem create mode 100644 test/js/node/test/fixtures/keys/ed448_public.pem create mode 100644 test/js/node/test/fixtures/keys/fake-cnnic-root-cert.pem create mode 100644 test/js/node/test/fixtures/keys/fake-cnnic-root-cert.srl create mode 100644 test/js/node/test/fixtures/keys/fake-cnnic-root-key.pem create mode 100644 test/js/node/test/fixtures/keys/fake-cnnic-root.cnf create mode 100644 test/js/node/test/fixtures/keys/fake-startcom-root-cert.pem create mode 100644 test/js/node/test/fixtures/keys/fake-startcom-root-database.txt create mode 100644 test/js/node/test/fixtures/keys/fake-startcom-root-database.txt.attr create mode 100644 test/js/node/test/fixtures/keys/fake-startcom-root-database.txt.attr.old create mode 100644 test/js/node/test/fixtures/keys/fake-startcom-root-database.txt.old create mode 100644 test/js/node/test/fixtures/keys/fake-startcom-root-issued-certs/01.pem create mode 100644 test/js/node/test/fixtures/keys/fake-startcom-root-issued-certs/02.pem create mode 100644 test/js/node/test/fixtures/keys/fake-startcom-root-issued-certs/03.pem create mode 100644 test/js/node/test/fixtures/keys/fake-startcom-root-issued-certs/04.pem create mode 100644 test/js/node/test/fixtures/keys/fake-startcom-root-key.pem create mode 100644 test/js/node/test/fixtures/keys/fake-startcom-root-serial create mode 100644 test/js/node/test/fixtures/keys/fake-startcom-root-serial.old create mode 100644 test/js/node/test/fixtures/keys/fake-startcom-root.cnf create mode 100644 test/js/node/test/fixtures/keys/incorrect_san_correct_subject-cert.pem create mode 100644 test/js/node/test/fixtures/keys/incorrect_san_correct_subject-key.pem create mode 100644 test/js/node/test/fixtures/keys/irrelevant_san_correct_subject-cert.pem create mode 100644 test/js/node/test/fixtures/keys/irrelevant_san_correct_subject-key.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_ca.crt create mode 100644 test/js/node/test/fixtures/keys/rsa_cert.cnf create mode 100644 test/js/node/test/fixtures/keys/rsa_cert.crt create mode 100644 test/js/node/test/fixtures/keys/rsa_cert.pfx create mode 100644 test/js/node/test/fixtures/keys/rsa_cert_foafssl_b.cnf create mode 100644 test/js/node/test/fixtures/keys/rsa_cert_foafssl_b.crt create mode 100644 test/js/node/test/fixtures/keys/rsa_cert_foafssl_b.exponent create mode 100644 test/js/node/test/fixtures/keys/rsa_cert_foafssl_b.modulus create mode 100644 test/js/node/test/fixtures/keys/rsa_private.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_private_2048.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_private_4096.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_private_b.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_private_encrypted.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_private_pkcs8.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_private_pkcs8_bad.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_pss_private_2048.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_pss_private_2048_sha1_sha1_20.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_pss_private_2048_sha256_sha256_16.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_pss_private_2048_sha512_sha256_20.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_pss_public_2048.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_pss_public_2048_sha1_sha1_20.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_pss_public_2048_sha256_sha256_16.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_pss_public_2048_sha512_sha256_20.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_public.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_public_2048.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_public_4096.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_public_b.pem create mode 100644 test/js/node/test/fixtures/keys/rsa_public_sha1_signature_signedby_rsa_private.sha1 create mode 100644 test/js/node/test/fixtures/keys/rsa_public_sha1_signature_signedby_rsa_private_pkcs8.sha1 create mode 100644 test/js/node/test/fixtures/keys/rsa_spkac.spkac create mode 100644 test/js/node/test/fixtures/keys/rsa_spkac_invalid.spkac create mode 100644 test/js/node/test/fixtures/keys/selfsigned-no-keycertsign/README.md create mode 100644 test/js/node/test/fixtures/keys/selfsigned-no-keycertsign/cert.conf create mode 100644 test/js/node/test/fixtures/keys/selfsigned-no-keycertsign/cert.pem create mode 100755 test/js/node/test/fixtures/keys/selfsigned-no-keycertsign/https_renew_cert.sh create mode 100644 test/js/node/test/fixtures/keys/selfsigned-no-keycertsign/key.pem create mode 100644 test/js/node/test/fixtures/keys/x25519_private.pem create mode 100644 test/js/node/test/fixtures/keys/x25519_public.pem create mode 100644 test/js/node/test/fixtures/keys/x448_private.pem create mode 100644 test/js/node/test/fixtures/keys/x448_public.pem create mode 100644 test/js/node/test/fixtures/klass-with-fields.js create mode 100644 test/js/node/test/fixtures/leakedGlobal.js create mode 100644 test/js/node/test/fixtures/linux-perf-logger.js create mode 100644 test/js/node/test/fixtures/linux-perf.js create mode 100644 test/js/node/test/fixtures/loop.js create mode 100644 test/js/node/test/fixtures/macos-app-sandbox/Info.plist create mode 100644 test/js/node/test/fixtures/macos-app-sandbox/node_sandboxed.entitlements create mode 100644 test/js/node/test/fixtures/mime-whatwg-generated.js create mode 100644 test/js/node/test/fixtures/mime-whatwg.js create mode 100644 test/js/node/test/fixtures/module-extension-over-directory/inner.js create mode 100644 test/js/node/test/fixtures/module-extension-over-directory/inner/package.json create mode 100644 test/js/node/test/fixtures/module-load-order/file1 create mode 100644 test/js/node/test/fixtures/module-load-order/file1.js create mode 100644 test/js/node/test/fixtures/module-load-order/file1.node create mode 100644 test/js/node/test/fixtures/module-load-order/file1.reg create mode 100644 test/js/node/test/fixtures/module-load-order/file1.reg2 create mode 100644 test/js/node/test/fixtures/module-load-order/file2.js create mode 100644 test/js/node/test/fixtures/module-load-order/file2.node create mode 100644 test/js/node/test/fixtures/module-load-order/file2.reg create mode 100644 test/js/node/test/fixtures/module-load-order/file2.reg2 create mode 100644 test/js/node/test/fixtures/module-load-order/file2/index.js create mode 100644 test/js/node/test/fixtures/module-load-order/file2/index.node create mode 100644 test/js/node/test/fixtures/module-load-order/file2/index.reg create mode 100644 test/js/node/test/fixtures/module-load-order/file2/index.reg2 create mode 100644 test/js/node/test/fixtures/module-load-order/file3.node create mode 100644 test/js/node/test/fixtures/module-load-order/file3.reg create mode 100644 test/js/node/test/fixtures/module-load-order/file3.reg2 create mode 100644 test/js/node/test/fixtures/module-load-order/file3/index.js create mode 100644 test/js/node/test/fixtures/module-load-order/file3/index.node create mode 100644 test/js/node/test/fixtures/module-load-order/file3/index.reg create mode 100644 test/js/node/test/fixtures/module-load-order/file3/index.reg2 create mode 100644 test/js/node/test/fixtures/module-load-order/file4.reg create mode 100644 test/js/node/test/fixtures/module-load-order/file4.reg2 create mode 100644 test/js/node/test/fixtures/module-load-order/file4/index.js create mode 100644 test/js/node/test/fixtures/module-load-order/file4/index.node create mode 100644 test/js/node/test/fixtures/module-load-order/file4/index.reg create mode 100644 test/js/node/test/fixtures/module-load-order/file4/index.reg2 create mode 100644 test/js/node/test/fixtures/module-load-order/file5.reg2 create mode 100644 test/js/node/test/fixtures/module-load-order/file5/index.js create mode 100644 test/js/node/test/fixtures/module-load-order/file5/index.node create mode 100644 test/js/node/test/fixtures/module-load-order/file5/index.reg create mode 100644 test/js/node/test/fixtures/module-load-order/file5/index.reg2 create mode 100644 test/js/node/test/fixtures/module-load-order/file6/index.js create mode 100644 test/js/node/test/fixtures/module-load-order/file6/index.node create mode 100644 test/js/node/test/fixtures/module-load-order/file6/index.reg create mode 100644 test/js/node/test/fixtures/module-load-order/file6/index.reg2 create mode 100644 test/js/node/test/fixtures/module-load-order/file7/index.node create mode 100644 test/js/node/test/fixtures/module-load-order/file7/index.reg create mode 100644 test/js/node/test/fixtures/module-load-order/file7/index.reg2 create mode 100644 test/js/node/test/fixtures/module-load-order/file8/index.reg create mode 100644 test/js/node/test/fixtures/module-load-order/file8/index.reg2 create mode 100644 test/js/node/test/fixtures/module-load-order/file9/index.reg2 create mode 100644 test/js/node/test/fixtures/module-loading-error.node create mode 100644 test/js/node/test/fixtures/module-mocking/basic-cjs.js create mode 100644 test/js/node/test/fixtures/module-mocking/basic-esm-mock.mjs create mode 100644 test/js/node/test/fixtures/module-mocking/basic-esm.mjs create mode 100644 test/js/node/test/fixtures/module-require-symlink/foo.js create mode 100644 test/js/node/test/fixtures/module-require-symlink/symlinked.js create mode 100644 test/js/node/test/fixtures/module-require/child/index.js create mode 100644 test/js/node/test/fixtures/module-require/not-found/trailingSlash.js create mode 100644 test/js/node/test/fixtures/module-require/parent/index.js create mode 100644 test/js/node/test/fixtures/module-require/relative/dot-slash.js create mode 100644 test/js/node/test/fixtures/module-require/relative/dot.js create mode 100644 test/js/node/test/fixtures/module-require/relative/index.js create mode 100644 test/js/node/test/fixtures/monkey-patch-run-main.js create mode 100644 test/js/node/test/fixtures/nested-index/one/hello.js create mode 100644 test/js/node/test/fixtures/nested-index/one/index.js create mode 100644 test/js/node/test/fixtures/nested-index/three.js create mode 100644 test/js/node/test/fixtures/nested-index/three/index.js create mode 100644 test/js/node/test/fixtures/nested-index/two/hello.js create mode 100644 test/js/node/test/fixtures/nested-index/two/index.js create mode 100644 test/js/node/test/fixtures/net-fd-passing-receiver.js create mode 100644 test/js/node/test/fixtures/no-wrapper.js create mode 100644 test/js/node/test/fixtures/not-main-module.js create mode 100644 test/js/node/test/fixtures/old-repl-history-file-faulty.json create mode 100644 test/js/node/test/fixtures/old-repl-history-file-obj.json create mode 100644 test/js/node/test/fixtures/openssl3-conf/base_only.cnf create mode 100644 test/js/node/test/fixtures/openssl3-conf/default_only.cnf create mode 100644 test/js/node/test/fixtures/openssl3-conf/legacy_provider_enabled.cnf create mode 100644 test/js/node/test/fixtures/openssl3-conf/legacy_provider_inactive.cnf create mode 100644 test/js/node/test/fixtures/openssl_fips_disabled.cnf create mode 100644 test/js/node/test/fixtures/openssl_fips_enabled.cnf create mode 100644 test/js/node/test/fixtures/order_of_end_tags_5873.md create mode 100644 test/js/node/test/fixtures/out-of-bound.wasm create mode 100644 test/js/node/test/fixtures/outside.txt create mode 100644 test/js/node/test/fixtures/overwrite-config-preload-module.js create mode 100644 test/js/node/test/fixtures/package-main-enoent/package.json create mode 100644 test/js/node/test/fixtures/package-main-enoent/test.js create mode 100644 test/js/node/test/fixtures/packages/index/index.js create mode 100644 test/js/node/test/fixtures/packages/index/package.json create mode 100644 test/js/node/test/fixtures/packages/is-dir/package.json/.placeholder create mode 100644 test/js/node/test/fixtures/packages/main-index/package-main-module/index.js create mode 100644 test/js/node/test/fixtures/packages/main-index/package.json create mode 100644 test/js/node/test/fixtures/packages/main/package-main-module.js create mode 100644 test/js/node/test/fixtures/packages/main/package.json create mode 100644 test/js/node/test/fixtures/packages/missing-main-no-index/package.json create mode 100644 test/js/node/test/fixtures/packages/missing-main-no-index/stray.js create mode 100644 test/js/node/test/fixtures/packages/missing-main/index.js create mode 100644 test/js/node/test/fixtures/packages/missing-main/package.json create mode 100644 test/js/node/test/fixtures/packages/unparseable/package.json create mode 100644 test/js/node/test/fixtures/parent-process-nonpersistent-fork.js create mode 100644 test/js/node/test/fixtures/parent-process-nonpersistent.js create mode 100644 test/js/node/test/fixtures/path-resolve.js create mode 100644 test/js/node/test/fixtures/path.js create mode 100644 test/js/node/test/fixtures/permission/deny/protected-file.md create mode 100644 test/js/node/test/fixtures/permission/deny/protected-folder/protected-file.md create mode 100644 test/js/node/test/fixtures/permission/deny/regular-file.md create mode 100644 test/js/node/test/fixtures/permission/fs-read.js create mode 100644 test/js/node/test/fixtures/permission/fs-symlink-target-write.js create mode 100644 test/js/node/test/fixtures/permission/fs-symlink.js create mode 100644 test/js/node/test/fixtures/permission/fs-traversal.js create mode 100644 test/js/node/test/fixtures/permission/fs-wildcard.js create mode 100644 test/js/node/test/fixtures/permission/fs-write.js create mode 100644 test/js/node/test/fixtures/permission/inspector-brk.js create mode 100644 test/js/node/test/fixtures/permission/loader/index.js create mode 100644 test/js/node/test/fixtures/permission/processbinding.js create mode 100644 test/js/node/test/fixtures/person-large.jpg create mode 100644 test/js/node/test/fixtures/person.jpg create mode 100644 test/js/node/test/fixtures/person.jpg.br create mode 100644 test/js/node/test/fixtures/person.jpg.gz create mode 100644 test/js/node/test/fixtures/pkgexports.mjs create mode 100644 test/js/node/test/fixtures/postject-copy/package.json create mode 100644 test/js/node/test/fixtures/print A.js create mode 100644 test/js/node/test/fixtures/print-10-lines.js create mode 100644 test/js/node/test/fixtures/print-chars-from-buffer.js create mode 100644 test/js/node/test/fixtures/print-chars.js create mode 100644 test/js/node/test/fixtures/print-delayed.js create mode 100644 test/js/node/test/fixtures/print-error-message.js create mode 100644 test/js/node/test/fixtures/print-intrinsic-mutation-name.js create mode 100644 test/js/node/test/fixtures/printA.js create mode 100644 test/js/node/test/fixtures/printB.js create mode 100644 test/js/node/test/fixtures/printC.js create mode 100644 test/js/node/test/fixtures/process-exit-code-cases.js create mode 100644 test/js/node/test/fixtures/pss-vectors.json create mode 100644 test/js/node/test/fixtures/readfile_pipe_test.txt create mode 100644 test/js/node/test/fixtures/recursive-a.cjs create mode 100644 test/js/node/test/fixtures/recursive-b.cjs create mode 100644 test/js/node/test/fixtures/recvfd.js create mode 100644 test/js/node/test/fixtures/registerExt.hello.world create mode 100644 test/js/node/test/fixtures/registerExt.test create mode 100644 test/js/node/test/fixtures/registerExt2.test create mode 100644 test/js/node/test/fixtures/report-oom.js create mode 100644 test/js/node/test/fixtures/require-bin/bin/req.js create mode 100644 test/js/node/test/fixtures/require-bin/lib/req.js create mode 100644 test/js/node/test/fixtures/require-bin/package.json create mode 100644 test/js/node/test/fixtures/require-empty-main/index.js create mode 100644 test/js/node/test/fixtures/require-empty-main/package.json create mode 100644 test/js/node/test/fixtures/require-resolve.js create mode 100644 test/js/node/test/fixtures/resolve-paths/default/verify-paths.js create mode 100644 test/js/node/test/fixtures/rsa-oaep-test-vectors.js create mode 100644 test/js/node/test/fixtures/run-script/package.json create mode 100644 test/js/node/test/fixtures/run-script/sub-directory/.gitkeep create mode 100644 test/js/node/test/fixtures/sample.png create mode 100644 test/js/node/test/fixtures/sample_document.md create mode 100644 test/js/node/test/fixtures/sea.js create mode 100644 test/js/node/test/fixtures/sea/get-asset-raw.js create mode 100644 test/js/node/test/fixtures/sea/get-asset.js create mode 100644 test/js/node/test/fixtures/self_ref_module/index.js create mode 100644 test/js/node/test/fixtures/self_ref_module/package.json create mode 100644 test/js/node/test/fixtures/semicolon.js create mode 100644 test/js/node/test/fixtures/shared-memory.wasm create mode 100644 test/js/node/test/fixtures/should_exit.js create mode 100644 test/js/node/test/fixtures/simple.wasm create mode 100644 test/js/node/test/fixtures/spawn_closed_stdio.py create mode 100644 test/js/node/test/fixtures/syntax/bad_syntax.js create mode 100644 test/js/node/test/fixtures/syntax/bad_syntax.mjs create mode 100644 test/js/node/test/fixtures/syntax/bad_syntax_shebang.js create mode 100644 test/js/node/test/fixtures/syntax/good_syntax.js create mode 100644 test/js/node/test/fixtures/syntax/good_syntax.mjs create mode 100644 test/js/node/test/fixtures/syntax/good_syntax_shebang.js create mode 100644 test/js/node/test/fixtures/syntax/illegal_if_not_wrapped.js create mode 100644 test/js/node/test/fixtures/test-error-first-line-offset.js create mode 100644 test/js/node/test/fixtures/test-fs-readfile-error.js create mode 100644 test/js/node/test/fixtures/test-fs-stat-sync-overflow.js create mode 100644 test/js/node/test/fixtures/test-init-index/index.js create mode 100644 test/js/node/test/fixtures/test-init-native/fs.js create mode 100644 test/js/node/test/fixtures/test-module-loading-globalpaths/home-pkg-in-both/.node_libraries/foo.js create mode 100644 test/js/node/test/fixtures/test-module-loading-globalpaths/home-pkg-in-both/.node_modules/foo.js create mode 100644 test/js/node/test/fixtures/test-module-loading-globalpaths/home-pkg-in-node_libraries/.node_libraries/foo.js create mode 100644 test/js/node/test/fixtures/test-module-loading-globalpaths/home-pkg-in-node_modules/.node_modules/foo.js create mode 100644 test/js/node/test/fixtures/test-module-loading-globalpaths/local-pkg/test.js create mode 100644 test/js/node/test/fixtures/test-module-loading-globalpaths/node_path/foo.js create mode 100644 test/js/node/test/fixtures/test-repl-tab-completion/.hiddenfiles create mode 100644 test/js/node/test/fixtures/test-repl-tab-completion/hellorandom.txt create mode 100644 test/js/node/test/fixtures/test-repl-tab-completion/helloworld.js create mode 100644 test/js/node/test/fixtures/test-resolution-inspect-brk-main.ext create mode 100644 test/js/node/test/fixtures/test-resolution-inspect-brk-resolver.js create mode 100644 test/js/node/test/fixtures/throws_error.js create mode 100644 test/js/node/test/fixtures/throws_error1.js create mode 100644 test/js/node/test/fixtures/throws_error2.js create mode 100644 test/js/node/test/fixtures/throws_error3.js create mode 100644 test/js/node/test/fixtures/throws_error4.js create mode 100644 test/js/node/test/fixtures/throws_error5.js create mode 100644 test/js/node/test/fixtures/throws_error6.js create mode 100644 test/js/node/test/fixtures/throws_error7.js create mode 100644 test/js/node/test/fixtures/tls-connect.js create mode 100644 test/js/node/test/fixtures/tls-session-ticket.txt create mode 100644 test/js/node/test/fixtures/tz-version.txt create mode 100644 test/js/node/test/fixtures/uncaught-exceptions/callbackify1.js create mode 100644 test/js/node/test/fixtures/uncaught-exceptions/callbackify2.js create mode 100644 test/js/node/test/fixtures/uncaught-exceptions/domain.js create mode 100644 test/js/node/test/fixtures/uncaught-exceptions/global.js create mode 100644 test/js/node/test/fixtures/uncaught-exceptions/parse-error-mod.js create mode 100644 test/js/node/test/fixtures/uncaught-exceptions/parse-error.js create mode 100644 test/js/node/test/fixtures/uncaught-exceptions/timeout.js create mode 100644 test/js/node/test/fixtures/uncaught-exceptions/uncaught-monitor1.js create mode 100644 test/js/node/test/fixtures/uncaught-exceptions/uncaught-monitor2.js create mode 100644 test/js/node/test/fixtures/url-idna.js create mode 100644 test/js/node/test/fixtures/url-searchparams.js create mode 100644 test/js/node/test/fixtures/url-setter-tests-additional.js create mode 100644 test/js/node/test/fixtures/url-tests-additional.js create mode 100644 test/js/node/test/fixtures/utf8-bom-shebang-shebang.js create mode 100644 test/js/node/test/fixtures/utf8-bom.js create mode 100644 test/js/node/test/fixtures/utf8-bom.json create mode 100644 test/js/node/test/fixtures/utf8-shebang-bom.js create mode 100644 test/js/node/test/fixtures/utf8_test_text.txt create mode 100644 test/js/node/test/fixtures/v8/v8_warning.js create mode 100644 test/js/node/test/fixtures/v8/v8_warning.snapshot create mode 100644 test/js/node/test/fixtures/vm/vm_caught_custom_runtime_error.js create mode 100644 test/js/node/test/fixtures/vm/vm_caught_custom_runtime_error.snapshot create mode 100644 test/js/node/test/fixtures/vm/vm_display_runtime_error.js create mode 100644 test/js/node/test/fixtures/vm/vm_display_runtime_error.snapshot create mode 100644 test/js/node/test/fixtures/vm/vm_display_syntax_error.js create mode 100644 test/js/node/test/fixtures/vm/vm_display_syntax_error.snapshot create mode 100644 test/js/node/test/fixtures/vm/vm_dont_display_runtime_error.js create mode 100644 test/js/node/test/fixtures/vm/vm_dont_display_runtime_error.snapshot create mode 100644 test/js/node/test/fixtures/vm/vm_dont_display_syntax_error.js create mode 100644 test/js/node/test/fixtures/vm/vm_dont_display_syntax_error.snapshot create mode 100644 test/js/node/test/fixtures/warnings.js create mode 100644 test/js/node/test/fixtures/wasi-preview-1.js create mode 100644 test/js/node/test/fixtures/wasi/input.txt create mode 100644 test/js/node/test/fixtures/wasi/input2.txt create mode 100644 test/js/node/test/fixtures/wasi/notadir create mode 120000 test/js/node/test/fixtures/wasi/subdir/input_link.txt create mode 120000 test/js/node/test/fixtures/wasi/subdir/outside.txt create mode 100644 test/js/node/test/fixtures/watch-mode/inspect.js create mode 100644 test/js/node/test/fixtures/watch-mode/inspect_with_signal.js create mode 100644 test/js/node/test/fixtures/watch-mode/ipc.js create mode 100644 test/js/node/test/fixtures/worker-data.cjs create mode 100644 test/js/node/test/fixtures/worker-data.mjs create mode 100644 test/js/node/test/fixtures/worker-from-argv.js create mode 100644 test/js/node/test/fixtures/worker-name.js create mode 100644 test/js/node/test/fixtures/worker-preload.js create mode 100644 test/js/node/test/fixtures/worker-script.mjs create mode 100644 test/js/node/test/fixtures/worker-script.ts create mode 100644 test/js/node/test/fixtures/workload/allocation-exit.js create mode 100644 test/js/node/test/fixtures/workload/allocation-sigint.js create mode 100644 test/js/node/test/fixtures/workload/allocation-worker-argv.js create mode 100644 test/js/node/test/fixtures/workload/allocation-worker.js create mode 100644 test/js/node/test/fixtures/workload/allocation.js create mode 100644 test/js/node/test/fixtures/workload/bounded.js create mode 100644 test/js/node/test/fixtures/workload/fibonacci-exit.js create mode 100644 test/js/node/test/fixtures/workload/fibonacci-sigint.js create mode 100644 test/js/node/test/fixtures/workload/fibonacci-worker-argv.js create mode 100644 test/js/node/test/fixtures/workload/fibonacci-worker.js create mode 100644 test/js/node/test/fixtures/workload/fibonacci.js create mode 100644 test/js/node/test/fixtures/workload/grow-and-set-near-heap-limit.js create mode 100644 test/js/node/test/fixtures/workload/grow-worker-and-set-near-heap-limit.js create mode 100644 test/js/node/test/fixtures/workload/grow-worker.js create mode 100644 test/js/node/test/fixtures/workload/grow.js create mode 100644 test/js/node/test/fixtures/x.txt create mode 100644 test/js/node/test/fixtures/x1024.txt create mode 100644 test/js/node/test/fixtures/x509-escaping/.gitignore create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-0-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-1-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-10-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-11-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-12-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-13-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-14-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-15-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-16-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-17-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-18-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-19-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-2-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-20-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-21-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-22-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-23-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-24-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-25-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-26-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-27-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-28-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-29-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-3-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-30-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-4-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-5-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-6-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-7-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-8-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/alt-9-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/create-certs.js create mode 100644 test/js/node/test/fixtures/x509-escaping/google/intermediate.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/google/key.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/google/leaf0.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/google/leaf1.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/google/leaf2.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/google/leaf3.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/google/leaf4.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/google/root.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/info-0-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/info-1-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/info-2-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/info-3-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/info-4-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/package.json create mode 100644 test/js/node/test/fixtures/x509-escaping/server-key.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/subj-0-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/subj-1-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/subj-2-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/subj-3-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/subj-4-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/subj-5-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/subj-6-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/subj-7-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/subj-8-cert.pem create mode 100644 test/js/node/test/fixtures/x509-escaping/subj-9-cert.pem create mode 100644 test/js/node/test/parallel/assert-esm-cjs-message-verify.test.js create mode 100644 test/js/node/test/parallel/child-process-exec-env.test.js create mode 100644 test/js/node/test/parallel/child-process-exec-timeout-kill.test.js create mode 100644 test/js/node/test/parallel/child-process-execfile-promisified-abortcontroller.test.js create mode 100644 test/js/node/test/parallel/child-process-fork-abort-signal.test.js create mode 100644 test/js/node/test/parallel/child-process-fork-args.test.js create mode 100644 test/js/node/test/parallel/child-process-fork-close.test.js create mode 100644 test/js/node/test/parallel/child-process-fork-detached.test.js create mode 100644 test/js/node/test/parallel/crypto-keygen-async-encrypted-private-key-der.test.js create mode 100644 test/js/node/test/parallel/crypto-keygen-async-explicit-elliptic-curve.test.js create mode 100644 test/js/node/test/parallel/crypto-keygen-async-named-elliptic-curve.test.js create mode 100644 test/js/node/test/parallel/crypto-keygen-missing-oid.test.js create mode 100644 test/js/node/test/parallel/crypto-keygen-sync.test.js create mode 100644 test/js/node/test/parallel/fs-promises-readfile-empty.test.js create mode 100644 test/js/node/test/parallel/fs-read-stream-fd-leak.test.js create mode 100644 test/js/node/test/parallel/heap-prof-exec-argv.test.js create mode 100644 test/js/node/test/parallel/http-get-pipeline-problem.test.js create mode 100644 test/js/node/test/parallel/http-url.parse-https.request.test.js create mode 100644 test/js/node/test/parallel/https-agent.test.js create mode 100644 test/js/node/test/parallel/https-byteswritten.test.js create mode 100644 test/js/node/test/parallel/https-foafssl.test.js create mode 100644 test/js/node/test/parallel/https-socket-options.test.js create mode 100644 test/js/node/test/parallel/jest.config.js create mode 100644 test/js/node/test/parallel/module-main-extension-lookup.test.js create mode 100644 test/js/node/test/parallel/net-autoselectfamily-attempt-timeout-default-value.test.js create mode 100644 test/js/node/test/parallel/process-chdir-errormessage.test.js create mode 100644 test/js/node/test/parallel/quic-internal-endpoint-options.test.js create mode 100644 test/js/node/test/parallel/require-empty-main.test.js create mode 100644 test/js/node/test/parallel/require-extensions-main.test.js create mode 100644 test/js/node/test/parallel/signal-unregister.test.js create mode 100644 test/js/node/test/parallel/stream-preprocess.test.js create mode 100644 test/js/node/test/parallel/tls-add-context.test.js create mode 100644 test/js/node/test/parallel/tls-ca-concat.test.js create mode 100644 test/js/node/test/parallel/tls-client-abort.test.js create mode 100644 test/js/node/test/parallel/tls-fast-writing.test.js create mode 100644 test/js/node/test/parallel/tls-net-socket-keepalive.test.js create mode 100644 test/js/node/test/parallel/tls-peer-certificate-multi-keys.test.js create mode 100644 test/js/node/test/parallel/tls-startcom-wosign-whitelist.test.js create mode 100644 test/js/node/test/parallel/tls-ticket-cluster.test.js create mode 100644 test/js/node/test/parallel/tls-transport-destroy-after-own-gc.test.js create mode 100644 test/js/node/test/parallel/tls-zero-clear-in.test.js create mode 100644 test/js/node/test/parallel/whatwg-url-custom-searchparams-entries.test.js create mode 100644 test/js/node/test/parallel/whatwg-url-custom-searchparams-foreach.test.js create mode 100644 test/js/node/test/parallel/whatwg-url-custom-searchparams-keys.test.js create mode 100644 test/js/node/test/parallel/whatwg-url-custom-searchparams-stringifier.test.js create mode 100644 test/js/node/test/parallel/whatwg-url-custom-searchparams-values.test.js create mode 100644 test/js/node/test/parallel/whatwg-url-custom-searchparams.test.js create mode 100644 test/js/node/test/parallel/worker-cjs-workerdata.test.js create mode 100644 test/js/node/test/parallel/worker-esmodule.test.js create mode 100644 test/js/node/test/parallel/worker-mjs-workerdata.test.js create mode 100644 test/js/node/test/parallel/worker-terminate-http2-respond-with-file.test.js diff --git a/.gitattributes b/.gitattributes index 6c3caa3fe5..589c9da751 100644 --- a/.gitattributes +++ b/.gitattributes @@ -45,3 +45,6 @@ examples/**/* linguist-documentation src/deps/*.c linguist-vendored src/deps/brotli/** linguist-vendored + +test/js/node/test/fixtures linguist-vendored +test/js/node/test/common linguist-vendored diff --git a/.vscode/settings.json b/.vscode/settings.json index 476f38ee4c..a533a0a9f0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -15,6 +15,9 @@ "src/bun.js/WebKit": true, "src/deps/*/**": true, "test/node.js/upstream": true, + // This will fill up your whole search history. + "test/js/node/test/fixtures": true, + "test/js/node/test/common": true, }, "search.followSymlinks": false, "search.useIgnoreFiles": true, diff --git a/test/js/node/test/.gitignore b/test/js/node/test/.gitignore new file mode 100644 index 0000000000..c08151e95f --- /dev/null +++ b/test/js/node/test/.gitignore @@ -0,0 +1,10 @@ +fixtures/wpt +fixtures/tools +fixtures/v8-coverage +fixtures/test-runner +fixtures/source-map +fixtures/snapshot +fixtures/repl* +.tmp.* +*shadow-realm* +**/fails.txt diff --git a/test/js/node/test/common/arraystream.js b/test/js/node/test/common/arraystream.js new file mode 100644 index 0000000000..c9dae0512b --- /dev/null +++ b/test/js/node/test/common/arraystream.js @@ -0,0 +1,23 @@ +'use strict'; + +const { Stream } = require('stream'); +function noop() {} + +// A stream to push an array into a REPL +function ArrayStream() { + this.run = function(data) { + data.forEach((line) => { + this.emit('data', `${line}\n`); + }); + }; +} + +Object.setPrototypeOf(ArrayStream.prototype, Stream.prototype); +Object.setPrototypeOf(ArrayStream, Stream); +ArrayStream.prototype.readable = true; +ArrayStream.prototype.writable = true; +ArrayStream.prototype.pause = noop; +ArrayStream.prototype.resume = noop; +ArrayStream.prototype.write = noop; + +module.exports = ArrayStream; diff --git a/test/js/node/test/common/assertSnapshot.js b/test/js/node/test/common/assertSnapshot.js new file mode 100644 index 0000000000..88f40281e0 --- /dev/null +++ b/test/js/node/test/common/assertSnapshot.js @@ -0,0 +1,97 @@ +'use strict'; +const common = require('.'); +const path = require('node:path'); +const test = require('node:test'); +const fs = require('node:fs/promises'); +const assert = require('node:assert/strict'); + +const stackFramesRegexp = /(?<=\n)(\s+)((.+?)\s+\()?(?:\(?(.+?):(\d+)(?::(\d+))?)\)?(\s+\{)?(\[\d+m)?(\n|$)/g; +const windowNewlineRegexp = /\r/g; + +function replaceNodeVersion(str) { + return str.replaceAll(process.version, '*'); +} + +function replaceStackTrace(str, replacement = '$1*$7$8\n') { + return str.replace(stackFramesRegexp, replacement); +} + +function replaceWindowsLineEndings(str) { + return str.replace(windowNewlineRegexp, ''); +} + +function replaceWindowsPaths(str) { + return common.isWindows ? str.replaceAll(path.win32.sep, path.posix.sep) : str; +} + +function replaceFullPaths(str) { + return str.replaceAll(process.cwd(), ''); +} + +function transform(...args) { + return (str) => args.reduce((acc, fn) => fn(acc), str); +} + +function getSnapshotPath(filename) { + const { name, dir } = path.parse(filename); + return path.resolve(dir, `${name}.snapshot`); +} + +async function assertSnapshot(actual, filename = process.argv[1]) { + const snapshot = getSnapshotPath(filename); + if (process.env.NODE_REGENERATE_SNAPSHOTS) { + await fs.writeFile(snapshot, actual); + } else { + let expected; + try { + expected = await fs.readFile(snapshot, 'utf8'); + } catch (e) { + if (e.code === 'ENOENT') { + console.log( + 'Snapshot file does not exist. You can create a new one by running the test with NODE_REGENERATE_SNAPSHOTS=1', + ); + } + throw e; + } + assert.strictEqual(actual, replaceWindowsLineEndings(expected)); + } +} + +/** + * Spawn a process and assert its output against a snapshot. + * if you want to automatically update the snapshot, run tests with NODE_REGENERATE_SNAPSHOTS=1 + * transform is a function that takes the output and returns a string that will be compared against the snapshot + * this is useful for normalizing output such as stack traces + * there are some predefined transforms in this file such as replaceStackTrace and replaceWindowsLineEndings + * both of which can be used as an example for writing your own + * compose multiple transforms by passing them as arguments to the transform function: + * assertSnapshot.transform(assertSnapshot.replaceStackTrace, assertSnapshot.replaceWindowsLineEndings) + * @param {string} filename + * @param {function(string): string} [transform] + * @param {object} [options] - control how the child process is spawned + * @param {boolean} [options.tty] - whether to spawn the process in a pseudo-tty + * @returns {Promise} + */ +async function spawnAndAssert(filename, transform = (x) => x, { tty = false, ...options } = {}) { + if (tty && common.isWindows) { + test({ skip: 'Skipping pseudo-tty tests, as pseudo terminals are not available on Windows.' }); + return; + } + const flags = common.parseTestFlags(filename); + const executable = tty ? 'tools/pseudo-tty.py' : process.execPath; + const args = tty ? [process.execPath, ...flags, filename] : [...flags, filename]; + const { stdout, stderr } = await common.spawnPromisified(executable, args, options); + await assertSnapshot(transform(`${stdout}${stderr}`), filename); +} + +module.exports = { + assertSnapshot, + getSnapshotPath, + replaceFullPaths, + replaceNodeVersion, + replaceStackTrace, + replaceWindowsLineEndings, + replaceWindowsPaths, + spawnAndAssert, + transform, +}; diff --git a/test/js/node/test/common/benchmark.js b/test/js/node/test/common/benchmark.js new file mode 100644 index 0000000000..d9c1cdc627 --- /dev/null +++ b/test/js/node/test/common/benchmark.js @@ -0,0 +1,43 @@ +'use strict'; + +const assert = require('assert'); +const fork = require('child_process').fork; +const path = require('path'); + +const runjs = path.join(__dirname, '..', '..', 'benchmark', 'run.js'); + +function runBenchmark(name, env) { + const argv = ['test']; + + argv.push(name); + + const mergedEnv = { ...process.env, ...env }; + + const child = fork(runjs, argv, { + env: mergedEnv, + stdio: ['inherit', 'pipe', 'inherit', 'ipc'], + }); + child.stdout.setEncoding('utf8'); + + let stdout = ''; + child.stdout.on('data', (line) => { + stdout += line; + }); + + child.on('exit', (code, signal) => { + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); + // This bit makes sure that each benchmark file is being sent settings such + // that the benchmark file runs just one set of options. This helps keep the + // benchmark tests from taking a long time to run. Therefore, each benchmark + // file should result in three lines of output: a blank line, a line with + // the name of the benchmark file, and a line with the only results that we + // get from testing the benchmark file. + assert.ok( + /^(?:\n.+?\n.+?\n)+$/.test(stdout), + `benchmark file not running exactly one configuration in test: ${stdout}`, + ); + }); +} + +module.exports = runBenchmark; diff --git a/test/js/node/test/common/child_process.js b/test/js/node/test/common/child_process.js new file mode 100644 index 0000000000..d555d09a94 --- /dev/null +++ b/test/js/node/test/common/child_process.js @@ -0,0 +1,146 @@ +'use strict'; + +const assert = require('assert'); +const { spawnSync, execFileSync } = require('child_process'); +const common = require('./'); +const util = require('util'); + +// Workaround for Windows Server 2008R2 +// When CMD is used to launch a process and CMD is killed too quickly, the +// process can stay behind running in suspended state, never completing. +function cleanupStaleProcess(filename) { + if (!common.isWindows) { + return; + } + process.once('beforeExit', () => { + const basename = filename.replace(/.*[/\\]/g, ''); + try { + execFileSync(`${process.env.SystemRoot}\\System32\\wbem\\WMIC.exe`, [ + 'process', + 'where', + `commandline like '%${basename}%child'`, + 'delete', + '/nointeractive', + ]); + } catch { + // Ignore failures, there might not be any stale process to clean up. + } + }); +} + +// This should keep the child process running long enough to expire +// the timeout. +const kExpiringChildRunTime = common.platformTimeout(20 * 1000); +const kExpiringParentTimer = 1; +assert(kExpiringChildRunTime > kExpiringParentTimer); + +function logAfterTime(time) { + setTimeout(() => { + // The following console statements are part of the test. + console.log('child stdout'); + console.error('child stderr'); + }, time); +} + +function checkOutput(str, check) { + if ((check instanceof RegExp && !check.test(str)) || + (typeof check === 'string' && check !== str)) { + return { passed: false, reason: `did not match ${util.inspect(check)}` }; + } + if (typeof check === 'function') { + try { + check(str); + } catch (error) { + return { + passed: false, + reason: `did not match expectation, checker throws:\n${util.inspect(error)}`, + }; + } + } + return { passed: true }; +} + +function expectSyncExit(child, { + status, + signal, + stderr: stderrCheck, + stdout: stdoutCheck, + trim = false, +}) { + const failures = []; + let stderrStr, stdoutStr; + if (status !== undefined && child.status !== status) { + failures.push(`- process terminated with status ${child.status}, expected ${status}`); + } + if (signal !== undefined && child.signal !== signal) { + failures.push(`- process terminated with signal ${child.signal}, expected ${signal}`); + } + + function logAndThrow() { + const tag = `[process ${child.pid}]:`; + console.error(`${tag} --- stderr ---`); + console.error(stderrStr === undefined ? child.stderr.toString() : stderrStr); + console.error(`${tag} --- stdout ---`); + console.error(stdoutStr === undefined ? child.stdout.toString() : stdoutStr); + console.error(`${tag} status = ${child.status}, signal = ${child.signal}`); + throw new Error(`${failures.join('\n')}`); + } + + // If status and signal are not matching expectations, fail early. + if (failures.length !== 0) { + logAndThrow(); + } + + if (stderrCheck !== undefined) { + stderrStr = child.stderr.toString(); + const { passed, reason } = checkOutput(trim ? stderrStr.trim() : stderrStr, stderrCheck); + if (!passed) { + failures.push(`- stderr ${reason}`); + } + } + if (stdoutCheck !== undefined) { + stdoutStr = child.stdout.toString(); + const { passed, reason } = checkOutput(trim ? stdoutStr.trim() : stdoutStr, stdoutCheck); + if (!passed) { + failures.push(`- stdout ${reason}`); + } + } + if (failures.length !== 0) { + logAndThrow(); + } + return { child, stderr: stderrStr, stdout: stdoutStr }; +} + +function spawnSyncAndExit(...args) { + const spawnArgs = args.slice(0, args.length - 1); + const expectations = args[args.length - 1]; + const child = spawnSync(...spawnArgs); + return expectSyncExit(child, expectations); +} + +function spawnSyncAndExitWithoutError(...args) { + return expectSyncExit(spawnSync(...args), { + status: 0, + signal: null, + }); +} + +function spawnSyncAndAssert(...args) { + const expectations = args.pop(); + const child = spawnSync(...args); + return expectSyncExit(child, { + status: 0, + signal: null, + ...expectations, + }); +} + +module.exports = { + cleanupStaleProcess, + logAfterTime, + kExpiringChildRunTime, + kExpiringParentTimer, + spawnSyncAndAssert, + spawnSyncAndExit, + spawnSyncAndExitWithoutError, +}; diff --git a/test/js/node/test/common/countdown.js b/test/js/node/test/common/countdown.js new file mode 100644 index 0000000000..4aa86b4253 --- /dev/null +++ b/test/js/node/test/common/countdown.js @@ -0,0 +1,28 @@ +'use strict'; + +const assert = require('assert'); +const kLimit = Symbol('limit'); +const kCallback = Symbol('callback'); +const common = require('./'); + +class Countdown { + constructor(limit, cb) { + assert.strictEqual(typeof limit, 'number'); + assert.strictEqual(typeof cb, 'function'); + this[kLimit] = limit; + this[kCallback] = common.mustCall(cb); + } + + dec() { + assert(this[kLimit] > 0, 'Countdown expired'); + if (--this[kLimit] === 0) + this[kCallback](); + return this[kLimit]; + } + + get remaining() { + return this[kLimit]; + } +} + +module.exports = Countdown; diff --git a/test/js/node/test/common/cpu-prof.js b/test/js/node/test/common/cpu-prof.js new file mode 100644 index 0000000000..42f55b35fe --- /dev/null +++ b/test/js/node/test/common/cpu-prof.js @@ -0,0 +1,50 @@ +'use strict'; + +require('./'); +const fs = require('fs'); +const path = require('path'); +const assert = require('assert'); + +function getCpuProfiles(dir) { + const list = fs.readdirSync(dir); + return list + .filter((file) => file.endsWith('.cpuprofile')) + .map((file) => path.join(dir, file)); +} + +function getFrames(file, suffix) { + const data = fs.readFileSync(file, 'utf8'); + const profile = JSON.parse(data); + const frames = profile.nodes.filter((i) => { + const frame = i.callFrame; + return frame.url.endsWith(suffix); + }); + return { frames, nodes: profile.nodes }; +} + +function verifyFrames(output, file, suffix) { + const { frames, nodes } = getFrames(file, suffix); + if (frames.length === 0) { + // Show native debug output and the profile for debugging. + console.log(output.stderr.toString()); + console.log(nodes); + } + assert.notDeepStrictEqual(frames, []); +} + +// We need to set --cpu-interval to a smaller value to make sure we can +// find our workload in the samples. 50us should be a small enough sampling +// interval for this. +const kCpuProfInterval = 50; +const env = { + ...process.env, + NODE_DEBUG_NATIVE: 'INSPECTOR_PROFILER', +}; + +module.exports = { + getCpuProfiles, + kCpuProfInterval, + env, + getFrames, + verifyFrames, +}; diff --git a/test/js/node/test/common/crypto.js b/test/js/node/test/common/crypto.js new file mode 100644 index 0000000000..ba47285df4 --- /dev/null +++ b/test/js/node/test/common/crypto.js @@ -0,0 +1,132 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +const assert = require('assert'); +const crypto = require('crypto'); +const { + createSign, + createVerify, + publicEncrypt, + privateDecrypt, + sign, + verify, +} = crypto; + +// The values below (modp2/modp2buf) are for a 1024 bits long prime from +// RFC 2412 E.2, see https://tools.ietf.org/html/rfc2412. */ +const modp2buf = Buffer.from([ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, + 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b, + 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, + 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, + 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd, 0xef, 0x95, + 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, + 0xf2, 0x5f, 0x14, 0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, + 0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, + 0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, + 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed, 0xee, 0x38, 0x6b, 0xfb, + 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, + 0x1f, 0xe6, 0x49, 0x28, 0x66, 0x51, 0xec, 0xe6, 0x53, 0x81, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +]); + +function testDH({ publicKey: alicePublicKey, privateKey: alicePrivateKey }, + { publicKey: bobPublicKey, privateKey: bobPrivateKey }, + expectedValue) { + const buf1 = crypto.diffieHellman({ + privateKey: alicePrivateKey, + publicKey: bobPublicKey, + }); + const buf2 = crypto.diffieHellman({ + privateKey: bobPrivateKey, + publicKey: alicePublicKey, + }); + assert.deepStrictEqual(buf1, buf2); + + if (expectedValue !== undefined) + assert.deepStrictEqual(buf1, expectedValue); +} + +// Asserts that the size of the given key (in chars or bytes) is within 10% of +// the expected size. +function assertApproximateSize(key, expectedSize) { + const u = typeof key === 'string' ? 'chars' : 'bytes'; + const min = Math.floor(0.9 * expectedSize); + const max = Math.ceil(1.1 * expectedSize); + assert(key.length >= min, + `Key (${key.length} ${u}) is shorter than expected (${min} ${u})`); + assert(key.length <= max, + `Key (${key.length} ${u}) is longer than expected (${max} ${u})`); +} + +// Tests that a key pair can be used for encryption / decryption. +function testEncryptDecrypt(publicKey, privateKey) { + const message = 'Hello Node.js world!'; + const plaintext = Buffer.from(message, 'utf8'); + for (const key of [publicKey, privateKey]) { + const ciphertext = publicEncrypt(key, plaintext); + const received = privateDecrypt(privateKey, ciphertext); + assert.strictEqual(received.toString('utf8'), message); + } +} + +// Tests that a key pair can be used for signing / verification. +function testSignVerify(publicKey, privateKey) { + const message = Buffer.from('Hello Node.js world!'); + + function oldSign(algo, data, key) { + return createSign(algo).update(data).sign(key); + } + + function oldVerify(algo, data, key, signature) { + return createVerify(algo).update(data).verify(key, signature); + } + + for (const signFn of [sign, oldSign]) { + const signature = signFn('SHA256', message, privateKey); + for (const verifyFn of [verify, oldVerify]) { + for (const key of [publicKey, privateKey]) { + const okay = verifyFn('SHA256', message, key, signature); + assert(okay); + } + } + } +} + +// Constructs a regular expression for a PEM-encoded key with the given label. +function getRegExpForPEM(label, cipher) { + const head = `\\-\\-\\-\\-\\-BEGIN ${label}\\-\\-\\-\\-\\-`; + const rfc1421Header = cipher == null ? '' : + `\nProc-Type: 4,ENCRYPTED\nDEK-Info: ${cipher},[^\n]+\n`; + const body = '([a-zA-Z0-9\\+/=]{64}\n)*[a-zA-Z0-9\\+/=]{1,64}'; + const end = `\\-\\-\\-\\-\\-END ${label}\\-\\-\\-\\-\\-`; + return new RegExp(`^${head}${rfc1421Header}\n${body}\n${end}\n$`); +} + +const pkcs1PubExp = getRegExpForPEM('RSA PUBLIC KEY'); +const pkcs1PrivExp = getRegExpForPEM('RSA PRIVATE KEY'); +const pkcs1EncExp = (cipher) => getRegExpForPEM('RSA PRIVATE KEY', cipher); +const spkiExp = getRegExpForPEM('PUBLIC KEY'); +const pkcs8Exp = getRegExpForPEM('PRIVATE KEY'); +const pkcs8EncExp = getRegExpForPEM('ENCRYPTED PRIVATE KEY'); +const sec1Exp = getRegExpForPEM('EC PRIVATE KEY'); +const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); + +module.exports = { + modp2buf, + testDH, + assertApproximateSize, + testEncryptDecrypt, + testSignVerify, + pkcs1PubExp, + pkcs1PrivExp, + pkcs1EncExp, // used once + spkiExp, + pkcs8Exp, // used once + pkcs8EncExp, // used once + sec1Exp, + sec1EncExp, +}; diff --git a/test/js/node/test/common/debugger.js b/test/js/node/test/common/debugger.js new file mode 100644 index 0000000000..d5d77fc7c6 --- /dev/null +++ b/test/js/node/test/common/debugger.js @@ -0,0 +1,183 @@ +'use strict'; +const common = require('../common'); +const spawn = require('child_process').spawn; + +const BREAK_MESSAGE = new RegExp('(?:' + [ + 'assert', 'break', 'break on start', 'debugCommand', + 'exception', 'other', 'promiseRejection', 'step', +].join('|') + ') in', 'i'); + +let TIMEOUT = common.platformTimeout(5000); +if (common.isWindows) { + // Some of the windows machines in the CI need more time to receive + // the outputs from the client. + // https://github.com/nodejs/build/issues/3014 + TIMEOUT = common.platformTimeout(15000); +} + +function isPreBreak(output) { + return /Break on start/.test(output) && /1 \(function \(exports/.test(output); +} + +function startCLI(args, flags = [], spawnOpts = {}) { + let stderrOutput = ''; + const child = + spawn(process.execPath, [...flags, 'inspect', ...args], spawnOpts); + + const outputBuffer = []; + function bufferOutput(chunk) { + if (this === child.stderr) { + stderrOutput += chunk; + } + outputBuffer.push(chunk); + } + + function getOutput() { + return outputBuffer.join('\n').replaceAll('\b', ''); + } + + child.stdout.setEncoding('utf8'); + child.stdout.on('data', bufferOutput); + child.stderr.setEncoding('utf8'); + child.stderr.on('data', bufferOutput); + + if (process.env.VERBOSE === '1') { + child.stdout.pipe(process.stdout); + child.stderr.pipe(process.stderr); + } + + return { + flushOutput() { + const output = this.output; + outputBuffer.length = 0; + return output; + }, + + waitFor(pattern) { + function checkPattern(str) { + if (Array.isArray(pattern)) { + return pattern.every((p) => p.test(str)); + } + return pattern.test(str); + } + + return new Promise((resolve, reject) => { + function checkOutput() { + if (checkPattern(getOutput())) { + tearDown(); + resolve(); + } + } + + function onChildClose(code, signal) { + tearDown(); + let message = 'Child exited'; + if (code) { + message += `, code ${code}`; + } + if (signal) { + message += `, signal ${signal}`; + } + message += ` while waiting for ${pattern}; found: ${this.output}`; + if (stderrOutput) { + message += `\n STDERR: ${stderrOutput}`; + } + reject(new Error(message)); + } + + const timer = setTimeout(() => { + tearDown(); + reject(new Error([ + `Timeout (${TIMEOUT}) while waiting for ${pattern}`, + `found: ${this.output}`, + ].join('; '))); + }, TIMEOUT); + + function tearDown() { + clearTimeout(timer); + child.stdout.removeListener('data', checkOutput); + child.removeListener('close', onChildClose); + } + + child.on('close', onChildClose); + child.stdout.on('data', checkOutput); + checkOutput(); + }); + }, + + waitForPrompt() { + return this.waitFor(/>\s+$/); + }, + + async waitForInitialBreak() { + await this.waitFor(/break (?:on start )?in/i); + + if (isPreBreak(this.output)) { + await this.command('next', false); + return this.waitFor(/break in/); + } + }, + + get breakInfo() { + const output = this.output; + const breakMatch = + output.match(/(step |break (?:on start )?)in ([^\n]+):(\d+)\n/i); + + if (breakMatch === null) { + throw new Error( + `Could not find breakpoint info in ${JSON.stringify(output)}`); + } + return { filename: breakMatch[2], line: +breakMatch[3] }; + }, + + ctrlC() { + return this.command('.interrupt'); + }, + + get output() { + return getOutput(); + }, + + get rawOutput() { + return outputBuffer.join('').toString(); + }, + + parseSourceLines() { + return getOutput().split('\n') + .map((line) => line.match(/(?:\*|>)?\s*(\d+)/)) + .filter((match) => match !== null) + .map((match) => +match[1]); + }, + + writeLine(input, flush = true) { + if (flush) { + this.flushOutput(); + } + if (process.env.VERBOSE === '1') { + process.stderr.write(`< ${input}\n`); + } + child.stdin.write(input); + child.stdin.write('\n'); + }, + + command(input, flush = true) { + this.writeLine(input, flush); + return this.waitForPrompt(); + }, + + stepCommand(input) { + this.writeLine(input, true); + return this + .waitFor(BREAK_MESSAGE) + .then(() => this.waitForPrompt()); + }, + + quit() { + return new Promise((resolve) => { + child.stdin.end(); + child.on('close', resolve); + }); + }, + }; +} +module.exports = startCLI; diff --git a/test/js/node/test/common/dns.js b/test/js/node/test/common/dns.js new file mode 100644 index 0000000000..d854c73629 --- /dev/null +++ b/test/js/node/test/common/dns.js @@ -0,0 +1,341 @@ +'use strict'; + +const assert = require('assert'); +const os = require('os'); +const { isIP } = require('net'); + +const types = { + A: 1, + AAAA: 28, + NS: 2, + CNAME: 5, + SOA: 6, + PTR: 12, + MX: 15, + TXT: 16, + ANY: 255, + CAA: 257, +}; + +const classes = { + IN: 1, +}; + +// Naïve DNS parser/serializer. + +function readDomainFromPacket(buffer, offset) { + assert.ok(offset < buffer.length); + const length = buffer[offset]; + if (length === 0) { + return { nread: 1, domain: '' }; + } else if ((length & 0xC0) === 0) { + offset += 1; + const chunk = buffer.toString('ascii', offset, offset + length); + // Read the rest of the domain. + const { nread, domain } = readDomainFromPacket(buffer, offset + length); + return { + nread: 1 + length + nread, + domain: domain ? `${chunk}.${domain}` : chunk, + }; + } + // Pointer to another part of the packet. + assert.strictEqual(length & 0xC0, 0xC0); + // eslint-disable-next-line @stylistic/js/space-infix-ops, @stylistic/js/space-unary-ops + const pointeeOffset = buffer.readUInt16BE(offset) &~ 0xC000; + return { + nread: 2, + domain: readDomainFromPacket(buffer, pointeeOffset), + }; +} + +function parseDNSPacket(buffer) { + assert.ok(buffer.length > 12); + + const parsed = { + id: buffer.readUInt16BE(0), + flags: buffer.readUInt16BE(2), + }; + + const counts = [ + ['questions', buffer.readUInt16BE(4)], + ['answers', buffer.readUInt16BE(6)], + ['authorityAnswers', buffer.readUInt16BE(8)], + ['additionalRecords', buffer.readUInt16BE(10)], + ]; + + let offset = 12; + for (const [ sectionName, count ] of counts) { + parsed[sectionName] = []; + for (let i = 0; i < count; ++i) { + const { nread, domain } = readDomainFromPacket(buffer, offset); + offset += nread; + + const type = buffer.readUInt16BE(offset); + + const rr = { + domain, + cls: buffer.readUInt16BE(offset + 2), + }; + offset += 4; + + for (const name in types) { + if (types[name] === type) + rr.type = name; + } + + if (sectionName !== 'questions') { + rr.ttl = buffer.readInt32BE(offset); + const dataLength = buffer.readUInt16BE(offset); + offset += 6; + + switch (type) { + case types.A: + assert.strictEqual(dataLength, 4); + rr.address = `${buffer[offset + 0]}.${buffer[offset + 1]}.` + + `${buffer[offset + 2]}.${buffer[offset + 3]}`; + break; + case types.AAAA: + assert.strictEqual(dataLength, 16); + rr.address = buffer.toString('hex', offset, offset + 16) + .replace(/(.{4}(?!$))/g, '$1:'); + break; + case types.TXT: + { + let position = offset; + rr.entries = []; + while (position < offset + dataLength) { + const txtLength = buffer[offset]; + rr.entries.push(buffer.toString('utf8', + position + 1, + position + 1 + txtLength)); + position += 1 + txtLength; + } + assert.strictEqual(position, offset + dataLength); + break; + } + case types.MX: + { + rr.priority = buffer.readInt16BE(buffer, offset); + offset += 2; + const { nread, domain } = readDomainFromPacket(buffer, offset); + rr.exchange = domain; + assert.strictEqual(nread, dataLength); + break; + } + case types.NS: + case types.CNAME: + case types.PTR: + { + const { nread, domain } = readDomainFromPacket(buffer, offset); + rr.value = domain; + assert.strictEqual(nread, dataLength); + break; + } + case types.SOA: + { + const mname = readDomainFromPacket(buffer, offset); + const rname = readDomainFromPacket(buffer, offset + mname.nread); + rr.nsname = mname.domain; + rr.hostmaster = rname.domain; + const trailerOffset = offset + mname.nread + rname.nread; + rr.serial = buffer.readUInt32BE(trailerOffset); + rr.refresh = buffer.readUInt32BE(trailerOffset + 4); + rr.retry = buffer.readUInt32BE(trailerOffset + 8); + rr.expire = buffer.readUInt32BE(trailerOffset + 12); + rr.minttl = buffer.readUInt32BE(trailerOffset + 16); + + assert.strictEqual(trailerOffset + 20, dataLength); + break; + } + default: + throw new Error(`Unknown RR type ${rr.type}`); + } + offset += dataLength; + } + + parsed[sectionName].push(rr); + + assert.ok(offset <= buffer.length); + } + } + + assert.strictEqual(offset, buffer.length); + return parsed; +} + +function writeIPv6(ip) { + const parts = ip.replace(/^:|:$/g, '').split(':'); + const buf = Buffer.alloc(16); + + let offset = 0; + for (const part of parts) { + if (part === '') { + offset += 16 - 2 * (parts.length - 1); + } else { + buf.writeUInt16BE(parseInt(part, 16), offset); + offset += 2; + } + } + + return buf; +} + +function writeDomainName(domain) { + return Buffer.concat(domain.split('.').map((label) => { + assert(label.length < 64); + return Buffer.concat([ + Buffer.from([label.length]), + Buffer.from(label, 'ascii'), + ]); + }).concat([Buffer.alloc(1)])); +} + +function writeDNSPacket(parsed) { + const buffers = []; + const kStandardResponseFlags = 0x8180; + + buffers.push(new Uint16Array([ + parsed.id, + parsed.flags === undefined ? kStandardResponseFlags : parsed.flags, + parsed.questions && parsed.questions.length, + parsed.answers && parsed.answers.length, + parsed.authorityAnswers && parsed.authorityAnswers.length, + parsed.additionalRecords && parsed.additionalRecords.length, + ])); + + for (const q of parsed.questions) { + assert(types[q.type]); + buffers.push(writeDomainName(q.domain)); + buffers.push(new Uint16Array([ + types[q.type], + q.cls === undefined ? classes.IN : q.cls, + ])); + } + + for (const rr of [].concat(parsed.answers, + parsed.authorityAnswers, + parsed.additionalRecords)) { + if (!rr) continue; + + assert(types[rr.type]); + buffers.push(writeDomainName(rr.domain)); + buffers.push(new Uint16Array([ + types[rr.type], + rr.cls === undefined ? classes.IN : rr.cls, + ])); + buffers.push(new Int32Array([rr.ttl])); + + const rdLengthBuf = new Uint16Array(1); + buffers.push(rdLengthBuf); + + switch (rr.type) { + case 'A': + rdLengthBuf[0] = 4; + buffers.push(new Uint8Array(rr.address.split('.'))); + break; + case 'AAAA': + rdLengthBuf[0] = 16; + buffers.push(writeIPv6(rr.address)); + break; + case 'TXT': { + const total = rr.entries.map((s) => s.length).reduce((a, b) => a + b); + // Total length of all strings + 1 byte each for their lengths. + rdLengthBuf[0] = rr.entries.length + total; + for (const txt of rr.entries) { + buffers.push(new Uint8Array([Buffer.byteLength(txt)])); + buffers.push(Buffer.from(txt)); + } + break; + } + case 'MX': + rdLengthBuf[0] = 2; + buffers.push(new Uint16Array([rr.priority])); + // fall through + case 'NS': + case 'CNAME': + case 'PTR': + { + const domain = writeDomainName(rr.exchange || rr.value); + rdLengthBuf[0] += domain.length; + buffers.push(domain); + break; + } + case 'SOA': + { + const mname = writeDomainName(rr.nsname); + const rname = writeDomainName(rr.hostmaster); + rdLengthBuf[0] = mname.length + rname.length + 20; + buffers.push(mname, rname); + buffers.push(new Uint32Array([ + rr.serial, rr.refresh, rr.retry, rr.expire, rr.minttl, + ])); + break; + } + case 'CAA': + { + rdLengthBuf[0] = 5 + rr.issue.length + 2; + buffers.push(Buffer.from([Number(rr.critical)])); + buffers.push(Buffer.from([Number(5)])); + buffers.push(Buffer.from('issue' + rr.issue)); + break; + } + default: + throw new Error(`Unknown RR type ${rr.type}`); + } + } + + return Buffer.concat(buffers.map((typedArray) => { + const buf = Buffer.from(typedArray.buffer, + typedArray.byteOffset, + typedArray.byteLength); + if (os.endianness() === 'LE') { + if (typedArray.BYTES_PER_ELEMENT === 2) buf.swap16(); + if (typedArray.BYTES_PER_ELEMENT === 4) buf.swap32(); + } + return buf; + })); +} + +const mockedErrorCode = 'ENOTFOUND'; +const mockedSysCall = 'getaddrinfo'; + +function errorLookupMock(code = mockedErrorCode, syscall = mockedSysCall) { + return function lookupWithError(hostname, dnsopts, cb) { + const err = new Error(`${syscall} ${code} ${hostname}`); + err.code = code; + err.errno = code; + err.syscall = syscall; + err.hostname = hostname; + cb(err); + }; +} + +function createMockedLookup(...addresses) { + addresses = addresses.map((address) => ({ address: address, family: isIP(address) })); + + // Create a DNS server which replies with a AAAA and a A record for the same host + return function lookup(hostname, options, cb) { + if (options.all === true) { + process.nextTick(() => { + cb(null, addresses); + }); + + return; + } + + process.nextTick(() => { + cb(null, addresses[0].address, addresses[0].family); + }); + }; +} + +module.exports = { + types, + classes, + writeDNSPacket, + parseDNSPacket, + errorLookupMock, + mockedErrorCode, + mockedSysCall, + createMockedLookup, +}; diff --git a/test/js/node/test/common/duplexpair.js b/test/js/node/test/common/duplexpair.js new file mode 100644 index 0000000000..1f41ed32f1 --- /dev/null +++ b/test/js/node/test/common/duplexpair.js @@ -0,0 +1,48 @@ +'use strict'; +const { Duplex } = require('stream'); +const assert = require('assert'); + +const kCallback = Symbol('Callback'); +const kOtherSide = Symbol('Other'); + +class DuplexSocket extends Duplex { + constructor() { + super(); + this[kCallback] = null; + this[kOtherSide] = null; + } + + _read() { + const callback = this[kCallback]; + if (callback) { + this[kCallback] = null; + callback(); + } + } + + _write(chunk, encoding, callback) { + assert.notStrictEqual(this[kOtherSide], null); + assert.strictEqual(this[kOtherSide][kCallback], null); + if (chunk.length === 0) { + process.nextTick(callback); + } else { + this[kOtherSide].push(chunk); + this[kOtherSide][kCallback] = callback; + } + } + + _final(callback) { + this[kOtherSide].on('end', callback); + this[kOtherSide].push(null); + } +} + +function makeDuplexPair() { + const clientSide = new DuplexSocket(); + const serverSide = new DuplexSocket(); + clientSide[kOtherSide] = serverSide; + serverSide[kOtherSide] = clientSide; + return { clientSide, serverSide }; +} + +module.exports = makeDuplexPair; diff --git a/test/js/node/test/common/fixtures.js b/test/js/node/test/common/fixtures.js new file mode 100644 index 0000000000..75815b035b --- /dev/null +++ b/test/js/node/test/common/fixtures.js @@ -0,0 +1,59 @@ +'use strict'; + +const path = require('path'); +const fs = require('fs'); +const { pathToFileURL } = require('url'); + +const fixturesDir = path.join(__dirname, '..', 'fixtures'); + +function fixturesPath(...args) { + return path.join(fixturesDir, ...args); +} + +function fixturesFileURL(...args) { + return pathToFileURL(fixturesPath(...args)); +} + +function readFixtureSync(args, enc) { + if (Array.isArray(args)) + return fs.readFileSync(fixturesPath(...args), enc); + return fs.readFileSync(fixturesPath(args), enc); +} + +function readFixtureKey(name, enc) { + return fs.readFileSync(fixturesPath('keys', name), enc); +} + +function readFixtureKeys(enc, ...names) { + return names.map((name) => readFixtureKey(name, enc)); +} + +// This should be in sync with test/fixtures/utf8_test_text.txt. +// We copy them here as a string because this is supposed to be used +// in fs API tests. +const utf8TestText = '永和ä¹å¹´ï¼Œåµ—在癸丑,暮春之åˆï¼Œæœƒæ–¼æœƒç¨½å±±éš‚之蘭亭,脩稧事也。' + + 'ç¾£è³¢ç•¢è‡³ï¼Œå°‘é•·å’¸é›†ã€‚æ­¤åœ°æœ‰å´‡å±±å³»é ˜ï¼ŒèŒ‚æž—è„©ç«¹ï¼›åˆæœ‰æ¸…æµæ¿€æ¹ï¼Œ' + + '暎帶左å³ã€‚引以為æµè§´æ›²æ°´ï¼Œåˆ—å其次。雖無絲竹管弦之盛,一觴一詠,' + + '亦足以暢敘幽情。是日也,天朗氣清,æµé¢¨å’Œæš¢ï¼›ä»°è§€å®‡å®™ä¹‹å¤§ï¼Œ' + + '俯察å“類之盛;所以éŠç›®é¨æ‡ï¼Œè¶³ä»¥æ¥µè¦–è½ä¹‹å¨›ï¼Œä¿¡å¯æ¨‚也。夫人之相與,' + + '俯仰一世,或å–è«¸æ‡æŠ±ï¼Œæ‚Ÿè¨€ä¸€å®¤ä¹‹å…§ï¼Œæˆ–å› å¯„æ‰€è¨—ï¼Œæ”¾æµªå½¢éª¸ä¹‹å¤–ã€‚' + + 'é›–è¶£èˆŽè¬æ®Šï¼Œéœèºä¸åŒï¼Œç•¶å…¶æ¬£æ‰µæ‰€é‡ï¼Œæš«å¾—扵己,æ€ç„¶è‡ªè¶³ï¼Œ' + + 'ä¸çŸ¥è€ä¹‹å°‡è‡³ã€‚åŠå…¶æ‰€ä¹‹æ—¢æƒ“,情隨事é·ï¼Œæ„Ÿæ…¨ä¿‚之矣。å‘之所欣,' + + '俛仰之閒以為陳跡,猶ä¸èƒ½ä¸ä»¥ä¹‹èˆˆæ‡ï¼›æ³è„©çŸ­éš¨åŒ–,終期扵盡。' + + 'å¤äººäº‘:「死生亦大矣。ã€è±ˆä¸ç—›å“‰ï¼æ¯æ”¬æ˜”人興感之由,若åˆä¸€å¥‘,' + + '未嘗ä¸è‡¨æ–‡å—Ÿæ‚¼ï¼Œä¸èƒ½å–»ä¹‹æ‰µæ‡ã€‚固知一死生為虛誕,齊彭殤為妄作。' + + 'å¾Œä¹‹è¦–ä»Šï¼Œäº¦ç”±ä»Šä¹‹è¦–æ˜”ï¼Œæ‚²å¤«ï¼æ•…列敘時人,錄其所述,雖世殊事異,' + + '所以興æ‡ï¼Œå…¶è‡´ä¸€ä¹Ÿã€‚後之攬者,亦將有感扵斯文。'; + +module.exports = { + fixturesDir, + path: fixturesPath, + fileURL: fixturesFileURL, + readSync: readFixtureSync, + readKey: readFixtureKey, + readKeys: readFixtureKeys, + utf8TestText, + get utf8TestTextPath() { + return fixturesPath('utf8_test_text.txt'); + }, +}; diff --git a/test/js/node/test/common/fixtures.mjs b/test/js/node/test/common/fixtures.mjs new file mode 100644 index 0000000000..d6f7f6c092 --- /dev/null +++ b/test/js/node/test/common/fixtures.mjs @@ -0,0 +1,17 @@ +import fixtures from './fixtures.js'; + +const { + fixturesDir, + path, + fileURL, + readSync, + readKey, +} = fixtures; + +export { + fixturesDir, + path, + fileURL, + readSync, + readKey, +}; diff --git a/test/js/node/test/common/gc.js b/test/js/node/test/common/gc.js new file mode 100644 index 0000000000..8e2c5ee5da --- /dev/null +++ b/test/js/node/test/common/gc.js @@ -0,0 +1,127 @@ +'use strict'; + +const wait = require('timers/promises').setTimeout; + +// TODO(joyeecheung): merge ongc.js and gcUntil from common/index.js +// into this. + +// This function can be used to check if an object factor leaks or not, +// but it needs to be used with care: +// 1. The test should be set up with an ideally small +// --max-old-space-size or --max-heap-size, which combined with +// the maxCount parameter can reproduce a leak of the objects +// created by fn(). +// 2. This works under the assumption that if *none* of the objects +// created by fn() can be garbage-collected, the test would crash due +// to OOM. +// 3. If *any* of the objects created by fn() can be garbage-collected, +// it is considered leak-free. The FinalizationRegistry is used to +// terminate the test early once we detect any of the object is +// garbage-collected to make the test less prone to false positives. +// This may be especially important for memory management relying on +// emphemeron GC which can be inefficient to deal with extremely fast +// heap growth. +// Note that this can still produce false positives. When the test using +// this function still crashes due to OOM, inspect the heap to confirm +// if a leak is present (e.g. using heap snapshots). +// The generateSnapshotAt parameter can be used to specify a count +// interval to create the heap snapshot which may enforce a more thorough GC. +// This can be tried for code paths that require it for the GC to catch up +// with heap growth. However this type of forced GC can be in conflict with +// other logic in V8 such as bytecode aging, and it can slow down the test +// significantly, so it should be used scarcely and only as a last resort. +async function checkIfCollectable( + fn, maxCount = 4096, generateSnapshotAt = Infinity, logEvery = 128) { + let anyFinalized = false; + let count = 0; + + const f = new FinalizationRegistry(() => { + anyFinalized = true; + }); + + async function createObject() { + const obj = await fn(); + f.register(obj); + if (count++ < maxCount && !anyFinalized) { + setImmediate(createObject, 1); + } + // This can force a more thorough GC, but can slow the test down + // significantly in a big heap. Use it with care. + if (count % generateSnapshotAt === 0) { + // XXX(joyeecheung): This itself can consume a bit of JS heap memory, + // but the other alternative writeHeapSnapshot can run into disk space + // not enough problems in the CI & be slower depending on file system. + // Just do this for now as long as it works and only invent some + // internal voodoo when we absolutely have no other choice. + require('v8').getHeapSnapshot().pause().read(); + console.log(`Generated heap snapshot at ${count}`); + } + if (count % logEvery === 0) { + console.log(`Created ${count} objects`); + } + if (anyFinalized) { + console.log(`Found finalized object at ${count}, stop testing`); + } + } + + createObject(); +} + +// Repeat an operation and give GC some breathing room at every iteration. +async function runAndBreathe(fn, repeat, waitTime = 20) { + for (let i = 0; i < repeat; i++) { + await fn(); + await wait(waitTime); + } +} + +/** + * This requires --expose-internals. + * This function can be used to check if an object factory leaks or not by + * iterating over the heap and count objects with the specified class + * (which is checked by looking up the prototype chain). + * @param {(i: number) => number} fn The factory receiving iteration count + * and returning number of objects created. The return value should be + * precise otherwise false negatives can be produced. + * @param {Function} ctor The constructor of the objects being counted. + * @param {number} count Number of iterations that this check should be done + * @param {number} waitTime Optional breathing time for GC. + */ +async function checkIfCollectableByCounting(fn, ctor, count, waitTime = 20) { + const { queryObjects } = require('v8'); + const { name } = ctor; + const initialCount = queryObjects(ctor, { format: 'count' }); + console.log(`Initial count of ${name}: ${initialCount}`); + let totalCreated = 0; + for (let i = 0; i < count; ++i) { + const created = await fn(i); + totalCreated += created; + console.log(`#${i}: created ${created} ${name}, total ${totalCreated}`); + await wait(waitTime); // give GC some breathing room. + const currentCount = queryObjects(ctor, { format: 'count' }); + const collected = totalCreated - (currentCount - initialCount); + console.log(`#${i}: counted ${currentCount} ${name}, collected ${collected}`); + if (collected > 0) { + console.log(`Detected ${collected} collected ${name}, finish early`); + return; + } + } + + await wait(waitTime); // give GC some breathing room. + const currentCount = queryObjects(ctor, { format: 'count' }); + const collected = totalCreated - (currentCount - initialCount); + console.log(`Last count: counted ${currentCount} ${name}, collected ${collected}`); + // Some objects with the prototype can be collected. + if (collected > 0) { + console.log(`Detected ${collected} collected ${name}`); + return; + } + + throw new Error(`${name} cannot be collected`); +} + +module.exports = { + checkIfCollectable, + runAndBreathe, + checkIfCollectableByCounting, +}; diff --git a/test/js/node/test/common/globals.js b/test/js/node/test/common/globals.js new file mode 100644 index 0000000000..42caece2b8 --- /dev/null +++ b/test/js/node/test/common/globals.js @@ -0,0 +1,146 @@ +'use strict'; + +const intrinsics = new Set([ + 'Object', + 'Function', + 'Array', + 'Number', + 'parseFloat', + 'parseInt', + 'Infinity', + 'NaN', + 'undefined', + 'Boolean', + 'String', + 'Symbol', + 'Date', + 'Promise', + 'RegExp', + 'Error', + 'AggregateError', + 'EvalError', + 'RangeError', + 'ReferenceError', + 'SyntaxError', + 'TypeError', + 'URIError', + 'globalThis', + 'JSON', + 'Math', + 'Intl', + 'ArrayBuffer', + 'Uint8Array', + 'Int8Array', + 'Uint16Array', + 'Int16Array', + 'Uint32Array', + 'Int32Array', + 'Float32Array', + 'Float64Array', + 'Uint8ClampedArray', + 'BigUint64Array', + 'BigInt64Array', + 'DataView', + 'Map', + 'BigInt', + 'Set', + 'WeakMap', + 'WeakSet', + 'Proxy', + 'Reflect', + 'ShadowRealm', + 'FinalizationRegistry', + 'WeakRef', + 'decodeURI', + 'decodeURIComponent', + 'encodeURI', + 'encodeURIComponent', + 'escape', + 'unescape', + 'eval', + 'isFinite', + 'isNaN', + 'SharedArrayBuffer', + 'Atomics', + 'WebAssembly', + 'Iterator', +]); + +if (global.gc) { + intrinsics.add('gc'); +} + +// v8 exposes console in the global scope. +intrinsics.add('console'); + +const webIdlExposedWildcard = new Set([ + 'DOMException', + 'TextEncoder', + 'TextDecoder', + 'AbortController', + 'AbortSignal', + 'CustomEvent', + 'EventTarget', + 'Event', + 'URL', + 'URLSearchParams', + 'ReadableStream', + 'ReadableStreamDefaultReader', + 'ReadableStreamBYOBReader', + 'ReadableStreamBYOBRequest', + 'ReadableByteStreamController', + 'ReadableStreamDefaultController', + 'TransformStream', + 'TransformStreamDefaultController', + 'WritableStream', + 'WritableStreamDefaultWriter', + 'WritableStreamDefaultController', + 'ByteLengthQueuingStrategy', + 'CountQueuingStrategy', + 'TextEncoderStream', + 'TextDecoderStream', + 'CompressionStream', + 'DecompressionStream', +]); + +const webIdlExposedWindow = new Set([ + 'console', + 'BroadcastChannel', + 'queueMicrotask', + 'structuredClone', + 'MessageChannel', + 'MessagePort', + 'MessageEvent', + 'clearInterval', + 'clearTimeout', + 'setInterval', + 'setTimeout', + 'atob', + 'btoa', + 'Blob', + 'Performance', + 'performance', + 'fetch', + 'FormData', + 'Headers', + 'Request', + 'Response', + 'WebSocket', + 'EventSource', + 'CloseEvent', +]); + +const nodeGlobals = new Set([ + 'process', + 'global', + 'Buffer', + 'clearImmediate', + 'setImmediate', +]); + +module.exports = { + intrinsics, + webIdlExposedWildcard, + webIdlExposedWindow, + nodeGlobals, +}; diff --git a/test/js/node/test/common/heap.js b/test/js/node/test/common/heap.js new file mode 100644 index 0000000000..8eb36a8bfc --- /dev/null +++ b/test/js/node/test/common/heap.js @@ -0,0 +1,249 @@ +'use strict'; +const assert = require('assert'); +const util = require('util'); + +let internalBinding; +try { + internalBinding = require('internal/test/binding').internalBinding; +} catch (e) { + console.log('using `test/common/heap.js` requires `--expose-internals`'); + throw e; +} + +const { buildEmbedderGraph } = internalBinding('heap_utils'); +const { getHeapSnapshot } = require('v8'); + +function createJSHeapSnapshot(stream = getHeapSnapshot()) { + stream.pause(); + const dump = JSON.parse(stream.read()); + const meta = dump.snapshot.meta; + + const nodes = + readHeapInfo(dump.nodes, meta.node_fields, meta.node_types, dump.strings); + const edges = + readHeapInfo(dump.edges, meta.edge_fields, meta.edge_types, dump.strings); + + for (const node of nodes) { + node.incomingEdges = []; + node.outgoingEdges = []; + } + + let fromNodeIndex = 0; + let edgeIndex = 0; + for (const { type, name_or_index, to_node } of edges) { + while (edgeIndex === nodes[fromNodeIndex].edge_count) { + edgeIndex = 0; + fromNodeIndex++; + } + const toNode = nodes[to_node / meta.node_fields.length]; + const fromNode = nodes[fromNodeIndex]; + const edge = { + type, + to: toNode, + from: fromNode, + name: typeof name_or_index === 'string' ? name_or_index : null, + }; + toNode.incomingEdges.push(edge); + fromNode.outgoingEdges.push(edge); + edgeIndex++; + } + + for (const node of nodes) { + assert.strictEqual(node.edge_count, node.outgoingEdges.length, + `${node.edge_count} !== ${node.outgoingEdges.length}`); + } + return nodes; +} + +function readHeapInfo(raw, fields, types, strings) { + const items = []; + + for (let i = 0; i < raw.length; i += fields.length) { + const item = {}; + for (let j = 0; j < fields.length; j++) { + const name = fields[j]; + let type = types[j]; + if (Array.isArray(type)) { + item[name] = type[raw[i + j]]; + } else if (name === 'name_or_index') { // type === 'string_or_number' + if (item.type === 'element' || item.type === 'hidden') + type = 'number'; + else + type = 'string'; + } + + if (type === 'string') { + item[name] = strings[raw[i + j]]; + } else if (type === 'number' || type === 'node') { + item[name] = raw[i + j]; + } + } + items.push(item); + } + + return items; +} + +function inspectNode(snapshot) { + return util.inspect(snapshot, { depth: 4 }); +} + +function isEdge(edge, { node_name, edge_name }) { + if (edge_name !== undefined && edge.name !== edge_name) { + return false; + } + // From our internal embedded graph + if (edge.to.value) { + if (edge.to.value.constructor.name !== node_name) { + return false; + } + } else if (edge.to.name !== node_name) { + return false; + } + return true; +} + +class State { + constructor(stream) { + this.snapshot = createJSHeapSnapshot(stream); + this.embedderGraph = buildEmbedderGraph(); + } + + // Validate the v8 heap snapshot + validateSnapshot(rootName, expected, { loose = false } = {}) { + const rootNodes = this.snapshot.filter( + (node) => node.name === rootName && node.type !== 'string'); + if (loose) { + assert(rootNodes.length >= expected.length, + `Expect to find at least ${expected.length} '${rootName}', ` + + `found ${rootNodes.length}`); + } else { + assert.strictEqual( + rootNodes.length, expected.length, + `Expect to find ${expected.length} '${rootName}', ` + + `found ${rootNodes.length}`); + } + + for (const expectation of expected) { + if (expectation.children) { + for (const expectedEdge of expectation.children) { + const check = typeof expectedEdge === 'function' ? expectedEdge : + (edge) => (isEdge(edge, expectedEdge)); + const hasChild = rootNodes.some( + (node) => node.outgoingEdges.some(check), + ); + // Don't use assert with a custom message here. Otherwise the + // inspection in the message is done eagerly and wastes a lot of CPU + // time. + if (!hasChild) { + throw new Error( + 'expected to find child ' + + `${util.inspect(expectedEdge)} in ${inspectNode(rootNodes)}`); + } + } + } + + if (expectation.detachedness !== undefined) { + const matchedNodes = rootNodes.filter( + (node) => node.detachedness === expectation.detachedness); + if (loose) { + assert(matchedNodes.length >= rootNodes.length, + `Expect to find at least ${rootNodes.length} with ` + + `detachedness ${expectation.detachedness}, ` + + `found ${matchedNodes.length}`); + } else { + assert.strictEqual( + matchedNodes.length, rootNodes.length, + `Expect to find ${rootNodes.length} with detachedness ` + + `${expectation.detachedness}, found ${matchedNodes.length}`); + } + } + } + } + + // Validate our internal embedded graph representation + validateGraph(rootName, expected, { loose = false } = {}) { + const rootNodes = this.embedderGraph.filter( + (node) => node.name === rootName, + ); + if (loose) { + assert(rootNodes.length >= expected.length, + `Expect to find at least ${expected.length} '${rootName}', ` + + `found ${rootNodes.length}`); + } else { + assert.strictEqual( + rootNodes.length, expected.length, + `Expect to find ${expected.length} '${rootName}', ` + + `found ${rootNodes.length}`); + } + for (const expectation of expected) { + if (expectation.children) { + for (const expectedEdge of expectation.children) { + const check = typeof expectedEdge === 'function' ? expectedEdge : + (edge) => (isEdge(edge, expectedEdge)); + // Don't use assert with a custom message here. Otherwise the + // inspection in the message is done eagerly and wastes a lot of CPU + // time. + const hasChild = rootNodes.some( + (node) => node.edges.some(check), + ); + if (!hasChild) { + throw new Error( + 'expected to find child ' + + `${util.inspect(expectedEdge)} in ${inspectNode(rootNodes)}`); + } + } + } + } + } + + validateSnapshotNodes(rootName, expected, { loose = false } = {}) { + this.validateSnapshot(rootName, expected, { loose }); + this.validateGraph(rootName, expected, { loose }); + } +} + +function recordState(stream = undefined) { + return new State(stream); +} + +function validateSnapshotNodes(...args) { + return recordState().validateSnapshotNodes(...args); +} + +function getHeapSnapshotOptionTests() { + const fixtures = require('../common/fixtures'); + const cases = [ + { + options: { exposeInternals: true }, + expected: [{ + children: [ + // We don't have anything special to test here yet + // because we don't use cppgc or embedder heap tracer. + { edge_name: 'nonNumeric', node_name: 'test' }, + ], + }], + }, + { + options: { exposeNumericValues: true }, + expected: [{ + children: [ + { edge_name: 'numeric', node_name: 'smi number' }, + ], + }], + }, + ]; + return { + fixtures: fixtures.path('klass-with-fields.js'), + check(snapshot, expected) { + snapshot.validateSnapshot('Klass', expected, { loose: true }); + }, + cases, + }; +} + +module.exports = { + recordState, + validateSnapshotNodes, + getHeapSnapshotOptionTests, +}; diff --git a/test/js/node/test/common/hijackstdio.js b/test/js/node/test/common/hijackstdio.js new file mode 100644 index 0000000000..749d6aab48 --- /dev/null +++ b/test/js/node/test/common/hijackstdio.js @@ -0,0 +1,32 @@ +'use strict'; + +// Hijack stdout and stderr +const stdWrite = {}; +function hijackStdWritable(name, listener) { + const stream = process[name]; + const _write = stdWrite[name] = stream.write; + + stream.writeTimes = 0; + stream.write = function(data, callback) { + try { + listener(data); + } catch (e) { + process.nextTick(() => { throw e; }); + } + + _write.call(stream, data, callback); + stream.writeTimes++; + }; +} + +function restoreWritable(name) { + process[name].write = stdWrite[name]; + delete process[name].writeTimes; +} + +module.exports = { + hijackStdout: hijackStdWritable.bind(null, 'stdout'), + hijackStderr: hijackStdWritable.bind(null, 'stderr'), + restoreStdout: restoreWritable.bind(null, 'stdout'), + restoreStderr: restoreWritable.bind(null, 'stderr'), +}; diff --git a/test/js/node/test/common/http2.js b/test/js/node/test/common/http2.js new file mode 100644 index 0000000000..6df1c29c09 --- /dev/null +++ b/test/js/node/test/common/http2.js @@ -0,0 +1,148 @@ +'use strict'; + +// An HTTP/2 testing tool used to create mock frames for direct testing +// of HTTP/2 endpoints. + +const kFrameData = Symbol('frame-data'); +const FLAG_EOS = 0x1; +const FLAG_ACK = 0x1; +const FLAG_EOH = 0x4; +const FLAG_PADDED = 0x8; +const PADDING = Buffer.alloc(255); + +const kClientMagic = Buffer.from('505249202a20485454502f322' + + 'e300d0a0d0a534d0d0a0d0a', 'hex'); + +const kFakeRequestHeaders = Buffer.from('828684410f7777772e65' + + '78616d706c652e636f6d', 'hex'); + + +const kFakeResponseHeaders = Buffer.from('4803333032580770726976617465611d' + + '4d6f6e2c203231204f63742032303133' + + '2032303a31333a323120474d546e1768' + + '747470733a2f2f7777772e6578616d70' + + '6c652e636f6d', 'hex'); + +function isUint32(val) { + return val >>> 0 === val; +} + +function isUint24(val) { + return val >>> 0 === val && val <= 0xFFFFFF; +} + +function isUint8(val) { + return val >>> 0 === val && val <= 0xFF; +} + +function write32BE(array, pos, val) { + if (!isUint32(val)) + throw new RangeError('val is not a 32-bit number'); + array[pos++] = (val >> 24) & 0xff; + array[pos++] = (val >> 16) & 0xff; + array[pos++] = (val >> 8) & 0xff; + array[pos++] = val & 0xff; +} + +function write24BE(array, pos, val) { + if (!isUint24(val)) + throw new RangeError('val is not a 24-bit number'); + array[pos++] = (val >> 16) & 0xff; + array[pos++] = (val >> 8) & 0xff; + array[pos++] = val & 0xff; +} + +function write8(array, pos, val) { + if (!isUint8(val)) + throw new RangeError('val is not an 8-bit number'); + array[pos] = val; +} + +class Frame { + constructor(length, type, flags, id) { + this[kFrameData] = Buffer.alloc(9); + write24BE(this[kFrameData], 0, length); + write8(this[kFrameData], 3, type); + write8(this[kFrameData], 4, flags); + write32BE(this[kFrameData], 5, id); + } + + get data() { + return this[kFrameData]; + } +} + +class SettingsFrame extends Frame { + constructor(ack = false) { + let flags = 0; + if (ack) + flags |= FLAG_ACK; + super(0, 4, flags, 0); + } +} + +class DataFrame extends Frame { + constructor(id, payload, padlen = 0, final = false) { + let len = payload.length; + let flags = 0; + if (final) flags |= FLAG_EOS; + const buffers = [payload]; + if (padlen > 0) { + buffers.unshift(Buffer.from([padlen])); + buffers.push(PADDING.slice(0, padlen)); + len += padlen + 1; + flags |= FLAG_PADDED; + } + super(len, 0, flags, id); + buffers.unshift(this[kFrameData]); + this[kFrameData] = Buffer.concat(buffers); + } +} + +class HeadersFrame extends Frame { + constructor(id, payload, padlen = 0, final = false) { + let len = payload.length; + let flags = FLAG_EOH; + if (final) flags |= FLAG_EOS; + const buffers = [payload]; + if (padlen > 0) { + buffers.unshift(Buffer.from([padlen])); + buffers.push(PADDING.slice(0, padlen)); + len += padlen + 1; + flags |= FLAG_PADDED; + } + super(len, 1, flags, id); + buffers.unshift(this[kFrameData]); + this[kFrameData] = Buffer.concat(buffers); + } +} + +class PingFrame extends Frame { + constructor(ack = false) { + const buffers = [Buffer.alloc(8)]; + super(8, 6, ack ? 1 : 0, 0); + buffers.unshift(this[kFrameData]); + this[kFrameData] = Buffer.concat(buffers); + } +} + +class AltSvcFrame extends Frame { + constructor(size) { + const buffers = [Buffer.alloc(size)]; + super(size, 10, 0, 0); + buffers.unshift(this[kFrameData]); + this[kFrameData] = Buffer.concat(buffers); + } +} + +module.exports = { + Frame, + AltSvcFrame, + DataFrame, + HeadersFrame, + SettingsFrame, + PingFrame, + kFakeRequestHeaders, + kFakeResponseHeaders, + kClientMagic, +}; diff --git a/test/js/node/test/common/index.js b/test/js/node/test/common/index.js new file mode 100644 index 0000000000..ea21d15c10 --- /dev/null +++ b/test/js/node/test/common/index.js @@ -0,0 +1,1156 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +/* eslint-disable node-core/crypto-check */ +'use strict'; +const process = global.process; // Some tests tamper with the process global. + +const assert = require('assert'); +const { exec, execSync, spawn, spawnSync } = require('child_process'); +const fs = require('fs'); +const net = require('net'); +// Do not require 'os' until needed so that test-os-checked-function can +// monkey patch it. If 'os' is required here, that test will fail. +const path = require('path'); +const { inspect } = require('util'); +const { isMainThread } = require('worker_threads'); +const { isModuleNamespaceObject } = require('util/types'); + +const tmpdir = require('./tmpdir'); +const bits = ['arm64', 'loong64', 'mips', 'mipsel', 'ppc64', 'riscv64', 's390x', 'x64'] + .includes(process.arch) ? 64 : 32; +const hasIntl = !!process.config.variables.v8_enable_i18n_support; + +const { + atob, + btoa, +} = require('buffer'); + +// Some tests assume a umask of 0o022 so set that up front. Tests that need a +// different umask will set it themselves. +// +// Workers can read, but not set the umask, so check that this is the main +// thread. +if (isMainThread) + process.umask(0o022); + +const noop = () => {}; + +const hasCrypto = Boolean(process.versions.openssl) && + !process.env.NODE_SKIP_CRYPTO; + +// Synthesize OPENSSL_VERSION_NUMBER format with the layout 0xMNN00PPSL +const opensslVersionNumber = (major = 0, minor = 0, patch = 0) => { + assert(major >= 0 && major <= 0xf); + assert(minor >= 0 && minor <= 0xff); + assert(patch >= 0 && patch <= 0xff); + return (major << 28) | (minor << 20) | (patch << 4); +}; + +let OPENSSL_VERSION_NUMBER; +const hasOpenSSL = (major = 0, minor = 0, patch = 0) => { + if (!hasCrypto) return false; + if (OPENSSL_VERSION_NUMBER === undefined) { + const regexp = /(?\d+)\.(?\d+)\.(?

\d+)/; + const { m, n, p } = process.versions.openssl.match(regexp).groups; + OPENSSL_VERSION_NUMBER = opensslVersionNumber(m, n, p); + } + return OPENSSL_VERSION_NUMBER >= opensslVersionNumber(major, minor, patch); +}; + +const hasQuic = hasCrypto && !!process.config.variables.openssl_quic; + +function parseTestFlags(filename = process.argv[1]) { + // The copyright notice is relatively big and the flags could come afterwards. + const bytesToRead = 1500; + const buffer = Buffer.allocUnsafe(bytesToRead); + const fd = fs.openSync(filename, 'r'); + const bytesRead = fs.readSync(fd, buffer, 0, bytesToRead); + fs.closeSync(fd); + const source = buffer.toString('utf8', 0, bytesRead); + + const flagStart = source.search(/\/\/ Flags:\s+--/) + 10; + + if (flagStart === 9) { + return []; + } + let flagEnd = source.indexOf('\n', flagStart); + // Normalize different EOL. + if (source[flagEnd - 1] === '\r') { + flagEnd--; + } + return source + .substring(flagStart, flagEnd) + .split(/\s+/) + .filter(Boolean); +} + +// Check for flags. Skip this for workers (both, the `cluster` module and +// `worker_threads`) and child processes. +// If the binary was built without-ssl then the crypto flags are +// invalid (bad option). The test itself should handle this case. +if (process.argv.length === 2 && + !process.env.NODE_SKIP_FLAG_CHECK && + isMainThread && + hasCrypto && + require('cluster').isPrimary && + fs.existsSync(process.argv[1])) { + const flags = parseTestFlags(); + for (const flag of flags) { + if (!process.execArgv.includes(flag) && + // If the binary is build without `intl` the inspect option is + // invalid. The test itself should handle this case. + (process.features.inspector || !flag.startsWith('--inspect'))) { + console.log( + 'NOTE: The test started as a child_process using these flags:', + inspect(flags), + 'Use NODE_SKIP_FLAG_CHECK to run the test with the original flags.', + ); + const args = [...flags, ...process.execArgv, ...process.argv.slice(1)]; + const options = { encoding: 'utf8', stdio: 'inherit' }; + const result = spawnSync(process.execPath, args, options); + if (result.signal) { + process.kill(0, result.signal); + } else { + process.exit(result.status); + } + } + } +} + +const isWindows = process.platform === 'win32'; +const isSunOS = process.platform === 'sunos'; +const isFreeBSD = process.platform === 'freebsd'; +const isOpenBSD = process.platform === 'openbsd'; +const isLinux = process.platform === 'linux'; +const isOSX = process.platform === 'darwin'; +const isASan = process.config.variables.asan === 1; +const isPi = (() => { + try { + // Normal Raspberry Pi detection is to find the `Raspberry Pi` string in + // the contents of `/sys/firmware/devicetree/base/model` but that doesn't + // work inside a container. Match the chipset model number instead. + const cpuinfo = fs.readFileSync('/proc/cpuinfo', { encoding: 'utf8' }); + const ok = /^Hardware\s*:\s*(.*)$/im.exec(cpuinfo)?.[1] === 'BCM2835'; + /^/.test(''); // Clear RegExp.$_, some tests expect it to be empty. + return ok; + } catch { + return false; + } +})(); + +const isDumbTerminal = process.env.TERM === 'dumb'; + +// When using high concurrency or in the CI we need much more time for each connection attempt +net.setDefaultAutoSelectFamilyAttemptTimeout(platformTimeout(net.getDefaultAutoSelectFamilyAttemptTimeout() * 10)); +const defaultAutoSelectFamilyAttemptTimeout = net.getDefaultAutoSelectFamilyAttemptTimeout(); + +const buildType = process.config.target_defaults ? + process.config.target_defaults.default_configuration : + 'Release'; + +// If env var is set then enable async_hook hooks for all tests. +if (process.env.NODE_TEST_WITH_ASYNC_HOOKS) { + const destroydIdsList = {}; + const destroyListList = {}; + const initHandles = {}; + const { internalBinding } = require('internal/test/binding'); + const async_wrap = internalBinding('async_wrap'); + + process.on('exit', () => { + // Iterate through handles to make sure nothing crashes + for (const k in initHandles) + inspect(initHandles[k]); + }); + + const _queueDestroyAsyncId = async_wrap.queueDestroyAsyncId; + async_wrap.queueDestroyAsyncId = function queueDestroyAsyncId(id) { + if (destroyListList[id] !== undefined) { + process._rawDebug(destroyListList[id]); + process._rawDebug(); + throw new Error(`same id added to destroy list twice (${id})`); + } + destroyListList[id] = inspect(new Error()); + _queueDestroyAsyncId(id); + }; + + require('async_hooks').createHook({ + init(id, ty, tr, resource) { + if (initHandles[id]) { + process._rawDebug( + `Is same resource: ${resource === initHandles[id].resource}`); + process._rawDebug(`Previous stack:\n${initHandles[id].stack}\n`); + throw new Error(`init called twice for same id (${id})`); + } + initHandles[id] = { + resource, + stack: inspect(new Error()).slice(6), + }; + }, + before() { }, + after() { }, + destroy(id) { + if (destroydIdsList[id] !== undefined) { + process._rawDebug(destroydIdsList[id]); + process._rawDebug(); + throw new Error(`destroy called for same id (${id})`); + } + destroydIdsList[id] = inspect(new Error()); + }, + }).enable(); +} + +let opensslCli = null; +let inFreeBSDJail = null; +let localhostIPv4 = null; + +const localIPv6Hosts = + isLinux ? [ + // Debian/Ubuntu + 'ip6-localhost', + 'ip6-loopback', + + // SUSE + 'ipv6-localhost', + 'ipv6-loopback', + + // Typically universal + 'localhost', + ] : [ 'localhost' ]; + +const PIPE = (() => { + const localRelative = path.relative(process.cwd(), `${tmpdir.path}/`); + const pipePrefix = isWindows ? '\\\\.\\pipe\\' : localRelative; + const pipeName = `node-test.${process.pid}.sock`; + return path.join(pipePrefix, pipeName); +})(); + +// Check that when running a test with +// `$node --abort-on-uncaught-exception $file child` +// the process aborts. +function childShouldThrowAndAbort() { + let testCmd = ''; + if (!isWindows) { + // Do not create core files, as it can take a lot of disk space on + // continuous testing and developers' machines + testCmd += 'ulimit -c 0 && '; + } + testCmd += `"${process.argv[0]}" --abort-on-uncaught-exception `; + testCmd += `"${process.argv[1]}" child`; + const child = exec(testCmd); + child.on('exit', function onExit(exitCode, signal) { + const errMsg = 'Test should have aborted ' + + `but instead exited with exit code ${exitCode}` + + ` and signal ${signal}`; + assert(nodeProcessAborted(exitCode, signal), errMsg); + }); +} + +function createZeroFilledFile(filename) { + const fd = fs.openSync(filename, 'w'); + fs.ftruncateSync(fd, 10 * 1024 * 1024); + fs.closeSync(fd); +} + + +const pwdCommand = isWindows ? + ['cmd.exe', ['/d', '/c', 'cd']] : + ['pwd', []]; + + +function platformTimeout(ms) { + const multipliers = typeof ms === 'bigint' ? + { two: 2n, four: 4n, seven: 7n } : { two: 2, four: 4, seven: 7 }; + + if (process.features.debug) + ms = multipliers.two * ms; + + if (exports.isAIX || exports.isIBMi) + return multipliers.two * ms; // Default localhost speed is slower on AIX + + if (isPi) + return multipliers.two * ms; // Raspberry Pi devices + + return ms; +} + +let knownGlobals = [ + AbortController, + atob, + btoa, + clearImmediate, + clearInterval, + clearTimeout, + global, + setImmediate, + setInterval, + setTimeout, + queueMicrotask, +]; + +if (global.gc) { + knownGlobals.push(global.gc); +} + +if (global.navigator) { + knownGlobals.push(global.navigator); +} + +if (global.Navigator) { + knownGlobals.push(global.Navigator); +} + +if (global.Performance) { + knownGlobals.push(global.Performance); +} +if (global.performance) { + knownGlobals.push(global.performance); +} +if (global.PerformanceMark) { + knownGlobals.push(global.PerformanceMark); +} +if (global.PerformanceMeasure) { + knownGlobals.push(global.PerformanceMeasure); +} + +// TODO(@ethan-arrowood): Similar to previous checks, this can be temporary +// until v16.x is EOL. Once all supported versions have structuredClone we +// can add this to the list above instead. +if (global.structuredClone) { + knownGlobals.push(global.structuredClone); +} + +if (global.EventSource) { + knownGlobals.push(EventSource); +} + +if (global.fetch) { + knownGlobals.push(fetch); +} +if (hasCrypto && global.crypto) { + knownGlobals.push(global.crypto); + knownGlobals.push(global.Crypto); + knownGlobals.push(global.CryptoKey); + knownGlobals.push(global.SubtleCrypto); +} +if (global.CustomEvent) { + knownGlobals.push(global.CustomEvent); +} +if (global.ReadableStream) { + knownGlobals.push( + global.ReadableStream, + global.ReadableStreamDefaultReader, + global.ReadableStreamBYOBReader, + global.ReadableStreamBYOBRequest, + global.ReadableByteStreamController, + global.ReadableStreamDefaultController, + global.TransformStream, + global.TransformStreamDefaultController, + global.WritableStream, + global.WritableStreamDefaultWriter, + global.WritableStreamDefaultController, + global.ByteLengthQueuingStrategy, + global.CountQueuingStrategy, + global.TextEncoderStream, + global.TextDecoderStream, + global.CompressionStream, + global.DecompressionStream, + ); +} + +if (global.Storage) { + knownGlobals.push( + global.localStorage, + global.sessionStorage, + global.Storage, + ); +} + +function allowGlobals(...allowlist) { + knownGlobals = knownGlobals.concat(allowlist); +} + +if (process.env.NODE_TEST_KNOWN_GLOBALS !== '0') { + if (process.env.NODE_TEST_KNOWN_GLOBALS) { + const knownFromEnv = process.env.NODE_TEST_KNOWN_GLOBALS.split(','); + allowGlobals(...knownFromEnv); + } + + function leakedGlobals() { + const leaked = []; + + for (const val in global) { + // globalThis.crypto is a getter that throws if Node.js was compiled + // without OpenSSL. + if (val !== 'crypto' && !knownGlobals.includes(global[val])) { + leaked.push(val); + } + } + + return leaked; + } + + process.on('exit', function() { + const leaked = leakedGlobals(); + if (leaked.length > 0) { + assert.fail(`Unexpected global(s) found: ${leaked.join(', ')}`); + } + }); +} + +const mustCallChecks = []; + +function runCallChecks(exitCode) { + if (exitCode !== 0) return; + + const failed = mustCallChecks.filter(function(context) { + if ('minimum' in context) { + context.messageSegment = `at least ${context.minimum}`; + return context.actual < context.minimum; + } + context.messageSegment = `exactly ${context.exact}`; + return context.actual !== context.exact; + }); + + failed.forEach(function(context) { + console.log('Mismatched %s function calls. Expected %s, actual %d.', + context.name, + context.messageSegment, + context.actual); + console.log(context.stack.split('\n').slice(2).join('\n')); + }); + + if (failed.length) process.exit(1); +} + +function mustCall(fn, exact) { + return _mustCallInner(fn, exact, 'exact'); +} + +function mustSucceed(fn, exact) { + return mustCall(function(err, ...args) { + assert.ifError(err); + if (typeof fn === 'function') + return fn.apply(this, args); + }, exact); +} + +function mustCallAtLeast(fn, minimum) { + return _mustCallInner(fn, minimum, 'minimum'); +} + +function _mustCallInner(fn, criteria = 1, field) { + if (process._exiting) + throw new Error('Cannot use common.mustCall*() in process exit handler'); + if (typeof fn === 'number') { + criteria = fn; + fn = noop; + } else if (fn === undefined) { + fn = noop; + } + + if (typeof criteria !== 'number') + throw new TypeError(`Invalid ${field} value: ${criteria}`); + + const context = { + [field]: criteria, + actual: 0, + stack: inspect(new Error()), + name: fn.name || '', + }; + + // Add the exit listener only once to avoid listener leak warnings + if (mustCallChecks.length === 0) process.on('exit', runCallChecks); + + mustCallChecks.push(context); + + const _return = function() { // eslint-disable-line func-style + context.actual++; + return fn.apply(this, arguments); + }; + // Function instances have own properties that may be relevant. + // Let's replicate those properties to the returned function. + // Refs: https://tc39.es/ecma262/#sec-function-instances + Object.defineProperties(_return, { + name: { + value: fn.name, + writable: false, + enumerable: false, + configurable: true, + }, + length: { + value: fn.length, + writable: false, + enumerable: false, + configurable: true, + }, + }); + return _return; +} + +function hasMultiLocalhost() { + const { internalBinding } = require('internal/test/binding'); + const { TCP, constants: TCPConstants } = internalBinding('tcp_wrap'); + const t = new TCP(TCPConstants.SOCKET); + const ret = t.bind('127.0.0.2', 0); + t.close(); + return ret === 0; +} + +function skipIfEslintMissing() { + if (!fs.existsSync( + path.join(__dirname, '..', '..', 'tools', 'eslint', 'node_modules', 'eslint'), + )) { + skip('missing ESLint'); + } +} + +function canCreateSymLink() { + // On Windows, creating symlinks requires admin privileges. + // We'll only try to run symlink test if we have enough privileges. + // On other platforms, creating symlinks shouldn't need admin privileges + if (isWindows) { + // whoami.exe needs to be the one from System32 + // If unix tools are in the path, they can shadow the one we want, + // so use the full path while executing whoami + const whoamiPath = path.join(process.env.SystemRoot, + 'System32', 'whoami.exe'); + + try { + const output = execSync(`${whoamiPath} /priv`, { timeout: 1000 }); + return output.includes('SeCreateSymbolicLinkPrivilege'); + } catch { + return false; + } + } + // On non-Windows platforms, this always returns `true` + return true; +} + +function getCallSite(top) { + const originalStackFormatter = Error.prepareStackTrace; + Error.prepareStackTrace = (err, stack) => + `${stack[0].getFileName()}:${stack[0].getLineNumber()}`; + const err = new Error(); + Error.captureStackTrace(err, top); + // With the V8 Error API, the stack is not formatted until it is accessed + err.stack; // eslint-disable-line no-unused-expressions + Error.prepareStackTrace = originalStackFormatter; + return err.stack; +} + +function mustNotCall(msg) { + const callSite = getCallSite(mustNotCall); + return function mustNotCall(...args) { + const argsInfo = args.length > 0 ? + `\ncalled with arguments: ${args.map((arg) => inspect(arg)).join(', ')}` : ''; + assert.fail( + `${msg || 'function should not have been called'} at ${callSite}` + + argsInfo); + }; +} + +const _mustNotMutateObjectDeepProxies = new WeakMap(); + +function mustNotMutateObjectDeep(original) { + // Return primitives and functions directly. Primitives are immutable, and + // proxied functions are impossible to compare against originals, e.g. with + // `assert.deepEqual()`. + if (original === null || typeof original !== 'object') { + return original; + } + + const cachedProxy = _mustNotMutateObjectDeepProxies.get(original); + if (cachedProxy) { + return cachedProxy; + } + + const _mustNotMutateObjectDeepHandler = { + __proto__: null, + defineProperty(target, property, descriptor) { + assert.fail(`Expected no side effects, got ${inspect(property)} ` + + 'defined'); + }, + deleteProperty(target, property) { + assert.fail(`Expected no side effects, got ${inspect(property)} ` + + 'deleted'); + }, + get(target, prop, receiver) { + return mustNotMutateObjectDeep(Reflect.get(target, prop, receiver)); + }, + preventExtensions(target) { + assert.fail('Expected no side effects, got extensions prevented on ' + + inspect(target)); + }, + set(target, property, value, receiver) { + assert.fail(`Expected no side effects, got ${inspect(value)} ` + + `assigned to ${inspect(property)}`); + }, + setPrototypeOf(target, prototype) { + assert.fail(`Expected no side effects, got set prototype to ${prototype}`); + }, + }; + + const proxy = new Proxy(original, _mustNotMutateObjectDeepHandler); + _mustNotMutateObjectDeepProxies.set(original, proxy); + return proxy; +} + +function printSkipMessage(msg) { + console.log(`1..0 # Skipped: ${msg}`); +} + +function skip(msg) { + printSkipMessage(msg); + // In known_issues test, skipping should produce a non-zero exit code. + process.exit(require.main?.filename.startsWith(path.resolve(__dirname, '../known_issues/')) ? 1 : 0); +} + +// Returns true if the exit code "exitCode" and/or signal name "signal" +// represent the exit code and/or signal name of a node process that aborted, +// false otherwise. +function nodeProcessAborted(exitCode, signal) { + // Depending on the compiler used, node will exit with either + // exit code 132 (SIGILL), 133 (SIGTRAP) or 134 (SIGABRT). + let expectedExitCodes = [132, 133, 134]; + + // On platforms using KSH as the default shell (like SmartOS), + // when a process aborts, KSH exits with an exit code that is + // greater than 256, and thus the exit code emitted with the 'exit' + // event is null and the signal is set to either SIGILL, SIGTRAP, + // or SIGABRT (depending on the compiler). + const expectedSignals = ['SIGILL', 'SIGTRAP', 'SIGABRT']; + + // On Windows, 'aborts' are of 2 types, depending on the context: + // (i) Exception breakpoint, if --abort-on-uncaught-exception is on + // which corresponds to exit code 2147483651 (0x80000003) + // (ii) Otherwise, _exit(134) which is called in place of abort() due to + // raising SIGABRT exiting with ambiguous exit code '3' by default + if (isWindows) + expectedExitCodes = [0x80000003, 134]; + + // When using --abort-on-uncaught-exception, V8 will use + // base::OS::Abort to terminate the process. + // Depending on the compiler used, the shell or other aspects of + // the platform used to build the node binary, this will actually + // make V8 exit by aborting or by raising a signal. In any case, + // one of them (exit code or signal) needs to be set to one of + // the expected exit codes or signals. + if (signal !== null) { + return expectedSignals.includes(signal); + } + return expectedExitCodes.includes(exitCode); +} + +function isAlive(pid) { + try { + process.kill(pid, 'SIGCONT'); + return true; + } catch { + return false; + } +} + +function _expectWarning(name, expected, code) { + if (typeof expected === 'string') { + expected = [[expected, code]]; + } else if (!Array.isArray(expected)) { + expected = Object.entries(expected).map(([a, b]) => [b, a]); + } else if (expected.length !== 0 && !Array.isArray(expected[0])) { + expected = [[expected[0], expected[1]]]; + } + // Deprecation codes are mandatory, everything else is not. + if (name === 'DeprecationWarning') { + expected.forEach(([_, code]) => assert(code, `Missing deprecation code: ${expected}`)); + } + return mustCall((warning) => { + const expectedProperties = expected.shift(); + if (!expectedProperties) { + assert.fail(`Unexpected extra warning received: ${warning}`); + } + const [ message, code ] = expectedProperties; + assert.strictEqual(warning.name, name); + if (typeof message === 'string') { + assert.strictEqual(warning.message, message); + } else { + assert.match(warning.message, message); + } + assert.strictEqual(warning.code, code); + }, expected.length); +} + +let catchWarning; + +// Accepts a warning name and description or array of descriptions or a map of +// warning names to description(s) ensures a warning is generated for each +// name/description pair. +// The expected messages have to be unique per `expectWarning()` call. +function expectWarning(nameOrMap, expected, code) { + if (catchWarning === undefined) { + catchWarning = {}; + process.on('warning', (warning) => { + if (!catchWarning[warning.name]) { + throw new TypeError( + `"${warning.name}" was triggered without being expected.\n` + + inspect(warning), + ); + } + catchWarning[warning.name](warning); + }); + } + if (typeof nameOrMap === 'string') { + catchWarning[nameOrMap] = _expectWarning(nameOrMap, expected, code); + } else { + Object.keys(nameOrMap).forEach((name) => { + catchWarning[name] = _expectWarning(name, nameOrMap[name]); + }); + } +} + +// Useful for testing expected internal/error objects +function expectsError(validator, exact) { + return mustCall((...args) => { + if (args.length !== 1) { + // Do not use `assert.strictEqual()` to prevent `inspect` from + // always being called. + assert.fail(`Expected one argument, got ${inspect(args)}`); + } + const error = args.pop(); + // The error message should be non-enumerable + assert.strictEqual(Object.prototype.propertyIsEnumerable.call(error, 'message'), false); + + assert.throws(() => { throw error; }, validator); + return true; + }, exact); +} + +function skipIfInspectorDisabled() { + if (!process.features.inspector) { + skip('V8 inspector is disabled'); + } +} + +function skipIf32Bits() { + if (bits < 64) { + skip('The tested feature is not available in 32bit builds'); + } +} + +function skipIfWorker() { + if (!isMainThread) { + skip('This test only works on a main thread'); + } +} + +function getArrayBufferViews(buf) { + const { buffer, byteOffset, byteLength } = buf; + + const out = []; + + const arrayBufferViews = [ + Int8Array, + Uint8Array, + Uint8ClampedArray, + Int16Array, + Uint16Array, + Int32Array, + Uint32Array, + Float32Array, + Float64Array, + BigInt64Array, + BigUint64Array, + DataView, + ]; + + for (const type of arrayBufferViews) { + const { BYTES_PER_ELEMENT = 1 } = type; + if (byteLength % BYTES_PER_ELEMENT === 0) { + out.push(new type(buffer, byteOffset, byteLength / BYTES_PER_ELEMENT)); + } + } + return out; +} + +function getBufferSources(buf) { + return [...getArrayBufferViews(buf), new Uint8Array(buf).buffer]; +} + +function getTTYfd() { + // Do our best to grab a tty fd. + const tty = require('tty'); + // Don't attempt fd 0 as it is not writable on Windows. + // Ref: ef2861961c3d9e9ed6972e1e84d969683b25cf95 + const ttyFd = [1, 2, 4, 5].find(tty.isatty); + if (ttyFd === undefined) { + try { + return fs.openSync('/dev/tty'); + } catch { + // There aren't any tty fd's available to use. + return -1; + } + } + return ttyFd; +} + +function runWithInvalidFD(func) { + let fd = 1 << 30; + // Get first known bad file descriptor. 1 << 30 is usually unlikely to + // be an valid one. + try { + while (fs.fstatSync(fd--) && fd > 0); + } catch { + return func(fd); + } + + printSkipMessage('Could not generate an invalid fd'); +} + +// A helper function to simplify checking for ERR_INVALID_ARG_TYPE output. +function invalidArgTypeHelper(input) { + if (input == null) { + return ` Received ${input}`; + } + if (typeof input === 'function') { + return ` Received function ${input.name}`; + } + if (typeof input === 'object') { + if (input.constructor?.name) { + return ` Received an instance of ${input.constructor.name}`; + } + return ` Received ${inspect(input, { depth: -1 })}`; + } + + let inspected = inspect(input, { colors: false }); + if (inspected.length > 28) { inspected = `${inspected.slice(inspected, 0, 25)}...`; } + + return ` Received type ${typeof input} (${inspected})`; +} + +function skipIfDumbTerminal() { + if (isDumbTerminal) { + skip('skipping - dumb terminal'); + } +} + +function gcUntil(name, condition) { + if (typeof name === 'function') { + condition = name; + name = undefined; + } + return new Promise((resolve, reject) => { + let count = 0; + function gcAndCheck() { + setImmediate(() => { + count++; + global.gc(); + if (condition()) { + resolve(); + } else if (count < 10) { + gcAndCheck(); + } else { + reject(name === undefined ? undefined : 'Test ' + name + ' failed'); + } + }); + } + gcAndCheck(); + }); +} + +function requireNoPackageJSONAbove(dir = __dirname) { + let possiblePackage = path.join(dir, '..', 'package.json'); + let lastPackage = null; + while (possiblePackage !== lastPackage) { + if (fs.existsSync(possiblePackage)) { + assert.fail( + 'This test shouldn\'t load properties from a package.json above ' + + `its file location. Found package.json at ${possiblePackage}.`); + } + lastPackage = possiblePackage; + possiblePackage = path.join(possiblePackage, '..', '..', 'package.json'); + } +} + +function spawnPromisified(...args) { + let stderr = ''; + let stdout = ''; + + const child = spawn(...args); + child.stderr.setEncoding('utf8'); + child.stderr.on('data', (data) => { stderr += data; }); + child.stdout.setEncoding('utf8'); + child.stdout.on('data', (data) => { stdout += data; }); + + return new Promise((resolve, reject) => { + child.on('close', (code, signal) => { + resolve({ + code, + signal, + stderr, + stdout, + }); + }); + child.on('error', (code, signal) => { + reject({ + code, + signal, + stderr, + stdout, + }); + }); + }); +} + +function getPrintedStackTrace(stderr) { + const lines = stderr.split('\n'); + + let state = 'initial'; + const result = { + message: [], + nativeStack: [], + jsStack: [], + }; + for (let i = 0; i < lines.length; ++i) { + const line = lines[i].trim(); + if (line.length === 0) { + continue; // Skip empty lines. + } + + switch (state) { + case 'initial': + result.message.push(line); + if (line.includes('Native stack trace')) { + state = 'native-stack'; + } else { + result.message.push(line); + } + break; + case 'native-stack': + if (line.includes('JavaScript stack trace')) { + state = 'js-stack'; + } else { + result.nativeStack.push(line); + } + break; + case 'js-stack': + result.jsStack.push(line); + break; + } + } + return result; +} + +/** + * Check the exports of require(esm). + * TODO(joyeecheung): use it in all the test-require-module-* tests to minimize changes + * if/when we change the layout of the result returned by require(esm). + * @param {object} mod result returned by require() + * @param {object} expectation shape of expected namespace. + */ +function expectRequiredModule(mod, expectation) { + assert(isModuleNamespaceObject(mod)); + assert.deepStrictEqual({ ...mod }, { ...expectation }); +} + +const common = { + allowGlobals, + buildType, + canCreateSymLink, + childShouldThrowAndAbort, + createZeroFilledFile, + defaultAutoSelectFamilyAttemptTimeout, + expectsError, + expectRequiredModule, + expectWarning, + gcUntil, + getArrayBufferViews, + getBufferSources, + getCallSite, + getPrintedStackTrace, + getTTYfd, + hasIntl, + hasCrypto, + hasOpenSSL, + hasQuic, + hasMultiLocalhost, + invalidArgTypeHelper, + isAlive, + isASan, + isDumbTerminal, + isFreeBSD, + isLinux, + isMainThread, + isOpenBSD, + isOSX, + isPi, + isSunOS, + isWindows, + localIPv6Hosts, + mustCall, + mustCallAtLeast, + mustNotCall, + mustNotMutateObjectDeep, + mustSucceed, + nodeProcessAborted, + PIPE, + parseTestFlags, + platformTimeout, + printSkipMessage, + pwdCommand, + requireNoPackageJSONAbove, + runWithInvalidFD, + skip, + skipIf32Bits, + skipIfDumbTerminal, + skipIfEslintMissing, + skipIfInspectorDisabled, + skipIfWorker, + spawnPromisified, + + get enoughTestMem() { + return require('os').totalmem() > 0x70000000; /* 1.75 Gb */ + }, + + get hasFipsCrypto() { + return hasCrypto && require('crypto').getFips(); + }, + + get hasIPv6() { + const iFaces = require('os').networkInterfaces(); + let re; + if (isWindows) { + re = /Loopback Pseudo-Interface/; + } else if (this.isIBMi) { + re = /\*LOOPBACK/; + } else { + re = /lo/; + } + return Object.keys(iFaces).some((name) => { + return re.test(name) && + iFaces[name].some(({ family }) => family === 'IPv6'); + }); + }, + + get hasOpenSSL3() { + return hasOpenSSL(3); + }, + + get hasOpenSSL31() { + return hasOpenSSL(3, 1); + }, + + get hasOpenSSL32() { + return hasOpenSSL(3, 2); + }, + + get inFreeBSDJail() { + if (inFreeBSDJail !== null) return inFreeBSDJail; + + if (exports.isFreeBSD && + execSync('sysctl -n security.jail.jailed').toString() === '1\n') { + inFreeBSDJail = true; + } else { + inFreeBSDJail = false; + } + return inFreeBSDJail; + }, + + // On IBMi, process.platform and os.platform() both return 'aix', + // when built with Python versions earlier than 3.9. + // It is not enough to differentiate between IBMi and real AIX system. + get isAIX() { + return require('os').type() === 'AIX'; + }, + + get isIBMi() { + return require('os').type() === 'OS400'; + }, + + get isLinuxPPCBE() { + return (process.platform === 'linux') && (process.arch === 'ppc64') && + (require('os').endianness() === 'BE'); + }, + + get localhostIPv4() { + if (localhostIPv4 !== null) return localhostIPv4; + + if (this.inFreeBSDJail) { + // Jailed network interfaces are a bit special - since we need to jump + // through loops, as well as this being an exception case, assume the + // user will provide this instead. + if (process.env.LOCALHOST) { + localhostIPv4 = process.env.LOCALHOST; + } else { + console.error('Looks like we\'re in a FreeBSD Jail. ' + + 'Please provide your default interface address ' + + 'as LOCALHOST or expect some tests to fail.'); + } + } + + if (localhostIPv4 === null) localhostIPv4 = '127.0.0.1'; + + return localhostIPv4; + }, + + // opensslCli defined lazily to reduce overhead of spawnSync + get opensslCli() { + if (opensslCli !== null) return opensslCli; + + if (process.config.variables.node_shared_openssl) { + // Use external command + opensslCli = 'openssl'; + } else { + // Use command built from sources included in Node.js repository + opensslCli = path.join(path.dirname(process.execPath), 'openssl-cli'); + } + + if (exports.isWindows) opensslCli += '.exe'; + + const opensslCmd = spawnSync(opensslCli, ['version']); + if (opensslCmd.status !== 0 || opensslCmd.error !== undefined) { + // OpenSSL command cannot be executed + opensslCli = false; + } + return opensslCli; + }, + + get PORT() { + if (+process.env.TEST_PARALLEL) { + throw new Error('common.PORT cannot be used in a parallelized test'); + } + return +process.env.NODE_COMMON_PORT || 12346; + }, + + /** + * Returns the EOL character used by this Git checkout. + */ + get checkoutEOL() { + return fs.readFileSync(__filename).includes('\r\n') ? '\r\n' : '\n'; + }, +}; + +const validProperties = new Set(Object.keys(common)); +module.exports = new Proxy(common, { + get(obj, prop) { + if (!validProperties.has(prop)) + throw new Error(`Using invalid common property: '${prop}'`); + return obj[prop]; + }, +}); diff --git a/test/js/node/test/common/index.mjs b/test/js/node/test/common/index.mjs new file mode 100644 index 0000000000..430527faf8 --- /dev/null +++ b/test/js/node/test/common/index.mjs @@ -0,0 +1,110 @@ +import { createRequire } from 'module'; + +const require = createRequire(import.meta.url); +const common = require('./index.js'); + +const { + allowGlobals, + buildType, + canCreateSymLink, + checkoutEOL, + childShouldThrowAndAbort, + createZeroFilledFile, + enoughTestMem, + expectsError, + expectWarning, + getArrayBufferViews, + getBufferSources, + getCallSite, + getTTYfd, + hasCrypto, + hasIntl, + hasIPv6, + hasMultiLocalhost, + isAIX, + isAlive, + isDumbTerminal, + isFreeBSD, + isIBMi, + isLinux, + isLinuxPPCBE, + isMainThread, + isOpenBSD, + isOSX, + isSunOS, + isWindows, + localIPv6Hosts, + mustCall, + mustCallAtLeast, + mustNotCall, + mustNotMutateObjectDeep, + mustSucceed, + nodeProcessAborted, + opensslCli, + parseTestFlags, + PIPE, + platformTimeout, + printSkipMessage, + runWithInvalidFD, + skip, + skipIf32Bits, + skipIfDumbTerminal, + skipIfEslintMissing, + skipIfInspectorDisabled, + spawnPromisified, +} = common; + +const getPort = () => common.PORT; + +export { + allowGlobals, + buildType, + canCreateSymLink, + checkoutEOL, + childShouldThrowAndAbort, + createRequire, + createZeroFilledFile, + enoughTestMem, + expectsError, + expectWarning, + getArrayBufferViews, + getBufferSources, + getCallSite, + getPort, + getTTYfd, + hasCrypto, + hasIntl, + hasIPv6, + hasMultiLocalhost, + isAIX, + isAlive, + isDumbTerminal, + isFreeBSD, + isIBMi, + isLinux, + isLinuxPPCBE, + isMainThread, + isOpenBSD, + isOSX, + isSunOS, + isWindows, + localIPv6Hosts, + mustCall, + mustCallAtLeast, + mustNotCall, + mustNotMutateObjectDeep, + mustSucceed, + nodeProcessAborted, + opensslCli, + parseTestFlags, + PIPE, + platformTimeout, + printSkipMessage, + runWithInvalidFD, + skip, + skipIf32Bits, + skipIfDumbTerminal, + skipIfEslintMissing, + skipIfInspectorDisabled, + spawnPromisified, +}; diff --git a/test/js/node/test/common/inspector-helper.js b/test/js/node/test/common/inspector-helper.js new file mode 100644 index 0000000000..2c4d4af6de --- /dev/null +++ b/test/js/node/test/common/inspector-helper.js @@ -0,0 +1,537 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const fs = require('fs'); +const http = require('http'); +const fixtures = require('../common/fixtures'); +const { spawn } = require('child_process'); +const { URL, pathToFileURL } = require('url'); +const { EventEmitter } = require('events'); + +const _MAINSCRIPT = fixtures.path('loop.js'); +const DEBUG = false; +const TIMEOUT = common.platformTimeout(15 * 1000); + +function spawnChildProcess(inspectorFlags, scriptContents, scriptFile) { + const args = [].concat(inspectorFlags); + if (scriptContents) { + args.push('-e', scriptContents); + } else { + args.push(scriptFile); + } + const child = spawn(process.execPath, args); + + const handler = tearDown.bind(null, child); + process.on('exit', handler); + process.on('uncaughtException', handler); + process.on('unhandledRejection', handler); + process.on('SIGINT', handler); + + return child; +} + +function makeBufferingDataCallback(dataCallback) { + let buffer = Buffer.alloc(0); + return (data) => { + const newData = Buffer.concat([buffer, data]); + const str = newData.toString('utf8'); + const lines = str.replace(/\r/g, '').split('\n'); + if (str.endsWith('\n')) + buffer = Buffer.alloc(0); + else + buffer = Buffer.from(lines.pop(), 'utf8'); + for (const line of lines) + dataCallback(line); + }; +} + +function tearDown(child, err) { + child.kill(); + if (err) { + console.error(err); + process.exit(1); + } +} + +function parseWSFrame(buffer) { + // Protocol described in https://tools.ietf.org/html/rfc6455#section-5 + let message = null; + if (buffer.length < 2) + return { length: 0, message }; + if (buffer[0] === 0x88 && buffer[1] === 0x00) { + return { length: 2, message, closed: true }; + } + assert.strictEqual(buffer[0], 0x81); + let dataLen = 0x7F & buffer[1]; + let bodyOffset = 2; + if (buffer.length < bodyOffset + dataLen) + return 0; + if (dataLen === 126) { + dataLen = buffer.readUInt16BE(2); + bodyOffset = 4; + } else if (dataLen === 127) { + assert(buffer[2] === 0 && buffer[3] === 0, 'Inspector message too big'); + dataLen = buffer.readUIntBE(4, 6); + bodyOffset = 10; + } + if (buffer.length < bodyOffset + dataLen) + return { length: 0, message }; + const jsonPayload = + buffer.slice(bodyOffset, bodyOffset + dataLen).toString('utf8'); + try { + message = JSON.parse(jsonPayload); + } catch (e) { + console.error(`JSON.parse() failed for: ${jsonPayload}`); + throw e; + } + if (DEBUG) + console.log('[received]', JSON.stringify(message)); + return { length: bodyOffset + dataLen, message }; +} + +function formatWSFrame(message) { + const messageBuf = Buffer.from(JSON.stringify(message)); + + const wsHeaderBuf = Buffer.allocUnsafe(16); + wsHeaderBuf.writeUInt8(0x81, 0); + let byte2 = 0x80; + const bodyLen = messageBuf.length; + + let maskOffset = 2; + if (bodyLen < 126) { + byte2 = 0x80 + bodyLen; + } else if (bodyLen < 65536) { + byte2 = 0xFE; + wsHeaderBuf.writeUInt16BE(bodyLen, 2); + maskOffset = 4; + } else { + byte2 = 0xFF; + wsHeaderBuf.writeUInt32BE(bodyLen, 2); + wsHeaderBuf.writeUInt32BE(0, 6); + maskOffset = 10; + } + wsHeaderBuf.writeUInt8(byte2, 1); + wsHeaderBuf.writeUInt32BE(0x01020408, maskOffset); + + for (let i = 0; i < messageBuf.length; i++) + messageBuf[i] = messageBuf[i] ^ (1 << (i % 4)); + + return Buffer.concat([wsHeaderBuf.slice(0, maskOffset + 4), messageBuf]); +} + +class InspectorSession { + constructor(socket, instance) { + this._instance = instance; + this._socket = socket; + this._nextId = 1; + this._commandResponsePromises = new Map(); + this._unprocessedNotifications = []; + this._notificationCallback = null; + this._scriptsIdsByUrl = new Map(); + this._pausedDetails = null; + + let buffer = Buffer.alloc(0); + socket.on('data', (data) => { + buffer = Buffer.concat([buffer, data]); + do { + const { length, message, closed } = parseWSFrame(buffer); + if (!length) + break; + + if (closed) { + socket.write(Buffer.from([0x88, 0x00])); // WS close frame + } + buffer = buffer.slice(length); + if (message) + this._onMessage(message); + } while (true); + }); + this._terminationPromise = new Promise((resolve) => { + socket.once('close', resolve); + }); + } + + + waitForServerDisconnect() { + return this._terminationPromise; + } + + async disconnect() { + this._socket.destroy(); + return this.waitForServerDisconnect(); + } + + _onMessage(message) { + if (message.id) { + const { resolve, reject } = this._commandResponsePromises.get(message.id); + this._commandResponsePromises.delete(message.id); + if (message.result) + resolve(message.result); + else + reject(message.error); + } else { + if (message.method === 'Debugger.scriptParsed') { + const { scriptId, url } = message.params; + this._scriptsIdsByUrl.set(scriptId, url); + const fileUrl = url.startsWith('file:') ? + url : pathToFileURL(url).toString(); + if (fileUrl === this.scriptURL().toString()) { + this.mainScriptId = scriptId; + } + } + if (message.method === 'Debugger.paused') + this._pausedDetails = message.params; + if (message.method === 'Debugger.resumed') + this._pausedDetails = null; + + if (this._notificationCallback) { + // In case callback needs to install another + const callback = this._notificationCallback; + this._notificationCallback = null; + callback(message); + } else { + this._unprocessedNotifications.push(message); + } + } + } + + unprocessedNotifications() { + return this._unprocessedNotifications; + } + + _sendMessage(message) { + const msg = JSON.parse(JSON.stringify(message)); // Clone! + msg.id = this._nextId++; + if (DEBUG) + console.log('[sent]', JSON.stringify(msg)); + + const responsePromise = new Promise((resolve, reject) => { + this._commandResponsePromises.set(msg.id, { resolve, reject }); + }); + + return new Promise( + (resolve) => this._socket.write(formatWSFrame(msg), resolve)) + .then(() => responsePromise); + } + + send(commands) { + if (Array.isArray(commands)) { + // Multiple commands means the response does not matter. There might even + // never be a response. + return Promise + .all(commands.map((command) => this._sendMessage(command))) + .then(() => {}); + } + return this._sendMessage(commands); + } + + waitForNotification(methodOrPredicate, description) { + const desc = description || methodOrPredicate; + const message = `Timed out waiting for matching notification (${desc})`; + return fires( + this._asyncWaitForNotification(methodOrPredicate), message, TIMEOUT); + } + + async _asyncWaitForNotification(methodOrPredicate) { + function matchMethod(notification) { + return notification.method === methodOrPredicate; + } + const predicate = + typeof methodOrPredicate === 'string' ? matchMethod : methodOrPredicate; + let notification = null; + do { + if (this._unprocessedNotifications.length) { + notification = this._unprocessedNotifications.shift(); + } else { + notification = await new Promise( + (resolve) => this._notificationCallback = resolve); + } + } while (!predicate(notification)); + return notification; + } + + _isBreakOnLineNotification(message, line, expectedScriptPath) { + if (message.method === 'Debugger.paused') { + const callFrame = message.params.callFrames[0]; + const location = callFrame.location; + const scriptPath = this._scriptsIdsByUrl.get(location.scriptId); + assert.strictEqual(scriptPath.toString(), + expectedScriptPath.toString(), + `${scriptPath} !== ${expectedScriptPath}`); + assert.strictEqual(location.lineNumber, line); + return true; + } + } + + waitForBreakOnLine(line, url) { + return this + .waitForNotification( + (notification) => + this._isBreakOnLineNotification(notification, line, url), + `break on ${url}:${line}`); + } + + pausedDetails() { + return this._pausedDetails; + } + + _matchesConsoleOutputNotification(notification, type, values) { + if (!Array.isArray(values)) + values = [ values ]; + if (notification.method === 'Runtime.consoleAPICalled') { + const params = notification.params; + if (params.type === type) { + let i = 0; + for (const value of params.args) { + if (value.value !== values[i++]) + return false; + } + return i === values.length; + } + } + } + + waitForConsoleOutput(type, values) { + const desc = `Console output matching ${JSON.stringify(values)}`; + return this.waitForNotification( + (notification) => this._matchesConsoleOutputNotification(notification, + type, values), + desc); + } + + async runToCompletion() { + console.log('[test]', 'Verify node waits for the frontend to disconnect'); + await this.send({ 'method': 'Debugger.resume' }); + await this.waitForNotification((notification) => { + if (notification.method === 'Debugger.paused') { + this.send({ 'method': 'Debugger.resume' }); + } + return notification.method === 'Runtime.executionContextDestroyed' && + notification.params.executionContextId === 1; + }); + while ((await this._instance.nextStderrString()) !== + 'Waiting for the debugger to disconnect...'); + await this.disconnect(); + } + + scriptPath() { + return this._instance.scriptPath(); + } + + script() { + return this._instance.script(); + } + + scriptURL() { + return pathToFileURL(this.scriptPath()); + } +} + +class NodeInstance extends EventEmitter { + constructor(inspectorFlags = ['--inspect-brk=0', '--expose-internals'], + scriptContents = '', + scriptFile = _MAINSCRIPT, + logger = console) { + super(); + + this._logger = logger; + this._scriptPath = scriptFile; + this._script = scriptFile ? null : scriptContents; + this._portCallback = null; + this.resetPort(); + this._process = spawnChildProcess(inspectorFlags, scriptContents, + scriptFile); + this._running = true; + this._stderrLineCallback = null; + this._unprocessedStderrLines = []; + + this._process.stdout.on('data', makeBufferingDataCallback( + (line) => { + this.emit('stdout', line); + this._logger.log('[out]', line); + })); + + this._process.stderr.on('data', makeBufferingDataCallback( + (message) => this.onStderrLine(message))); + + this._shutdownPromise = new Promise((resolve) => { + this._process.once('exit', (exitCode, signal) => { + if (signal) { + this._logger.error(`[err] child process crashed, signal ${signal}`); + } + resolve({ exitCode, signal }); + this._running = false; + }); + }); + } + + get pid() { + return this._process.pid; + } + + resetPort() { + this.portPromise = new Promise((resolve) => this._portCallback = resolve); + } + + static async startViaSignal(scriptContents) { + const instance = new NodeInstance( + ['--expose-internals', '--inspect-port=0'], + `${scriptContents}\nprocess._rawDebug('started');`, undefined); + const msg = 'Timed out waiting for process to start'; + while (await fires(instance.nextStderrString(), msg, TIMEOUT) !== 'started'); + process._debugProcess(instance._process.pid); + return instance; + } + + onStderrLine(line) { + this.emit('stderr', line); + this._logger.log('[err]', line); + if (this._portCallback) { + const matches = line.match(/Debugger listening on ws:\/\/.+:(\d+)\/.+/); + if (matches) { + this._portCallback(matches[1]); + this._portCallback = null; + } + } + if (this._stderrLineCallback) { + this._stderrLineCallback(line); + this._stderrLineCallback = null; + } else { + this._unprocessedStderrLines.push(line); + } + } + + httpGet(host, path, hostHeaderValue) { + this._logger.log('[test]', `Testing ${path}`); + const headers = hostHeaderValue ? { 'Host': hostHeaderValue } : null; + return this.portPromise.then((port) => new Promise((resolve, reject) => { + const req = http.get({ host, port, family: 4, path, headers }, (res) => { + let response = ''; + res.setEncoding('utf8'); + res + .on('data', (data) => response += data.toString()) + .on('end', () => { + resolve(response); + }); + }); + req.on('error', reject); + })).then((response) => { + try { + return JSON.parse(response); + } catch (e) { + e.body = response; + throw e; + } + }); + } + + async sendUpgradeRequest() { + const response = await this.httpGet(null, '/json/list'); + const devtoolsUrl = response[0].webSocketDebuggerUrl; + const port = await this.portPromise; + return http.get({ + port, + family: 4, + path: new URL(devtoolsUrl).pathname, + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Version': 13, + 'Sec-WebSocket-Key': 'key==', + }, + }); + } + + async connectInspectorSession() { + this._logger.log('[test]', 'Connecting to a child Node process'); + const upgradeRequest = await this.sendUpgradeRequest(); + return new Promise((resolve) => { + upgradeRequest + .on('upgrade', + (message, socket) => resolve(new InspectorSession(socket, this))) + .on('response', common.mustNotCall('Upgrade was not received')); + }); + } + + async expectConnectionDeclined() { + this._logger.log('[test]', 'Checking upgrade is not possible'); + const upgradeRequest = await this.sendUpgradeRequest(); + return new Promise((resolve) => { + upgradeRequest + .on('upgrade', common.mustNotCall('Upgrade was received')) + .on('response', (response) => + response.on('data', () => {}) + .on('end', () => resolve(response.statusCode))); + }); + } + + expectShutdown() { + return this._shutdownPromise; + } + + nextStderrString() { + if (this._unprocessedStderrLines.length) + return Promise.resolve(this._unprocessedStderrLines.shift()); + return new Promise((resolve) => this._stderrLineCallback = resolve); + } + + write(message) { + this._process.stdin.write(message); + } + + kill() { + this._process.kill(); + return this.expectShutdown(); + } + + scriptPath() { + return this._scriptPath; + } + + script() { + if (this._script === null) + this._script = fs.readFileSync(this.scriptPath(), 'utf8'); + return this._script; + } +} + +function onResolvedOrRejected(promise, callback) { + return promise.then((result) => { + callback(); + return result; + }, (error) => { + callback(); + throw error; + }); +} + +function timeoutPromise(error, timeoutMs) { + let clearCallback = null; + let done = false; + const promise = onResolvedOrRejected(new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(error), timeoutMs); + clearCallback = () => { + if (done) + return; + clearTimeout(timeout); + resolve(); + }; + }), () => done = true); + promise.clear = clearCallback; + return promise; +} + +// Returns a new promise that will propagate `promise` resolution or rejection +// if that happens within the `timeoutMs` timespan, or rejects with `error` as +// a reason otherwise. +function fires(promise, error, timeoutMs) { + const timeout = timeoutPromise(error, timeoutMs); + return Promise.race([ + onResolvedOrRejected(promise, () => timeout.clear()), + timeout, + ]); +} + +module.exports = { + NodeInstance, +}; diff --git a/test/js/node/test/common/internet.js b/test/js/node/test/common/internet.js new file mode 100644 index 0000000000..51f18aeb44 --- /dev/null +++ b/test/js/node/test/common/internet.js @@ -0,0 +1,58 @@ +'use strict'; + +// Utilities for internet-related tests + +const addresses = { + // A generic host that has registered common DNS records, + // supports both IPv4 and IPv6, and provides basic HTTP/HTTPS services + INET_HOST: 'nodejs.org', + // A host that provides IPv4 services + INET4_HOST: 'nodejs.org', + // A host that provides IPv6 services + INET6_HOST: 'nodejs.org', + // An accessible IPv4 IP, + // defaults to the Google Public DNS IPv4 address + INET4_IP: '8.8.8.8', + // An accessible IPv6 IP, + // defaults to the Google Public DNS IPv6 address + INET6_IP: '2001:4860:4860::8888', + // An invalid host that cannot be resolved + // See https://tools.ietf.org/html/rfc2606#section-2 + INVALID_HOST: 'something.invalid', + // A host with MX records registered + MX_HOST: 'nodejs.org', + // On some systems, .invalid returns a server failure/try again rather than + // record not found. Use this to guarantee record not found. + NOT_FOUND: 'come.on.fhqwhgads.test', + // A host with SRV records registered + SRV_HOST: '_caldav._tcp.google.com', + // A host with PTR records registered + PTR_HOST: '8.8.8.8.in-addr.arpa', + // A host with NAPTR records registered + NAPTR_HOST: 'sip2sip.info', + // A host with SOA records registered + SOA_HOST: 'nodejs.org', + // A host with CAA record registered + CAA_HOST: 'google.com', + // A host with CNAME records registered + CNAME_HOST: 'blog.nodejs.org', + // A host with NS records registered + NS_HOST: 'nodejs.org', + // A host with TXT records registered + TXT_HOST: 'nodejs.org', + // An accessible IPv4 DNS server + DNS4_SERVER: '8.8.8.8', + // An accessible IPv4 DNS server + DNS6_SERVER: '2001:4860:4860::8888', +}; + +for (const key of Object.keys(addresses)) { + const envName = `NODE_TEST_${key}`; + if (process.env[envName]) { + addresses[key] = process.env[envName]; + } +} + +module.exports = { + addresses, +}; diff --git a/test/js/node/test/common/measure-memory.js b/test/js/node/test/common/measure-memory.js new file mode 100644 index 0000000000..ffde35f285 --- /dev/null +++ b/test/js/node/test/common/measure-memory.js @@ -0,0 +1,57 @@ +'use strict'; + +const assert = require('assert'); +const common = require('./'); + +// The formats could change when V8 is updated, then the tests should be +// updated accordingly. +function assertResultShape(result) { + assert.strictEqual(typeof result.jsMemoryEstimate, 'number'); + assert.strictEqual(typeof result.jsMemoryRange[0], 'number'); + assert.strictEqual(typeof result.jsMemoryRange[1], 'number'); +} + +function assertSummaryShape(result) { + assert.strictEqual(typeof result, 'object'); + assert.strictEqual(typeof result.total, 'object'); + assertResultShape(result.total); +} + +function assertDetailedShape(result, contexts = 0) { + assert.strictEqual(typeof result, 'object'); + assert.strictEqual(typeof result.total, 'object'); + assert.strictEqual(typeof result.current, 'object'); + assertResultShape(result.total); + assertResultShape(result.current); + if (contexts === 0) { + assert.deepStrictEqual(result.other, []); + } else { + assert.strictEqual(result.other.length, contexts); + for (const item of result.other) { + assertResultShape(item); + } + } +} + +function assertSingleDetailedShape(result) { + assert.strictEqual(typeof result, 'object'); + assert.strictEqual(typeof result.total, 'object'); + assert.strictEqual(typeof result.current, 'object'); + assert.deepStrictEqual(result.other, []); + assertResultShape(result.total); + assertResultShape(result.current); +} + +function expectExperimentalWarning() { + common.expectWarning( + 'ExperimentalWarning', + 'vm.measureMemory is an experimental feature and might change at any time', + ); +} + +module.exports = { + assertSummaryShape, + assertDetailedShape, + assertSingleDetailedShape, + expectExperimentalWarning, +}; diff --git a/test/js/node/test/common/ongc.js b/test/js/node/test/common/ongc.js new file mode 100644 index 0000000000..d361c55b51 --- /dev/null +++ b/test/js/node/test/common/ongc.js @@ -0,0 +1,32 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const gcTrackerMap = new WeakMap(); +const gcTrackerTag = 'NODE_TEST_COMMON_GC_TRACKER'; + +function onGC(obj, gcListener) { + const async_hooks = require('async_hooks'); + + const onGcAsyncHook = async_hooks.createHook({ + init: common.mustCallAtLeast(function(id, type) { + if (this.trackedId === undefined) { + assert.strictEqual(type, gcTrackerTag); + this.trackedId = id; + } + }), + destroy(id) { + assert.notStrictEqual(this.trackedId, -1); + if (id === this.trackedId) { + this.gcListener.ongc(); + onGcAsyncHook.disable(); + } + }, + }).enable(); + onGcAsyncHook.gcListener = gcListener; + + gcTrackerMap.set(obj, new async_hooks.AsyncResource(gcTrackerTag)); + obj = null; +} + +module.exports = onGC; diff --git a/test/js/node/test/common/package.json b/test/js/node/test/common/package.json new file mode 100644 index 0000000000..5bbefffbab --- /dev/null +++ b/test/js/node/test/common/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/test/js/node/test/common/prof.js b/test/js/node/test/common/prof.js new file mode 100644 index 0000000000..13047406dc --- /dev/null +++ b/test/js/node/test/common/prof.js @@ -0,0 +1,67 @@ +'use strict'; + +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); + +function getHeapProfiles(dir) { + const list = fs.readdirSync(dir); + return list + .filter((file) => file.endsWith('.heapprofile')) + .map((file) => path.join(dir, file)); +} + +function findFirstFrameInNode(root, func) { + const first = root.children.find( + (child) => child.callFrame.functionName === func, + ); + if (first) { + return first; + } + for (const child of root.children) { + const first = findFirstFrameInNode(child, func); + if (first) { + return first; + } + } + return undefined; +} + +function findFirstFrame(file, func) { + const data = fs.readFileSync(file, 'utf8'); + const profile = JSON.parse(data); + const first = findFirstFrameInNode(profile.head, func); + return { frame: first, roots: profile.head.children }; +} + +function verifyFrames(output, file, func) { + const { frame, roots } = findFirstFrame(file, func); + if (!frame) { + // Show native debug output and the profile for debugging. + console.log(output.stderr.toString()); + console.log(roots); + } + assert.notStrictEqual(frame, undefined); +} + +// We need to set --heap-prof-interval to a small enough value to make +// sure we can find our workload in the samples, so we need to set +// TEST_ALLOCATION > kHeapProfInterval. +const kHeapProfInterval = 128; +const TEST_ALLOCATION = kHeapProfInterval * 2; + +const env = { + ...process.env, + TEST_ALLOCATION, + NODE_DEBUG_NATIVE: 'INSPECTOR_PROFILER', +}; + +// TODO(joyeecheung): share the fixutres with v8 coverage tests +module.exports = { + getHeapProfiles, + verifyFrames, + findFirstFrame, + kHeapProfInterval, + TEST_ALLOCATION, + env, +}; diff --git a/test/js/node/test/common/report.js b/test/js/node/test/common/report.js new file mode 100644 index 0000000000..6e41561186 --- /dev/null +++ b/test/js/node/test/common/report.js @@ -0,0 +1,339 @@ +'use strict'; +const assert = require('assert'); +const fs = require('fs'); +const net = require('net'); +const os = require('os'); +const path = require('path'); +const util = require('util'); +const cpus = os.cpus(); + +function findReports(pid, dir) { + // Default filenames are of the form + // report..

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

00jHv6S|N{HyjWGAVepgZhO<Q%=L+F4!0 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%0D{5QF)fKDd}br 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 E15V*r*Z=?k literal 0 HcmV?d00001 diff --git a/test/js/node/test/fixtures/person.jpg b/test/js/node/test/fixtures/person.jpg new file mode 100644 index 0000000000000000000000000000000000000000..96d46888d76c19a976eaed55fb1987183b69bbc7 GIT binary patch literal 45658 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%0D*%BK~3)9Ck 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 Fe0+PQAB_M2 literal 0 HcmV?d00001 diff --git a/test/js/node/test/fixtures/person.jpg.gz b/test/js/node/test/fixtures/person.jpg.gz new file mode 100644 index 0000000000000000000000000000000000000000..0d3239a3c842298d4aa98f56e236bf91e1ddbb6c GIT binary patch literal 45429 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 B3jzQD literal 0 HcmV?d00001 diff --git a/test/js/node/test/fixtures/pkgexports.mjs b/test/js/node/test/fixtures/pkgexports.mjs new file mode 100644 index 0000000000..7d642c443e --- /dev/null +++ b/test/js/node/test/fixtures/pkgexports.mjs @@ -0,0 +1,12 @@ +import { fileURLToPath } from 'url'; +import { createRequire } from 'module'; + +const rawRequire = createRequire(fileURLToPath(import.meta.url)); + +export async function requireFixture(specifier) { + return { default: rawRequire(specifier ) }; +} + +export function importFixture(specifier) { + return import(specifier); +} diff --git a/test/js/node/test/fixtures/postject-copy/package.json b/test/js/node/test/fixtures/postject-copy/package.json new file mode 100644 index 0000000000..9718ddc63f --- /dev/null +++ b/test/js/node/test/fixtures/postject-copy/package.json @@ -0,0 +1,15 @@ +{ + "name": "postject-copy", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "postject": "^1.0.0-alpha.6" + } +} diff --git a/test/js/node/test/fixtures/print A.js b/test/js/node/test/fixtures/print A.js new file mode 100644 index 0000000000..30a56425de --- /dev/null +++ b/test/js/node/test/fixtures/print A.js @@ -0,0 +1 @@ +console.log('A') diff --git a/test/js/node/test/fixtures/print-10-lines.js b/test/js/node/test/fixtures/print-10-lines.js new file mode 100644 index 0000000000..e672ef80cf --- /dev/null +++ b/test/js/node/test/fixtures/print-10-lines.js @@ -0,0 +1,24 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +for (var i = 0; i < 10; i++) { + console.log(`count ${i}`); +} diff --git a/test/js/node/test/fixtures/print-chars-from-buffer.js b/test/js/node/test/fixtures/print-chars-from-buffer.js new file mode 100644 index 0000000000..30b0c00168 --- /dev/null +++ b/test/js/node/test/fixtures/print-chars-from-buffer.js @@ -0,0 +1,31 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +const assert = require('assert'); + +var n = parseInt(process.argv[2]); + +var b = Buffer.allocUnsafe(n); +for (var i = 0; i < n; i++) { + b[i] = 100; +} + +process.stdout.write(b); diff --git a/test/js/node/test/fixtures/print-chars.js b/test/js/node/test/fixtures/print-chars.js new file mode 100644 index 0000000000..26ff958d33 --- /dev/null +++ b/test/js/node/test/fixtures/print-chars.js @@ -0,0 +1,26 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +const assert = require('assert'); + +var n = parseInt(process.argv[2]); + +process.stdout.write('c'.repeat(n)); diff --git a/test/js/node/test/fixtures/print-delayed.js b/test/js/node/test/fixtures/print-delayed.js new file mode 100644 index 0000000000..42eb45615b --- /dev/null +++ b/test/js/node/test/fixtures/print-delayed.js @@ -0,0 +1,3 @@ +setTimeout(() => { + console.log('delayed'); +}, 100); diff --git a/test/js/node/test/fixtures/print-error-message.js b/test/js/node/test/fixtures/print-error-message.js new file mode 100644 index 0000000000..0650bfbd52 --- /dev/null +++ b/test/js/node/test/fixtures/print-error-message.js @@ -0,0 +1 @@ +console.error('Bad command or file name'); diff --git a/test/js/node/test/fixtures/print-intrinsic-mutation-name.js b/test/js/node/test/fixtures/print-intrinsic-mutation-name.js new file mode 100644 index 0000000000..95b4690d93 --- /dev/null +++ b/test/js/node/test/fixtures/print-intrinsic-mutation-name.js @@ -0,0 +1,2 @@ +'use strict'; +console.log({}.flatten.name); diff --git a/test/js/node/test/fixtures/printA.js b/test/js/node/test/fixtures/printA.js new file mode 100644 index 0000000000..30a56425de --- /dev/null +++ b/test/js/node/test/fixtures/printA.js @@ -0,0 +1 @@ +console.log('A') diff --git a/test/js/node/test/fixtures/printB.js b/test/js/node/test/fixtures/printB.js new file mode 100644 index 0000000000..241b6bdcf6 --- /dev/null +++ b/test/js/node/test/fixtures/printB.js @@ -0,0 +1 @@ +console.log('B') diff --git a/test/js/node/test/fixtures/printC.js b/test/js/node/test/fixtures/printC.js new file mode 100644 index 0000000000..9a203c981e --- /dev/null +++ b/test/js/node/test/fixtures/printC.js @@ -0,0 +1 @@ +console.log('C') diff --git a/test/js/node/test/fixtures/process-exit-code-cases.js b/test/js/node/test/fixtures/process-exit-code-cases.js new file mode 100644 index 0000000000..05b01afd8f --- /dev/null +++ b/test/js/node/test/fixtures/process-exit-code-cases.js @@ -0,0 +1,136 @@ +'use strict'; + +const assert = require('assert'); + +function getTestCases(isWorker = false) { + const cases = []; + function exitsOnExitCodeSet() { + process.exitCode = 42; + process.on('exit', (code) => { + assert.strictEqual(process.exitCode, 42); + assert.strictEqual(code, 42); + }); + } + cases.push({ func: exitsOnExitCodeSet, result: 42 }); + + function changesCodeViaExit() { + process.exitCode = 99; + process.on('exit', (code) => { + assert.strictEqual(process.exitCode, 42); + assert.strictEqual(code, 42); + }); + process.exit(42); + } + cases.push({ func: changesCodeViaExit, result: 42 }); + + function changesCodeZeroExit() { + process.exitCode = 99; + process.on('exit', (code) => { + assert.strictEqual(process.exitCode, 0); + assert.strictEqual(code, 0); + }); + process.exit(0); + } + cases.push({ func: changesCodeZeroExit, result: 0 }); + + function exitWithOneOnUncaught() { + process.exitCode = 99; + process.on('exit', (code) => { + // cannot use assert because it will be uncaughtException -> 1 exit code + // that will render this test useless + if (code !== 1 || process.exitCode !== 1) { + console.log('wrong code! expected 1 for uncaughtException'); + process.exit(99); + } + }); + throw new Error('ok'); + } + cases.push({ + func: exitWithOneOnUncaught, + result: 1, + error: /^Error: ok$/, + }); + + function changeCodeInsideExit() { + process.exitCode = 95; + process.on('exit', (code) => { + assert.strictEqual(process.exitCode, 95); + assert.strictEqual(code, 95); + process.exitCode = 99; + }); + } + cases.push({ func: changeCodeInsideExit, result: 99 }); + + function zeroExitWithUncaughtHandler() { + process.on('exit', (code) => { + assert.strictEqual(process.exitCode, 0); + assert.strictEqual(code, 0); + }); + process.on('uncaughtException', () => { }); + throw new Error('ok'); + } + cases.push({ func: zeroExitWithUncaughtHandler, result: 0 }); + + function changeCodeInUncaughtHandler() { + process.on('exit', (code) => { + assert.strictEqual(process.exitCode, 97); + assert.strictEqual(code, 97); + }); + process.on('uncaughtException', () => { + process.exitCode = 97; + }); + throw new Error('ok'); + } + cases.push({ func: changeCodeInUncaughtHandler, result: 97 }); + + function changeCodeInExitWithUncaught() { + process.on('exit', (code) => { + assert.strictEqual(process.exitCode, 1); + assert.strictEqual(code, 1); + process.exitCode = 98; + }); + throw new Error('ok'); + } + cases.push({ + func: changeCodeInExitWithUncaught, + result: 98, + error: /^Error: ok$/, + }); + + function exitWithZeroInExitWithUncaught() { + process.on('exit', (code) => { + assert.strictEqual(process.exitCode, 1); + assert.strictEqual(code, 1); + process.exitCode = 0; + }); + throw new Error('ok'); + } + cases.push({ + func: exitWithZeroInExitWithUncaught, + result: 0, + error: /^Error: ok$/, + }); + + function exitWithThrowInUncaughtHandler() { + process.on('uncaughtException', () => { + throw new Error('ok') + }); + throw new Error('bad'); + } + cases.push({ + func: exitWithThrowInUncaughtHandler, + result: isWorker ? 1 : 7, + error: /^Error: ok$/, + }); + + function exitWithUndefinedFatalException() { + process._fatalException = undefined; + throw new Error('ok'); + } + cases.push({ + func: exitWithUndefinedFatalException, + result: 6, + }); + return cases; +} +exports.getTestCases = getTestCases; diff --git a/test/js/node/test/fixtures/pss-vectors.json b/test/js/node/test/fixtures/pss-vectors.json new file mode 100644 index 0000000000..b540d13a54 --- /dev/null +++ b/test/js/node/test/fixtures/pss-vectors.json @@ -0,0 +1,89 @@ +{ + "example01": { + "publicKey": [ + "-----BEGIN PUBLIC KEY-----", + "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClbkoOcBAXWJpRh9x+qEHRVvLs", + "DjatUqRN/rHmH3rZkdjFEFb/7bFitMDyg6EqiKOU3/Umq3KRy7MHzqv84LHf1c2V", + "CAltWyuLbfXWce9jd8CSHLI8Jwpw4lmOb/idGfEFrMLT8Ms18pKA4Thrb2TE7yLh", + "4fINDOjP+yJJvZohNwIDAQAB", + "-----END PUBLIC KEY-----" + ], + "tests": [ + { + "message": "cdc87da223d786df3b45e0bbbc721326d1ee2af806cc315475cc6f0d9c66e1b62371d45ce2392e1ac92844c310102f156a0d8d52c1f4c40ba3aa65095786cb769757a6563ba958fed0bcc984e8b517a3d5f515b23b8a41e74aa867693f90dfb061a6e86dfaaee64472c00e5f20945729cbebe77f06ce78e08f4098fba41f9d6193c0317e8b60d4b6084acb42d29e3808a3bc372d85e331170fcbf7cc72d0b71c296648b3a4d10f416295d0807aa625cab2744fd9ea8fd223c42537029828bd16be02546f130fd2e33b936d2676e08aed1b73318b750a0167d0", + "salt": "dee959c7e06411361420ff80185ed57f3e6776af", + "signature": "9074308fb598e9701b2294388e52f971faac2b60a5145af185df5287b5ed2887e57ce7fd44dc8634e407c8e0e4360bc226f3ec227f9d9e54638e8d31f5051215df6ebb9c2f9579aa77598a38f914b5b9c1bd83c4e2f9f382a0d0aa3542ffee65984a601bc69eb28deb27dca12c82c2d4c3f66cd500f1ff2b994d8a4e30cbb33c" + }, + { + "message": "851384cdfe819c22ed6c4ccb30daeb5cf059bc8e1166b7e3530c4c233e2b5f8f71a1cca582d43ecc72b1bca16dfc7013226b9e", + "salt": "ef2869fa40c346cb183dab3d7bffc98fd56df42d", + "signature": "3ef7f46e831bf92b32274142a585ffcefbdca7b32ae90d10fb0f0c729984f04ef29a9df0780775ce43739b97838390db0a5505e63de927028d9d29b219ca2c4517832558a55d694a6d25b9dab66003c4cccd907802193be5170d26147d37b93590241be51c25055f47ef62752cfbe21418fafe98c22c4d4d47724fdb5669e843" + }, + { + "message": "a4b159941761c40c6a82f2b80d1b94f5aa2654fd17e12d588864679b54cd04ef8bd03012be8dc37f4b83af7963faff0dfa225477437c48017ff2be8191cf3955fc07356eab3f322f7f620e21d254e5db4324279fe067e0910e2e81ca2cab31c745e67a54058eb50d993cdb9ed0b4d029c06d21a94ca661c3ce27fae1d6cb20f4564d66ce4767583d0e5f060215b59017be85ea848939127bd8c9c4d47b51056c031cf336f17c9980f3b8f5b9b6878e8b797aa43b882684333e17893fe9caa6aa299f7ed1a18ee2c54864b7b2b99b72618fb02574d139ef50f019c9eef416971338e7d470", + "salt": "710b9c4747d800d4de87f12afdce6df18107cc77", + "signature": "666026fba71bd3e7cf13157cc2c51a8e4aa684af9778f91849f34335d141c00154c4197621f9624a675b5abc22ee7d5baaffaae1c9baca2cc373b3f33e78e6143c395a91aa7faca664eb733afd14d8827259d99a7550faca501ef2b04e33c23aa51f4b9e8282efdb728cc0ab09405a91607c6369961bc8270d2d4f39fce612b1" + }, + { + "message": "bc656747fa9eafb3f0", + "salt": "056f00985de14d8ef5cea9e82f8c27bef720335e", + "signature": "4609793b23e9d09362dc21bb47da0b4f3a7622649a47d464019b9aeafe53359c178c91cd58ba6bcb78be0346a7bc637f4b873d4bab38ee661f199634c547a1ad8442e03da015b136e543f7ab07c0c13e4225b8de8cce25d4f6eb8400f81f7e1833b7ee6e334d370964ca79fdb872b4d75223b5eeb08101591fb532d155a6de87" + }, + { + "message": "b45581547e5427770c768e8b82b75564e0ea4e9c32594d6bff706544de0a8776c7a80b4576550eee1b2acabc7e8b7d3ef7bb5b03e462c11047eadd00629ae575480ac1470fe046f13a2bf5af17921dc4b0aa8b02bee6334911651d7f8525d10f32b51d33be520d3ddf5a709955a3dfe78283b9e0ab54046d150c177f037fdccc5be4ea5f68b5e5a38c9d7edcccc4975f455a6909b4", + "salt": "80e70ff86a08de3ec60972b39b4fbfdcea67ae8e", + "signature": "1d2aad221ca4d31ddf13509239019398e3d14b32dc34dc5af4aeaea3c095af73479cf0a45e5629635a53a018377615b16cb9b13b3e09d671eb71e387b8545c5960da5a64776e768e82b2c93583bf104c3fdb23512b7b4e89f633dd0063a530db4524b01c3f384c09310e315a79dcd3d684022a7f31c865a664e316978b759fad" + }, + { + "message": "10aae9a0ab0b595d0841207b700d48d75faedde3b775cd6b4cc88ae06e4694ec74ba18f8520d4f5ea69cbbe7cc2beba43efdc10215ac4eb32dc302a1f53dc6c4352267e7936cfebf7c8d67035784a3909fa859c7b7b59b8e39c5c2349f1886b705a30267d402f7486ab4f58cad5d69adb17ab8cd0ce1caf5025af4ae24b1fb8794c6070cc09a51e2f9911311e3877d0044c71c57a993395008806b723ac38373d395481818528c1e7053739282053529510e935cd0fa77b8fa53cc2d474bd4fb3cc5c672d6ffdc90a00f9848712c4bcfe46c60573659b11e6457e861f0f604b6138d144f8ce4e2da73", + "salt": "a8ab69dd801f0074c2a1fc60649836c616d99681", + "signature": "2a34f6125e1f6b0bf971e84fbd41c632be8f2c2ace7de8b6926e31ff93e9af987fbc06e51e9be14f5198f91f3f953bd67da60a9df59764c3dc0fe08e1cbef0b75f868d10ad3fba749fef59fb6dac46a0d6e504369331586f58e4628f39aa278982543bc0eeb537dc61958019b394fb273f215858a0a01ac4d650b955c67f4c58" + } + ] + }, + "example10": { + "publicKey": [ + "-----BEGIN PUBLIC KEY-----", + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApd2GesTLAvkLlFfUjBSn", + "cO+ZHFbDnA7GX9Ea+ok3zqV7m+esc7RcABdhW4LWIuMYdTtgJ8D9FXvhL4CQ/uKn", + "rc0O73WfiLpJl8ekLVjJqhLLma4AH+UhwTu1QxRFqNWuT15MfpSKwifTYEBx8g5X", + "fpBfvrFd+vBtHeWuYlPWOmohILMaXaXavJVQYA4g8n03OeJieSX+o8xQnyHf8E5u", + "6kVJxUDWgJ/5MH7t6R//WHM9g4WiN9bTcFoz45GQCZIHDfet8TV89+NwDONmfeg/", + "F7jfF3jbOB3OCctK0FilEQAac4GY7ifPVaE7dUU5kGWC7IsXS9WNXR89dnxhNyGu", + "BQIDAQAB", + "-----END PUBLIC KEY-----" + ], + "tests": [ + { + "message": "883177e5126b9be2d9a9680327d5370c6f26861f5820c43da67a3ad609", + "salt": "04e215ee6ff934b9da70d7730c8734abfcecde89", + "signature": "82c2b160093b8aa3c0f7522b19f87354066c77847abf2a9fce542d0e84e920c5afb49ffdfdace16560ee94a1369601148ebad7a0e151cf16331791a5727d05f21e74e7eb811440206935d744765a15e79f015cb66c532c87a6a05961c8bfad741a9a6657022894393e7223739796c02a77455d0f555b0ec01ddf259b6207fd0fd57614cef1a5573baaff4ec00069951659b85f24300a25160ca8522dc6e6727e57d019d7e63629b8fe5e89e25cc15beb3a647577559299280b9b28f79b0409000be25bbd96408ba3b43cc486184dd1c8e62553fa1af4040f60663de7f5e49c04388e257f1ce89c95dab48a315d9b66b1b7628233876ff2385230d070d07e1666" + }, + { + "message": "dd670a01465868adc93f26131957a50c52fb777cdbaa30892c9e12361164ec13979d43048118e4445db87bee58dd987b3425d02071d8dbae80708b039dbb64dbd1de5657d9fed0c118a54143742e0ff3c87f74e45857647af3f79eb0a14c9d75ea9a1a04b7cf478a897a708fd988f48e801edb0b7039df8c23bb3c56f4e821ac", + "salt": "8b2bdd4b40faf545c778ddf9bc1a49cb57f9b71b", + "signature": "14ae35d9dd06ba92f7f3b897978aed7cd4bf5ff0b585a40bd46ce1b42cd2703053bb9044d64e813d8f96db2dd7007d10118f6f8f8496097ad75e1ff692341b2892ad55a633a1c55e7f0a0ad59a0e203a5b8278aec54dd8622e2831d87174f8caff43ee6c46445345d84a59659bfb92ecd4c818668695f34706f66828a89959637f2bf3e3251c24bdba4d4b7649da0022218b119c84e79a6527ec5b8a5f861c159952e23ec05e1e717346faefe8b1686825bd2b262fb2531066c0de09acde2e4231690728b5d85e115a2f6b92b79c25abc9bd9399ff8bcf825a52ea1f56ea76dd26f43baafa18bfa92a504cbd35699e26d1dcc5a2887385f3c63232f06f3244c3" + }, + { + "message": "48b2b6a57a63c84cea859d65c668284b08d96bdcaabe252db0e4a96cb1bac6019341db6fbefb8d106b0e90eda6bcc6c6262f37e7ea9c7e5d226bd7df85ec5e71efff2f54c5db577ff729ff91b842491de2741d0c631607df586b905b23b91af13da12304bf83eca8a73e871ff9db", + "salt": "4e96fc1b398f92b44671010c0dc3efd6e20c2d73", + "signature": "6e3e4d7b6b15d2fb46013b8900aa5bbb3939cf2c095717987042026ee62c74c54cffd5d7d57efbbf950a0f5c574fa09d3fc1c9f513b05b4ff50dd8df7edfa20102854c35e592180119a70ce5b085182aa02d9ea2aa90d1df03f2daae885ba2f5d05afdac97476f06b93b5bc94a1a80aa9116c4d615f333b098892b25fface266f5db5a5a3bcc10a824ed55aad35b727834fb8c07da28fcf416a5d9b2224f1f8b442b36f91e456fdea2d7cfe3367268de0307a4c74e924159ed33393d5e0655531c77327b89821bdedf880161c78cd4196b5419f7acc3f13e5ebf161b6e7c6724716ca33b85c2e25640192ac2859651d50bde7eb976e51cec828b98b6563b86bb" + }, + { + "message": "0b8777c7f839baf0a64bbbdbc5ce79755c57a205b845c174e2d2e90546a089c4e6ec8adffa23a7ea97bae6b65d782b82db5d2b5a56d22a29a05e7c4433e2b82a621abba90add05ce393fc48a840542451a", + "salt": "c7cd698d84b65128d8835e3a8b1eb0e01cb541ec", + "signature": "34047ff96c4dc0dc90b2d4ff59a1a361a4754b255d2ee0af7d8bf87c9bc9e7ddeede33934c63ca1c0e3d262cb145ef932a1f2c0a997aa6a34f8eaee7477d82ccf09095a6b8acad38d4eec9fb7eab7ad02da1d11d8e54c1825e55bf58c2a23234b902be124f9e9038a8f68fa45dab72f66e0945bf1d8bacc9044c6f07098c9fcec58a3aab100c805178155f030a124c450e5acbda47d0e4f10b80a23f803e774d023b0015c20b9f9bbe7c91296338d5ecb471cafb032007b67a60be5f69504a9f01abb3cb467b260e2bce860be8d95bf92c0c8e1496ed1e528593a4abb6df462dde8a0968dffe4683116857a232f5ebf6c85be238745ad0f38f767a5fdbf486fb" + }, + { + "message": "f1036e008e71e964dadc9219ed30e17f06b4b68a955c16b312b1eddf028b74976bed6b3f6a63d4e77859243c9cccdc98016523abb02483b35591c33aad81213bb7c7bb1a470aabc10d44256c4d4559d916", + "salt": "efa8bff96212b2f4a3f371a10d574152655f5dfb", + "signature": "7e0935ea18f4d6c1d17ce82eb2b3836c55b384589ce19dfe743363ac9948d1f346b7bfddfe92efd78adb21faefc89ade42b10f374003fe122e67429a1cb8cbd1f8d9014564c44d120116f4990f1a6e38774c194bd1b8213286b077b0499d2e7b3f434ab12289c556684deed78131934bb3dd6537236f7c6f3dcb09d476be07721e37e1ceed9b2f7b406887bd53157305e1c8b4f84d733bc1e186fe06cc59b6edb8f4bd7ffefdf4f7ba9cfb9d570689b5a1a4109a746a690893db3799255a0cb9215d2d1cd490590e952e8c8786aa0011265252470c041dfbc3eec7c3cbf71c24869d115c0cb4a956f56d530b80ab589acfefc690751ddf36e8d383f83cedd2cc" + }, + { + "message": "25f10895a87716c137450bb9519dfaa1f207faa942ea88abf71e9c17980085b555aebab76264ae2a3ab93c2d12981191ddac6fb5949eb36aee3c5da940f00752c916d94608fa7d97ba6a2915b688f20323d4e9d96801d89a72ab5892dc2117c07434fcf972e058cf8c41ca4b4ff554f7d5068ad3155fced0f3125bc04f9193378a8f5c4c3b8cb4dd6d1cc69d30ecca6eaa51e36a05730e9e342e855baf099defb8afd7", + "salt": "ad8b1523703646224b660b550885917ca2d1df28", + "signature": "6d3b5b87f67ea657af21f75441977d2180f91b2c5f692de82955696a686730d9b9778d970758ccb26071c2209ffbd6125be2e96ea81b67cb9b9308239fda17f7b2b64ecda096b6b935640a5a1cb42a9155b1c9ef7a633a02c59f0d6ee59b852c43b35029e73c940ff0410e8f114eed46bbd0fae165e42be2528a401c3b28fd818ef3232dca9f4d2a0f5166ec59c42396d6c11dbc1215a56fa17169db9575343ef34f9de32a49cdc3174922f229c23e18e45df9353119ec4319cedce7a17c64088c1f6f52be29634100b3919d38f3d1ed94e6891e66a73b8fb849f5874df59459e298c7bbce2eee782a195aa66fe2d0732b25e595f57d3e061b1fc3e4063bf98f" + } + ] + } +} \ No newline at end of file diff --git a/test/js/node/test/fixtures/readfile_pipe_test.txt b/test/js/node/test/fixtures/readfile_pipe_test.txt new file mode 100644 index 0000000000..65975655dc --- /dev/null +++ b/test/js/node/test/fixtures/readfile_pipe_test.txt @@ -0,0 +1,5 @@ +xxxx xxxx xxxx xxxx +xxxx xxxx xxxx xxxx +xxxx xxxx xxxx xxxx +xxxx xxxx xxxx xxxx +xxxx xxxx xxxx xxxx diff --git a/test/js/node/test/fixtures/recursive-a.cjs b/test/js/node/test/fixtures/recursive-a.cjs new file mode 100644 index 0000000000..a60c0a635d --- /dev/null +++ b/test/js/node/test/fixtures/recursive-a.cjs @@ -0,0 +1,6 @@ +'use strict'; + +global.counter ??= 0; +global.counter++; + +require('./recursive-b.cjs'); diff --git a/test/js/node/test/fixtures/recursive-b.cjs b/test/js/node/test/fixtures/recursive-b.cjs new file mode 100644 index 0000000000..e9f0b5d070 --- /dev/null +++ b/test/js/node/test/fixtures/recursive-b.cjs @@ -0,0 +1,3 @@ +'use strict'; + +require('./recursive-a.cjs'); diff --git a/test/js/node/test/fixtures/recvfd.js b/test/js/node/test/fixtures/recvfd.js new file mode 100644 index 0000000000..c27a312c65 --- /dev/null +++ b/test/js/node/test/fixtures/recvfd.js @@ -0,0 +1,77 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// See test/simple/test-sendfd.js for a complete description of what this +// script is doing and how it fits into the test as a whole. + +const net = require('net'); + +var receivedData = []; +var receivedFDs = []; +var numSentMessages = 0; + +function processData(s) { + if (receivedData.length == 0 || receivedFDs.length == 0) { + return; + } + + var fd = receivedFDs.shift(); + var d = receivedData.shift(); + + // Augment our received object before sending it back across the pipe. + d.pid = process.pid; + + // Create a stream around the FD that we received and send a serialized + // version of our modified object back. Clean up when we're done. + var pipeStream = new net.Stream(fd); + + var drainFunc = function() { + pipeStream.destroy(); + + if (++numSentMessages == 2) { + s.destroy(); + } + }; + + pipeStream.on('drain', drainFunc); + pipeStream.resume(); + + if (pipeStream.write(JSON.stringify(d) + '\n')) { + drainFunc(); + } +} + +// Create a UNIX socket to the path defined by argv[2] and read a file +// descriptor and misc data from it. +var s = new net.Stream(); +s.on('fd', function(fd) { + receivedFDs.unshift(fd); + processData(s); +}); +s.on('data', function(data) { + data.toString('utf8').trim().split('\n').forEach(function(d) { + receivedData.unshift(JSON.parse(d)); + }); + processData(s); +}); +s.connect(process.argv[2]); + +// vim:ts=2 sw=2 et diff --git a/test/js/node/test/fixtures/registerExt.hello.world b/test/js/node/test/fixtures/registerExt.hello.world new file mode 100644 index 0000000000..0420edca79 --- /dev/null +++ b/test/js/node/test/fixtures/registerExt.hello.world @@ -0,0 +1 @@ +exports.test = 'passed' diff --git a/test/js/node/test/fixtures/registerExt.test b/test/js/node/test/fixtures/registerExt.test new file mode 100644 index 0000000000..d08e5b1d02 --- /dev/null +++ b/test/js/node/test/fixtures/registerExt.test @@ -0,0 +1 @@ +this is custom source diff --git a/test/js/node/test/fixtures/registerExt2.test b/test/js/node/test/fixtures/registerExt2.test new file mode 100644 index 0000000000..94544f1d0f --- /dev/null +++ b/test/js/node/test/fixtures/registerExt2.test @@ -0,0 +1 @@ +This is for the object return test diff --git a/test/js/node/test/fixtures/report-oom.js b/test/js/node/test/fixtures/report-oom.js new file mode 100644 index 0000000000..1677dc239e --- /dev/null +++ b/test/js/node/test/fixtures/report-oom.js @@ -0,0 +1,13 @@ +'use strict'; + +const list = []; +while (true) { + const record = new MyRecord(); + list.push(record); +} + +function MyRecord() { + this.name = 'foo'; + this.id = 128; + this.account = 98454324; +} diff --git a/test/js/node/test/fixtures/require-bin/bin/req.js b/test/js/node/test/fixtures/require-bin/bin/req.js new file mode 100644 index 0000000000..4b2e02c0cc --- /dev/null +++ b/test/js/node/test/fixtures/require-bin/bin/req.js @@ -0,0 +1 @@ +module.exports = require('../'); diff --git a/test/js/node/test/fixtures/require-bin/lib/req.js b/test/js/node/test/fixtures/require-bin/lib/req.js new file mode 100644 index 0000000000..9dc5fc1e4a --- /dev/null +++ b/test/js/node/test/fixtures/require-bin/lib/req.js @@ -0,0 +1 @@ +module.exports = ''; diff --git a/test/js/node/test/fixtures/require-bin/package.json b/test/js/node/test/fixtures/require-bin/package.json new file mode 100644 index 0000000000..5ffac0c1e3 --- /dev/null +++ b/test/js/node/test/fixtures/require-bin/package.json @@ -0,0 +1,4 @@ +{ + "name": "req", + "main": "./lib/req.js" +} diff --git a/test/js/node/test/fixtures/require-empty-main/index.js b/test/js/node/test/fixtures/require-empty-main/index.js new file mode 100644 index 0000000000..d2ed2dd220 --- /dev/null +++ b/test/js/node/test/fixtures/require-empty-main/index.js @@ -0,0 +1,2 @@ +'use strict'; +module.exports = 42; diff --git a/test/js/node/test/fixtures/require-empty-main/package.json b/test/js/node/test/fixtures/require-empty-main/package.json new file mode 100644 index 0000000000..3f0b7c677a --- /dev/null +++ b/test/js/node/test/fixtures/require-empty-main/package.json @@ -0,0 +1 @@ +{"main":""} diff --git a/test/js/node/test/fixtures/require-resolve.js b/test/js/node/test/fixtures/require-resolve.js new file mode 100644 index 0000000000..ae0609f97c --- /dev/null +++ b/test/js/node/test/fixtures/require-resolve.js @@ -0,0 +1,109 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const path = require('path'); +const nodeModules = path.join(__dirname, 'node_modules'); +const nestedNodeModules = path.join(__dirname, 'node_modules', 'node_modules'); +const nestedIndex = path.join(__dirname, 'nested-index'); + +// Test the default behavior. +assert.strictEqual( + require.resolve('bar'), + path.join(nodeModules, 'bar.js') +); + +if (require.resolve.paths) { + // Verify that existing paths are removed. + assert.throws(() => { + require.resolve('bar', { paths: [] }) + }, /^Error: Cannot find module 'bar'/); +} + +// Verify that resolution path can be overwritten. +{ + // three.js cannot be loaded from this file by default. + assert.throws(() => { + require.resolve('three') + }, /^Error: Cannot find module 'three'/); + + // If the nested-index directory is provided as a resolve path, 'three' + // cannot be found because nested-index is used as a starting point and not + // a searched directory. + assert.throws(() => { + require.resolve('three', { paths: [nestedIndex] }) + }, /^Error: Cannot find module 'three'/); + + // Resolution from nested index directory also checks node_modules. + assert.strictEqual( + require.resolve('bar', { paths: [nestedIndex] }), + path.join(nodeModules, 'bar.js') + ); +} + +// Verify that the default paths can be used and modified. +if (require.resolve.paths) { + const paths = require.resolve.paths('bar'); + + assert.strictEqual(paths[0], nodeModules); + assert.strictEqual( + require.resolve('bar', { paths }), + path.join(nodeModules, 'bar.js') + ); + + paths.unshift(nestedNodeModules); + assert.strictEqual( + require.resolve('bar', { paths }), + path.join(nodeModules, 'bar.js') + ); +} + +// Verify that relative request paths work properly. +if (require.resolve.paths) { + const searchIn = './' + path.relative(process.cwd(), nestedIndex); + + // Search in relative paths. + assert.strictEqual( + require.resolve('./three.js', { paths: [searchIn] }), + path.join(nestedIndex, 'three.js') + ); + + // Search in absolute paths. + assert.strictEqual( + require.resolve('./three.js', { paths: [nestedIndex] }), + path.join(nestedIndex, 'three.js') + ); + + // Repeat the same tests with Windows slashes in the request path. + if (common.isWindows) { + assert.strictEqual( + require.resolve('.\\three.js', { paths: [searchIn] }), + path.join(nestedIndex, 'three.js') + ); + + assert.strictEqual( + require.resolve('.\\three.js', { paths: [nestedIndex] }), + path.join(nestedIndex, 'three.js') + ); + } +} + +if (require.resolve.paths) { + // Test paths option validation + assert.throws(() => { + require.resolve('.\\three.js', { paths: 'foo' }) + }, { + code: 'ERR_INVALID_ARG_VALUE', + name: 'TypeError', + }); +} + +// Verify that the default require.resolve() is used for empty options. +assert.strictEqual( + require.resolve('./printA.js', {}), + require.resolve('./printA.js') +); + +assert.strictEqual( + require.resolve('no_index/'), + path.join(__dirname, 'node_modules', 'no_index', 'lib', 'index.js'), +) diff --git a/test/js/node/test/fixtures/resolve-paths/default/verify-paths.js b/test/js/node/test/fixtures/resolve-paths/default/verify-paths.js new file mode 100644 index 0000000000..dee03fbfe3 --- /dev/null +++ b/test/js/node/test/fixtures/resolve-paths/default/verify-paths.js @@ -0,0 +1,21 @@ +'use strict'; +require('../../../common'); +const assert = require('assert'); +const path = require('path'); + +// By default, resolving 'dep' should return +// fixturesDir/resolve-paths/default/node_modules/dep/index.js. By setting +// the path to fixturesDir/resolve-paths/default, the 'default' directory +// structure should be ignored. + +assert.strictEqual( + require.resolve('dep'), + path.join(__dirname, 'node_modules', 'dep', 'index.js') +); + +const paths = [path.resolve(__dirname, '..', 'defined')]; + +assert.strictEqual( + require.resolve('dep', { paths }), + path.join(paths[0], 'node_modules', 'dep', 'index.js') +); diff --git a/test/js/node/test/fixtures/rsa-oaep-test-vectors.js b/test/js/node/test/fixtures/rsa-oaep-test-vectors.js new file mode 100644 index 0000000000..47e681f84d --- /dev/null +++ b/test/js/node/test/fixtures/rsa-oaep-test-vectors.js @@ -0,0 +1,30 @@ +{ + "comment": "RSA-OAEP test vectors for test-crypto-rsa-dsa.js", + "decryptionTests": [ + { + "ct": "16ece59cf985a8cf1a3434e4b9707c922c20638fdf9abf7e5dc7943f4136899348c54116d15b2c17563b9c7143f9d5b85b45615ad0598ea6d21c900f3957b65400612306a9bebae441f005646f7a7c97129a103ab54e777168ef966514adb17786b968ea0ff430a524904c4a11c683764b7c8dbb60df0952768381cdba4d665e5006034393a10d56d33e75b2714db824a18da46441ef7f94a34a7058c0bbad0394083a038558bcc6dd370f8e518e1bd8d73b296fc51d77da44799e4ee774926ded7910e8768f92db76f63107338d33354b735d3ad094240dbd7ffdfda27ef0255306dcf4a6462849492abd1a97fdd37743ff87c4d2ec89866c5cdbb696bd2b30" + }, + { + "ct": "16ece59cf985a8cf1a3434e4b9707c922c20638fdf9abf7e5dc7943f4136899348c54116d15b2c17563b9c7143f9d5b85b45615ad0598ea6d21c900f3957b65400612306a9bebae441f005646f7a7c97129a103ab54e777168ef966514adb17786b968ea0ff430a524904c4a11c683764b7c8dbb60df0952768381cdba4d665e5006034393a10d56d33e75b2714db824a18da46441ef7f94a34a7058c0bbad0394083a038558bcc6dd370f8e518e1bd8d73b296fc51d77da44799e4ee774926ded7910e8768f92db76f63107338d33354b735d3ad094240dbd7ffdfda27ef0255306dcf4a6462849492abd1a97fdd37743ff87c4d2ec89866c5cdbb696bd2b30", + "oaepHash": "sha1" + }, + { + "ct": "16ccf09afe5eb0130182b9fc1ca4af61a38e772047cac42146bfa0fa5879aa9639203e4d01442d212ff95bddfbe4661222215a2e91908c37ab926edea7cfc53f83357bc27f86af0f5f2818ae141f4e9e934d4e66189aff30f062c9c3f6eb9bc495a59082cb978f99b56ce5fa530a8469e46129258e5c42897cb194b6805e936e5cbbeaa535bad6b1d3cdfc92119b7dd325a2e6d2979e316bdacc9f80e29c7bbdf6846d738e380deadcb48df8c1e8aabf7a9dd2f8c71d6681dbec7dcadc01887c51288674268796bc77fdf8f1c94c9ca50b1cc7cddbaf4e56cb151d23e2c699d2844c0104ee2e7e9dcdb907cfab43339120a40c59ca54f32b8d21b48a29656c77", + "oaepHash": "sha256" + }, + { + "ct": "831b72e8dd91841729ecbddf2647d6f19dc0094734f8803d8c651b5655a12ae6156b74d9b594bcc0eacd002728380b94f46e8657f130f354e03b6e7815ee257eda78dba296d67d24410c31c48e5875cc79e4bde594b412be5f357f57a7ac1f1d18b718e408df162d1795508e6a0616192b647ad942ea068a44fb2b323d35a3a61b926feb105d6c0b2a8fc8050222d1cf4a9e44da1f95bbc677fd643749c6c89ac551d072f04cd9320c97a8d94755c8a804954c082bed7fa59199a00aca154c14a7b584b63c538daf9b9c7c90abfca19387d2131f9d9b9ecfc8672249c33144d1be3bfc41558a13f994663661a3af24fd0a97619d508db36f5fc131af86fc68cf", + "oaepHash": "sha512" + }, + { + "ct": "04a25a3dbe0a44b10b7dde19632ce0963e7a7e9876905cd4a4f68ba8e0bda593a738847235df4494f9c28927b165511d22006ef6fae0eb7fe01883e4ae495643328d21e13dad65e71e45f885c7e1e2fe77c39fa84b8bbd2d7d3ed72fea2bf3c87a5c864bdc41b45caa3d668ca3f35297f43dc97950fa959ee88031c8385da7628d03923dfd26a7e0568c95a2f38ec5760335b00fa30935abdd9ab5b3581fc319ff787c59930319707caa24fe9e5d0ce6c48eff4ee6e124fd6c595353acc29a194863dbf7b74d08edf7129ca52eb5f4ccf3888311e97602fcd37b476c41749b260efad4e0760064082f7c9ea0f8704134936b2e38fd0f82886486b5f7e5fb9696", + "oaepHash": "sha384", + "oaepLabel": "01020304" + }, + { + "ct": "678f9ff724e0f48b48e6ff3cbdac5eb995d263da1c23f948d8d09411131f69f40da07f0c650e1aedc82fbaf0972a5d3b3e8f1f82cc4fa1780abfebb4e06b6827a52bf768b12388817c1e3ee1324342e05135733a4056a6cc02f5211172c338eb96e5e33c1d6f53560e3f3aab2419c13a600c4e67648088ffe8aac2cea8bce78e2ab899741cf7c9a9d5246cde6ce97aae0157f42db68eea380dec6dcd842c1e6900ae21d5275c4bf21810b5e1b0e1bc0441cbce34e00a31b9e857f6f2c791257d45997c278ea928f42e8cb6476f633f5de102fa0c4af964a9c4f4336869509e933ebc0aa94ad16b0b1db2aaa924f409a5f9f29dfbd88849c5eaa4818e1c3e335e", + "oaepHash": "sha1", + "oaepLabel": "00112233445566778899" + } + ] +} diff --git a/test/js/node/test/fixtures/run-script/package.json b/test/js/node/test/fixtures/run-script/package.json new file mode 100644 index 0000000000..c103b48840 --- /dev/null +++ b/test/js/node/test/fixtures/run-script/package.json @@ -0,0 +1,15 @@ +{ + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "ada": "ada", + "ada-windows": "ada.bat", + "positional-args": "positional-args", + "positional-args-windows": "positional-args.bat", + "custom-env": "custom-env", + "custom-env-windows": "custom-env.bat", + "path-env": "path-env", + "path-env-windows": "path-env.bat", + "special-env-variables": "special-env-variables", + "special-env-variables-windows": "special-env-variables.bat" + } +} diff --git a/test/js/node/test/fixtures/run-script/sub-directory/.gitkeep b/test/js/node/test/fixtures/run-script/sub-directory/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/js/node/test/fixtures/sample.png b/test/js/node/test/fixtures/sample.png new file mode 100644 index 0000000000000000000000000000000000000000..258622019038678b7c3abd376dfeedd62fe99f14 GIT binary patch literal 9416 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 V$!9S&9?O68iny#6$KVeO{{!3ra})po literal 0 HcmV?d00001 diff --git a/test/js/node/test/fixtures/sample_document.md b/test/js/node/test/fixtures/sample_document.md new file mode 100644 index 0000000000..d1ba308b6d --- /dev/null +++ b/test/js/node/test/fixtures/sample_document.md @@ -0,0 +1,8 @@ +# Sample Markdown + +## Seussian Rhymes +1. fish +2. fish + +* Red fish +* Blue fish diff --git a/test/js/node/test/fixtures/sea.js b/test/js/node/test/fixtures/sea.js new file mode 100644 index 0000000000..e7b7f46ff0 --- /dev/null +++ b/test/js/node/test/fixtures/sea.js @@ -0,0 +1,60 @@ +const { Module: { createRequire } } = require('module'); +const createdRequire = createRequire(__filename); + +// Although, require('../common') works locally, that couldn't be used here +// because we set NODE_TEST_DIR=/Users/iojs/node-tmp on Jenkins CI. +const { expectWarning, mustNotCall } = createdRequire(process.env.COMMON_DIRECTORY); + +// This additionally makes sure that no unexpected warnings are emitted. +if (createdRequire('./sea-config.json').disableExperimentalSEAWarning) { + process.on('warning', mustNotCall()); +} else { + expectWarning('ExperimentalWarning', + 'Single executable application is an experimental feature and ' + + 'might change at any time'); + // Any unexpected warning would throw this error: + // https://github.com/nodejs/node/blob/c301404105a7256b79a0b8c4522ce47af96dfa17/test/common/index.js#L697-L700. +} + +// Should be possible to require core modules that optionally require the +// "node:" scheme. +const { deepStrictEqual, strictEqual, throws } = require('assert'); +const { dirname } = require('node:path'); + +// Checks that the source filename is used in the error stack trace. +strictEqual(new Error('lol').stack.split('\n')[1], ' at sea.js:25:13'); + +// Should be possible to require a core module that requires using the "node:" +// scheme. +{ + const { test } = require('node:test'); + strictEqual(typeof test, 'function'); +} + +// Should not be possible to require a core module without the "node:" scheme if +// it requires using the "node:" scheme. +throws(() => require('test'), { + code: 'ERR_UNKNOWN_BUILTIN_MODULE', +}); + +deepStrictEqual(process.argv, [process.execPath, process.execPath, '-a', '--b=c', 'd']); + +strictEqual(require.cache, undefined); +strictEqual(require.extensions, undefined); +strictEqual(require.main, module); +strictEqual(require.resolve, undefined); + +strictEqual(__filename, process.execPath); +strictEqual(__dirname, dirname(process.execPath)); +strictEqual(module.exports, exports); + +throws(() => require('./requirable.js'), { + code: 'ERR_UNKNOWN_BUILTIN_MODULE', +}); + +const requirable = createdRequire('./requirable.js'); +deepStrictEqual(requirable, { + hello: 'world', +}); + +console.log('Hello, world! 😊'); diff --git a/test/js/node/test/fixtures/sea/get-asset-raw.js b/test/js/node/test/fixtures/sea/get-asset-raw.js new file mode 100644 index 0000000000..0ba9858c01 --- /dev/null +++ b/test/js/node/test/fixtures/sea/get-asset-raw.js @@ -0,0 +1,31 @@ +'use strict'; + +const { isSea, getAsset, getRawAsset } = require('node:sea'); +const { readFileSync } = require('fs'); +const assert = require('assert'); + +assert(isSea()); + +{ + assert.throws(() => getRawAsset('nonexistent'), { + code: 'ERR_SINGLE_EXECUTABLE_APPLICATION_ASSET_NOT_FOUND' + }); + assert.throws(() => getRawAsset(null), { + code: 'ERR_INVALID_ARG_TYPE' + }); + assert.throws(() => getRawAsset(1), { + code: 'ERR_INVALID_ARG_TYPE' + }); +} + +{ + // Check that the asset embedded is the same as the original. + const assetOnDisk = readFileSync(process.env.__TEST_PERSON_JPG); + const assetCopy = getAsset('person.jpg') + const assetCopyBuffer = Buffer.from(assetCopy); + assert.deepStrictEqual(assetCopyBuffer, assetOnDisk); + + // Check that the copied asset is the same as the raw one. + const rawAsset = getRawAsset('person.jpg'); + assert.deepStrictEqual(rawAsset, assetCopy); +} diff --git a/test/js/node/test/fixtures/sea/get-asset.js b/test/js/node/test/fixtures/sea/get-asset.js new file mode 100644 index 0000000000..e1a2189aa4 --- /dev/null +++ b/test/js/node/test/fixtures/sea/get-asset.js @@ -0,0 +1,102 @@ +'use strict'; + +const { isSea, getAsset, getAssetAsBlob } = require('node:sea'); +const { readFileSync } = require('node:fs'); +const assert = require('node:assert'); + +assert(isSea()); + +// Test invalid getAsset() calls. +{ + assert.throws(() => getAsset('utf8_test_text.txt', 'invalid'), { + code: 'ERR_ENCODING_NOT_SUPPORTED' + }); + + [ + 1, + 1n, + Symbol(), + false, + () => {}, + {}, + [], + null, + undefined, + ].forEach(arg => assert.throws(() => getAsset(arg), { + code: 'ERR_INVALID_ARG_TYPE' + })); + + assert.throws(() => getAsset('nonexistent'), { + code: 'ERR_SINGLE_EXECUTABLE_APPLICATION_ASSET_NOT_FOUND' + }); +} + +// Test invalid getAssetAsBlob() calls. +{ + // Invalid options argument. + [ + 123, + 123n, + Symbol(), + '', + true, + ].forEach(arg => assert.throws(() => { + getAssetAsBlob('utf8_test_text.txt', arg) + }, { + code: 'ERR_INVALID_ARG_TYPE' + })); + + assert.throws(() => getAssetAsBlob('nonexistent'), { + code: 'ERR_SINGLE_EXECUTABLE_APPLICATION_ASSET_NOT_FOUND' + }); +} + +const textAssetOnDisk = readFileSync(process.env.__TEST_UTF8_TEXT_PATH, 'utf8'); +const binaryAssetOnDisk = readFileSync(process.env.__TEST_PERSON_JPG); + +// Check getAsset() buffer copies. +{ + // Check that the asset embedded is the same as the original. + const assetCopy1 = getAsset('person.jpg') + const assetCopyBuffer1 = Buffer.from(assetCopy1); + assert.deepStrictEqual(assetCopyBuffer1, binaryAssetOnDisk); + + const assetCopy2 = getAsset('person.jpg'); + const assetCopyBuffer2 = Buffer.from(assetCopy2); + assert.deepStrictEqual(assetCopyBuffer2, binaryAssetOnDisk); + + // Zero-fill copy1. + assetCopyBuffer1.fill(0); + + // Test that getAsset() returns an immutable copy. + assert.deepStrictEqual(assetCopyBuffer2, binaryAssetOnDisk); + assert.notDeepStrictEqual(assetCopyBuffer1, binaryAssetOnDisk); +} + +// Check getAsset() with encoding. +{ + const actualAsset = getAsset('utf8_test_text.txt', 'utf8') + assert.strictEqual(actualAsset, textAssetOnDisk); + // Log it out so that the test could compare it and see if + // it's encoded/decoded correctly in the SEA. + console.log(actualAsset); +} + +// Check getAssetAsBlob(). +{ + let called = false; + async function test() { + const blob = getAssetAsBlob('person.jpg'); + const buffer = await blob.arrayBuffer(); + assert.deepStrictEqual(Buffer.from(buffer), binaryAssetOnDisk); + const blob2 = getAssetAsBlob('utf8_test_text.txt'); + const text = await blob2.text(); + assert.strictEqual(text, textAssetOnDisk); + } + test().then(() => { + called = true; + }); + process.on('exit', () => { + assert(called); + }); +} diff --git a/test/js/node/test/fixtures/self_ref_module/index.js b/test/js/node/test/fixtures/self_ref_module/index.js new file mode 100644 index 0000000000..7faa73693b --- /dev/null +++ b/test/js/node/test/fixtures/self_ref_module/index.js @@ -0,0 +1,4 @@ +'use strict' + +module.exports = 'Self resolution working'; + diff --git a/test/js/node/test/fixtures/self_ref_module/package.json b/test/js/node/test/fixtures/self_ref_module/package.json new file mode 100644 index 0000000000..7280b184c7 --- /dev/null +++ b/test/js/node/test/fixtures/self_ref_module/package.json @@ -0,0 +1,13 @@ +{ + "name": "self_ref", + "version": "1.0.0", + "description": "", + "main": "index.js", + "exports": "./index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/test/js/node/test/fixtures/semicolon.js b/test/js/node/test/fixtures/semicolon.js new file mode 100644 index 0000000000..79a3084499 --- /dev/null +++ b/test/js/node/test/fixtures/semicolon.js @@ -0,0 +1,22 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +; diff --git a/test/js/node/test/fixtures/shared-memory.wasm b/test/js/node/test/fixtures/shared-memory.wasm new file mode 100644 index 0000000000000000000000000000000000000000..497b8440bd212e14fe51694b9c0e0fddf31f975f GIT binary patch literal 26 hcmZQbEY4+QU|?WnVPs}xWanaJ%T3MAFREl>001se1O)&9 literal 0 HcmV?d00001 diff --git a/test/js/node/test/fixtures/should_exit.js b/test/js/node/test/fixtures/should_exit.js new file mode 100644 index 0000000000..1c3b765b1e --- /dev/null +++ b/test/js/node/test/fixtures/should_exit.js @@ -0,0 +1,28 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +function tmp() {} +process.on('SIGINT', tmp); +process.removeListener('SIGINT', tmp); +setInterval(function() { + process.stdout.write('keep alive\n'); +}, 1000); +process.stdout.write('start\n'); diff --git a/test/js/node/test/fixtures/simple.wasm b/test/js/node/test/fixtures/simple.wasm new file mode 100644 index 0000000000000000000000000000000000000000..357f72da7a0db8add83699082fd51d46bf3352fb GIT binary patch literal 41 wcmZQbEY4+QU|?WmXG~zKuV<`hW@2PuXJ=$iOi5v2;NoOtXHZ~JV9eqM0DJxgJ^%m! literal 0 HcmV?d00001 diff --git a/test/js/node/test/fixtures/spawn_closed_stdio.py b/test/js/node/test/fixtures/spawn_closed_stdio.py new file mode 100644 index 0000000000..b5de2552c2 --- /dev/null +++ b/test/js/node/test/fixtures/spawn_closed_stdio.py @@ -0,0 +1,8 @@ +import os +import sys +import subprocess +os.close(0) +os.close(1) +os.close(2) +exit_code = subprocess.call(sys.argv[1:], shell=False) +sys.exit(exit_code) diff --git a/test/js/node/test/fixtures/syntax/bad_syntax.js b/test/js/node/test/fixtures/syntax/bad_syntax.js new file mode 100644 index 0000000000..c2cd118b23 --- /dev/null +++ b/test/js/node/test/fixtures/syntax/bad_syntax.js @@ -0,0 +1 @@ +var foo bar; diff --git a/test/js/node/test/fixtures/syntax/bad_syntax.mjs b/test/js/node/test/fixtures/syntax/bad_syntax.mjs new file mode 100644 index 0000000000..c2cd118b23 --- /dev/null +++ b/test/js/node/test/fixtures/syntax/bad_syntax.mjs @@ -0,0 +1 @@ +var foo bar; diff --git a/test/js/node/test/fixtures/syntax/bad_syntax_shebang.js b/test/js/node/test/fixtures/syntax/bad_syntax_shebang.js new file mode 100644 index 0000000000..1de5d2adc4 --- /dev/null +++ b/test/js/node/test/fixtures/syntax/bad_syntax_shebang.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +var foo bar; diff --git a/test/js/node/test/fixtures/syntax/good_syntax.js b/test/js/node/test/fixtures/syntax/good_syntax.js new file mode 100644 index 0000000000..d8427075a4 --- /dev/null +++ b/test/js/node/test/fixtures/syntax/good_syntax.js @@ -0,0 +1 @@ +var foo = 'bar'; diff --git a/test/js/node/test/fixtures/syntax/good_syntax.mjs b/test/js/node/test/fixtures/syntax/good_syntax.mjs new file mode 100644 index 0000000000..b07312f4f6 --- /dev/null +++ b/test/js/node/test/fixtures/syntax/good_syntax.mjs @@ -0,0 +1,3 @@ +export function testFunction(req, res) { + return 'PASS'; +} diff --git a/test/js/node/test/fixtures/syntax/good_syntax_shebang.js b/test/js/node/test/fixtures/syntax/good_syntax_shebang.js new file mode 100644 index 0000000000..f9ff7d5694 --- /dev/null +++ b/test/js/node/test/fixtures/syntax/good_syntax_shebang.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +var foo = 'bar'; diff --git a/test/js/node/test/fixtures/syntax/illegal_if_not_wrapped.js b/test/js/node/test/fixtures/syntax/illegal_if_not_wrapped.js new file mode 100644 index 0000000000..d76a836c88 --- /dev/null +++ b/test/js/node/test/fixtures/syntax/illegal_if_not_wrapped.js @@ -0,0 +1,3 @@ +if (true) { + return; +} diff --git a/test/js/node/test/fixtures/test-error-first-line-offset.js b/test/js/node/test/fixtures/test-error-first-line-offset.js new file mode 100644 index 0000000000..8276753746 --- /dev/null +++ b/test/js/node/test/fixtures/test-error-first-line-offset.js @@ -0,0 +1 @@ +error diff --git a/test/js/node/test/fixtures/test-fs-readfile-error.js b/test/js/node/test/fixtures/test-fs-readfile-error.js new file mode 100644 index 0000000000..9bac28f8ef --- /dev/null +++ b/test/js/node/test/fixtures/test-fs-readfile-error.js @@ -0,0 +1,22 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +require('fs').readFileSync('/'); // throws EISDIR diff --git a/test/js/node/test/fixtures/test-fs-stat-sync-overflow.js b/test/js/node/test/fixtures/test-fs-stat-sync-overflow.js new file mode 100644 index 0000000000..9f947fa091 --- /dev/null +++ b/test/js/node/test/fixtures/test-fs-stat-sync-overflow.js @@ -0,0 +1,7 @@ +const fs = require('fs'); + +function load() { + fs.statSync('.'); + load(); +} +load(); diff --git a/test/js/node/test/fixtures/test-init-index/index.js b/test/js/node/test/fixtures/test-init-index/index.js new file mode 100644 index 0000000000..433f44b6ca --- /dev/null +++ b/test/js/node/test/fixtures/test-init-index/index.js @@ -0,0 +1,25 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +(function() { + process.stdout.write('Loaded successfully!'); +})(); + diff --git a/test/js/node/test/fixtures/test-init-native/fs.js b/test/js/node/test/fixtures/test-init-native/fs.js new file mode 100644 index 0000000000..37043125d5 --- /dev/null +++ b/test/js/node/test/fixtures/test-init-native/fs.js @@ -0,0 +1,28 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +(function() { + const fs = require('fs'); + if (fs.readFile) { + process.stdout.write('fs loaded successfully'); + } +})(); + diff --git a/test/js/node/test/fixtures/test-module-loading-globalpaths/home-pkg-in-both/.node_libraries/foo.js b/test/js/node/test/fixtures/test-module-loading-globalpaths/home-pkg-in-both/.node_libraries/foo.js new file mode 100644 index 0000000000..eb278f9576 --- /dev/null +++ b/test/js/node/test/fixtures/test-module-loading-globalpaths/home-pkg-in-both/.node_libraries/foo.js @@ -0,0 +1 @@ +exports.string = '$HOME/.node_libraries'; diff --git a/test/js/node/test/fixtures/test-module-loading-globalpaths/home-pkg-in-both/.node_modules/foo.js b/test/js/node/test/fixtures/test-module-loading-globalpaths/home-pkg-in-both/.node_modules/foo.js new file mode 100644 index 0000000000..8a665b3e98 --- /dev/null +++ b/test/js/node/test/fixtures/test-module-loading-globalpaths/home-pkg-in-both/.node_modules/foo.js @@ -0,0 +1 @@ +exports.string = '$HOME/.node_modules'; diff --git a/test/js/node/test/fixtures/test-module-loading-globalpaths/home-pkg-in-node_libraries/.node_libraries/foo.js b/test/js/node/test/fixtures/test-module-loading-globalpaths/home-pkg-in-node_libraries/.node_libraries/foo.js new file mode 100644 index 0000000000..eb278f9576 --- /dev/null +++ b/test/js/node/test/fixtures/test-module-loading-globalpaths/home-pkg-in-node_libraries/.node_libraries/foo.js @@ -0,0 +1 @@ +exports.string = '$HOME/.node_libraries'; diff --git a/test/js/node/test/fixtures/test-module-loading-globalpaths/home-pkg-in-node_modules/.node_modules/foo.js b/test/js/node/test/fixtures/test-module-loading-globalpaths/home-pkg-in-node_modules/.node_modules/foo.js new file mode 100644 index 0000000000..8a665b3e98 --- /dev/null +++ b/test/js/node/test/fixtures/test-module-loading-globalpaths/home-pkg-in-node_modules/.node_modules/foo.js @@ -0,0 +1 @@ +exports.string = '$HOME/.node_modules'; diff --git a/test/js/node/test/fixtures/test-module-loading-globalpaths/local-pkg/test.js b/test/js/node/test/fixtures/test-module-loading-globalpaths/local-pkg/test.js new file mode 100644 index 0000000000..8054983e99 --- /dev/null +++ b/test/js/node/test/fixtures/test-module-loading-globalpaths/local-pkg/test.js @@ -0,0 +1,2 @@ +'use strict'; +console.log(require('foo').string); diff --git a/test/js/node/test/fixtures/test-module-loading-globalpaths/node_path/foo.js b/test/js/node/test/fixtures/test-module-loading-globalpaths/node_path/foo.js new file mode 100644 index 0000000000..3ce43c4920 --- /dev/null +++ b/test/js/node/test/fixtures/test-module-loading-globalpaths/node_path/foo.js @@ -0,0 +1 @@ +exports.string = '$NODE_PATH'; diff --git a/test/js/node/test/fixtures/test-repl-tab-completion/.hiddenfiles b/test/js/node/test/fixtures/test-repl-tab-completion/.hiddenfiles new file mode 100644 index 0000000000..8943faefed --- /dev/null +++ b/test/js/node/test/fixtures/test-repl-tab-completion/.hiddenfiles @@ -0,0 +1 @@ +This is hidden \ No newline at end of file diff --git a/test/js/node/test/fixtures/test-repl-tab-completion/hellorandom.txt b/test/js/node/test/fixtures/test-repl-tab-completion/hellorandom.txt new file mode 100644 index 0000000000..35268b4f15 --- /dev/null +++ b/test/js/node/test/fixtures/test-repl-tab-completion/hellorandom.txt @@ -0,0 +1 @@ +Random txt \ No newline at end of file diff --git a/test/js/node/test/fixtures/test-repl-tab-completion/helloworld.js b/test/js/node/test/fixtures/test-repl-tab-completion/helloworld.js new file mode 100644 index 0000000000..0f504264f5 --- /dev/null +++ b/test/js/node/test/fixtures/test-repl-tab-completion/helloworld.js @@ -0,0 +1 @@ +console.log("hello world"); \ No newline at end of file diff --git a/test/js/node/test/fixtures/test-resolution-inspect-brk-main.ext b/test/js/node/test/fixtures/test-resolution-inspect-brk-main.ext new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/js/node/test/fixtures/test-resolution-inspect-brk-resolver.js b/test/js/node/test/fixtures/test-resolution-inspect-brk-resolver.js new file mode 100644 index 0000000000..b5569e69fc --- /dev/null +++ b/test/js/node/test/fixtures/test-resolution-inspect-brk-resolver.js @@ -0,0 +1,4 @@ +'use strict'; +const common = require('../common'); + +require.extensions['.ext'] = require.extensions['.js']; diff --git a/test/js/node/test/fixtures/throws_error.js b/test/js/node/test/fixtures/throws_error.js new file mode 100644 index 0000000000..b38000894b --- /dev/null +++ b/test/js/node/test/fixtures/throws_error.js @@ -0,0 +1,22 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +throw new Error('blah'); diff --git a/test/js/node/test/fixtures/throws_error1.js b/test/js/node/test/fixtures/throws_error1.js new file mode 100644 index 0000000000..b38000894b --- /dev/null +++ b/test/js/node/test/fixtures/throws_error1.js @@ -0,0 +1,22 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +throw new Error('blah'); diff --git a/test/js/node/test/fixtures/throws_error2.js b/test/js/node/test/fixtures/throws_error2.js new file mode 100644 index 0000000000..835ad5aa44 --- /dev/null +++ b/test/js/node/test/fixtures/throws_error2.js @@ -0,0 +1,23 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +JSON.parse(undefined); + diff --git a/test/js/node/test/fixtures/throws_error3.js b/test/js/node/test/fixtures/throws_error3.js new file mode 100644 index 0000000000..a53084c68c --- /dev/null +++ b/test/js/node/test/fixtures/throws_error3.js @@ -0,0 +1,24 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +process.nextTick(function() { + JSON.parse(undefined); +}); diff --git a/test/js/node/test/fixtures/throws_error4.js b/test/js/node/test/fixtures/throws_error4.js new file mode 100644 index 0000000000..bc7d6f8c6b --- /dev/null +++ b/test/js/node/test/fixtures/throws_error4.js @@ -0,0 +1,41 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +01234567890123456789012345/** +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 +01234567890123456789012345678901234567890123456789 diff --git a/test/js/node/test/fixtures/throws_error5.js b/test/js/node/test/fixtures/throws_error5.js new file mode 100644 index 0000000000..a0eba5d8b2 --- /dev/null +++ b/test/js/node/test/fixtures/throws_error5.js @@ -0,0 +1 @@ +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000k0000000000000000000 diff --git a/test/js/node/test/fixtures/throws_error6.js b/test/js/node/test/fixtures/throws_error6.js new file mode 100644 index 0000000000..8e650d4bf4 --- /dev/null +++ b/test/js/node/test/fixtures/throws_error6.js @@ -0,0 +1 @@ +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000k000000000 diff --git a/test/js/node/test/fixtures/throws_error7.js b/test/js/node/test/fixtures/throws_error7.js new file mode 100644 index 0000000000..f730bc6def --- /dev/null +++ b/test/js/node/test/fixtures/throws_error7.js @@ -0,0 +1,5 @@ +throw { + toString: function() { + throw this; + } +}; diff --git a/test/js/node/test/fixtures/tls-connect.js b/test/js/node/test/fixtures/tls-connect.js new file mode 100644 index 0000000000..51c0b328e9 --- /dev/null +++ b/test/js/node/test/fixtures/tls-connect.js @@ -0,0 +1,108 @@ +// One shot call to connect a TLS client and server based on options to +// tls.createServer() and tls.connect(), so assertions can be made on both ends +// of the connection. +'use strict'; + +const common = require('../common'); +// Check if Node was compiled --without-ssl and if so exit early +// as the require of tls will otherwise throw an Error. +if (!common.hasCrypto) + common.skip('missing crypto'); + +const fixtures = require('../common/fixtures'); +const tls = require('tls'); +const util = require('util'); + +exports.assert = require('assert'); +exports.debug = util.debuglog('test'); +exports.tls = tls; + +// Pre-load keys from common fixtures for ease of use by tests. +exports.keys = { + agent1: load('agent1', 'ca1'), + agent2: load('agent2', 'agent2'), + agent3: load('agent3', 'ca2'), + agent4: load('agent4', 'ca2'), + agent5: load('agent5', 'ca2'), + agent6: load('agent6', 'ca1'), + agent7: load('agent7', 'fake-cnnic-root'), + agent10: load('agent10', 'ca2'), + ec10: load('ec10', 'ca5'), + ec: load('ec', 'ec'), +}; + +// `root` is the self-signed root of the trust chain, not an intermediate ca. +function load(cert, root) { + root = root || cert; // Assume self-signed if no issuer. + const id = { + key: fixtures.readKey(cert + '-key.pem', 'binary'), + cert: fixtures.readKey(cert + '-cert.pem', 'binary'), + ca: fixtures.readKey(root + '-cert.pem', 'binary'), + }; + return id; +} + +exports.connect = function connect(options, callback) { + callback = common.mustCall(callback); + + const server = {}; + const client = {}; + const pair = { server, client }; + + try { + tls.createServer(options.server, function(conn) { + server.conn = conn; + conn.pipe(conn); + maybeCallback(); + }).listen(0, function() { + server.server = this; + + const optClient = util._extend({ + port: this.address().port, + }, options.client); + + try { + tls.connect(optClient) + .on('secureConnect', function() { + client.conn = this; + maybeCallback(); + }) + .on('error', function(err) { + client.err = err; + client.conn = this; + maybeCallback(); + }); + } catch (err) { + client.err = err; + // The server won't get a connection, we are done. + callback(err, pair, cleanup); + callback = null; + } + }).on('tlsClientError', function(err, sock) { + server.conn = sock; + server.err = err; + maybeCallback(); + }); + } catch (err) { + // Invalid options can throw, report the error. + pair.server.err = err; + callback(err, pair, () => {}); + } + + function maybeCallback() { + if (!callback) + return; + if (server.conn && client.conn) { + const err = pair.client.err || pair.server.err; + callback(err, pair, cleanup); + callback = null; + } + } + + function cleanup() { + if (server.server) + server.server.close(); + if (client.conn) + client.conn.end(); + } +}; diff --git a/test/js/node/test/fixtures/tls-session-ticket.txt b/test/js/node/test/fixtures/tls-session-ticket.txt new file mode 100644 index 0000000000..bc0f6b58e1 --- /dev/null +++ b/test/js/node/test/fixtures/tls-session-ticket.txt @@ -0,0 +1,23 @@ +-----BEGIN SSL SESSION PARAMETERS----- +MIID2wIBAQICAwEEAgA1BCAMjLe+70uBSPGvybkTnPVUMwdbdtVbkMIXf8L5M8Kl +VAQwog+Afs00cnYUcgD1BQewJyxX1e561oRuDTpy7BHABC1hC7hxTaul+pwv+cBx +8D72oQYCBFFQF3OiBAICASyjggNhMIIDXTCCAkWgAwIBAgIJAMUSOvlaeyQHMA0G +CSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRl +MSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTAxMTE2MDkz +MjQ5WhcNMTMxMTE1MDkzMjQ5WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29t +ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+LXZOjcQCJq3+ZKUFabj71oo/ex +/XsBcFqtBThjjTw9CVEVwfPQQp4XwtPiB204vnYXwQ1/R2NdTQqCZu47l79LssL/ +u2a5Y9+0NEU3nQA5qdt+1FAE0c5oexPimXOrR3GWfKz7PmZ2O0117IeCUUXPG5U8 +umhDe/4mDF4ZNJiKc404WthquTqgS7rLQZHhZ6D0EnGnOkzlmxJMYPNHSOY1/6iv +dNUUcC87awNEA3lgfhy25IyBK3QJc+aYKNTbt70Lery3bu2wWLFGtmNiGlQTS4Js +xImRsECTI727ObS7/FWAQsqW+COL0Sa5BuMFrFIpjPrEe0ih7vRRbdmXRwIDAQAB +o1AwTjAdBgNVHQ4EFgQUDnV4d6mDtOnluLoCjkUHTX/n4agwHwYDVR0jBBgwFoAU +DnV4d6mDtOnluLoCjkUHTX/n4agwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUF +AAOCAQEAFwV4MQfTo+qMv9JMiynoIEiqfOz4RgtmBqRnXUffcjS2dhc7/z+FPZnM +79Kej8eLHoVfxCyWRHFlzm93vEdvwxOCrD13EDOi08OOZfxWyIlCa6Bg8cMAKqQz +d2OvQOWqlRWBTThBJIhWflU33izXQn5GdmYqhfpc+9ZHHGhvXNydtRQkdxVK2dZN +zLBvBlLlRmtoClU7xm3A+/5dddePAQHEPtyFlUw49VYtZ3ru6KqPms7MKvcRhYLs +y9rwSfuuniMlx4d0bDR7TOkw0QQSA0N8MGQRQpzl4mw4jLzyM5d5QtuGBh2P6hPG +a0YQxtI3RPT/p6ENzzBiAKXiSfzox6QCBAClAwIBEg== +-----END SSL SESSION PARAMETERS----- diff --git a/test/js/node/test/fixtures/tz-version.txt b/test/js/node/test/fixtures/tz-version.txt new file mode 100644 index 0000000000..04fe674443 --- /dev/null +++ b/test/js/node/test/fixtures/tz-version.txt @@ -0,0 +1 @@ +2024a diff --git a/test/js/node/test/fixtures/uncaught-exceptions/callbackify1.js b/test/js/node/test/fixtures/uncaught-exceptions/callbackify1.js new file mode 100644 index 0000000000..1fbe7c8ebf --- /dev/null +++ b/test/js/node/test/fixtures/uncaught-exceptions/callbackify1.js @@ -0,0 +1,15 @@ +'use strict'; + +// Used to test that `uncaughtException` is emitted + +const { callbackify } = require('util'); + +{ + async function fn() { } + + const cbFn = callbackify(fn); + + cbFn((err, ret) => { + throw new Error(__filename); + }); +} diff --git a/test/js/node/test/fixtures/uncaught-exceptions/callbackify2.js b/test/js/node/test/fixtures/uncaught-exceptions/callbackify2.js new file mode 100644 index 0000000000..7b4ee4f565 --- /dev/null +++ b/test/js/node/test/fixtures/uncaught-exceptions/callbackify2.js @@ -0,0 +1,22 @@ +'use strict'; + +// Used to test the `uncaughtException` err object + +const assert = require('assert'); +const { callbackify } = require('util'); + +{ + const sentinel = new Error(__filename); + process.once('uncaughtException', (err) => { + assert.notStrictEqual(err, sentinel); + // Calling test will use `stdout` to assert value of `err.message` + console.log(err.message); + }); + + function fn() { + return Promise.reject(sentinel); + } + + const cbFn = callbackify(fn); + cbFn((err, ret) => assert.ifError(err)); +} diff --git a/test/js/node/test/fixtures/uncaught-exceptions/domain.js b/test/js/node/test/fixtures/uncaught-exceptions/domain.js new file mode 100644 index 0000000000..8b69f52f14 --- /dev/null +++ b/test/js/node/test/fixtures/uncaught-exceptions/domain.js @@ -0,0 +1,12 @@ +const domain = require('domain'); + +var d = domain.create(); +d.on('error', function(err) { + console.log('[ignored]', err); +}); + +d.run(function() { + setImmediate(function() { + throw new Error('in domain'); + }); +}); diff --git a/test/js/node/test/fixtures/uncaught-exceptions/global.js b/test/js/node/test/fixtures/uncaught-exceptions/global.js new file mode 100644 index 0000000000..df14e88c47 --- /dev/null +++ b/test/js/node/test/fixtures/uncaught-exceptions/global.js @@ -0,0 +1,2 @@ +console.log('going to throw an error'); +throw new Error('global'); diff --git a/test/js/node/test/fixtures/uncaught-exceptions/parse-error-mod.js b/test/js/node/test/fixtures/uncaught-exceptions/parse-error-mod.js new file mode 100644 index 0000000000..05dbf29f00 --- /dev/null +++ b/test/js/node/test/fixtures/uncaught-exceptions/parse-error-mod.js @@ -0,0 +1,2 @@ +console.log('parse error on next line'); +var a = '; diff --git a/test/js/node/test/fixtures/uncaught-exceptions/parse-error.js b/test/js/node/test/fixtures/uncaught-exceptions/parse-error.js new file mode 100644 index 0000000000..8ec4d4ec85 --- /dev/null +++ b/test/js/node/test/fixtures/uncaught-exceptions/parse-error.js @@ -0,0 +1,2 @@ +console.log('require fails on next line'); +require('./parse-error-mod.js'); diff --git a/test/js/node/test/fixtures/uncaught-exceptions/timeout.js b/test/js/node/test/fixtures/uncaught-exceptions/timeout.js new file mode 100644 index 0000000000..1d8491ff62 --- /dev/null +++ b/test/js/node/test/fixtures/uncaught-exceptions/timeout.js @@ -0,0 +1,3 @@ +setTimeout(function() { + throw new Error('timeout'); +}, 10); diff --git a/test/js/node/test/fixtures/uncaught-exceptions/uncaught-monitor1.js b/test/js/node/test/fixtures/uncaught-exceptions/uncaught-monitor1.js new file mode 100644 index 0000000000..9724539a25 --- /dev/null +++ b/test/js/node/test/fixtures/uncaught-exceptions/uncaught-monitor1.js @@ -0,0 +1,10 @@ +'use strict'; + +// Keep the event loop alive. +setTimeout(() => {}, 1e6); + +process.on('uncaughtExceptionMonitor', (err) => { + console.log(`Monitored: ${err.message}`); +}); + +throw new Error('Shall exit'); diff --git a/test/js/node/test/fixtures/uncaught-exceptions/uncaught-monitor2.js b/test/js/node/test/fixtures/uncaught-exceptions/uncaught-monitor2.js new file mode 100644 index 0000000000..743a561100 --- /dev/null +++ b/test/js/node/test/fixtures/uncaught-exceptions/uncaught-monitor2.js @@ -0,0 +1,11 @@ +'use strict'; + +// Keep the event loop alive. +setTimeout(() => {}, 1e6); + +process.on('uncaughtExceptionMonitor', (err) => { + console.log(`Monitored: ${err.message}, will throw now`); + missingFunction(); +}); + +throw new Error('Shall exit'); diff --git a/test/js/node/test/fixtures/url-idna.js b/test/js/node/test/fixtures/url-idna.js new file mode 100644 index 0000000000..4b8f5a48cc --- /dev/null +++ b/test/js/node/test/fixtures/url-idna.js @@ -0,0 +1,215 @@ +'use strict'; + +// Credit for list: http://www.i18nguy.com/markup/idna-examples.html +module.exports = [ + { ascii: 'xn--mgbaal8b0b9b2b.icom.museum', + unicode: 'Ø§ÙØºØ§Ù†Ø³ØªØ§.icom.museum' + }, + { + ascii: 'xn--lgbbat1ad8j.icom.museum', + unicode: 'الجزائر.icom.museum' + }, + { + ascii: 'xn--sterreich-z7a.icom.museum', + unicode: 'österreich.icom.museum' + }, + { + ascii: 'xn--54b6eqazv8bc7e.icom.museum', + unicode: 'বাংলাদেশ.icom.museum' + }, + { + ascii: 'xn--80abmy0agn7e.icom.museum', + unicode: 'беларуÑÑŒ.icom.museum' + }, + { + ascii: 'xn--belgi-rsa.icom.museum', + unicode: 'belgië.icom.museum' + }, + { + ascii: 'xn--80abgvm6a7d2b.icom.museum', + unicode: 'българиÑ.icom.museum' + }, + { + ascii: 'xn--mgbfqim.icom.museum', + unicode: 'تشادر.icom.museum' + }, + { + ascii: 'xn--fiqs8s.icom.museum', + unicode: '中国.icom.museum' + }, + { + ascii: 'xn--mgbu4chg.icom.museum', + unicode: 'القمر.icom.museum' + }, + { + ascii: 'xn--vxakcego.icom.museum', + unicode: 'κυπÏος.icom.museum' + }, + { + ascii: 'xn--eskrepublika-ebb62d.icom.museum', + unicode: 'Äeskárepublika.icom.museum' + }, + { + ascii: 'xn--wgbh1c.icom.museum', + unicode: 'مصر.icom.museum' + }, + { + ascii: 'xn--hxakic4aa.icom.museum', + unicode: 'ελλάδα.icom.museum' + }, + { + ascii: 'xn--magyarorszg-t7a.icom.museum', + unicode: 'magyarország.icom.museum' + }, + { + ascii: 'xn--sland-ysa.icom.museum', + unicode: 'ísland.icom.museum' + }, + { + ascii: 'xn--h2brj9c.icom.museum', + unicode: 'भारत.icom.museum' + }, + { + ascii: 'xn--mgba3a4fra.icom.museum', + unicode: 'ايران.icom.museum' + }, + { + ascii: 'xn--ire-9la.icom.museum', + unicode: 'éire.icom.museum' + }, + { + ascii: 'xn--4dbklr2c8d.xn--4dbrk0ce.museum', + unicode: '×יקו״×.ישר×ל.museum' + }, + { + ascii: 'xn--wgv71a.icom.museum', + unicode: '日本.icom.museum' + }, + { + ascii: 'xn--igbhzh7gpa.icom.museum', + unicode: 'الأردن.icom.museum' + }, + { + ascii: 'xn--80aaa0a6awh12ed.icom.museum', + unicode: 'қазақÑтан.icom.museum' + }, + { + ascii: 'xn--3e0b707e.icom.museum', + unicode: '한국.icom.museum' + }, + { + ascii: 'xn--80afmksoji0fc.icom.museum', + unicode: 'кыргызÑтан.icom.museum' + }, + { + ascii: 'xn--q7ce6a.icom.museum', + unicode: 'ລາວ.icom.museum' + }, + { + ascii: 'xn--mgbb7fjb.icom.museum', + unicode: 'لبنان.icom.museum' + }, + { + ascii: 'xn--80aaldqjmmi6x.icom.museum', + unicode: 'македонија.icom.museum' + }, + { + ascii: 'xn--mgbah1a3hjkrd.icom.museum', + unicode: 'موريتانيا.icom.museum' + }, + { + ascii: 'xn--mxico-bsa.icom.museum', + unicode: 'méxico.icom.museum' + }, + { + ascii: 'xn--c1aqabffc0aq.icom.museum', + unicode: 'монголулÑ.icom.museum' + }, + { + ascii: 'xn--mgbc0a9azcg.icom.museum', + unicode: 'المغرب.icom.museum' + }, + { + ascii: 'xn--l2bey1c2b.icom.museum', + unicode: 'नेपाल.icom.museum' + }, + { + ascii: 'xn--mgb9awbf.icom.museum', + unicode: 'عمان.icom.museum' + }, + { + ascii: 'xn--wgbl6a.icom.museum', + unicode: 'قطر.icom.museum' + }, + { + ascii: 'xn--romnia-yta.icom.museum', + unicode: 'românia.icom.museum' + }, + { + ascii: 'xn--h1alffa9f.xn--h1aegh.museum', + unicode: 'роÑÑиÑ.иком.museum' + }, + { + ascii: 'xn--80aaabm1ab4blmeec9e7n.xn--h1aegh.museum', + unicode: 'Ñрбијаицрнагора.иком.museum' + }, + { + ascii: 'xn--xkc2al3hye2a.icom.museum', + unicode: 'இலஙà¯à®•ை.icom.museum' + }, + { + ascii: 'xn--espaa-rta.icom.museum', + unicode: 'españa.icom.museum' + }, + { + ascii: 'xn--o3cw4h.icom.museum', + unicode: 'ไทย.icom.museum' + }, + { + ascii: 'xn--pgbs0dh.icom.museum', + unicode: 'تونس.icom.museum' + }, + { + ascii: 'xn--trkiye-3ya.icom.museum', + unicode: 'türkiye.icom.museum' + }, + { + ascii: 'xn--80aaxgrpt.icom.museum', + unicode: 'украина.icom.museum' + }, + { + ascii: 'xn--vitnam-jk8b.icom.museum', + unicode: 'việtnam.icom.museum' + }, + // long label + { + ascii: `${'a'.repeat(64)}.com`, + unicode: `${'a'.repeat(64)}.com`, + }, + // long URL + { + ascii: `${`${'a'.repeat(64)}.`.repeat(4)}com`, + unicode: `${`${'a'.repeat(64)}.`.repeat(4)}com` + }, + // URLs with hyphen + { + ascii: 'r4---sn-a5mlrn7s.gevideo.com', + unicode: 'r4---sn-a5mlrn7s.gevideo.com' + }, + { + ascii: '-sn-a5mlrn7s.gevideo.com', + unicode: '-sn-a5mlrn7s.gevideo.com' + }, + { + ascii: 'sn-a5mlrn7s-.gevideo.com', + unicode: 'sn-a5mlrn7s-.gevideo.com' + }, + { + ascii: '-sn-a5mlrn7s-.gevideo.com', + unicode: '-sn-a5mlrn7s-.gevideo.com' + }, + { + ascii: '-sn--a5mlrn7s-.gevideo.com', + unicode: '-sn--a5mlrn7s-.gevideo.com' + } +]; diff --git a/test/js/node/test/fixtures/url-searchparams.js b/test/js/node/test/fixtures/url-searchparams.js new file mode 100644 index 0000000000..918af678bc --- /dev/null +++ b/test/js/node/test/fixtures/url-searchparams.js @@ -0,0 +1,77 @@ +module.exports = [ + ['', '', []], + [ + 'foo=918854443121279438895193', + 'foo=918854443121279438895193', + [['foo', '918854443121279438895193']] + ], + ['foo=bar', 'foo=bar', [['foo', 'bar']]], + ['foo=bar&foo=quux', 'foo=bar&foo=quux', [['foo', 'bar'], ['foo', 'quux']]], + ['foo=1&bar=2', 'foo=1&bar=2', [['foo', '1'], ['bar', '2']]], + [ + "my%20weird%20field=q1!2%22'w%245%267%2Fz8)%3F", + 'my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F', + [['my weird field', 'q1!2"\'w$5&7/z8)?']] + ], + ['foo%3Dbaz=bar', 'foo%3Dbaz=bar', [['foo=baz', 'bar']]], + ['foo=baz=bar', 'foo=baz%3Dbar', [['foo', 'baz=bar']]], + [ + 'str=foo&arr=1&somenull&arr=2&undef=&arr=3', + 'str=foo&arr=1&somenull=&arr=2&undef=&arr=3', + [ + ['str', 'foo'], + ['arr', '1'], + ['somenull', ''], + ['arr', '2'], + ['undef', ''], + ['arr', '3'] + ] + ], + [' foo = bar ', '+foo+=+bar+', [[' foo ', ' bar ']]], + ['foo=%zx', 'foo=%25zx', [['foo', '%zx']]], + ['foo=%EF%BF%BD', 'foo=%EF%BF%BD', [['foo', '\ufffd']]], + // See: https://github.com/joyent/node/issues/3058 + ['foo&bar=baz', 'foo=&bar=baz', [['foo', ''], ['bar', 'baz']]], + ['a=b&c&d=e', 'a=b&c=&d=e', [['a', 'b'], ['c', ''], ['d', 'e']]], + ['a=b&c=&d=e', 'a=b&c=&d=e', [['a', 'b'], ['c', ''], ['d', 'e']]], + ['a=b&=c&d=e', 'a=b&=c&d=e', [['a', 'b'], ['', 'c'], ['d', 'e']]], + ['a=b&=&d=e', 'a=b&=&d=e', [['a', 'b'], ['', ''], ['d', 'e']]], + ['&&foo=bar&&', 'foo=bar', [['foo', 'bar']]], + ['&', '', []], + ['&&&&', '', []], + ['&=&', '=', [['', '']]], + ['&=&=', '=&=', [['', ''], ['', '']]], + ['=', '=', [['', '']]], + ['+', '+=', [[' ', '']]], + ['+=', '+=', [[' ', '']]], + ['+&', '+=', [[' ', '']]], + ['=+', '=+', [['', ' ']]], + ['+=&', '+=', [[' ', '']]], + ['a&&b', 'a=&b=', [['a', ''], ['b', '']]], + ['a=a&&b=b', 'a=a&b=b', [['a', 'a'], ['b', 'b']]], + ['&a', 'a=', [['a', '']]], + ['&=', '=', [['', '']]], + ['a&a&', 'a=&a=', [['a', ''], ['a', '']]], + ['a&a&a&', 'a=&a=&a=', [['a', ''], ['a', ''], ['a', '']]], + ['a&a&a&a&', 'a=&a=&a=&a=', [['a', ''], ['a', ''], ['a', ''], ['a', '']]], + ['a=&a=value&a=', 'a=&a=value&a=', [['a', ''], ['a', 'value'], ['a', '']]], + ['foo%20bar=baz%20quux', 'foo+bar=baz+quux', [['foo bar', 'baz quux']]], + ['+foo=+bar', '+foo=+bar', [[' foo', ' bar']]], + ['a+', 'a+=', [['a ', '']]], + ['=a+', '=a+', [['', 'a ']]], + ['a+&', 'a+=', [['a ', '']]], + ['=a+&', '=a+', [['', 'a ']]], + ['%20+', '++=', [[' ', '']]], + ['=%20+', '=++', [['', ' ']]], + ['%20+&', '++=', [[' ', '']]], + ['=%20+&', '=++', [['', ' ']]], + [ + // fake percent encoding + 'foo=%©ar&baz=%A©uux&xyzzy=%©ud', + 'foo=%25%C2%A9ar&baz=%25A%C2%A9uux&xyzzy=%25%C2%A9ud', + [['foo', '%©ar'], ['baz', '%A©uux'], ['xyzzy', '%©ud']] + ], + // always preserve order of key-value pairs + ['a=1&b=2&a=3', 'a=1&b=2&a=3', [['a', '1'], ['b', '2'], ['a', '3']]], + ['?a', '%3Fa=', [['?a', '']]] +]; diff --git a/test/js/node/test/fixtures/url-setter-tests-additional.js b/test/js/node/test/fixtures/url-setter-tests-additional.js new file mode 100644 index 0000000000..b27ae336a2 --- /dev/null +++ b/test/js/node/test/fixtures/url-setter-tests-additional.js @@ -0,0 +1,237 @@ +module.exports = { + 'username': [ + { + 'comment': 'Surrogate pair', + 'href': 'https://github.com/', + 'new_value': '\uD83D\uDE00', + 'expected': { + 'href': 'https://%F0%9F%98%80@github.com/', + 'username': '%F0%9F%98%80' + } + }, + { + 'comment': 'Unpaired low surrogate 1', + 'href': 'https://github.com/', + 'new_value': '\uD83D', + 'expected': { + 'href': 'https://%EF%BF%BD@github.com/', + 'username': '%EF%BF%BD' + } + }, + { + 'comment': 'Unpaired low surrogate 2', + 'href': 'https://github.com/', + 'new_value': '\uD83Dnode', + 'expected': { + 'href': 'https://%EF%BF%BDnode@github.com/', + 'username': '%EF%BF%BDnode' + } + }, + { + 'comment': 'Unpaired high surrogate 1', + 'href': 'https://github.com/', + 'new_value': '\uDE00', + 'expected': { + 'href': 'https://%EF%BF%BD@github.com/', + 'username': '%EF%BF%BD' + } + }, + { + 'comment': 'Unpaired high surrogate 2', + 'href': 'https://github.com/', + 'new_value': '\uDE00node', + 'expected': { + 'href': 'https://%EF%BF%BDnode@github.com/', + 'username': '%EF%BF%BDnode' + } + } + ], + 'password': [ + { + 'comment': 'Surrogate pair', + 'href': 'https://github.com/', + 'new_value': '\uD83D\uDE00', + 'expected': { + 'href': 'https://:%F0%9F%98%80@github.com/', + 'password': '%F0%9F%98%80' + } + }, + { + 'comment': 'Unpaired low surrogate 1', + 'href': 'https://github.com/', + 'new_value': '\uD83D', + 'expected': { + 'href': 'https://:%EF%BF%BD@github.com/', + 'password': '%EF%BF%BD' + } + }, + { + 'comment': 'Unpaired low surrogate 2', + 'href': 'https://github.com/', + 'new_value': '\uD83Dnode', + 'expected': { + 'href': 'https://:%EF%BF%BDnode@github.com/', + 'password': '%EF%BF%BDnode' + } + }, + { + 'comment': 'Unpaired high surrogate 1', + 'href': 'https://github.com/', + 'new_value': '\uDE00', + 'expected': { + 'href': 'https://:%EF%BF%BD@github.com/', + 'password': '%EF%BF%BD' + } + }, + { + 'comment': 'Unpaired high surrogate 2', + 'href': 'https://github.com/', + 'new_value': '\uDE00node', + 'expected': { + 'href': 'https://:%EF%BF%BDnode@github.com/', + 'password': '%EF%BF%BDnode' + } + } + ], + 'pathname': [ + { + 'comment': 'Surrogate pair', + 'href': 'https://github.com/', + 'new_value': '/\uD83D\uDE00', + 'expected': { + 'href': 'https://github.com/%F0%9F%98%80', + 'pathname': '/%F0%9F%98%80' + } + }, + { + 'comment': 'Unpaired low surrogate 1', + 'href': 'https://github.com/', + 'new_value': '/\uD83D', + 'expected': { + 'href': 'https://github.com/%EF%BF%BD', + 'pathname': '/%EF%BF%BD' + } + }, + { + 'comment': 'Unpaired low surrogate 2', + 'href': 'https://github.com/', + 'new_value': '/\uD83Dnode', + 'expected': { + 'href': 'https://github.com/%EF%BF%BDnode', + 'pathname': '/%EF%BF%BDnode' + } + }, + { + 'comment': 'Unpaired high surrogate 1', + 'href': 'https://github.com/', + 'new_value': '/\uDE00', + 'expected': { + 'href': 'https://github.com/%EF%BF%BD', + 'pathname': '/%EF%BF%BD' + } + }, + { + 'comment': 'Unpaired high surrogate 2', + 'href': 'https://github.com/', + 'new_value': '/\uDE00node', + 'expected': { + 'href': 'https://github.com/%EF%BF%BDnode', + 'pathname': '/%EF%BF%BDnode' + } + } + ], + 'search': [ + { + 'comment': 'Surrogate pair', + 'href': 'https://github.com/', + 'new_value': '\uD83D\uDE00', + 'expected': { + 'href': 'https://github.com/?%F0%9F%98%80', + 'search': '?%F0%9F%98%80' + } + }, + { + 'comment': 'Unpaired low surrogate 1', + 'href': 'https://github.com/', + 'new_value': '\uD83D', + 'expected': { + 'href': 'https://github.com/?%EF%BF%BD', + 'search': '?%EF%BF%BD' + } + }, + { + 'comment': 'Unpaired low surrogate 2', + 'href': 'https://github.com/', + 'new_value': '\uD83Dnode', + 'expected': { + 'href': 'https://github.com/?%EF%BF%BDnode', + 'search': '?%EF%BF%BDnode' + } + }, + { + 'comment': 'Unpaired high surrogate 1', + 'href': 'https://github.com/', + 'new_value': '\uDE00', + 'expected': { + 'href': 'https://github.com/?%EF%BF%BD', + 'search': '?%EF%BF%BD' + } + }, + { + 'comment': 'Unpaired high surrogate 2', + 'href': 'https://github.com/', + 'new_value': '\uDE00node', + 'expected': { + 'href': 'https://github.com/?%EF%BF%BDnode', + 'search': '?%EF%BF%BDnode' + } + } + ], + 'hash': [ + { + 'comment': 'Surrogate pair', + 'href': 'https://github.com/', + 'new_value': '\uD83D\uDE00', + 'expected': { + 'href': 'https://github.com/#%F0%9F%98%80', + 'hash': '#%F0%9F%98%80' + } + }, + { + 'comment': 'Unpaired low surrogate 1', + 'href': 'https://github.com/', + 'new_value': '\uD83D', + 'expected': { + 'href': 'https://github.com/#%EF%BF%BD', + 'hash': '#%EF%BF%BD' + } + }, + { + 'comment': 'Unpaired low surrogate 2', + 'href': 'https://github.com/', + 'new_value': '\uD83Dnode', + 'expected': { + 'href': 'https://github.com/#%EF%BF%BDnode', + 'hash': '#%EF%BF%BDnode' + } + }, + { + 'comment': 'Unpaired high surrogate 1', + 'href': 'https://github.com/', + 'new_value': '\uDE00', + 'expected': { + 'href': 'https://github.com/#%EF%BF%BD', + 'hash': '#%EF%BF%BD' + } + }, + { + 'comment': 'Unpaired high surrogate 2', + 'href': 'https://github.com/', + 'new_value': '\uDE00node', + 'expected': { + 'href': 'https://github.com/#%EF%BF%BDnode', + 'hash': '#%EF%BF%BDnode' + } + } + ] +}; diff --git a/test/js/node/test/fixtures/url-tests-additional.js b/test/js/node/test/fixtures/url-tests-additional.js new file mode 100644 index 0000000000..c1c640f4bb --- /dev/null +++ b/test/js/node/test/fixtures/url-tests-additional.js @@ -0,0 +1,36 @@ +'use strict'; + +// This file contains test cases not part of the WPT + +module.exports = [ + { + // surrogate pair + 'url': 'https://github.com/nodejs/\uD83D\uDE00node', + 'protocol': 'https:', + 'pathname': '/nodejs/%F0%9F%98%80node' + }, + { + // unpaired low surrogate + 'url': 'https://github.com/nodejs/\uD83D', + 'protocol': 'https:', + 'pathname': '/nodejs/%EF%BF%BD' + }, + { + // unpaired low surrogate + 'url': 'https://github.com/nodejs/\uD83Dnode', + 'protocol': 'https:', + 'pathname': '/nodejs/%EF%BF%BDnode' + }, + { + // unmatched high surrogate + 'url': 'https://github.com/nodejs/\uDE00', + 'protocol': 'https:', + 'pathname': '/nodejs/%EF%BF%BD' + }, + { + // unmatched high surrogate + 'url': 'https://github.com/nodejs/\uDE00node', + 'protocol': 'https:', + 'pathname': '/nodejs/%EF%BF%BDnode' + } +]; diff --git a/test/js/node/test/fixtures/utf8-bom-shebang-shebang.js b/test/js/node/test/fixtures/utf8-bom-shebang-shebang.js new file mode 100644 index 0000000000..4cf986dff2 --- /dev/null +++ b/test/js/node/test/fixtures/utf8-bom-shebang-shebang.js @@ -0,0 +1,3 @@ +#!shebang +#!shebang +module.exports = 42; \ No newline at end of file diff --git a/test/js/node/test/fixtures/utf8-bom.js b/test/js/node/test/fixtures/utf8-bom.js new file mode 100644 index 0000000000..0a6f80d74f --- /dev/null +++ b/test/js/node/test/fixtures/utf8-bom.js @@ -0,0 +1 @@ +module.exports = 42; diff --git a/test/js/node/test/fixtures/utf8-bom.json b/test/js/node/test/fixtures/utf8-bom.json new file mode 100644 index 0000000000..68264e1ab7 --- /dev/null +++ b/test/js/node/test/fixtures/utf8-bom.json @@ -0,0 +1 @@ +42 diff --git a/test/js/node/test/fixtures/utf8-shebang-bom.js b/test/js/node/test/fixtures/utf8-shebang-bom.js new file mode 100644 index 0000000000..4ff8fd8d45 --- /dev/null +++ b/test/js/node/test/fixtures/utf8-shebang-bom.js @@ -0,0 +1,2 @@ +#!shebang +module.exports = 42; \ No newline at end of file diff --git a/test/js/node/test/fixtures/utf8_test_text.txt b/test/js/node/test/fixtures/utf8_test_text.txt new file mode 100644 index 0000000000..f4b6fc9bcf --- /dev/null +++ b/test/js/node/test/fixtures/utf8_test_text.txt @@ -0,0 +1 @@ +永和ä¹å¹´ï¼Œåµ—在癸丑,暮春之åˆï¼Œæœƒæ–¼æœƒç¨½å±±éš‚ä¹‹è˜­äº­ï¼Œè„©ç¨§äº‹ä¹Ÿã€‚ç¾£è³¢ç•¢è‡³ï¼Œå°‘é•·å’¸é›†ã€‚æ­¤åœ°æœ‰å´‡å±±å³»é ˜ï¼ŒèŒ‚æž—è„©ç«¹ï¼›åˆæœ‰æ¸…æµæ¿€æ¹ï¼ŒæšŽå¸¶å·¦å³ã€‚引以為æµè§´æ›²æ°´ï¼Œåˆ—å其次。雖無絲竹管弦之盛,一觴一詠,亦足以暢敘幽情。是日也,天朗氣清,æµé¢¨å’Œæš¢ï¼›ä»°è§€å®‡å®™ä¹‹å¤§ï¼Œä¿¯å¯Ÿå“類之盛;所以éŠç›®é¨æ‡ï¼Œè¶³ä»¥æ¥µè¦–è½ä¹‹å¨›ï¼Œä¿¡å¯æ¨‚也。夫人之相與,俯仰一世,或å–è«¸æ‡æŠ±ï¼Œæ‚Ÿè¨€ä¸€å®¤ä¹‹å…§ï¼Œæˆ–å› å¯„æ‰€è¨—ï¼Œæ”¾æµªå½¢éª¸ä¹‹å¤–ã€‚é›–è¶£èˆŽè¬æ®Šï¼Œéœèºä¸åŒï¼Œç•¶å…¶æ¬£æ‰µæ‰€é‡ï¼Œæš«å¾—扵己,æ€ç„¶è‡ªè¶³ï¼Œä¸çŸ¥è€ä¹‹å°‡è‡³ã€‚åŠå…¶æ‰€ä¹‹æ—¢æƒ“,情隨事é·ï¼Œæ„Ÿæ…¨ä¿‚之矣。å‘之所欣,俛仰之閒以為陳跡,猶ä¸èƒ½ä¸ä»¥ä¹‹èˆˆæ‡ï¼›æ³è„©çŸ­éš¨åŒ–,終期扵盡。å¤äººäº‘:「死生亦大矣。ã€è±ˆä¸ç—›å“‰ï¼æ¯æ”¬æ˜”人興感之由,若åˆä¸€å¥‘,未嘗ä¸è‡¨æ–‡å—Ÿæ‚¼ï¼Œä¸èƒ½å–»ä¹‹æ‰µæ‡ã€‚å›ºçŸ¥ä¸€æ­»ç”Ÿç‚ºè™›èª•ï¼Œé½Šå½­æ®¤ç‚ºå¦„ä½œã€‚å¾Œä¹‹è¦–ä»Šï¼Œäº¦ç”±ä»Šä¹‹è¦–æ˜”ï¼Œæ‚²å¤«ï¼æ•…列敘時人,錄其所述,雖世殊事異,所以興æ‡ï¼Œå…¶è‡´ä¸€ä¹Ÿã€‚後之攬者,亦將有感扵斯文。 \ No newline at end of file diff --git a/test/js/node/test/fixtures/v8/v8_warning.js b/test/js/node/test/fixtures/v8/v8_warning.js new file mode 100644 index 0000000000..ab4d2bf305 --- /dev/null +++ b/test/js/node/test/fixtures/v8/v8_warning.js @@ -0,0 +1,19 @@ +'use strict'; + +require('../../common'); + +function AsmModule() { + 'use asm'; + + function add(a, b) { + a = a | 0; + b = b | 0; + + // Should be `return (a + b) | 0;` + return a + b; + } + + return { add: add }; +} + +AsmModule(); diff --git a/test/js/node/test/fixtures/v8/v8_warning.snapshot b/test/js/node/test/fixtures/v8/v8_warning.snapshot new file mode 100644 index 0000000000..6c419c83cd --- /dev/null +++ b/test/js/node/test/fixtures/v8/v8_warning.snapshot @@ -0,0 +1,2 @@ +(node:*) V8: *v8_warning.js:* Invalid asm.js: Invalid return type +(Use `* --trace-warnings ...` to show where the warning was created) diff --git a/test/js/node/test/fixtures/vm/vm_caught_custom_runtime_error.js b/test/js/node/test/fixtures/vm/vm_caught_custom_runtime_error.js new file mode 100644 index 0000000000..81349fc9bf --- /dev/null +++ b/test/js/node/test/fixtures/vm/vm_caught_custom_runtime_error.js @@ -0,0 +1,18 @@ +'use strict'; +require('../../common'); +const vm = require('vm'); + +console.error('beginning'); + +// Regression test for https://github.com/nodejs/node/issues/7397: +// vm.runInThisContext() should not print out anything to stderr by itself. +try { + vm.runInThisContext(`throw ({ + name: 'MyCustomError', + message: 'This is a custom message' + })`, { filename: 'test.vm' }); +} catch (e) { + console.error('received error', e.name); +} + +console.error('end'); diff --git a/test/js/node/test/fixtures/vm/vm_caught_custom_runtime_error.snapshot b/test/js/node/test/fixtures/vm/vm_caught_custom_runtime_error.snapshot new file mode 100644 index 0000000000..9aa1e6c648 --- /dev/null +++ b/test/js/node/test/fixtures/vm/vm_caught_custom_runtime_error.snapshot @@ -0,0 +1,3 @@ +beginning +received error MyCustomError +end diff --git a/test/js/node/test/fixtures/vm/vm_display_runtime_error.js b/test/js/node/test/fixtures/vm/vm_display_runtime_error.js new file mode 100644 index 0000000000..390727d1f0 --- /dev/null +++ b/test/js/node/test/fixtures/vm/vm_display_runtime_error.js @@ -0,0 +1,38 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; +require('../../common'); +Error.stackTraceLimit = 4; + +const vm = require('vm'); + +console.error('beginning'); + +try { + vm.runInThisContext('throw new Error("boo!")', { filename: 'test.vm' }); +} catch (err) { + console.error(err); +} + +vm.runInThisContext('throw new Error("spooky!")', { filename: 'test.vm' }); + +console.error('end'); diff --git a/test/js/node/test/fixtures/vm/vm_display_runtime_error.snapshot b/test/js/node/test/fixtures/vm/vm_display_runtime_error.snapshot new file mode 100644 index 0000000000..47c7d54bae --- /dev/null +++ b/test/js/node/test/fixtures/vm/vm_display_runtime_error.snapshot @@ -0,0 +1,21 @@ +beginning +test.vm:1 +throw new Error("boo!") +^ + +Error: boo! + at test.vm:1:7 + at Script.runInThisContext (node:vm:*) + at Object.runInThisContext (node:vm:*) + at Object. (*fixtures*vm*vm_display_runtime_error.js:31:6) +test.vm:1 +throw new Error("spooky!") +^ + +Error: spooky! + at test.vm:1:7 + at Script.runInThisContext (node:vm:*) + at Object.runInThisContext (node:vm:*) + at Object. (*fixtures*vm*vm_display_runtime_error.js:36:4) + +Node.js * diff --git a/test/js/node/test/fixtures/vm/vm_display_syntax_error.js b/test/js/node/test/fixtures/vm/vm_display_syntax_error.js new file mode 100644 index 0000000000..9d802eac62 --- /dev/null +++ b/test/js/node/test/fixtures/vm/vm_display_syntax_error.js @@ -0,0 +1,38 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; +require('../../common'); +Error.stackTraceLimit = 4; + +const vm = require('vm'); + +console.error('beginning'); + +try { + vm.runInThisContext('var 4;', { filename: 'foo.vm', displayErrors: true }); +} catch (err) { + console.error(err); +} + +vm.runInThisContext('var 5;', { filename: 'test.vm' }); + +console.error('end'); diff --git a/test/js/node/test/fixtures/vm/vm_display_syntax_error.snapshot b/test/js/node/test/fixtures/vm/vm_display_syntax_error.snapshot new file mode 100644 index 0000000000..84f52ce4db --- /dev/null +++ b/test/js/node/test/fixtures/vm/vm_display_syntax_error.snapshot @@ -0,0 +1,21 @@ +beginning +foo.vm:1 +var 4; + ^ + +SyntaxError: Unexpected number + at new Script (node:vm:*) + at createScript (node:vm:*) + at Object.runInThisContext (node:vm:*) + at Object. (*fixtures*vm*vm_display_syntax_error.js:31:6) +test.vm:1 +var 5; + ^ + +SyntaxError: Unexpected number + at new Script (node:vm:*) + at createScript (node:vm:*) + at Object.runInThisContext (node:vm:*) + at Object. (*fixtures*vm*vm_display_syntax_error.js:36:4) + +Node.js * diff --git a/test/js/node/test/fixtures/vm/vm_dont_display_runtime_error.js b/test/js/node/test/fixtures/vm/vm_dont_display_runtime_error.js new file mode 100644 index 0000000000..128a312cc8 --- /dev/null +++ b/test/js/node/test/fixtures/vm/vm_dont_display_runtime_error.js @@ -0,0 +1,46 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; +require('../../common'); +Error.stackTraceLimit = 4; + +const vm = require('vm'); + +console.error('beginning'); + +try { + vm.runInThisContext('throw new Error("boo!")', { + filename: 'test.vm', + displayErrors: false, + }); +} catch { + // Continue regardless of error. +} + +console.error('middle'); + +vm.runInThisContext('throw new Error("boo!")', { + filename: 'test.vm', + displayErrors: false, +}); + +console.error('end'); diff --git a/test/js/node/test/fixtures/vm/vm_dont_display_runtime_error.snapshot b/test/js/node/test/fixtures/vm/vm_dont_display_runtime_error.snapshot new file mode 100644 index 0000000000..045183d4a3 --- /dev/null +++ b/test/js/node/test/fixtures/vm/vm_dont_display_runtime_error.snapshot @@ -0,0 +1,13 @@ +beginning +middle +test.vm:1 +throw new Error("boo!") +^ + +Error: boo! + at test.vm:1:7 + at Script.runInThisContext (node:vm:*) + at Object.runInThisContext (node:vm:*) + at Object. (*fixtures*vm*vm_dont_display_runtime_error.js:41:4) + +Node.js * diff --git a/test/js/node/test/fixtures/vm/vm_dont_display_syntax_error.js b/test/js/node/test/fixtures/vm/vm_dont_display_syntax_error.js new file mode 100644 index 0000000000..6ce013b423 --- /dev/null +++ b/test/js/node/test/fixtures/vm/vm_dont_display_syntax_error.js @@ -0,0 +1,46 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; +require('../../common'); +Error.stackTraceLimit = 4; + +const vm = require('vm'); + +console.error('beginning'); + +try { + vm.runInThisContext('var 5;', { + filename: 'test.vm', + displayErrors: false, + }); +} catch { + // Continue regardless of error. +} + +console.error('middle'); + +vm.runInThisContext('var 5;', { + filename: 'test.vm', + displayErrors: false, +}); + +console.error('end'); diff --git a/test/js/node/test/fixtures/vm/vm_dont_display_syntax_error.snapshot b/test/js/node/test/fixtures/vm/vm_dont_display_syntax_error.snapshot new file mode 100644 index 0000000000..27c4faf563 --- /dev/null +++ b/test/js/node/test/fixtures/vm/vm_dont_display_syntax_error.snapshot @@ -0,0 +1,13 @@ +beginning +middle +test.vm:1 +var 5; + ^ + +SyntaxError: Unexpected number + at new Script (node:vm:*) + at createScript (node:vm:*) + at Object.runInThisContext (node:vm:*) + at Object. (*fixtures*vm*vm_dont_display_syntax_error.js:41:4) + +Node.js * diff --git a/test/js/node/test/fixtures/warnings.js b/test/js/node/test/fixtures/warnings.js new file mode 100644 index 0000000000..2b2939442d --- /dev/null +++ b/test/js/node/test/fixtures/warnings.js @@ -0,0 +1,3 @@ +'use strict'; + +process.emitWarning('a bad practice warning'); diff --git a/test/js/node/test/fixtures/wasi-preview-1.js b/test/js/node/test/fixtures/wasi-preview-1.js new file mode 100644 index 0000000000..3c11c6db16 --- /dev/null +++ b/test/js/node/test/fixtures/wasi-preview-1.js @@ -0,0 +1,48 @@ +'use strict'; + +const assert = require('assert'); +const fixtures = require('../common/fixtures'); +const tmpdir = require('../common/tmpdir'); +const fs = require('fs'); +const path = require('path'); +const common = require('../common'); +const { WASI } = require('wasi'); + +function returnOnExitEnvToValue(env) { + const envValue = env.RETURN_ON_EXIT; + if (envValue === undefined) { + return undefined; + } + + return envValue === 'true'; +} + +common.expectWarning('ExperimentalWarning', + 'WASI is an experimental feature and might change at any time'); + +tmpdir.refresh(); +const wasmDir = path.join(__dirname, '..', 'wasi', 'wasm'); +const wasiPreview1 = new WASI({ + version: 'preview1', + args: ['foo', '-bar', '--baz=value'], + env: process.env, + preopens: { + '/sandbox': fixtures.path('wasi'), + '/tmp': tmpdir.path, + }, + returnOnExit: returnOnExitEnvToValue(process.env), +}); + +// Validate the getImportObject helper +assert.strictEqual(wasiPreview1.wasiImport, + wasiPreview1.getImportObject().wasi_snapshot_preview1); +const modulePathPreview1 = path.join(wasmDir, `${process.argv[2]}.wasm`); +const bufferPreview1 = fs.readFileSync(modulePathPreview1); + +(async () => { + const { instance: instancePreview1 } = + await WebAssembly.instantiate(bufferPreview1, + wasiPreview1.getImportObject()); + + wasiPreview1.start(instancePreview1); +})().then(common.mustCall()); diff --git a/test/js/node/test/fixtures/wasi/input.txt b/test/js/node/test/fixtures/wasi/input.txt new file mode 100644 index 0000000000..4c38053764 --- /dev/null +++ b/test/js/node/test/fixtures/wasi/input.txt @@ -0,0 +1 @@ +hello from input.txt diff --git a/test/js/node/test/fixtures/wasi/input2.txt b/test/js/node/test/fixtures/wasi/input2.txt new file mode 100644 index 0000000000..6aadea3800 --- /dev/null +++ b/test/js/node/test/fixtures/wasi/input2.txt @@ -0,0 +1 @@ +hello from input2.txt diff --git a/test/js/node/test/fixtures/wasi/notadir b/test/js/node/test/fixtures/wasi/notadir new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/js/node/test/fixtures/wasi/subdir/input_link.txt b/test/js/node/test/fixtures/wasi/subdir/input_link.txt new file mode 120000 index 0000000000..4a6d09bf82 --- /dev/null +++ b/test/js/node/test/fixtures/wasi/subdir/input_link.txt @@ -0,0 +1 @@ +../input.txt \ No newline at end of file diff --git a/test/js/node/test/fixtures/wasi/subdir/outside.txt b/test/js/node/test/fixtures/wasi/subdir/outside.txt new file mode 120000 index 0000000000..2e06947067 --- /dev/null +++ b/test/js/node/test/fixtures/wasi/subdir/outside.txt @@ -0,0 +1 @@ +../../outside.txt \ No newline at end of file diff --git a/test/js/node/test/fixtures/watch-mode/inspect.js b/test/js/node/test/fixtures/watch-mode/inspect.js new file mode 100644 index 0000000000..f836b77e8a --- /dev/null +++ b/test/js/node/test/fixtures/watch-mode/inspect.js @@ -0,0 +1,2 @@ +console.log('safe to debug now'); +setInterval(() => {}, 1000); diff --git a/test/js/node/test/fixtures/watch-mode/inspect_with_signal.js b/test/js/node/test/fixtures/watch-mode/inspect_with_signal.js new file mode 100644 index 0000000000..6abf3ab2b5 --- /dev/null +++ b/test/js/node/test/fixtures/watch-mode/inspect_with_signal.js @@ -0,0 +1,2 @@ +console.log('pid is', process.pid); +setInterval(() => {}, 1000); diff --git a/test/js/node/test/fixtures/watch-mode/ipc.js b/test/js/node/test/fixtures/watch-mode/ipc.js new file mode 100644 index 0000000000..d2a5a63854 --- /dev/null +++ b/test/js/node/test/fixtures/watch-mode/ipc.js @@ -0,0 +1,12 @@ +const path = require('node:path'); +const url = require('node:url'); +const fs = require('node:fs'); +const tmpdir = require('../../common/tmpdir'); + +const tmpfile = tmpdir.resolve('file'); +fs.writeFileSync(tmpfile, ''); + +process.send({ 'watch:require': [path.resolve(__filename)] }); +process.send({ 'watch:import': [url.pathToFileURL(path.resolve(__filename)).toString()] }); +process.send({ 'watch:import': [url.pathToFileURL(tmpfile).toString()] }); +process.send({ 'watch:import': [new URL('http://invalid.com').toString()] }); diff --git a/test/js/node/test/fixtures/worker-data.cjs b/test/js/node/test/fixtures/worker-data.cjs new file mode 100644 index 0000000000..731b77eb36 --- /dev/null +++ b/test/js/node/test/fixtures/worker-data.cjs @@ -0,0 +1,3 @@ +const { workerData, parentPort } = require('worker_threads'); + +parentPort.postMessage(workerData); diff --git a/test/js/node/test/fixtures/worker-data.mjs b/test/js/node/test/fixtures/worker-data.mjs new file mode 100644 index 0000000000..1ec884aadb --- /dev/null +++ b/test/js/node/test/fixtures/worker-data.mjs @@ -0,0 +1,3 @@ +import { workerData, parentPort } from 'worker_threads'; + +parentPort.postMessage(workerData); diff --git a/test/js/node/test/fixtures/worker-from-argv.js b/test/js/node/test/fixtures/worker-from-argv.js new file mode 100644 index 0000000000..dcf9cb4cea --- /dev/null +++ b/test/js/node/test/fixtures/worker-from-argv.js @@ -0,0 +1,3 @@ +'use strict'; +const {Worker} = require('worker_threads'); +new Worker(process.argv[2]).on('exit', process.exit); diff --git a/test/js/node/test/fixtures/worker-name.js b/test/js/node/test/fixtures/worker-name.js new file mode 100644 index 0000000000..45adea78f7 --- /dev/null +++ b/test/js/node/test/fixtures/worker-name.js @@ -0,0 +1,17 @@ +const { Session } = require('inspector'); +const { parentPort } = require('worker_threads'); + +const session = new Session(); + +parentPort.once('message', () => {}); // Prevent the worker from exiting. + +session.connectToMainThread(); + +session.on( + 'NodeWorker.attachedToWorker', + ({ params: { workerInfo } }) => { + // send the worker title to the main thread + parentPort.postMessage(workerInfo.title); + } +); +session.post('NodeWorker.enable', { waitForDebuggerOnStart: false }); diff --git a/test/js/node/test/fixtures/worker-preload.js b/test/js/node/test/fixtures/worker-preload.js new file mode 100644 index 0000000000..6e5c4a31d2 --- /dev/null +++ b/test/js/node/test/fixtures/worker-preload.js @@ -0,0 +1,9 @@ +const { + Worker, + workerData, + threadId +} = require('worker_threads'); + +if (threadId < 2) { + new Worker('1 + 1', { eval: true }); +} diff --git a/test/js/node/test/fixtures/worker-script.mjs b/test/js/node/test/fixtures/worker-script.mjs new file mode 100644 index 0000000000..b92905e06c --- /dev/null +++ b/test/js/node/test/fixtures/worker-script.mjs @@ -0,0 +1,3 @@ +import worker from 'worker_threads'; + +worker.parentPort.postMessage('Hello, world!'); diff --git a/test/js/node/test/fixtures/worker-script.ts b/test/js/node/test/fixtures/worker-script.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/js/node/test/fixtures/workload/allocation-exit.js b/test/js/node/test/fixtures/workload/allocation-exit.js new file mode 100644 index 0000000000..dccc61ac94 --- /dev/null +++ b/test/js/node/test/fixtures/workload/allocation-exit.js @@ -0,0 +1,17 @@ +'use strict'; + +const util = require('util'); +const total = parseInt(process.env.TEST_ALLOCATION) || 100; +let count = 0; +let string = ''; +function runAllocation() { + string += util.inspect(process.env); + if (count++ < total) { + setTimeout(runAllocation, 1); + } else { + console.log(string.length); + process.exit(55); + } +} + +setTimeout(runAllocation, 1); diff --git a/test/js/node/test/fixtures/workload/allocation-sigint.js b/test/js/node/test/fixtures/workload/allocation-sigint.js new file mode 100644 index 0000000000..96ae669016 --- /dev/null +++ b/test/js/node/test/fixtures/workload/allocation-sigint.js @@ -0,0 +1,17 @@ +'use strict'; + +const util = require('util'); +const total = parseInt(process.env.TEST_ALLOCATION) || 100; +let count = 0; +let string = ''; +function runAllocation() { + string += util.inspect(process.env); + if (count++ < total) { + setTimeout(runAllocation, 1); + } else { + console.log(string.length); + process.kill(process.pid, "SIGINT"); + } +} + +setTimeout(runAllocation, 1); diff --git a/test/js/node/test/fixtures/workload/allocation-worker-argv.js b/test/js/node/test/fixtures/workload/allocation-worker-argv.js new file mode 100644 index 0000000000..299eb884e5 --- /dev/null +++ b/test/js/node/test/fixtures/workload/allocation-worker-argv.js @@ -0,0 +1,11 @@ +'use strict'; + +const { Worker } = require('worker_threads'); +const path = require('path'); +new Worker(path.join(__dirname, 'allocation.js'), { + execArgv: [ + '--heap-prof', + '--heap-prof-interval', + process.HEAP_PROF_INTERVAL || '128', + ] +}); diff --git a/test/js/node/test/fixtures/workload/allocation-worker.js b/test/js/node/test/fixtures/workload/allocation-worker.js new file mode 100644 index 0000000000..21be6ce91a --- /dev/null +++ b/test/js/node/test/fixtures/workload/allocation-worker.js @@ -0,0 +1,5 @@ +'use strict'; + +const { Worker } = require('worker_threads'); +const path = require('path'); +new Worker(path.join(__dirname, 'allocation.js')); diff --git a/test/js/node/test/fixtures/workload/allocation.js b/test/js/node/test/fixtures/workload/allocation.js new file mode 100644 index 0000000000..b9a767f0f5 --- /dev/null +++ b/test/js/node/test/fixtures/workload/allocation.js @@ -0,0 +1,16 @@ +'use strict'; + +const util = require('util'); +const total = parseInt(process.env.TEST_ALLOCATION) || 100; +let count = 0; +let string = ''; +function runAllocation() { + string += util.inspect(process.env); + if (count++ < total) { + setTimeout(runAllocation, 1); + } else { + console.log(string.length); + } +} + +setTimeout(runAllocation, 1); diff --git a/test/js/node/test/fixtures/workload/bounded.js b/test/js/node/test/fixtures/workload/bounded.js new file mode 100644 index 0000000000..ddf288d034 --- /dev/null +++ b/test/js/node/test/fixtures/workload/bounded.js @@ -0,0 +1,22 @@ +'use strict'; + +const total = parseInt(process.env.TEST_ALLOCATION) || 5000; +const chunk = parseInt(process.env.TEST_CHUNK) || 1000; +const cleanInterval = parseInt(process.env.TEST_CLEAN_INTERVAL) || 100; +let count = 0; +let arr = []; +function runAllocation() { + count++; + if (count < total) { + if (count % cleanInterval === 0) { + arr.splice(0, arr.length); + setImmediate(runAllocation); + } else { + const str = JSON.stringify(process.config).slice(0, chunk); + arr.push(str); + setImmediate(runAllocation); + } + } +} + +setImmediate(runAllocation); diff --git a/test/js/node/test/fixtures/workload/fibonacci-exit.js b/test/js/node/test/fixtures/workload/fibonacci-exit.js new file mode 100644 index 0000000000..6509075b22 --- /dev/null +++ b/test/js/node/test/fixtures/workload/fibonacci-exit.js @@ -0,0 +1,7 @@ +'use strict'; +function fib(n) { + if (n === 0 || n === 1) return n; + return fib(n - 1) + fib(n - 2); +} +fib(parseInt(process.argv[2]) || 35); +process.exit(55); diff --git a/test/js/node/test/fixtures/workload/fibonacci-sigint.js b/test/js/node/test/fixtures/workload/fibonacci-sigint.js new file mode 100644 index 0000000000..d0508c7371 --- /dev/null +++ b/test/js/node/test/fixtures/workload/fibonacci-sigint.js @@ -0,0 +1,7 @@ +'use strict'; +function fib(n) { + if (n === 0 || n === 1) return n; + return fib(n - 1) + fib(n - 2); +} +fib(parseInt(process.argv[2]) || 35); +process.kill(process.pid, "SIGINT"); diff --git a/test/js/node/test/fixtures/workload/fibonacci-worker-argv.js b/test/js/node/test/fixtures/workload/fibonacci-worker-argv.js new file mode 100644 index 0000000000..69a78ec4e1 --- /dev/null +++ b/test/js/node/test/fixtures/workload/fibonacci-worker-argv.js @@ -0,0 +1,11 @@ +'use strict'; + +const { Worker } = require('worker_threads'); +const path = require('path'); +new Worker(path.join(__dirname, 'fibonacci.js'), { + execArgv: [ + '--cpu-prof', + '--cpu-prof-interval', + process.env.CPU_PROF_INTERVAL || '100' + ] +}); diff --git a/test/js/node/test/fixtures/workload/fibonacci-worker.js b/test/js/node/test/fixtures/workload/fibonacci-worker.js new file mode 100644 index 0000000000..d92fb16931 --- /dev/null +++ b/test/js/node/test/fixtures/workload/fibonacci-worker.js @@ -0,0 +1,5 @@ +'use strict'; + +const { Worker } = require('worker_threads'); +const path = require('path'); +new Worker(path.join(__dirname, 'fibonacci.js')); diff --git a/test/js/node/test/fixtures/workload/fibonacci.js b/test/js/node/test/fixtures/workload/fibonacci.js new file mode 100644 index 0000000000..90ef3e99fb --- /dev/null +++ b/test/js/node/test/fixtures/workload/fibonacci.js @@ -0,0 +1,8 @@ +'use strict'; +function fib(n) { + if (n === 0 || n === 1) return n; + return fib(n - 1) + fib(n - 2); +} + +const n = parseInt(process.env.FIB, 10) || 40; +process.stdout.write(`${fib(n)}\n`); diff --git a/test/js/node/test/fixtures/workload/grow-and-set-near-heap-limit.js b/test/js/node/test/fixtures/workload/grow-and-set-near-heap-limit.js new file mode 100644 index 0000000000..62d2c1ffdc --- /dev/null +++ b/test/js/node/test/fixtures/workload/grow-and-set-near-heap-limit.js @@ -0,0 +1,9 @@ +'use strict'; +const path = require('path'); +const v8 = require('v8'); + +v8.setHeapSnapshotNearHeapLimit(+process.env.limit); +if (process.env.limit2) { + v8.setHeapSnapshotNearHeapLimit(+process.env.limit2); +} +require(path.resolve(__dirname, 'grow.js')); diff --git a/test/js/node/test/fixtures/workload/grow-worker-and-set-near-heap-limit.js b/test/js/node/test/fixtures/workload/grow-worker-and-set-near-heap-limit.js new file mode 100644 index 0000000000..598088bcf9 --- /dev/null +++ b/test/js/node/test/fixtures/workload/grow-worker-and-set-near-heap-limit.js @@ -0,0 +1,15 @@ +'use strict'; +const path = require('path'); +const { Worker } = require('worker_threads'); +const max_snapshots = parseInt(process.env.TEST_SNAPSHOTS) || 1; +new Worker(path.join(__dirname, 'grow-and-set-near-heap-limit.js'), { + env: { + ...process.env, + limit: max_snapshots, + }, + resourceLimits: { + maxOldGenerationSizeMb: + parseInt(process.env.TEST_OLD_SPACE_SIZE) || 20 + } +}); + diff --git a/test/js/node/test/fixtures/workload/grow-worker.js b/test/js/node/test/fixtures/workload/grow-worker.js new file mode 100644 index 0000000000..092d8f2775 --- /dev/null +++ b/test/js/node/test/fixtures/workload/grow-worker.js @@ -0,0 +1,14 @@ +'use strict'; + +const { Worker } = require('worker_threads'); +const path = require('path'); +const max_snapshots = parseInt(process.env.TEST_SNAPSHOTS) || 1; +new Worker(path.join(__dirname, 'grow.js'), { + execArgv: [ + `--heapsnapshot-near-heap-limit=${max_snapshots}`, + ], + resourceLimits: { + maxOldGenerationSizeMb: + parseInt(process.env.TEST_OLD_SPACE_SIZE) || 20 + } +}); diff --git a/test/js/node/test/fixtures/workload/grow.js b/test/js/node/test/fixtures/workload/grow.js new file mode 100644 index 0000000000..9ac0139b33 --- /dev/null +++ b/test/js/node/test/fixtures/workload/grow.js @@ -0,0 +1,12 @@ +'use strict'; + +const chunk = parseInt(process.env.TEST_CHUNK) || 1000; + +let arr = []; +function runAllocation() { + const str = JSON.stringify(process.config).slice(0, chunk); + arr.push(str); + setImmediate(runAllocation); +} + +setImmediate(runAllocation); diff --git a/test/js/node/test/fixtures/x.txt b/test/js/node/test/fixtures/x.txt new file mode 100644 index 0000000000..cd470e6190 --- /dev/null +++ b/test/js/node/test/fixtures/x.txt @@ -0,0 +1 @@ +xyz diff --git a/test/js/node/test/fixtures/x1024.txt b/test/js/node/test/fixtures/x1024.txt new file mode 100644 index 0000000000..c6a9d2f1a5 --- /dev/null +++ b/test/js/node/test/fixtures/x1024.txt @@ -0,0 +1 @@ +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \ No newline at end of file diff --git a/test/js/node/test/fixtures/x509-escaping/.gitignore b/test/js/node/test/fixtures/x509-escaping/.gitignore new file mode 100644 index 0000000000..504afef81f --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +package-lock.json diff --git a/test/js/node/test/fixtures/x509-escaping/alt-0-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-0-cert.pem new file mode 100644 index 0000000000..30e6fa6c3f --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-0-cert.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +NTAzMDEGA1UdEQQqMCiCJmdvb2QuZXhhbXBsZS5jb20sIEROUzpldmlsLmV4YW1w +bGUuY29tMA0GCSqGSIb3DQEBCwUAA4ICAQAcsy+PIduM8NRrdqcTqufiajsAajQz +eB5+5+lZLi9MliXqoS4HsdrDMDevMa2cC+wB+XZW9SJXjtqrwXAxTAHtEyhsCi25 +XV0sJPWmZM+OQkGTtp7Ain12htr/t/DJ13YJpT03W6kYogA1kKJ5OMYMTcGT+7UB +zM4G2LUSrrSisxhfz9bF8Q9s1piG2gb5ACEQUiMLRrZXl8WLlaY59lloKyMa/9g6 +i3TgLxhp7XNS/bh/f2tDx+7ZgdtHUlkNhl1MycIVQRGK3BaZBEd+sDxS52kwym5I +CWLXGLutU3OeaNgqyvZuMvy//2oER3PysizyjwNoFlUbIz3zMnXvBeEjeGtEHsCJ +EBtX+xBWwMhUKE2QcMLxQaZNJCZFVFw8fDeEgFjTdEBcLsZ1PngT3jgXSHEWA+YL +C3rQhFMjyjy2h8u1sjySFrTlbZPm8gC3q/+LaXxhf5i5xiZOOcVfeYiWFUa5gQal +FaWj2SlQFaN2nidPaQO62vRIYn0Y/qbtUQAPkq4VVeycgxiuZaVVWCdct8UCYb9F +b9QSMpK4r99MKy+s41RiJodDJy0XraOxy7hUDjyObL2fuuPUK6mQAFGwWtajv3qq +vrRMvBEXdOPVmbETyzIosUHvOXT+v8WoCbC14mqMZTWVywRg7bD/NTHJDRIBrqvi +O6Zqbod3EImVnQ== +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-1-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-1-cert.pem new file mode 100644 index 0000000000..63883c2bbf --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-1-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE0zCCArugAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +IjAgMB4GA1UdEQQXMBWGE2h0dHA6Ly9leGFtcGxlLmNvbS8wDQYJKoZIhvcNAQEL +BQADggIBACFwNHWQ5w3UBbyq17emn7Z0BT0Zm5iFr8Qeik75WzbyzXd5QIeFWewB +qmiuaoKGGZ674sGcuomnIwoZBCoqvzbBBqBHp+O3/6pq59THQxeE6vhjKAe8oaih +emdigRmkX+Qi8UwUh76B51wHtkp6zAZnLDn8M67qmP7bjNrrMQeE81wRWYz9ssfd +N63dzu2BdD3EGl4CepdszpfUYLkz6iiDwFkc1NaBcQbBDoGqn2ubNXTHAyGGeL5a +ulDCND0FQtg+jhHHE3zXBqh1nPg/cXXRUG2zjxzUnaU2eMs5b4yqoLN/2n7fb7mV +HRh0T6X1HZcYpf5BSsgmr3Ngd/9b3sYRvNXBkVmKAu8dH7zguksczsvbL9r/u2YX +hgGjNT3xSphJbZTzqsACcoDo67EFkJ5p25f0N1i/rxk7O6uLMtrUqnzOXs6NXgEQ +8lyfVEgLFrXzdKXuk2l/6bwym80Eqdpjv5yCckCl24cFVpc15MRP3MPwIHrtoOLw +bdNZA5NUAnppLmG6zTdPPgBWEmf5+4ei9WjmpG1hq72/nJ1qM2dLIgV5nLggr1UH +i+vih+ujceBLVumAu/naP440xO5HRvpPfDWI+eU/wuXjUyAqe6YlYS+Txu/5YnFh +aMHO+PIgudWwGPhkABtrc/1jC+Yfy+GCtih10zBagoN9/DSugh0H +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-10-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-10-cert.pem new file mode 100644 index 0000000000..14bec45d28 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-10-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIExTCCAq2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +FDASMBAGA1UdEQQJMAeHBQAICAQEMA0GCSqGSIb3DQEBCwUAA4ICAQA+jnyjJ/9X +ENWXApq2g+GlWBM07KpsrxzwDXc6wsOnZCIiMoDqpcH96X8Q2Lahc4mZuz4yOZtv +z8Q9YUDTnJY+RtKYNDbxlz7wI1ASxKdP0X1qdzkYtHH752tG/zwVU2FSvqJLw+nl +rPJvQQ82/30BspejbW0JIfO7JnfN5BHPzzJp/V5tI1KQe+Wh0gEq6UvXjFrkCoeU +gaedPaG2RYDi1LWawRque7pnYzrcJCtc+wb8wiL1dRv7fDDmI7fFm3Bj6Rnid4/6 +/CxK3WqLBQrXoGnPGwI4iR17Rx08hPCL2V8NvDuJlagJe/Vc6LzOEixofoHGx4rG +Cm0AKubKbak/ML/rjyP2TiUmOhhm3Xdml3xexedErkgTLtlvmC0jesYuc4MeypNx +Q0eKRnChRGZYT9kaNgXZG1Scq63vpxKhayVvwU4ahGQS+nmuZdbRMEMIH6YkGxo/ +i5qmNxQPLMLE6HclSdDtUxN4ywQAQ49CaTCxVYq7dLTzpII3ldQ+KuefenaXrYGE +7TyqJBVdsTq0Bg2Ftf7GaoidJ/ZjjkB3Sj5uVQFMfU8uSATOolBOzh6fSiQJ60Zn +CtAAkb9uOwTl67Qijo4qAe9JRNqR9H5d65D0Vx+gdhcZVEriqIVhXVcgsvYQ55Ju +VGhc/foVd+vBuM3jXEdGR+DN/dEu+HZrhQ== +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-11-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-11-cert.pem new file mode 100644 index 0000000000..694cb7e9d8 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-11-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIExjCCAq6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +FTATMBEGA1UdEQQKMAiHBgABAgMEBTANBgkqhkiG9w0BAQsFAAOCAgEAp2nxfYla +giNJ9S2owtp/5DxB3jIhQJzmdSxuUKVwWBffmzxrTkOoK/IcGkq3hu27GIy+ICFc +YkSsAE3DfboSTStxhkVZKMVv+e5tXPQ0i+Z+CSgHZbrnaA7nH0UPEgFFddhqogGw +LGE54iZ3D7ZYebTw/ELCIHNu9KeOStF7j04WXG7qRrqza5NmKqlxTC5tGoWAljzN +cdC2BdK7H2+6de3c4dBsYqcL2IgwNhA1uKIsDjJwwkOPmCEPl+7DjleI3IAKpROh +vX66DLaAsLEkoHsN7XTienHF8o/avIMGUfb0rtNLbwW8tzfjeAaJ7iTSm7ibhBLP +fK+n7Osh9QH+lG0K7M2zez7Kd3u+eNgTEG63gVR+zDZQwkA2Hy1o4zmZ+a3iCtdi +w6JGq3TT8nfPNO4kSoq7EYs6daPnGi3sqNRC20t4FZw0jOpvI4Uw7rPcTTqmAeAw +9H37WU3URD2EP8BpkoZiOShMHzNGqlC9qbqr5dd83Lkdz9gN4w3ipdbiiGFGPXhT +YubUecjwXoBUUI+be/edVbg7RtSSuplDv5l4bBSy+BG8JEUL6CKAUEtt2Tpt2SVD +AIaj0B19/DSYq1e4x8IBVBsI2RnEEpP70bdLiSYLhVhMdzp0PRqDVDE+zt4mm0lx +NRDSdNS1/rJEH1gLQEh4SGMs9iY5Vv+kx28= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-12-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-12-cert.pem new file mode 100644 index 0000000000..7e48ebdf05 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-12-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE0DCCArigAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +HzAdMBsGA1UdEQQUMBKHEAoLDA0ODwAAAAAAAHp7fH0wDQYJKoZIhvcNAQELBQAD +ggIBAEMU6XcjSdQ+EG22BsyAYin2d3g9Fd0gljsuyEyw2qwFE1zeNqz2sFX7GdmP +hEmUVdzQ0EQsHtKiO2BIhU5fkLoGIkJQT0MY/Tkc3xCLjVBG9ryHNjhv4aYfcvZ2 +K8LwWu5na5YtpmEHppFTmhQFHK9Yf2Jeh5Ms1VH2jwKR8iFM9dk0wcB74Y1WqyX0 +bhNUzv0ISvz/DK6rN0CM0OiZ7D1toMFJIslEcZD/MCZ0icFwRgGLzooDbm1xtixo +NjgdswdiL0cS/wgSdzu9eIugUQZU2KvUWYXGqYMDpn7iukiZSKQuFhZGcuK17zyR +y6TkDFe9rTxVtw9SAxjlo94rEqWN9Cns0n7tqAI/Wg6ILHUjUFwqSdrZQTEgH4O3 +tfhRkV4HCgP1Tzfz/20uMBqjCLbdt7xcSfLIiHgaxgwM0LGhH2Uk3oYinL2WIUDi +bZPI+1bzeyZ/tHw4sDxkGn3W3Nr44Td/5DAFz1lRMxAliVwHNzFTiY7IjCqmB0DL +z91agdgPMdh/huFvGJZHS/v7EXMSXyNLyIw+5JO12iwf4+pu8NLnOtMoHDB4yY0w +MEerc4e8SmygBQGF0MrcmirdT+7yiKRktZZFuyQoj4fBSKeBaBKUrnnk4UYw9H8f +j/EQwM87PmYjTwYPrJ0Kz5r4dmAUvq4z2ReLgM08Ve4SPa79 +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-13-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-13-cert.pem new file mode 100644 index 0000000000..574ad1ca8f --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-13-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEzzCCAregAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +HjAcMBoGA1UdEQQTMBGBD2Zvb0BleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOC +AgEAkx9jG86PMjL+/UxlhX0B/gIKHyTVrEt8j+/fn74uMnd7CV7toK6f5DANIxYp +3OJWAFYZ2lNS3MQMxpbjpd7D0BeNwhiJyBnRPhJ9KdsvdXnupF5ANNzr3oMioWwL +3WxvmQDEz35sorae5nzuZu8EpuwgodR0NCEmoPdW9JOUiB7k3Ku5goZHqlrdzM8f +YPbRDNOxSIpRqr5eqhEM9tEf+TF6qOM/NZJlXxtGDVdaDTbaULuCJGEW8TdVajnY +FfWWtIHwF64G5qJTgENqJjR1kkJy5vg2lFoDXE8MG+LvTHfyY0rMilncD2YOBLcj +gb3mBTxZGI2w2KZbchgEvA9+0heumAVJQPfdGs+pCUdvlhwWh8FCvu3aQb5X57OU +3D97vwvEs8Mxm0KHf0o0ZnTvaBWN5htX2bbpvYxGGB0SsWM8r1LIXj8bwGNdViV8 +UWNrg37XyGCppL1jXJ1q+DDKOvi0JR384ocRmS8mWUf9qiAMOqveix38rHezWlEm +4TCscq4tv135nM194D6uilzv4mUxLAMTX8Lvag1R3aKuOHio9lCGep4v776kALE6 +9/rekRGoMwNApoaC96x+V/dkbfnjWcxRXL5TvjDwVInl+RCcn6ijYZM0HYc+U1Dw +MwqBCbP2Y9Ee7xcnAgPbqH2svWG7XadQHAcOEDc/DFsPRG8= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-14-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-14-cert.pem new file mode 100644 index 0000000000..0265b5992c --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-14-cert.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE5TCCAs2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +NDAyMDAGA1UdEQQpMCeBJWZvb0BleGFtcGxlLmNvbSwgRE5TOmdvb2QuZXhhbXBs +ZS5jb20wDQYJKoZIhvcNAQELBQADggIBABf7bojDeoFEFyk/Xzo50sAL+5irJYzV +n//5aEvUotYxQt5coi7UnkKUgdiUhIXD8WaxD9KP3nUH+C3cxAQ+I7iVjFhjqFQB +X4c/ZjJA2QIX7VMWA3kpOFvR5N0HHest097Fi/HUEEXNkcUtCkRNtI2Msse9uz09 +DIv9P0IQ2TFgBRCTJwq2ZfVebHk/xoQ5fV9b0b39ts6ToiuMvGJVng2zz8fVNMah +hycCn0WSb6dPi9k0ItSvRTYL6vp9X842+Q0Xkq0FxQPUcvzN7D1tSmHXDM7nYXp3 +FB6DKASp0+nn+J88RXVSpO0JedEyRDEluxHJcan+hqhWJ4DgamlVTEPN3q5yE4lt +Jr/R5tnx0Lv0CxDTAfZLaFiKb2jz9nVhzbCh7t21mxyb2mOM+GAxRaIgxodeNJoY +QA6Ezz4cbjjA72Rgi+tBxy2abXpbbJ/vX7FUhs0ICFKZJHvFoxazgtSGgHHYNxhc +/+9o6Y9jhunwGn/MaoxWJsdSjZ8VX7HY0iOSU3z4d4PWvIz05n4sGoJET6s1JuKe +dZAAeQy0V5/EzxIu4GPGrzVtk2SQhNHVJZKponZeCRruruGT5Z1T+gF5YSqVM6BA +XA0ZVXwOEbZ5XRIzBBbaiX3Eeful50ILOiP/uxLlcZtTtOyT4wNBgijfJehRHbED +ppJk42EFZKb2 +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-15-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-15-cert.pem new file mode 100644 index 0000000000..70a98fb90b --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-15-cert.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE4jCCAsqgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +MTAvMC0GA1UdEQQmMCSkIjAgMQswCQYDVQQGEwJERTERMA8GA1UEBwwISGFubm92 +ZXIwDQYJKoZIhvcNAQELBQADggIBABIv7Wlg5F1gh0+0v/+LnushmLeypcXQGqkg +E2IxXC2VnZxq8xTFCHy/m1qTBLPJK5VIg5qmtstL9zIk9rOUshQvusvNLplC0j3o +GuQdQJNKV7rrzYYpUZO1en11q27AgDsO6lwSNg4U+mqzJxxIHc8IMeJpfaGTkUz/ +ZXXNz04JJalUff+W2436vSvu8Y82fD72/qNu6EMiOl0EHJFQ/7eCAlz6hSNleLT/ +N2GztApNzujbPgH7+PHOeVpwppDuXY1rkmPJMxCqkY8yOwyM5dMov0bjIN1f+QXv +7voxVGMTefUajKADaNGMShH5rhgjIWBgujvdCyLPr6W2R4S1QPzjx4X26eTX1G8V +/eTsJ6mMc+3cd6CEmEahUnc6LdEdwm+1SMRG2nejea4o8c+crwYX5KQVrqx92FqB +SdkdCtS6qlnxJVvSz+HW6lEM0EShvjKEz/udsnttALQjhxfB7AHNWA073o/OiH25 +Y9QpUudmWJjOoqRokN0SV4rDQnfNcLKIoVFPu+rG2CpBDjUsoxG3/aC8Owcd8Ceh +w+O/DqQXudXFS3RsePbz4rPfID9YtBHrihCE10B70DUutWPsbe5lKie3wJpQbqvl +zp5kkI5RffVU7OFD6os3+wPomdIG21Cf/fru56nV3FmkINCabLQddes7OarQcZ5y +xsumEzq+ +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-16-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-16-cert.pem new file mode 100644 index 0000000000..64f852ceeb --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-16-cert.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE4jCCAsqgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +MTAvMC0GA1UdEQQmMCSkIjAgMQswCQYDVQQGEwJERTERMA8GA1UEBwwITcO8bmNo +ZW4wDQYJKoZIhvcNAQELBQADggIBAEID22h5WK1YJrKUmmO0owley+tL519YwJbs +FwbwPz7+SJKA+UQNqVXYOGLwDJ6A6OzsV1TnJuwGotTmvNwr7eOVyLf03qggIYEj +5Twgk57gJmqE+Q8UXUq2ocALUcgReZhluhNoL1XYQMbDaHYwh9HSOP7udEszVQoE +m1D74cSiW803XnqPJGj0i1s9mD6AEewPl2k0mQ0hTMM3rlE1jOCj4Jx81tWH5KNY +LXn/LhFomeo/LAU4PCFTt65tAomKTNXq0GwuunU62fy8pwh9QUpD3Vfrkm4+08uz +WXSk9PeaF8tOs5pRwVMRr0GIdnQHa9GKuBBSZEvkGTxLM+cxO7jp5qSs2IRVpI5s +ztlJQcJpeTRNCEF7gM98nMqDqve/IySGle9s1RjpnBuSD9UKzbMGeBuZK8d0JfBt +7XF3i6Tu74EbBL/mP/0xoHausW9Yo8HZhXjm5k9P7m9xxlq2JSSXeQCLbKFT/SN+ +Q3bS6rh0HaqLP8Gd3OyU+aOOy13Tr167LEFNK6DlfSadITuHwRMNvCk8UIDRDzAZ +kXVXdT5UfUe4IJU6OPVsFfntTX6G8s2/K4WropnjD5NjBJ0ppvPgCBqEA03mCGVt +IunRhQypiA0+SilM7BX6jD97IcmnbSyQ6fUkIdDBTMlX3MoYXkT00gDT3y8D/aKw +KTd5SKbD +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-17-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-17-cert.pem new file mode 100644 index 0000000000..f09f41b918 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-17-cert.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE9jCCAt6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +RTBDMEEGA1UdEQQ6MDikNjA0MQswCQYDVQQGEwJERTElMCMGA1UEBwwcQmVybGlu +LCBETlM6Z29vZC5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAgEAchR9+hds +zMK0NKgiX32XxJJ79tlo2sRMCZqij8Lqfyz7JDlTMSvIVqcrmimlAMX5u8BxKRXG +99KzXhbJb6Hnj2i6fQobxpD6nKnPSUcoiiWccmp8jmcKQW7M6TuqOfEdEnKpf0BF +vNFBjXGxs0KqOArX/1d0DqYS1LTnxaC6NimgvjAqKVRm9mqj62pc9//ixCgHkqLJ +stuoSerbo/mO0ieY1wq9r9TZT1epacVrQpJFWeJWhow94WutMNesJSWLcxX63mH4 +j0LHEEkHLa1UkMzM2RkHTVhKrthCiuyrtqrglLsdPInU7ZYVONyUrR2D1tMy52mB +b1HzzP43pomBJtp3OeEZtBDwmmGgD8RBdVK/T9hcK02cvB1w1yr4LHUeYLMqrZaP +SJHQ7kv9AV5Os64SYW9+7cqjt1q4VmaEqcuCqvB6mORHWHnsa6PQ19myA7OdqNpT +WAK3D94tpbGPTzfhUCHk0w0fPzJ4A1+S6g4eHX4iQQxxDg9sXV4ZRvAEKnJhs2S7 +OhtXdfyu/1+lfaunN13SyxMwyyxHzylEU707Sisxse2usX1Zy2zxqD+LO/9iIu1S +76/rquhiOFRWxSpjb7ewpH97OGFmtzfH70vBBukn0alT4xjkje10NlBfzcFwHWQH +59nxPd5sUEqq+DxTjoAgwO91woU7UTs98lw= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-18-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-18-cert.pem new file mode 100644 index 0000000000..341ac0b7ce --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-18-cert.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIFBzCCAu+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +VjBUMFIGA1UdEQRLMEmkRzBFMQswCQYDVQQGEwJERTE2MDQGA1UEBwwtQmVybGlu +LCBETlM6Z29vZC5leGFtcGxlLmNvbQBldmlsLmV4YW1wbGUuY29tMA0GCSqGSIb3 +DQEBCwUAA4ICAQBFUk2Z1E5Q4mW7S8dLz5h78AmfNbwx9eNtECc8iLQq2Q0MuIzQ +noURyNSHhH2hkohU4afXjolCr54DkJNYogrBwHaNDt3Y3wqGQXc+BKRnqblfr1+A +1EoIaqRFjv/Mu2gB0H4U3vBRYriZu7BhQFXiQHAr6hWLG91B1eN1i+my9zOSoSZF +7BuemB/9F4wjvwmDJieSwOgGk3FhNV64Ce9M95RwDKNSJBTBqOTLoyvOw2jgs22m +MntqW9oRywGeHdJ5EucPBrZQKDNysNFj3We8H7PedGNlnG/QknE6pzpRgqbRCAax +hcvGQIaMcUJ3oWhJuPNscjsJ/nfaitz58nH5raj4O8JhlS1h49NpbJO/pAWMHh0d +ZruXspxdEwW17aMJJ365q0XyVysRHiwQuIQYCo8L7oVUsH5FUJ9xxPH22b+PG05r +EABdID+aDV7X/MNwBxgeBOFVOgE5bfrH8NBjkx/F7ID/hjcQDLVWWoFnpIjekebC +EeqTRl5TcnoN9Dc7zkfwmuYGoaYJrGhj7WRvfFgcw1Cr1xujiJtoKbEbMoeD45+H +SQ8MwBb37Gm3aBNakpVmJlp/QZSJY403hA8QrZdjnqoS4THrC0+gN2q71aZ9ZCZY +3+OPNg659ZcYvo1onBSA0p1WGKEAWdHKqZCVRdsl5LnRg4H5gEVW4gmhjA== +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-19-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-19-cert.pem new file mode 100644 index 0000000000..f163184204 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-19-cert.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIFCDCCAvCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +VzBVMFMGA1UdEQRMMEqkSDBGMQswCQYDVQQGEwJERTE3MDUGA1UEBwwuQmVybGlu +LCBETlM6Z29vZC5leGFtcGxlLmNvbVwAZXZpbC5leGFtcGxlLmNvbTANBgkqhkiG +9w0BAQsFAAOCAgEAWtSJOhwRpYdB/aq/AixRTIpwf5VR3MWaDNh7clpnpYhYoLDY +7dJ8cv3AR5dOScFXLrCZ2UYVD+tTPyt18opnYDT4h6If/U9TTHVu5tRSX0wGIdPc +j3zVVegty/HWMA5LfwygNTvZjgXhocckNND7hC42+BuXE2bqoqnkqMRer/R+9PmU +FXpyLk0aDl2QmspDAz86FYpEuxpMfmDNmM1nWDz+n+uBbeuriTttsFqFWkfOGoNN +/3tAmUjAt5IqkL+7rnDt6Lc9inY0z3uYGJEdqa0GJJFJ7U+8wcw8rUwvKETqAtW1 +mBOswkoCImPeNDpiqiotwl4cfrsb1+j9gNpYTP2oSurh/bF0mxGLoJa1iDeibwqg ++f6oWcCdYQ94ItvS3d+lNXT0MWM6HU6sHXf3+5SqvsvsKjUBRyy1Nvnug1bha6Qv +bdeErN0ZSGy12Vc90Y5fpl8kebmYiJc79OqvuTNDeRfgBm+U4ASAj/AEhtbN+wDd +HrUHbk/9U9h0UFRZ5s7Pqoy5PEoLRoFeA/jQQa/fLC8nl7YTSwidVgj8cyAy36sV +uaBNXrcgelqlR26SBynXM3APaFlv5IdSlF199swMCusQrGbiNajl21TUm+Iv+84g +x7rnUPnQ1grkLpMOBtGaraKc93e2VfH5bAZvyaIq99qdA10ERCtE2grvjik= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-2-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-2-cert.pem new file mode 100644 index 0000000000..6ae58f5636 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-2-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE2zCCAsOgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +KjAoMCYGA1UdEQQfMB2GG2h0dHA6Ly9leGFtcGxlLmNvbS8/YT1iJmM9ZDANBgkq +hkiG9w0BAQsFAAOCAgEANTZFCjNmspLkZaVYkcAXfT2poPPWAu7wS/wG4VEmKwPV +A4dnFV2McXNW/iyABeoofeIjsjiYLpxTvz3teD2JJh+hidNED77PV7f4hj7vs4Dn +DGB3HKJvTD63AVOiPJ4bbfUyiuvLO5TwdxAGm+q9lsf/fWFraTF2qlnFwyWf6Qul ++NQo3bM8mErvntZMscq7wo0cOdAXA0bNqxKS+IDnc+HLxoEr2egbRJmEagMgV4/U ++AGVQ1sY+HrEszOPUA6NZ/OzLuXUT3swm+4rqJZEQ3AVr2BdqSzoiGHqqzmfKO33 +sODcYXuED0sUkIhRZE1vW+wXR94WQsT5C4MtHabNjpPLSH7cVjGvEfTX8DJH/F7p +OdMmXxvPey0wLGJwoZMMhG/XC8Nb1g+qCLLou9WuA7KHMibfiYdBnPcMDg3fwWwg +pYzrvK/S6f5h6TS8y9zKxCJwTdfC7f4KT6EjxQFhgHCm8oFupOLSEZKF0UmLMeOA +J504ZnGdhEG5p9AqQNBlyBsGGmSyQkSJg1BPB6U7wFBSwrXS+3b2ph4J5RivH68O +CKjR7yWl7M75LOa1dt133GmhPUUGHLsjHTnuCDVB0eHcgboonKTjCSAmckNKm/uw +tAUMkO3puty5JM38b8AwFRDXLnlWdSsNr9j243SHOfKyFWidjwglRpVGBhoECtA= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-20-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-20-cert.pem new file mode 100644 index 0000000000..eca176f2df --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-20-cert.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE4jCCAsqgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +MTAvMC0GA1UdEQQmMCSkIjAgMQswCQYDVQQGEwJERTERMA8GA1UEBwwIQmVybGlu +DQowDQYJKoZIhvcNAQELBQADggIBAKvkEHjR6lk0AlKiC7oltE+gp7SpVHdKs7I4 +zswnbZ1EcddA9D6hjemU+nIUriLkt8BxY+KxNtkwDm5mvXZn5E4XDXzRDsCdNZXE +qx9og9LhkhfGbPJ1LPutQ0VmqPwY17mRUeaLhNIwOmD7g++oVHYmZWqA8tHVB9f+ +gP5Ni2x/PX772Vt/hIpI14VoYIsMFs4Ewjc0Gc02DvOdsDT9eUmAo6GNOAbxeRS/ +D2D0w6CQhwJ+cemcAo0lGw8KemCYfqzL+MQd8wUGPsiZgm5wQACOp+ImL4guy2gX +h60W9Gtxu77jsjF7n0n4LlInylrZAgw09CkehUfF4+cP2kZDTcsuqOoCVYATAGxa +49ZvuRHoo5Ine5PcfuARS09LmxgI0fdsjaRvRELYIRWHTvE+zCLlNkxkpwXULgZZ +bpJ08L52P+jz+HJPeiHZnYKXgtXyGLpwG1danS600tqiMmDh0G9Ss+UzwhS+jhN5 +viIvpmns0zvI1Z1IWPw3y27pw7rmLVcFMbEZFK5mwHiT10iRrT4sxihWIT+sn6n5 +5baup/od4kSJABQy9LAuhhuZHyCfxC2yPYz70sP8qGVtY+rA3LNe0ns6pY1L77DR +QIRD/Mm2hql91+U222mxikdT4WQEheh2cLwdg/T1uo/SQDruliNZncdNbTGDmnhc +cg1mw5tk +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-21-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-21-cert.pem new file mode 100644 index 0000000000..16d5e7265b --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-21-cert.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE9DCCAtygAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +QzBBMD8GA1UdEQQ4MDakNDAyMQswCQYDVQQGEwJERTEjMCEGA1UEBwwaQmVybGlu +L0NOPWdvb2QuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggIBAHdccJEkqezS +GSNNVIWv9XffNTrZnejms90h66UDC4O9shHMy0aNWgmGuu7uFi1BK4sTciXT+ZR5 +3+1ni3WKMhJ5Iu1aNlNeXULOlmuHKVJKrAj8BR7lflSFqj/MHnw22HU+BTmddZPj +F/OCl2W+O+eUNBTTmYI2+pZgmyyU9v8qEwLZn57qlpAJa4gpnSRYQS1xfSaUgAcM +xtZM/AE4F9mDFOdO86/RxXsYRyT0+sOGmaoJrlTWoKduoI7fhzQAIGHnhn9yBT60 +0K6LmCR2dXRyLxxVTy0Laiz487IXpQTJ8jo6c0wT6SeiQBlE0W3FTH3IM8Shzd7b +5tbix0bCR1pUT2Q46oaB4xkEweKNGKS46kIps6mpTav3TMhNDVyalUfF4fOu4FQu +RLB6B/I1TI1KHiTeD9xfNInBAdO9ewjWQ9spFei3EExZmvnnWKZIA82mjG/9Wcdh +HFK/uEylzo1Nsxujv2V6ueMYc0pF4XH2U1Azjxb0+pWUZhoy537Nlf8b+PO/GSG8 +del0yPwf6JP5AZdXfiV8vNqwEGCC/BEIPrbZ6Zz1q6lT+7GZAGkzbMYlfkzA1lXh +JteRIracA38WfQOHf3FOPYvTBOPlVHWB+tJbwlalYQqCPupMaaxxizCLPIsNvqdy +TAtC5Jbx6N1DdeyHpRuKRUe1M926oKTp +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-22-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-22-cert.pem new file mode 100644 index 0000000000..5f89b00dfd --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-22-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEyTCCArGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +GDAWMBQGA1UdEQQNMAuICSqGSIb3DQEBCzANBgkqhkiG9w0BAQsFAAOCAgEAE8vG +nLYo/G+3Cuzir4toX726vLOkCEqZrkRE18dc3px/CgmEI/6+4lWjp3u/9MxER+kT +t5o5Xin+vmg5F+hocR16mMeX6pjD6tXJ+uzDacTxDgRBFdbqX4x8Fjiig0FXsr3H +jFBY2c4UcKszFlCTqjH1/RfwLYJPU6Q1WZM+1iJotSKnhK7y4A/3jho7sL0PPuMG +WEoxbTBmpAf+jPT+LRe2MY++VnVJHjlPba+S4Y9PHOzizQuIJs7YnhNIqA9So7Iv +eA7Lp8GID+w/eY4DEq4z6CIuCplKZTrrWH0kQbG1sV4J5+W+JL0DOXDk91JwkOPH +rWf6aOb3akFRk5Z/PrrcTAlqtApPQF4uGycQBo8KgcatZyP/3HZZHyyxhEjF9sw/ +STHm93GlCIwocJ+SkwjBmdupv6Yk8fRmA7LinjVvi7EnQQ7qcRE3oUCPPReDD96G +TuDsGkQbv5WQSh+0mBAiTFze3C6FSNcldQBrlWReqOj6pVWtUN49lpYOJ2XfLCQe +RjS7IUYNn7Ku3xXi2etgNzmJXcSnNXZkh+3henpFqkwEFJ5b5RgOHXULTwoqo9KS +YMs3eKHp62J6l0pQD+wTGUyVU8cJghJ0hR1WnNR7o32Bos2dfBmIQgET4ZH/P2+H +A2gtbJO5mRsTvuD+kZut1jxJvUzuO0yZoNpuUVQ= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-23-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-23-cert.pem new file mode 100644 index 0000000000..5cd6795cde --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-23-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIExTCCAq2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +FDASMBAGA1UdEQQJMAeIBSvODwwiMA0GCSqGSIb3DQEBCwUAA4ICAQBps3VQshvW +9HDR2oDXSldWNW2SWksa+9npI4IEMDusiDbLdR0VBphw2R3iUuJ4IAPDc1s/SMi0 +1t1o92lC5zVeTq9LvOOC1KxwbZXDubFDmdsuJ/DYPDkaRoDqoH7eFsJuIyD/TKqm +HXPYmWmjUNv51SSLTTqPRz2TmLQVA1Iw7J7H3fz2LExsAtczx6gRZJPIZGdMx6do +E67SUp/2RPYtkEmmCELOxCAh/Pzm6pBPncI86AMTNwppl+FpqaH0LPrqMre40tTt +cQq/0XrMWRoWsS3VU8uor+aGTnNp5VT3ZLVmXZNyG7nISW7ERaGCeTZJRcqwjeH/ +yPxhQc7IpYCm5x+HN2sDuvVC7l/q1A7+CbO3jNR5Gb7aEEyGiKb5ZkElbsulfwom +JOg1K8+SBDGrErEf0MDCenKY2g0lhpKGBwu6O+RVmKbhlHEjt2/31/NCSBMLopdU +AmCNoBo3+KaRljo1lVf7tWbffNRCqsbPZPHtq9uXs0DliJTUroaJ584h92VrSLJB +SdAUVLAwzmwu2Pa4bp0STv5tJy1hFNJdVFQ4rgAfaFudXy41K9zqrDCB7RbzX7Yi +97TCDu/phzkoFpOZabqTrvcP13N0wfDeOx4Y9nx77aeqTAaQ0ooTG9IWrHmjuUKF +wpEXQBfkuXug5+xq/hlCllkPj67cIaldDQ== +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-24-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-24-cert.pem new file mode 100644 index 0000000000..2a858dd39a --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-24-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE1DCCArygAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +IzAhMB8GA1UdEQQYMBagFAYIKwYBBQUHCAWgCAwGYWJjMTIzMA0GCSqGSIb3DQEB +CwUAA4ICAQCKRaPaQO4+oztra70h3g1qwmJurQ1vGBdcXh27nf9epFAwhU1zL5v7 +7wN7iclY15BX3w3WrZ+ag74AvQLG6WQkDY1JCmidEjjt2bmVTxIus0H9Bb2AlUEw +BtVYMJrr+fiWbfSwRxhMQa9BQ6ZcUA7EluYQFApo2m7GIcMc4x51L/bwzmsXYj4t +2tjnkU7clL+7GR/w/+ZB7nIe80j7wYvIbOfMS3Yxh+uu0aQCNdoh9Tsdtu1jtmJv +4lJ5aZIDABE/XIFVkWRyHv2ou14J/LXUKE3HPEhSKWu7GShrdTeS+gZpOixM+uPG +ieHah1GfJMS69P82Z72Cr7XWpQY0NKwMB+ePhTzz1LMBHQ5ySXQCViQRClRMc5K+ +cXZm8cs6oe4IEhMcf3kc/9xblgRWqxX7vsb6Gcrn1eXsfxco17S1yNBzTt75ybt9 +kvPmrWqpg+sQ0r4473DjEASoSCPwlzCpd7AHOw+XxSwsOUNXkEnXMa2v2VHBjx06 +QnrLenB/n7EQ5Vo9JLDMLM6ie4gfehHxfdyoBg21jN9eUPpKGnjARVvyfDWV+7rI +ZHU7wc2iMnqroAqm9FZ0YBqZ/eI8M4ZAYSvDKnGZQlUWfhdNDhI4FsHBPymMFtjW +ln5eFUNLMoitMGs12Ib+omr9WSTxRj97GvRkRTNK5Gxmo9Mi/Pkxng== +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-25-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-25-cert.pem new file mode 100644 index 0000000000..695b8ebba8 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-25-cert.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE6jCCAtKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +OTA3MDUGA1UdEQQuMCygKgYIKwYBBQUHCAWgHgwcYWJjMTIzLCBETlM6Z29vZC5l +eGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAgEAIgp7IrYYdLCoUqg7E4igLD3u +C68B896uoeenMmTKDfCzvB5svYKZlfIi3njJUZ2G6kgBNcSd/mwQ2ggex9AEUiGp +uaT7Dpev3RpwtCz5zpOZxN+B0LJk4hPzzE4sjJFrmHRgJVzADL5RdcEF7+GV81nP +X/cXviffkxSihAFALArAaOA6/hBoT6unvlDsY3cxgZWFl3ao76vTQFLs7ZNHYbHe +WDkkNpheWmNlOrVTEz0vjNCQz5wYOM6HJ0O3cxzR/6+OnhPQagZRCWApPopYGuxc +kXHAPbEkXpVzJTrNgHIvZ3l3JdJSHsh+DdGVz1NY4bogQNKCVa3xt+zLpUrr34XM +61Z91MekMijfjOsy7LGLSBdCPCZ00enXPkflDEhv1kRlbo/ZdYGHynzl6Xzu1A5B +nuwDbpsCzR6ij8fZDXGUS7F8Iemdfag4XTtrXnVXLgPpD/FMzJUx4kCIAjgh2MaP +0nUvZDVYt+GKGohCNDrSt2ByFtbYGaX5GeMIp8zW+GT8KUW/K7pp9PjsmzG6vvQd +kqxB45ddf87E8NoDWh/ptdj3pjfbDc5A1SeXKGXrt1TwgWHtUNW0zF8qOuG+PZ1P +u10lUx4gayyF3unaSLZwYu8nYq5C7mC9DjjnbjLhsh0VOIEEh+Q8vJH8OvZFkyti +l2ADXC+6evQTvqLwXi8= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-26-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-26-cert.pem new file mode 100644 index 0000000000..1204d95a8a --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-26-cert.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE5TCCAs2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +NDAyMDAGA1UdEQQpMCegJQYIKwYBBQUHCAWgGQwXZ29vZC5leGFtcGxlLmNvbQBh +YmMxMjMwDQYJKoZIhvcNAQELBQADggIBAKmgEHc9b/bscpyO5mTKrITyoYtbhz/P +0Uz2Uc4tKokUI9EBuuD/XX4EjtVzne9mssAAs9EhBSFmNhDjpAUYh9n2cFvAJQit +4d9EbaNbB3SuzG5onu8ZBtfLsABr5L5tQspO3tinamSM2ZuRo4dvcQ2a38C38LAQ +HBnvZ744Th3LckPMLTWNChe3E2jAt8Av0XA2yVJ/B+EeEaqSYDALKhI49CLeq96L +m/Vq/mqADborW51pMNFn7CAF1jxizQNHy6K0E95ziq8q/OL7j4+j8Erh4x7bcjrQ +X04Z+hrA9q5AjG++ieztKqGuGxHeSclqBhOdnU0UI528Vn0OXRxeMmbqMF+qhx17 +nHuxxs4z5CIdTwHA6LgMUpDxcOhdUctIj32gwZM3UHI8lmdRTWn13y/Ht6CpIXCL +1ohSXne5y34z4AKeJQpdUfwQD552Ui8B+bhH1JBm5phjLn1fboXCYiCgnPQ+SJzx +3hsIv7Fji7lfk1UPkr0s7Ze8b/seYS8nVB5rg4qXEwFDMo9zsjCEIyg0tKwj5Ani +HlYzqjjsIK50TPjXYOA9J+NHcBDCDa3r8TBtRGtQqOXQGzvWTqAyT8Uwn7jimmh+ +EGDr4PJSTJxv43EYL+of0sRHkOhnfFfJYF9vQLT+wD6l+6T1xNPE/gjX8DyQS9a3 +zOgdOiTp0AKH +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-27-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-27-cert.pem new file mode 100644 index 0000000000..268abdd300 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-27-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE0TCCArmgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +IDAeMBwGA1UdEQQVMBOgEQYFK84PDCKgCAwGYWJjMTIzMA0GCSqGSIb3DQEBCwUA +A4ICAQBtXT+t0fuBRClJdY6y01k1jqcsXEkmKOr4czznuiloGVEjpbjmxzxsgvzw +nz3od6Sx56SHG1xYbKDCapX9Ld2IDsPvpF2wdH2wpIS5DI7tQdBpLm7vr3vTYKwm +Wns+WKO5VBHDLCyuYvHNo37MJCAfBlr1ni7BCLOg3eycPiANJHPD2T9BnXlJm49K +166VMviuiLBEyO9tadhvQHGqCX3D4pW31zwsKHvS4wau15N4yt053Iac6eaysdTp +mspw5jX85tlQ9XxKNTftUVJU9Uzk2ll4A0Gvnq2FEjiqf6m3tye2nsqDI3C81Dwb +Y/+AeO7ZsVyLpIstfUBFmpLGPUoZ5MNmgrboGf8K8dPPgVbmbS0msrsI4LWSQb8P +R2hzj0F7bFvgbZad7rFXJW9FQOqTwvJrZBkkDpZpeNbhah14avV2Ftrc5+PtVfP0 +jB1L3nhc5KGpGL4xqE19K+GVR/KBREgiFD7B7NYUOPt9NjFTrbbC3XA8L0MC7PNh +ySDN/NCiIF9K9MtpC8BYuNBlRt5C82L37qPY4Tw3z9sCyXK5oOQ4xdbdDEWdwzc5 +F2S4zfQiB7y+C9RigOyGPChxBqDK/bCExrG1S2b95oP4QMuaL55iXnaG9ME8sCoa +cUd62cMPk7piQW29oFiQPYsStfo09u9JXbalKhol9oPrDtQfrQ== +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-28-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-28-cert.pem new file mode 100644 index 0000000000..147fba3aff --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-28-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE1DCCArygAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +IzAhMB8GA1UdEQQYMBagFAYIKwYBBQUHCAegCBYGYWJjMTIzMA0GCSqGSIb3DQEB +CwUAA4ICAQA2KjgKCSLg/rDajrBTtVIu14rAP1pMwFZWrxcpTbN+fOs2dYQXZf7d +/GaozSMSchjPAJ8lTFfEB20Mur/E284LlQPuQKqHHn3gIh92VkHHBHjj0ohnfigg +eBHNMUisuGyNzKV7VI1+iwCoPBZC7ptbE4X08osVxxRESj+IT0TwtKDONTIIeogW +6VhsKTQ1HM6AMbhVe0Led/ENxFFMquB25GG/hVB4ZzPmsJZzNdZYNNMa34kNcMN3 +5OFcxWV/4Hc77JYsqM9fE9gBaKC9pQE0XwIrOMQSaGYx+GO8Ty33YlM+oYBt6TMH +/9oU8HVvEYW9GAyptNbXPOwyv/wikNBsJyDGfvuDoiTZ9iMFb/bEoWHSK/rYmAgk +D272zxiPS3YgaZkvhlYZ+60w5CCgXoN5L0Zq9yAOTv92/VHFnMPrTP7zfD+4eUHY +lg+A7pOCIUK4cIDUXQefn1dU5/8DHJ8aM+KQDBfkKOH3me3GzIKjtKQjhwYFiJ8L +vD4V6+nq90GasShQDKUbMVbCxfyqlvrXOP0an+FxdknadnD5hRT3UsU9SRxAdkXi +3er2sXpuULYqOst55Ahnj7D5uDN4KBoatZwFd1iw0CVPoox7ixZ2zOAkwVqzaEAq +0yWyIlELm9/FdF78fu6LPrFKI1H4MH+0TQrF4MiyJWPvET7t8WKJsA== +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-29-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-29-cert.pem new file mode 100644 index 0000000000..434bda3e8e --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-29-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE1DCCArygAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +IzAhMB8GA1UdEQQYMBagFAYIKwYBBQUHCAegCAwGYWJjMTIzMA0GCSqGSIb3DQEB +CwUAA4ICAQCIFfHE09aftJrS629ZBBRKjRiVcxN0/FjeEHWbnb+3Re/LoU/Y64BT +LmjMBB6wik3JxxUtLs2UYExQKfz3zmB+O99lR94of3V3RXPCe9Dz8C12iohYBvVO +q+WzXyg8g4zoIndn9+ByR+JJsuk+WVTZd50wRaRvssUB5yhpLaFdZpnLUBdV5J2d +shmefZxr0NgMb9p75wvWgZ2BiZQDeTR93+PWaZTMdSxZh6ynfG//5sxxw5fLm3pv +eVo3oQQ8px9j8G83ouiDZJn7XZgNfXYNq7wo3yaqXX0zlCE00K6tXGI6FkKJnVdQ +si+JYfGjzTM39JqFU9YYOOc3Gfw20iKIEQ0jnE0Z+z9Pv2GAel0UNdovluttxu9R +CJcPJOLS+TMd/sAwCAELvhPpeWsDLhfd+lG7ofE/nM6hzec6apWYyCqqlYIdE8WK +rtHXBIMGk/5Eo+2KDGQHgpMs/P8fNUL6FBx/i1pjm5nSHveDQryepEmOJq9NJCBW +1AJhE4jCXMv+43Fnr1OSATNiOd+1KfQ7KC5PFkpZLY4GDFZcbLBKYj1TWx4WzRnm +EW7cC/00Z3Cd76L5i+y1Xr44nbQcAMw6TlT6vvZjFCbCO+ZDUJSZBZMpWwBI/gAf +MNzYPltOGm+GZUuxib2MSF9Qy8c9NegENmsK+zyPT3N9mUHCl9nknA== +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-3-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-3-cert.pem new file mode 100644 index 0000000000..59185b64a4 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-3-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE1jCCAr6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +JTAjMCEGA1UdEQQaMBiGFmh0dHA6Ly9leGFtcGxlLmNvbS9hLGIwDQYJKoZIhvcN +AQELBQADggIBAEKwv45Zp5xJEGENPrOIwrGmuBDMtBPmXtSKydKSNUgrv08u4dHL +n295L7jIwQ3SnRjS8PrZWD8RQ46hgFRY9pqk1uTys4jB7lki0eAUBC7oPn7q0GUv +ojdSwOEjp5bfXyuRv7Z+3y2gD8pcCZsqcCjF5Svim6Q3pXMLRKQFhzhzL9k/gsNF +lJ8KcLBECJSm5nUrZIRHPdIGYmWJG+t8CfS3E6OIyHILK1xCc1MasEpmYVoY9uzT +2W2z+3pvwQqfdXO+lEOsT9dnjM/WbnkQMTWAn+++YFtkvA4kON4b/cp9imnXok02 +vq7MCbN+b5CJXIhKMC5eNA36ez5hou0MUmnsNo9ai1gVJXRoL67YgUh1yMfcAaSM +Sfy3UBF++Az/yQo4AWtqWk4KPePdcsrYo9Fke1inUl+M12gkdIz+efbElHMqehbt +lunbyFI/7CY6/Tno+T1cDkQlTouHK8Ddb1cPhkJbE4euRuLGdtn2AcFSemYGtib0 +ffuhnEBF8M8enPVyLjYA/3sELkmmaHMtgDTm0+XYQJtjIbvGcY7+bftPZgbXPVGv +7+tiYjwarIexXN5yzMasgFI5+7qLSQJHcmwrzOm8K+Bzx34f20vwR4M2FJ6cqUeN +qzdN1HSNp8aYNilaFa3+hfGRG9CZnVP8up8BwYx736EMu0G3yAp6UqqJ +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-30-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-30-cert.pem new file mode 100644 index 0000000000..1b67d1f782 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-30-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE1TCCAr2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +JDAiMCAGA1UdEQQZMBegFQYIKwYBBQUHCAegCRYHYWJjAGRlZjANBgkqhkiG9w0B +AQsFAAOCAgEAgG06c7GRpPohHa1X/YQVQGWa/J/f3qok3cu1nrD2H5Dkw1eAVPcQ +lsng08lOxwSI0OgqJw0jl+ljLKuhHI3U68KbFmUO3Jw7uLDk1+UniRSNkfxVOrlc +7YTlmsxiDgQdX6/TAHu6bERx147NqVzB4/I6qpX7ouLv4E7xdQgjKuvhWlJ+Fg/0 +pQ7EleQymRN6Y8qO6RwEWYao5pypg8/22cE3jgXleLM+5qWHqJs2ZewPQf7uo4Bf +IwSUV5H0weftiSN+kOLYiNfUago108VHuk5sCIKr92q4WAJgA5C6ylcUWaJCKbCv +HQYR/QG10Mrn4JCzzni90aBHrQoYQ8msEDH1QKyMJiNz6XXzwBP6bvgPlB2f7nPW +ERpH45M2I4Z3dZYFw8bF7CcOIUuR0/Zu2WN22IhqhjVQSZPzdRWJt5Rr1mFUz+Nv +Ymdi0w68KyRUiuOpKNLczDDnYpc9EqGBprnMOxALS4mQn1ySBXbZAXnTTdEzN5fM +L4CXWUzIBVKv56Mn5YskhbCd+N8GV9Nj/A6dBwa004CQxbgAj+ndNWc7+h4iSNlz +9VPHK2Kju6j4fVpe10jzSoEs0nnrsPy5Lxa6C4KhXBBJ3cPl6wWNe2mgbEqG9Pq2 +KrCizuFkIfZTAeSrR+prZXLw6cjmKPPEtNbK2JbteL2SEDT/3AjmmZE= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-4-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-4-cert.pem new file mode 100644 index 0000000000..086af8e02e --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-4-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE2DCCAsCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +JzAlMCMGA1UdEQQcMBqGGGh0dHA6Ly9leGFtcGxlLmNvbS9hJTJDYjANBgkqhkiG +9w0BAQsFAAOCAgEAPu7ubyZw1rOQJhFX6nBHyCYaBzaKxRZOHOFCjMrD/YQXPUNM +Hs+8ChOeQ4M82jTyiP7XgF8EumDcckDIlIYvGXGrCB/6VcCVL1vPPtzjSaiF3PlG +/dh0OlPvevr5Ajz7ZtFFwxeQ2EfsHiry8qnlDJSEjrh4Trcx9YzdkSZz8DaoODXz +ctR/p1JEnQ6h/Axa6hdqTzbzTsINN7gD5Wi3ObfQbK6Ug/CuH6Zr8bdTsmeGcnD0 +fqHptuLVNcROykneYziXDzcqGwrZnYaOF54a4ibV/OfrBcgEKeDwsCrLs3nztSC4 +whV7DXZwaLl2KWl4/suBNI1cIKbxII1xTFLTog+UYz0zSZGPrtbt7zrlM4yG033t +h9xIGUKebaNpQYkoxOc/+kKhbKCeL3klfxJoX+6Gf8DkTP7byX2HovfWV1rJbh57 +YZ04Bh69VmyxE4iyb1tAh5xh1bArCR9m96eXS/0KIZbykxltQGyHf1jpWw/4Wi3n +oadkpMcyNX76M1xBJ5u03JL8+LWrXuzf/ScWdmPUWulAEhbo4fn4oRwP2C3l0vVQ +iL482cIq1zF91lssRwQ17k38phulRdm+7W65/VI7hLoG6lXiSiHLH8e39hHO8Jey +Z+BBvn8x+aFgIvpBK/MX35s0gSrl/UiIZPU9glnktSsX5D+aaQynbuvbOW8= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-5-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-5-cert.pem new file mode 100644 index 0000000000..04a918008c --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-5-cert.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE6jCCAtKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +OTA3MDUGA1UdEQQuMCyGKmh0dHA6Ly9leGFtcGxlLmNvbS9hLCBETlM6Z29vZC5l +eGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAgEANAyZnL8f81Aax/0Rhw3CCdcQ +SXF3dpAolObQB8rlirRZ7yOY1v3Poj411aV0x9zM6mjOJZwarUTL7kbO7odQxGhB +x7O0DvUoG15VTvs0XLNHTPgnXtNjKOZ7XXVMzb46APfYSqdzMqhRWfy+Iaikp494 +urtqkVt05q2amzq7EXbXI8JQWhkJkhjBTowfZnpZUw4JeeqMNRZT9Ldv2XDZjaYS +lkHOLzTmSmm2mf1oxhKGcRCgUCr/pzVUfDA3RBz25a6PWAQt4b2r8k5jydWyOeCZ ++sjacoK5/E1PcdaOFJAjuAfbRMeK/gz2+yJwaB39Yh77t/9vQC0G6aiAmO0HxjJE +L6Lb8BG/QNYBS7gGhzKFVXVVv5yXRioO9vMv0i8uxShqD2Lo/MbrNtRgi3eMFESd +3NxUPXS1jMq2/SaXrENdKqNNi06LbnLaYpI3BLZ/Katq0V9ESlhcC2nT5uNBPiLr +DNSekaIGobbTDkuV896L7jqsQpU+sgs4XqaISGgk2wAfnwbfpeiBCL8oH9yCYAO0 +1YlevrMGjBNvhysoABv7qaorqeL97ffRhjOZ72/fm2axD5l9MvWEFIf7L5uOah0f +hF5vScQYgyWNuK8wjzT2tl0CuxvEyI7N4fkUEk+ZMkyI1Obx17p+d4SFyuq7wTXR +05oWMsCMDyzxvFDv92w= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-6-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-6-cert.pem new file mode 100644 index 0000000000..6643519957 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-6-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEyzCCArOgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +GjAYMBYGA1UdEQQPMA2CC2V45G1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4ICAQBB +lBfIjUH7/PbpC00TWTOSR6sAzyBr681lSxYAgFLduDdfR/bTkI1p7txIAgennoUq ++9slIIMaR799BUtQDfAQRYdbsWiG/+5Lj3JXs33LPPTdW1C97LOPlnnbRJh1sjbi +UfGdxvdPA6iuyWhfwPZd+4IrcN+kefkvEnRkvDMGwmfmKQDjbu2mSIAIe+ECyLLu +wdSI2sPBSUKQEKk+dABYq9TcdxlA+OSPjgs5ZF3NK3s/or7ay2r/i8be5TswY4Up +IwByEk+7AST6ijwi3P8EN0HAyyuOfpBelWZCQgdEGt40Mpa58AwBGqdrCZ5wDAz5 +nBx6GscZUsqG9sVM71Tgq7Bc1b69FXUYAhmFucnXizHv1Ys0oGQVza1tkKbaLEFQ +WvXWc7zW/0hTzvmtogKn/oM6GoNcQiW8KCwaCJq1TTv7Tip9znfB496tDruOr+2w +HoqZTJ7ERklz0mlZ38ISTuaz+Qkn1KjBYh4tgP/wZIjIyppAaAr+JdqXzBejfb4M +6x0S1AG9QgvyR1xDv3Vljjkh3m55kktTWSOfjS6aSzomaAyVAgi/vhHkxhsoBhgQ +41+ffkhM9ps9wkmguwqOXsByQAZUQEJQigO39qYuGuJEDV8Bu8i/T5BuuJWP4BRF +X+now5ObP73ufyFwYGsSgblivHUX4z/zAt4kp4AMXw== +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-7-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-7-cert.pem new file mode 100644 index 0000000000..6c0f287a1b --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-7-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE0jCCArqgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +ITAfMB0GA1UdEQQWMBSCEiJldmlsLmV4YW1wbGUuY29tIjANBgkqhkiG9w0BAQsF +AAOCAgEAKmYr4QEnNq1Sy9lYePNRR60jufFXk44bczNT/wA6kvXKgv472V9wltVb +yJVvYUWkTO8ahlELNLfqRcuih6myV64WJoewog8mwby0lBYr6bAz86DdeN/B9rFD +OYnev1Ux4um45l42XP8acgJCoqn8+EE+H4AeMrz2xxHt+IDy4vUOowZna82f1Pcp +O+vhod2uXlukfnhofVK4lMHl4++4kECkmUYl8U+L/zXwzOb4S3Yksffmadgo7ERk +rJYLMLztvCk6TtP+p4NcvrE90dmss7R8hfw3asfjXsRbAMigdfSMKzGB2IHoHeV6 +fpmJy6kotfwulDrbr2QtrWOYdMrm1wT6ohT355KZQxcZr3VcK9gqEjcYafqIsXtA +wYAaorKXaz7UkmFCDbk/24UuHgNgCl4KkGsFNwW6whTMpb9WnvPR7F798tiIbOL+ +FK6yA1q3Z2500lmloQWcUFBX48DViG3bsTJ9wmQ28aPqHVd5gTmTm/7W2iRGx36N +PmbAk17J/bUzUSORgrPi2FLNNFg64x40pfdAyrF9ZBNcsVCFCUgOQHgMh4OjX/n7 +khmNbMYiOvJEoUbZ9flNr4AYY3ucpxQ2peTl4DNsVZZ8Xyh96h3URu63Ji9+xLrQ +jSUtNHUCJaC3E9yTaIDc8jMli9s5/ElDZRkPxRP8o4VOt9KcLvU= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-8-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-8-cert.pem new file mode 100644 index 0000000000..201b520f8b --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-8-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIExDCCAqygAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +EzARMA8GA1UdEQQIMAaHBAgICAgwDQYJKoZIhvcNAQELBQADggIBAHfvavrzBLuS +MMJwNkJGVt1W856zeZ6NZJ5vx2ZXziYxAkzw9N0pLHwgfzS8pXEPSZ6vMoeYMaH0 +zr/S5tHSMGEwOp/dIoxE4Hm1uMzugHFxNp34hvqsaDbwKMpQQzEPhN1QvAkD9IXL +H2wOLqm+ZaTkT3OvOyJoml56wyUJ0nU746RuXgJHTFiWsUTPqT9bvofedC80MUyH +MX2lA1oy8nzJa9h7JqsxOE4uccRhpCRf+PxeYvOdsUxyDWw8+rjwe4Ulr0yVjwnD +x9ha/fTl96mYXyJGLtQvZmkllrctxcs0o82+wMZWBw4iPH/VnI7dj36b2uIHdrrf +cVurEPcVE03zLwukjQPZh9otleTwmQI1wqg/Gm2OahXy/0f0fpBDQnPycczn8nFw +nj6avmHubWVvzmEoKmOtavGEAbUn7ntQfsvM5JpiM+ck3MDMP9i9cMZvWKH8Eial +ZnYcXkgAatWwp4Cbsv4H7LMNisKjrcY+r+MpaYYIpTRNp/s/P5bMCIVt07yosePg +m9VWy03+hQJmD4/THeJsjuczPSBtsoJiKoTJ5TndmpFaG6J6lBVvpXJhoiW/QIgX +u2QIb8Z6bRK/eQ8UVYm0/ZQLN+OOzYiQfm0AFbFpYhl46o6QNZ03P6GRLshv+N3E +CX66ucPLd4QJitUy39LZjMlC0YxTZUry +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/alt-9-cert.pem b/test/js/node/test/fixtures/x509-escaping/alt-9-cert.pem new file mode 100644 index 0000000000..660e65b8ed --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/alt-9-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIExDCCAqygAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +EzARMA8GA1UdEQQIMAaHBAgIBAQwDQYJKoZIhvcNAQELBQADggIBAIefUJjnOtt8 +viFkr3lupabUMwSgtBXVCp+M9xhKqcSnYReSgg/LcqVDaXmU4s23n0Bc0M51HQMG +puTpfr34ZUSQiLup9huELm5L+lcpYANJsKrBo+vz1w+fkPlcxXvXHpLzgb393XSJ +/Prn7lNBrrh9b74azUEhz1KPmFbbMs7IwlhE1+stQ107VeSGvKlAOmaYdnVG1PXl +AG7KJynpE5Ex8XF1ONQLneTdvo8gXZueb07SY+my5wrCQhSlh4/6Y2MnE9h+9ugx +BfdU72okDaYRH1MAfFeAsUE7Y52cQqm26b7nBz0+IeP+uk7oqDLF+PGHfjeUGXGW +aGFfaLk8Dl2gMg1DsRE8zcT215Dl4rqOtwbhW8kX7XzYE0sA7cnyZ0daLrrtxwe6 +MhrAOjYklRZpwUvy6E2IyipKwWSuKHLUk3mVxPrxVqvye2enZWW1PJeHNdL//Ogx +5Mm++BOTNR+61pg/UrATlO3GMK6ggAfkP8H1r3jp24hc/TkXRkoUuWZqtjC5+qwB +KVIPlr+/0zIhzDjNbN0TMgqv/Yz4/wCUjsmCPJu21C3+BP2O5ZD2e4hYe/X9kuhC +YGWTf8dpq0LgYgVHqwXo0gCU/Ich9KtaJmCgZRUrzMl1aIYhqpuR2EW8H1bs3a0P +/7wXhGudHCwm6j2H5/tbsREeYInl3mv4 +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/create-certs.js b/test/js/node/test/fixtures/x509-escaping/create-certs.js new file mode 100644 index 0000000000..abb01756be --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/create-certs.js @@ -0,0 +1,643 @@ +'use strict'; + +const asn1 = require('asn1.js'); +const crypto = require('crypto'); +const { writeFileSync } = require('fs'); +const rfc5280 = require('asn1.js-rfc5280'); +const BN = asn1.bignum; + +const oid = { + commonName: [2, 5, 4, 3], + countryName: [2, 5, 4, 6], + localityName: [2, 5, 4, 7], + rsaEncryption: [1, 2, 840, 113549, 1, 1, 1], + sha256WithRSAEncryption: [1, 2, 840, 113549, 1, 1, 11], + xmppAddr: [1, 3, 6, 1, 5, 5, 7, 8, 5], + srvName: [1, 3, 6, 1, 5, 5, 7, 8, 7], + ocsp: [1, 3, 6, 1, 5, 5, 7, 48, 1], + caIssuers: [1, 3, 6, 1, 5, 5, 7, 48, 2], + privateUnrecognized: [1, 3, 9999, 12, 34] +}; + +const digest = 'SHA256'; + +const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', { + modulusLength: 4096, + publicKeyEncoding: { + type: 'pkcs1', + format: 'der' + } +}); + +writeFileSync('server-key.pem', privateKey.export({ + type: 'pkcs8', + format: 'pem' +})); + +const now = Date.now(); +const days = 3650; + +function utilType(name, fn) { + return asn1.define(name, function() { + this[fn](); + }); +} + +const Null_ = utilType('Null_', 'null_'); +const null_ = Null_.encode('der'); + +const IA5String = utilType('IA5String', 'ia5str'); +const PrintableString = utilType('PrintableString', 'printstr'); +const UTF8String = utilType('UTF8String', 'utf8str'); + +const subjectCommonName = PrintableString.encode('evil.example.com', 'der'); + +const sans = [ + { type: 'dNSName', value: 'good.example.com, DNS:evil.example.com' }, + { type: 'uniformResourceIdentifier', value: 'http://example.com/' }, + { type: 'uniformResourceIdentifier', value: 'http://example.com/?a=b&c=d' }, + { type: 'uniformResourceIdentifier', value: 'http://example.com/a,b' }, + { type: 'uniformResourceIdentifier', value: 'http://example.com/a%2Cb' }, + { + type: 'uniformResourceIdentifier', + value: 'http://example.com/a, DNS:good.example.com' + }, + { type: 'dNSName', value: Buffer.from('exämple.com', 'latin1') }, + { type: 'dNSName', value: '"evil.example.com"' }, + { type: 'iPAddress', value: Buffer.from('08080808', 'hex') }, + { type: 'iPAddress', value: Buffer.from('08080404', 'hex') }, + { type: 'iPAddress', value: Buffer.from('0008080404', 'hex') }, + { type: 'iPAddress', value: Buffer.from('000102030405', 'hex') }, + { + type: 'iPAddress', + value: Buffer.from('0a0b0c0d0e0f0000000000007a7b7c7d', 'hex') + }, + { type: 'rfc822Name', value: 'foo@example.com' }, + { type: 'rfc822Name', value: 'foo@example.com, DNS:good.example.com' }, + { + type: 'directoryName', + value: { + type: 'rdnSequence', + value: [ + [ + { + type: oid.countryName, + value: PrintableString.encode('DE', 'der') + } + ], + [ + { + type: oid.localityName, + value: UTF8String.encode('Hannover', 'der') + } + ] + ] + } + }, + { + type: 'directoryName', + value: { + type: 'rdnSequence', + value: [ + [ + { + type: oid.countryName, + value: PrintableString.encode('DE', 'der') + } + ], + [ + { + type: oid.localityName, + value: UTF8String.encode('München', 'der') + } + ] + ] + } + }, + { + type: 'directoryName', + value: { + type: 'rdnSequence', + value: [ + [ + { + type: oid.countryName, + value: PrintableString.encode('DE', 'der') + } + ], + [ + { + type: oid.localityName, + value: UTF8String.encode('Berlin, DNS:good.example.com', 'der') + } + ] + ] + } + }, + { + type: 'directoryName', + value: { + type: 'rdnSequence', + value: [ + [ + { + type: oid.countryName, + value: PrintableString.encode('DE', 'der') + } + ], + [ + { + type: oid.localityName, + value: UTF8String.encode('Berlin, DNS:good.example.com\0evil.example.com', 'der') + } + ] + ] + } + }, + { + type: 'directoryName', + value: { + type: 'rdnSequence', + value: [ + [ + { + type: oid.countryName, + value: PrintableString.encode('DE', 'der') + } + ], + [ + { + type: oid.localityName, + value: UTF8String.encode( + 'Berlin, DNS:good.example.com\\\0evil.example.com', 'der') + } + ] + ] + } + }, + { + type: 'directoryName', + value: { + type: 'rdnSequence', + value: [ + [ + { + type: oid.countryName, + value: PrintableString.encode('DE', 'der') + } + ], + [ + { + type: oid.localityName, + value: UTF8String.encode('Berlin\r\n', 'der') + } + ] + ] + } + }, + { + type: 'directoryName', + value: { + type: 'rdnSequence', + value: [ + [ + { + type: oid.countryName, + value: PrintableString.encode('DE', 'der') + } + ], + [ + { + type: oid.localityName, + value: UTF8String.encode('Berlin/CN=good.example.com', 'der') + } + ] + ] + } + }, + { + type: 'registeredID', + value: oid.sha256WithRSAEncryption + }, + { + type: 'registeredID', + value: oid.privateUnrecognized + }, + { + type: 'otherName', + value: { + 'type-id': oid.xmppAddr, + value: UTF8String.encode('abc123', 'der') + } + }, + { + type: 'otherName', + value: { + 'type-id': oid.xmppAddr, + value: UTF8String.encode('abc123, DNS:good.example.com', 'der') + } + }, + { + type: 'otherName', + value: { + 'type-id': oid.xmppAddr, + value: UTF8String.encode('good.example.com\0abc123', 'der') + } + }, + { + type: 'otherName', + value: { + 'type-id': oid.privateUnrecognized, + value: UTF8String.encode('abc123', 'der') + } + }, + { + type: 'otherName', + value: { + 'type-id': oid.srvName, + value: IA5String.encode('abc123', 'der') + } + }, + { + type: 'otherName', + value: { + 'type-id': oid.srvName, + value: UTF8String.encode('abc123', 'der') + } + }, + { + type: 'otherName', + value: { + 'type-id': oid.srvName, + value: IA5String.encode('abc\0def', 'der') + } + } +]; + +for (let i = 0; i < sans.length; i++) { + const san = sans[i]; + + const tbs = { + version: 'v3', + serialNumber: new BN('01', 16), + signature: { + algorithm: oid.sha256WithRSAEncryption, + parameters: null_ + }, + issuer: { + type: 'rdnSequence', + value: [ + [ + { type: oid.commonName, value: subjectCommonName } + ] + ] + }, + validity: { + notBefore: { type: 'utcTime', value: now }, + notAfter: { type: 'utcTime', value: now + days * 86400000 } + }, + subject: { + type: 'rdnSequence', + value: [ + [ + { type: oid.commonName, value: subjectCommonName } + ] + ] + }, + subjectPublicKeyInfo: { + algorithm: { + algorithm: oid.rsaEncryption, + parameters: null_ + }, + subjectPublicKey: { + unused: 0, + data: publicKey + } + }, + extensions: [ + { + extnID: 'subjectAlternativeName', + critical: false, + extnValue: [san] + } + ] + }; + + // Self-sign the certificate. + const tbsDer = rfc5280.TBSCertificate.encode(tbs, 'der'); + const signature = crypto.createSign(digest).update(tbsDer).sign(privateKey); + + // Construct the signed certificate. + const cert = { + tbsCertificate: tbs, + signatureAlgorithm: { + algorithm: oid.sha256WithRSAEncryption, + parameters: null_ + }, + signature: { + unused: 0, + data: signature + } + }; + + // Store the signed certificate. + const pem = rfc5280.Certificate.encode(cert, 'pem', { + label: 'CERTIFICATE' + }); + writeFileSync(`./alt-${i}-cert.pem`, `${pem}\n`); +} + +const infoAccessExtensions = [ + [ + { + accessMethod: oid.ocsp, + accessLocation: { + type: 'uniformResourceIdentifier', + value: 'http://good.example.com/\nOCSP - URI:http://evil.example.com/', + }, + }, + ], + [ + { + accessMethod: oid.caIssuers, + accessLocation: { + type: 'uniformResourceIdentifier', + value: 'http://ca.example.com/\nOCSP - URI:http://evil.example.com', + }, + }, + { + accessMethod: oid.ocsp, + accessLocation: { + type: 'dNSName', + value: 'good.example.com\nOCSP - URI:http://ca.nodejs.org/ca.cert', + }, + }, + ], + [ + { + accessMethod: oid.privateUnrecognized, + accessLocation: { + type: 'uniformResourceIdentifier', + value: 'http://ca.example.com/', + }, + }, + ], + [ + { + accessMethod: oid.ocsp, + accessLocation: { + type: 'otherName', + value: { + 'type-id': oid.xmppAddr, + value: UTF8String.encode('good.example.com', 'der'), + }, + }, + }, + { + accessMethod: oid.ocsp, + accessLocation: { + type: 'otherName', + value: { + 'type-id': oid.privateUnrecognized, + value: UTF8String.encode('abc123', 'der') + }, + }, + }, + { + accessMethod: oid.ocsp, + accessLocation: { + type: 'otherName', + value: { + 'type-id': oid.srvName, + value: IA5String.encode('abc123', 'der') + } + } + }, + ], + [ + { + accessMethod: oid.ocsp, + accessLocation: { + type: 'otherName', + value: { + 'type-id': oid.xmppAddr, + value: UTF8String.encode('good.example.com\0abc123', 'der'), + }, + }, + }, + ], +]; + +for (let i = 0; i < infoAccessExtensions.length; i++) { + const infoAccess = infoAccessExtensions[i]; + + const tbs = { + version: 'v3', + serialNumber: new BN('01', 16), + signature: { + algorithm: oid.sha256WithRSAEncryption, + parameters: null_ + }, + issuer: { + type: 'rdnSequence', + value: [ + [ + { type: oid.commonName, value: subjectCommonName } + ] + ] + }, + validity: { + notBefore: { type: 'utcTime', value: now }, + notAfter: { type: 'utcTime', value: now + days * 86400000 } + }, + subject: { + type: 'rdnSequence', + value: [ + [ + { type: oid.commonName, value: subjectCommonName } + ] + ] + }, + subjectPublicKeyInfo: { + algorithm: { + algorithm: oid.rsaEncryption, + parameters: null_ + }, + subjectPublicKey: { + unused: 0, + data: publicKey + } + }, + extensions: [ + { + extnID: 'authorityInformationAccess', + critical: false, + extnValue: infoAccess + } + ] + }; + + // Self-sign the certificate. + const tbsDer = rfc5280.TBSCertificate.encode(tbs, 'der'); + const signature = crypto.createSign(digest).update(tbsDer).sign(privateKey); + + // Construct the signed certificate. + const cert = { + tbsCertificate: tbs, + signatureAlgorithm: { + algorithm: oid.sha256WithRSAEncryption, + parameters: null_ + }, + signature: { + unused: 0, + data: signature + } + }; + + // Store the signed certificate. + const pem = rfc5280.Certificate.encode(cert, 'pem', { + label: 'CERTIFICATE' + }); + writeFileSync(`./info-${i}-cert.pem`, `${pem}\n`); +} + +const subjects = [ + [ + [ + { type: oid.localityName, value: UTF8String.encode('Somewhere') } + ], + [ + { type: oid.commonName, value: UTF8String.encode('evil.example.com') } + ] + ], + [ + [ + { + type: oid.localityName, + value: UTF8String.encode('Somewhere\0evil.example.com'), + } + ] + ], + [ + [ + { + type: oid.localityName, + value: UTF8String.encode('Somewhere\nCN=evil.example.com') + } + ] + ], + [ + [ + { + type: oid.localityName, + value: UTF8String.encode('Somewhere, CN = evil.example.com') + } + ] + ], + [ + [ + { + type: oid.localityName, + value: UTF8String.encode('Somewhere/CN=evil.example.com') + } + ] + ], + [ + [ + { + type: oid.localityName, + value: UTF8String.encode('M\u00fcnchen\\\nCN=evil.example.com') + } + ] + ], + [ + [ + { type: oid.localityName, value: UTF8String.encode('Somewhere') }, + { type: oid.commonName, value: UTF8String.encode('evil.example.com') }, + ] + ], + [ + [ + { + type: oid.localityName, + value: UTF8String.encode('Somewhere + CN=evil.example.com'), + } + ] + ], + [ + [ + { type: oid.localityName, value: UTF8String.encode('L1') }, + { type: oid.localityName, value: UTF8String.encode('L2') }, + ], + [ + { type: oid.localityName, value: UTF8String.encode('L3') }, + ] + ], + [ + [ + { type: oid.localityName, value: UTF8String.encode('L1') }, + ], + [ + { type: oid.localityName, value: UTF8String.encode('L2') }, + ], + [ + { type: oid.localityName, value: UTF8String.encode('L3') }, + ], + ], +]; + +for (let i = 0; i < subjects.length; i++) { + const tbs = { + version: 'v3', + serialNumber: new BN('01', 16), + signature: { + algorithm: oid.sha256WithRSAEncryption, + parameters: null_ + }, + issuer: { + type: 'rdnSequence', + value: subjects[i] + }, + validity: { + notBefore: { type: 'utcTime', value: now }, + notAfter: { type: 'utcTime', value: now + days * 86400000 } + }, + subject: { + type: 'rdnSequence', + value: subjects[i] + }, + subjectPublicKeyInfo: { + algorithm: { + algorithm: oid.rsaEncryption, + parameters: null_ + }, + subjectPublicKey: { + unused: 0, + data: publicKey + } + } + }; + + // Self-sign the certificate. + const tbsDer = rfc5280.TBSCertificate.encode(tbs, 'der'); + const signature = crypto.createSign(digest).update(tbsDer).sign(privateKey); + + // Construct the signed certificate. + const cert = { + tbsCertificate: tbs, + signatureAlgorithm: { + algorithm: oid.sha256WithRSAEncryption, + parameters: null_ + }, + signature: { + unused: 0, + data: signature + } + }; + + // Store the signed certificate. + const pem = rfc5280.Certificate.encode(cert, 'pem', { + label: 'CERTIFICATE' + }); + writeFileSync(`./subj-${i}-cert.pem`, `${pem}\n`); +} diff --git a/test/js/node/test/fixtures/x509-escaping/google/intermediate.pem b/test/js/node/test/fixtures/x509-escaping/google/intermediate.pem new file mode 100644 index 0000000000..9d2aeb32c4 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/google/intermediate.pem @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBjjCCATSgAwIBAgIBAjAKBggqhkjOPQQDAjAPMQ0wCwYDVQQDEwRSb290MCAX +DTAwMDEwMTAwMDAwMFoYDzIwOTkwMTAxMDAwMDAwWjAXMRUwEwYDVQQDEwxJbnRl +cm1lZGlhdGUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR7DaOQvpvA47q2XxjM +qxJVf/FvZm2ftiFRXNJMe/fhSlDh2CybdkFIw2mE5g4ShW5UBJe+sohqy5V9WRkY +tM/Bo3cwdTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQlGcYbYohaK3S+XGeq +CTi4LLHeLTAfBgNVHSMEGDAWgBQlGcYbYohaK3S+XGeqCTi4LLHeLTAiBgNVHR4B +Af8EGDAWoBQwEoIQYXR0YWNrZXIuZXhhbXBsZTAKBggqhkjOPQQDAgNIADBFAiEA +uZhmF3buUdhzHjXLZQSOyT41DqUUX/VKBEraDu+gj+wCIG/R1arbHFRFnEuoVgZI +bihwUpUZjIZ5YwJcBu6yuXlZ +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/google/key.pem b/test/js/node/test/fixtures/x509-escaping/google/key.pem new file mode 100644 index 0000000000..102a9d8816 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/google/key.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgaNbpDxJET5xVHxd/ +ig5x2u2KUIe0jaCVWqarpIN/582hRANCAAR7DaOQvpvA47q2XxjMqxJVf/FvZm2f +tiFRXNJMe/fhSlDh2CybdkFIw2mE5g4ShW5UBJe+sohqy5V9WRkYtM/B +-----END PRIVATE KEY----- diff --git a/test/js/node/test/fixtures/x509-escaping/google/leaf0.pem b/test/js/node/test/fixtures/x509-escaping/google/leaf0.pem new file mode 100644 index 0000000000..ce19dc9699 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/google/leaf0.pem @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE----- +MIIBajCCARCgAwIBAgIBAzAKBggqhkjOPQQDAjAXMRUwEwYDVQQDEwxJbnRlcm1l +ZGlhdGUwIBcNMDAwMTAxMDAwMDAwWhgPMjA5OTAxMDEwMDAwMDBaMA8xDTALBgNV +BAMTBExlYWYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR7DaOQvpvA47q2XxjM +qxJVf/FvZm2ftiFRXNJMe/fhSlDh2CybdkFIw2mE5g4ShW5UBJe+sohqy5V9WRkY +tM/Bo1MwUTAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFCUZxhtiiFordL5cZ6oJ +OLgssd4tMCAGA1UdEQQZMBeCFWJsYWguYXR0YWNrZXIuZXhhbXBsZTAKBggqhkjO +PQQDAgNIADBFAiEA4NgHDxVrBjNW+So4MrRZMwDknvjRaBsB4j2IwVRKl4sCIDpg +Bhm4ZdHwlUYrALkXa3dFBy8kXBkVumY7UJpbB2mO +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/google/leaf1.pem b/test/js/node/test/fixtures/x509-escaping/google/leaf1.pem new file mode 100644 index 0000000000..0b45056656 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/google/leaf1.pem @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE----- +MIIBdTCCARygAwIBAgIBBDAKBggqhkjOPQQDAjAXMRUwEwYDVQQDEwxJbnRlcm1l +ZGlhdGUwIBcNMDAwMTAxMDAwMDAwWhgPMjA5OTAxMDEwMDAwMDBaMA8xDTALBgNV +BAMTBExlYWYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR7DaOQvpvA47q2XxjM +qxJVf/FvZm2ftiFRXNJMe/fhSlDh2CybdkFIw2mE5g4ShW5UBJe+sohqy5V9WRkY +tM/Bo18wXTAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFCUZxhtiiFordL5cZ6oJ +OLgssd4tMCwGA1UdEQQlMCOCCm5vZGVqcy5vcmeCFWJsYWguYXR0YWNrZXIuZXhh +bXBsZTAKBggqhkjOPQQDAgNHADBEAiAOFFOCfA6c/iZWxbDn5QMjNdtZbtJPBcRv +uEgSqWrGTAIgK5RK0xGK8UZb2aM2VjGNTYozlcwKaLgQukA+UnKrrJg= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/google/leaf2.pem b/test/js/node/test/fixtures/x509-escaping/google/leaf2.pem new file mode 100644 index 0000000000..9cf03fae7d --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/google/leaf2.pem @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE----- +MIIBejCCASCgAwIBAgIBBTAKBggqhkjOPQQDAjAXMRUwEwYDVQQDEwxJbnRlcm1l +ZGlhdGUwIBcNMDAwMTAxMDAwMDAwWhgPMjA5OTAxMDEwMDAwMDBaMA8xDTALBgNV +BAMTBExlYWYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR7DaOQvpvA47q2XxjM +qxJVf/FvZm2ftiFRXNJMe/fhSlDh2CybdkFIw2mE5g4ShW5UBJe+sohqy5V9WRkY +tM/Bo2MwYTAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFCUZxhtiiFordL5cZ6oJ +OLgssd4tMDAGA1UdEQQpMCeCJW5vZGVqcy5vcmcsIEROUzpibGFoLmF0dGFja2Vy +LmV4YW1wbGUwCgYIKoZIzj0EAwIDSAAwRQIgWfT1VXQA79PxgM0DsfeoiwZCc2Be +v3/RCRYoRky9DgICIQDUTjndnBQ0KeIWhuMjtSz1C5uPUYofKe7pV2qb/57kvA== +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/google/leaf3.pem b/test/js/node/test/fixtures/x509-escaping/google/leaf3.pem new file mode 100644 index 0000000000..55a64fdc89 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/google/leaf3.pem @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE----- +MIIBZzCCAQ2gAwIBAgIBBjAKBggqhkjOPQQDAjAXMRUwEwYDVQQDEwxJbnRlcm1l +ZGlhdGUwIBcNMDAwMTAxMDAwMDAwWhgPMjA5OTAxMDEwMDAwMDBaMA8xDTALBgNV +BAMTBExlYWYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR7DaOQvpvA47q2XxjM +qxJVf/FvZm2ftiFRXNJMe/fhSlDh2CybdkFIw2mE5g4ShW5UBJe+sohqy5V9WRkY +tM/Bo1AwTjAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFCUZxhtiiFordL5cZ6oJ +OLgssd4tMB0GA1UdEQQWMBSGEmh0dHBzOi8vbm9kZWpzLm9yZzAKBggqhkjOPQQD +AgNIADBFAiEArZgaxFBuPYFWCXeFTkXhV57MKxG/tIJ2Z3Wzts2Im7QCICoukuRf +EsQN7g6h30fRuLOIdbfCCduc7YVpkkSlwe99 +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/google/leaf4.pem b/test/js/node/test/fixtures/x509-escaping/google/leaf4.pem new file mode 100644 index 0000000000..668a659f45 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/google/leaf4.pem @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE----- +MIIBdTCCARugAwIBAgIBBzAKBggqhkjOPQQDAjAXMRUwEwYDVQQDEwxJbnRlcm1l +ZGlhdGUwIBcNMDAwMTAxMDAwMDAwWhgPMjA5OTAxMDEwMDAwMDBaMDwxHzAdBgNV +BAsMFm9yZyB1bml0CkNOPW5vZGVqcy5vcmcxGTAXBgNVBAMTEGF0dGFja2VyLmV4 +YW1wbGUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR7DaOQvpvA47q2XxjMqxJV +f/FvZm2ftiFRXNJMe/fhSlDh2CybdkFIw2mE5g4ShW5UBJe+sohqy5V9WRkYtM/B +ozEwLzAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFCUZxhtiiFordL5cZ6oJOLgs +sd4tMAoGCCqGSM49BAMCA0gAMEUCIQCpchwik2NT0v8ifDT8aMqOLv5YwqB7oeOu +LincYQYMagIgZc2U7DBrdEAWNfuAJx4I+ZkluIcswcdnOhbriOrTSHg= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/google/root.pem b/test/js/node/test/fixtures/x509-escaping/google/root.pem new file mode 100644 index 0000000000..68eb00ae86 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/google/root.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBQTCB56ADAgECAgEBMAoGCCqGSM49BAMCMA8xDTALBgNVBAMTBFJvb3QwIBcN +MDAwMTAxMDAwMDAwWhgPMjA5OTAxMDEwMDAwMDBaMA8xDTALBgNVBAMTBFJvb3Qw +WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR7DaOQvpvA47q2XxjMqxJVf/FvZm2f +tiFRXNJMe/fhSlDh2CybdkFIw2mE5g4ShW5UBJe+sohqy5V9WRkYtM/BozIwMDAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQlGcYbYohaK3S+XGeqCTi4LLHeLTAK +BggqhkjOPQQDAgNJADBGAiEA+Y5oEpcG6aRK5qQFLYRi2FrOSSLF1/dI4HtBh0mk +GFoCIQD1DpNg6m5ZaogRW1mY1wmR5HFIr3gG8PYDRimQogXUxg== +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/info-0-cert.pem b/test/js/node/test/fixtures/x509-escaping/info-0-cert.pem new file mode 100644 index 0000000000..6872b9870a --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/info-0-cert.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFDTCCAvWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +XDBaMFgGCCsGAQUFBwEBBEwwSjBIBggrBgEFBQcwAYY8aHR0cDovL2dvb2QuZXhh +bXBsZS5jb20vCk9DU1AgLSBVUkk6aHR0cDovL2V2aWwuZXhhbXBsZS5jb20vMA0G +CSqGSIb3DQEBCwUAA4ICAQAAd/bIBmSIOJg+Rp96/BDpsZQYgYTyBNWrnBkuHQ0M +bovgqEEI/5xiYGEzXhrzmWrUoG40PDeVrpCSsW5m+bsO4zDQeWW5mXejbr0Iwflf +TYDxwGUUakAcZ1c5yJ/ABjKy0Tocb9bSzln+tc+HNStp86bbgrhb/wjddn6ca21V +cuNFZbN+0SM0LxcWO8oGKXF0HFo0durGhamcH5B/D38FYkaVR5QXoOsWVqtPFjW2 +t67rmKS6XKaz2JhZDpWDZmDofCoFu/zlkPHXkq7yyrkJ/8qpJCznkZmLn+B1WA+y +SrSOYMpQ6RnzMx7wK5UafX5J+lMv16+LTb/n1KAd4zElcqt5eRPLcEuknIEgC2X/ +AY1ooyN/Xb4QnqvtTmhzIDb7lzzMowi5QrG3rRYMldxG2Rdqwjc8qa5Tgh7EsiU8 +A/n5X/6cxA1zoyakSHFXzGtazIkPc+zFfOaV1+gpJtd2vD2T+FrmkL1fgazuHXNZ +hAQq0RGZWPsCdxm7dG4w5bd3YgRKfD2ck+b9Imu0ta4pqMDHZYgncaeOuuHzHgXA +MIvxIG5JfwYUJLUqBUz8hwDVcNMpnscyn2msdpiwXK0AahucBQjbyZ6sovoxmgk5 +xLdnq2GTtdghwdkF9DYK0ZekDlk1XWbP0tR5Cevo6WlMx+cbEBG+OSfNd8/dFrkd +aw== +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/info-1-cert.pem b/test/js/node/test/fixtures/x509-escaping/info-1-cert.pem new file mode 100644 index 0000000000..05247873d8 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/info-1-cert.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFVTCCAz2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +gaMwgaAwgZ0GCCsGAQUFBwEBBIGQMIGNMEUGCCsGAQUFBzAChjlodHRwOi8vY2Eu +ZXhhbXBsZS5jb20vCk9DU1AgLSBVUkk6aHR0cDovL2V2aWwuZXhhbXBsZS5jb20w +RAYIKwYBBQUHMAGCOGdvb2QuZXhhbXBsZS5jb20KT0NTUCAtIFVSSTpodHRwOi8v +Y2Eubm9kZWpzLm9yZy9jYS5jZXJ0MA0GCSqGSIb3DQEBCwUAA4ICAQCbwqw8YKIt +Ht9qegR076xpnxuiH0THPGsgazvhCmEr5YHJ68sR1LexjneQDhpNXcnpYpfk6J4d +Tu0ApMSbVypFyHcd88g0qVYI9JF+CTNnzut/Zn6xgnUjVjrSz6SZPhkMcBX9ahtY +tzswzcyTzso5Do5pxvCWDI+bshgIhC3CYNyAjyOyyhnQrwcOcoatlhDmX1fCk+dC +fhmzurBFNIz2gwDC7aRjcaUdTIlYnd6qHk5xLs3neBm44gNk17GazPIPo04LTKXs +ZYzvDEUAdJ2FJMiYqSvvEv4k9ozx5HtwtncZpu46El2PQRANgj1UhemYVmHfbdU+ +7Q+rCv+Loq2v76fddhc1cM3gCQ+6SW2QmRo2rShRGxpuSuZiTngwgdQEGrkQq7Sv +r695V7NlHWJgvv1r49wGmqWkviH5l6A0QdzL6TNYhwqCRsjxgsvCZUpOlZPASiME +jhwBIOMy1YUSdEMnBrbuemawvbfocSuUlHaodwLZvwMgqHvNz/8ebMyRyyZrnmCx +TYh8d0JIcA57VvfaZvvsPPV7TO7WLoJgbmuqM02JzzkJMh0fbt2oi1cqJL65V5Sn +z0sXh/A/BzB4QawI93f9m0hX7RtuT1SolTNVyhg7dm1MwfO8khpfz5LLgflVwgN8 +6egKc6L755SlqZRMT03txH2UCBizLz1gjA== +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/info-2-cert.pem b/test/js/node/test/fixtures/x509-escaping/info-2-cert.pem new file mode 100644 index 0000000000..06212d4e12 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/info-2-cert.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE5DCCAsygAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +MzAxMC8GCCsGAQUFBwEBBCMwITAfBgUrzg8MIoYWaHR0cDovL2NhLmV4YW1wbGUu +Y29tLzANBgkqhkiG9w0BAQsFAAOCAgEABR5VyTZEQ0AQvdqlk+IDQT85qyf891eN +BREiSg5KCei9Kmubv3ZJGoNVwZgybr5sCi5GqWOtG7S0GXvzS6c2Qy+cW0R4DDYs +s6IIUn+ex1XygGrRHTDHu6tEUwSJMmOMKBh+iLjhtamD+YHjgOLG3MfadO5/9mvp +r412MPhU1VvQ3FC3dZmBUW2gIKNEU4mzwISgPkLJXmBsnxu8F9YqHPgppqsfJ9AF +KIc2nX7N3s8w9fCc03FrihdkE2C802jy71px5aPqa1xrIT/YBq/1fKTcYRAWF/pd +iy2G1v0pz0kYu2/yPIC/xlFcUgeFqR/biwxAD9T9rp7rq+dpIJA5BUCpXVULqhY1 +SVZ22WKS0NR5rbu4BPDMShTOiwaDSwFQtI0OxM0g5zVFVjFOc6YbFu7ZyfLQ582S +vgVU5/vaHANnEsCSUegXyLofqxTMPbM1rqibFmv2A4pm1Mp18ZFmqwh8cm6C0f7F +qjdzBuSkcktTCq/dLX5yTm9aocyzye9cfNBjiGUregJEF7sD3nzsokEGj+S320w2 +5yUl95xgrHr+5bdDUEox+trTeBnddC4VxrieeH+Wv45try0Go48yK7b1Aqfu9G4B +B/as+upQ+YjMG8mAe6JJ9JibpTvTmatYAsssEKT1vDZ5trqo4C5/utfbuyaf7qtx +O+jFfYToPtE= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/info-3-cert.pem b/test/js/node/test/fixtures/x509-escaping/info-3-cert.pem new file mode 100644 index 0000000000..1825949bd3 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/info-3-cert.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFMDCCAxigAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +fzB9MHsGCCsGAQUFBwEBBG8wbTAqBggrBgEFBQcwAaAeBggrBgEFBQcIBaASDBBn +b29kLmV4YW1wbGUuY29tMB0GCCsGAQUFBzABoBEGBSvODwwioAgMBmFiYzEyMzAg +BggrBgEFBQcwAaAUBggrBgEFBQcIB6AIFgZhYmMxMjMwDQYJKoZIhvcNAQELBQAD +ggIBACR9nH4pRlcSIIF9DEExlJvLtkeFWHGIAYLBuauHmdzPdbq9Py9M5DOcc7yd +OQYVYwW26hASb+3CYzhRQaWKOR+T/OwP+QMUl5Y6nc3HzLdYTSen2LLAYHySXK3G +gTdOhmVQwdh+IzhpjLXC67/9gn/F1p73Ixv/0PBZzmC64DOp1ogso9RICu0xTAbo +h8mdN4/Tbh9Ikd89lb91x1Xf86NyC7ZvSA9dUO07/3B6B0kkqCdP9Ytlsrt2wbt3 +2TVPp+ghjbPjdLrJUi3fbdC2CgjV2oLiYr1h7qn7SmYPNgOpDPKBI4Cei7UO+Wow +yLCxBO0HgLZKcZorJFofekPjqtQYYj1sw3OEIcifMAmoHT7H57onfoQbRDpt57k2 +rHJKgzrRuT8Qbl3OHSkiWRE3u0S9kAg7QEq27e2fuvh23p+YHEiYIjAR9XLVh7/Q +EG5QDfDq3MvtgD/khAd36il61T5h8F4u3MhONFMuwJ/TYtGR6QINrv4DqLBM1pRr +LMApQYi0w/MCRj2wLeAro9NflE+PFDk+l44ojvnEUYAGUyIzWp80bjQrV7Up6sgQ +HehcmxxTrOmiqrfw08c1aHhmGeplmPpQEET1wIjnyj49sfdSPYxg5Lh+f/l79fLb +jFemE8otKfog84vNGbPFl/AHwxjKCeCA/MaNJz3y3RYVsZn6 +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/info-4-cert.pem b/test/js/node/test/fixtures/x509-escaping/info-4-cert.pem new file mode 100644 index 0000000000..8f1e69afec --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/info-4-cert.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE9jCCAt6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExBldmls +LmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIxODE0NTczNVowGzEZ +MBcGA1UEAxMQZXZpbC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALERZ3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4Bv +WiayictqCJWtmsbsSli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGt +qJe4EOpret1jgkFqQJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1 +aRjqayh3TDU8NwuFlLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMN +DnVXZ3paRJTcps6d/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaY +BRPx6WFdepWr410GpzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3 +icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4Z +UoyzTvwN2i/uPqJxi/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tc +nedukufld8QEW7iMn7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61M +iLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUm +R7J4QEuQSEN2cZMOpn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAGj +RTBDMEEGCCsGAQUFBwEBBDUwMzAxBggrBgEFBQcwAaAlBggrBgEFBQcIBaAZDBdn +b29kLmV4YW1wbGUuY29tAGFiYzEyMzANBgkqhkiG9w0BAQsFAAOCAgEAQERLvjQB +E2fmTVgHbr4MVXPfse9Xxk9TK8/IhxDNnql4bor3xat5oP+tDHVRi2StajfIcJlX +C9blYOWg4w6QH3pmD6M7eQGOw7ntOUid4R2vhX3XiK3QB1h8lWSPFmSwBHA47mMJ +IkrKNIo9+M9b7M05YwbAENi3TPgT8h2Ej9V4DUjLIEhDcu8fSh3FkNpZ2HohZ2I3 +QPe23FB052jX7uPfeZ9gcjL/iGxuTuPbKWxzZ/Gy2RmS8xfLkJESvvQ8a0H4f7Ij +yjn7qYUkY6FoHxyg5BU34YNaJCmfgzRIE53Kv2FMPwj2JaXmIguR+mSDAbc0xjw3 +G3dRoCqhZugn8C6I5FhuXHdu6zSuuHtwOGEf07y5Im2sBsPVoq+Txh/mv3Zy9Ydy +0yCDuq87jKSZd7FKorHOEoQY94UMs33PYjS4h/hYWiysYUeR0mlbjr4gyv1KH6K8 +JERGpI/OE+vzfOtgj/Z46/+wn7jF0LBCin7Jn5Zw1a1TNsiHKAjqW/P4vJxxUW++ +FtYwJhI7XJehwNNFra9rSC5M4TkpaqAZnbPvWZWxWVJIEYFgNjnt+b/VOpRpv5bJ +7BOlVvP+56KF+vlmCnzVBmlHcr45sZUZ3mw3Sb6dcF0V0VaNQKw/F5EteQyafIIl +dvCwwV4OwLwPliPAvwYfVEI41Dv3mF4fN7k= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/package.json b/test/js/node/test/fixtures/x509-escaping/package.json new file mode 100644 index 0000000000..37d9f2a938 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/package.json @@ -0,0 +1,12 @@ +{ + "name": "x509-escaping", + "version": "1.0.0", + "description": "create certificates for x509-escaping test", + "main": "createCert.js", + "license": "SEE LICENSE IN ../../../LICENSE", + "private": true, + "dependencies": { + "asn1.js": "^5.4.1", + "asn1.js-rfc5280": "^3.0.0" + } +} diff --git a/test/js/node/test/fixtures/x509-escaping/server-key.pem b/test/js/node/test/fixtures/x509-escaping/server-key.pem new file mode 100644 index 0000000000..db1d2652d0 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/server-key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCxEWd00u9E9T/k +o6WcCKjhZ7tjnfVylnA7M0EHOwvdivgD46eAb1omsonLagiVrZrG7EpYuMhtz+g3 +Yv1d0nvFvv8ge9UIdnN8EDTDzLpJ3KbNqHURraiXuBDqa3rdY4JBakCcuYHl1bj1 +OTew7xl1FWc1je04rBTQGTFIRdmJZYyc9bIw9WkY6msod0w1PDcLhZS3emh/eYaL +4zAQWrVhQfWzf4rZzFaI/a5n0o75aUkTuvxDDQ51V2d6WkSU3KbOnf2JW+QJXfzs +NOeiYA9AnfY59evr4GEeG8VZdGuUG39uDCIWmAUT8elhXXqVq+NdBqc6VUNLDJbq +CmMx/Ecp48EHO6X5uXm0xViZIVPNIzqiiRhVt4nFfwPQZrTgaq2+tD7/zD1yED4O +1FhlDl5twH2N7+oG06HsEluQdLPrj7IedpneGVKMs078Ddov7j6icYv/RZHVetDl +rzDDHjLJWwxyAWzdGdkhtMGPd6B9i4TtF/PU3J3nbpLn5XfEBFu4jJ+w+5Wvk5a6 +0gF1ERy/OLBM/e8sro2sEBIpp1tN1wJVBZOtTIi4VVDhwDRQUiwb2d1Re7GQ7+mc +z5D/01qxW6S+w0IKrpwJUjR3mpa0OU98KfKVJkeyeEBLkEhDdnGTDqZ9E/ickGos +rW2gAAYKgzXk725dpxTdpLEosfDbpwIDAQABAoICAAwUElkTPHQZQKsBiL38jzyU +/WDduQ0AexZmuCRcoEIUBTgKsvXdYqpqGmEwUfaX2YuBOc8Uh8OJ357Ll1nrjjre +fPvDxrPllJodZuQGVpzMOuqjd5zlmi8DRNAg1cg9TfjVXSPzuYsqiYvcw9JDdRqa +A6jRDiIEBwVs+oIiFaU8MpvQXL/fNbSX5QhlHuMwwNZ93beoV3F+ojFvpWswLNg+ +DhsY86lIuYxttZRqdgtIZc49PpD6VoalmC7t8mivJofImi9g/8ytxx97umNGpzOy +ssWgY1/7NdS+czdXbDE1sPsaQ8cDxrDmGxPjswV7rK4/Um/1ufnoGXFMlRinS1lQ +nns4VAFefVUCk81LRyFb+X97NXPGC1p4zNlC1ZoihMgWKJBzH0uk5K/hURS/wDNZ +epm9ssnEQrFGJhEI+635srfn9SVRZ8xNh+oCguo5NaZm/BezC6iBQeoaBmVL2lY8 +KLztN/JQd6MMZi3CWhTn0ZAtVNMxGjU9/yrdWIkX9EV8Sw68fqLGoKQXI67AOynQ +5AnUyEjhVu7M39gYL71l7BVpuG7qaX8l4brzBcgzFldvuhuNCx0SW4gU2/Nx4OwY +BLOX1LOrpD+5M9YwcbtSxcxz97nP8efb3hUK3QD2iuZ9Fa6zKWsoreMb7Jku38i7 +e41lupAIkxxuxGBe1YrZAoIBAQDVF7Kru6tsaWtvJw5cbZpKxcuUHHQ0X3XRgA+H +uWfT8EbxmDpgcG8polqiYuXPFWcrElmtWeBCYXazGZocHRV8y+ri/9c2rMTH6Bni +TcYfsc4E8WY6adxfUqajgQ2zShdZbxZtBvSP50HheZ0a+L2qn2MWDUN/mbwYEmom +SonVx3MSJWm/Vrh5i4b/L/+9u7uumIjWYFK6pKdLerTfbXO7ZsNR9KDIOBLDnUcf ++6K2vcclZN7aga1S7wTsrX+k9C/OQuj8ONMWQHCxryp5RAmgtArTBrJZq8el1lcG +518Vo4QuOqsqTdAhqiImoPKe4NNCs1iTS9BdCqNYiF8sbmeJAoIBAQDUuL5ebQ68 +6vqTKYD47ZtCzeqziN3Y/0a1BsyZh0/snNmK5WIr4T0vX0Y/XG0EpkZdpW3odMBv +CemKs6Zm+pfOUGu20PTJcdSOXRbFiVYSeQnfa0l3iXZvY9Ottz/IU/mWPuU3hc18 +hOZD9tKiwYDzZREg6L4XRizfT70UkD2eTz4lGBjR092TTj8WqSaI9GF6d9B6Aw9Y +OCZdTqV7hPe0Rnvd1XiGsk68HN2Np47HHwwPsKMCYj8YNKmsUF8QSXmCkijlDeJW +bC6TjAHlvnN6n1LjaLwULUs9Rb2fkNUOqsgR+T8YlqbclJbzC7gW53M/68c9eOQ1 +Y01JnzsB3S2vAoIBAQDT8DP2djtzIg6GiNPRvfj9cWifMQWqqV8nNTU9Cnxn4MzO +sVcuX+VQBXgblj13D5SC1Ed5ELDplMJYM5iBabPbYX2GtGq6qG83XHOSD0SEdXWw +mN/SLUPPUwcGC+8yaPh8LO6jFY3cKmft9+T31Hnf35LPdfWyTZc0YexNlUkt5Kdg +XvGkKn5j9RAZcwXrEXMDnhZLEZZ2qBj0C2El71hyBS0ysBnRyWNwR1dcSgx1sJ8H +ZCH6NYvLtoqxU4Zm6684eHf9lA7uTL1JHC0kWzUwLqGtbTWp1h5FpL790NVTUkS/ +Lf7bnnTpZqt8vAtTVc0IxBPOvFLKlzALd+cg69XxAoIBAQCv6Sbkh2NMrzUQRZ42 +PKfMkuSoG2L6dABQ65J+0/swPHVZ+1830kf6yNsawqAU3DwMbSV6ujH4oUXUQcQ2 +HL01DCRHRn1nqQ6RvEF8kZnwJNAZRmu2wqKCcxc17Ph9/ZPEv7ZmN+w6MN0LDy4Z +EdRFcyq7AD1SmeG5ugMu4ilSpU1K96ZuvrnZezeI0dDgKNgDotlwTN9/oM95EfSf +NNJy7ma4iDPnj8S0o1pELnBQEkizIOtsqTpsFgDKUpyKp3golh3jbZvixAuwUHOx +PdHZca/mB1KhjONPhEDPl8HZIznYQzn+Z3cNqoM58lMF/di834ogN7zguYHMhDUT +0YhZAoIBAHlYhuni+gyrn4tyZgep68VXW7wQxSvgSj8cpZAuT/w0UKAU53J5QTWZ +aGHeICXvgvpalUL+2dGwASlOvPa52ekcOPd2+qKWyss0zA4ksI7mNE2vjFUcOr+S +n9QSNvu3E8dYAjzSIsizcQbPTlk6A/TmytNJ4x67ZVGCmKXw1ZzzSrxSbAIdY254 +TxSGchrfcy0ofXIL2HXq16FRmesORTJFkkyQaldzn4y7S6HJ/vGppImTfeac1MwG +jLYljIkIbt+nB1c8HeNvARmBa6M2pxB9f72oRMVqFdUUc5AxXuWP9v6xk227EuCq +TBORAafu9WxKVwUsHa1rE1uGgNEfRJ8= +-----END PRIVATE KEY----- diff --git a/test/js/node/test/fixtures/x509-escaping/subj-0-cert.pem b/test/js/node/test/fixtures/x509-escaping/subj-0-cert.pem new file mode 100644 index 0000000000..ae853c8931 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/subj-0-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE1zCCAr+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAvMRIwEAYDVQQHDAlTb21l +d2hlcmUxGTAXBgNVBAMMEGV2aWwuZXhhbXBsZS5jb20wHhcNMjExMjIwMTQ1NzM1 +WhcNMzExMjE4MTQ1NzM1WjAvMRIwEAYDVQQHDAlTb21ld2hlcmUxGTAXBgNVBAMM +EGV2aWwuZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCxEWd00u9E9T/ko6WcCKjhZ7tjnfVylnA7M0EHOwvdivgD46eAb1omsonLagiV +rZrG7EpYuMhtz+g3Yv1d0nvFvv8ge9UIdnN8EDTDzLpJ3KbNqHURraiXuBDqa3rd +Y4JBakCcuYHl1bj1OTew7xl1FWc1je04rBTQGTFIRdmJZYyc9bIw9WkY6msod0w1 +PDcLhZS3emh/eYaL4zAQWrVhQfWzf4rZzFaI/a5n0o75aUkTuvxDDQ51V2d6WkSU +3KbOnf2JW+QJXfzsNOeiYA9AnfY59evr4GEeG8VZdGuUG39uDCIWmAUT8elhXXqV +q+NdBqc6VUNLDJbqCmMx/Ecp48EHO6X5uXm0xViZIVPNIzqiiRhVt4nFfwPQZrTg +aq2+tD7/zD1yED4O1FhlDl5twH2N7+oG06HsEluQdLPrj7IedpneGVKMs078Ddov +7j6icYv/RZHVetDlrzDDHjLJWwxyAWzdGdkhtMGPd6B9i4TtF/PU3J3nbpLn5XfE +BFu4jJ+w+5Wvk5a60gF1ERy/OLBM/e8sro2sEBIpp1tN1wJVBZOtTIi4VVDhwDRQ +Uiwb2d1Re7GQ7+mcz5D/01qxW6S+w0IKrpwJUjR3mpa0OU98KfKVJkeyeEBLkEhD +dnGTDqZ9E/ickGosrW2gAAYKgzXk725dpxTdpLEosfDbpwIDAQABMA0GCSqGSIb3 +DQEBCwUAA4ICAQAnszSuVqfEmpjf2VMvk9TUuiop0tejHP+hB30IURJqA9K51edx +IRszXXU4Sj8uHT88RpKxgDm/GcfEA0l2rWZ6Mal6pmUyjteJJPMVA6fgeNM8XvtJ +eoxi2wm8FzxXJrPK7fOMG5/fLb7ENUZYFRHVFJ+Gk290DP7x81Gzb5tcsolrVqW+ +TZdV2aBZya28NjgXncjinIlD61I6LzoQbDInab5nEPKMRuRTXMLfbAypXrPAbsfz ++Z6ZKhfNEo0/5cI4iG8MQXM1HgbFCkWOTPPeR53lo+1f9dN3IZ+1PYUjkOJzuxUZ +HIA+Dy+S1ocfK582LqohexhjeC5AL74rJJcgns9ORxz2GN1buIRTzi9XL2egp7cd ++XgZ3phpY4mIM0bH+DJ7eIqkM17WkEwJ3vazu7tEmIldc06Pmt2vFEcQB3T0bsw7 +lBZdwSEkqTb+IexaQerSyztuxKc2DhOLTqZfVPCd2LWhasNSHzGmanI3vmBy98MN +LZzo7+G1BDMyMsl3DwEiwOGYARXJklU1LxCj6nVCTymNToLXtF2xHcZuK94Pqol9 +n8zMCUYNOr7USWA25GwfpN65UHN7YXsOl9XIMWl+iVA5QepAI9sL0n3CyFW0ZXgn +DsZkfikYa+xhQSUANV4zDx1X8FxZmT0Op/+mhkvwL1+YKUHJy3WdXrIFgw== +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/subj-1-cert.pem b/test/js/node/test/fixtures/x509-escaping/subj-1-cert.pem new file mode 100644 index 0000000000..3e193e25c2 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/subj-1-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQHDBpTb21l +d2hlcmUAZXZpbC5leGFtcGxlLmNvbTAeFw0yMTEyMjAxNDU3MzVaFw0zMTEyMTgx +NDU3MzVaMCUxIzAhBgNVBAcMGlNvbWV3aGVyZQBldmlsLmV4YW1wbGUuY29tMIIC +IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsRFndNLvRPU/5KOlnAio4We7 +Y531cpZwOzNBBzsL3Yr4A+OngG9aJrKJy2oIla2axuxKWLjIbc/oN2L9XdJ7xb7/ +IHvVCHZzfBA0w8y6Sdymzah1Ea2ol7gQ6mt63WOCQWpAnLmB5dW49Tk3sO8ZdRVn +NY3tOKwU0BkxSEXZiWWMnPWyMPVpGOprKHdMNTw3C4WUt3pof3mGi+MwEFq1YUH1 +s3+K2cxWiP2uZ9KO+WlJE7r8Qw0OdVdnelpElNymzp39iVvkCV387DTnomAPQJ32 +OfXr6+BhHhvFWXRrlBt/bgwiFpgFE/HpYV16lavjXQanOlVDSwyW6gpjMfxHKePB +Bzul+bl5tMVYmSFTzSM6ookYVbeJxX8D0Ga04GqtvrQ+/8w9chA+DtRYZQ5ebcB9 +je/qBtOh7BJbkHSz64+yHnaZ3hlSjLNO/A3aL+4+onGL/0WR1XrQ5a8wwx4yyVsM +cgFs3RnZIbTBj3egfYuE7Rfz1Nyd526S5+V3xARbuIyfsPuVr5OWutIBdREcvziw +TP3vLK6NrBASKadbTdcCVQWTrUyIuFVQ4cA0UFIsG9ndUXuxkO/pnM+Q/9NasVuk +vsNCCq6cCVI0d5qWtDlPfCnylSZHsnhAS5BIQ3Zxkw6mfRP4nJBqLK1toAAGCoM1 +5O9uXacU3aSxKLHw26cCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAmjKOoKxLwPY4 +e65pYTUSBctPZ2juW5uNs8UvH5O32OC9RhENJBIIKn3B9Z/wkexR2zcvaQmJObLW +6mkR7O0tNgsXVYJFzLRBfjM/nyP6nafiCUekmoh9Kojq6x5IQQgEsK+Uw123kkoI +w/h3hBYBq8+CFPnYtBLZBVVFMNGaATXrYJPCcjVrtAHYxIWaDN2R+1DWLRIV72sF +hu4xGz0kmUbzforl/FA3gdgM7mwfZMF4+EoQZi5mShdWnyfzAHIbtahnA4lPNtx9 +vBqYIZ/a2ITsXmWc2KGs/rRG+SDLzg+H1Xudvu/y2d1ULpZQfT6bg6Ro855FiU9h +TyHHQGGqlC9/DjHy//wERsFEJZh5/j21LGyalEjgfOYtzPkjZlIweYr8LlHTrauo +/gWihriaaWAkD+2fwQ09CUHdvOG6yoT+j/E50FsekfqV3tKMwoZoph6dF1TWQg32 +JXV0akpd5ff1cca8sZgJfUksDfSkrwG7fl3tje30vQTlvNrhu2MCKFGQwyXed3qg +86lx+sTZjxMYvqWWysKTx8aIJ95XAK2jJ2OEVI2X6cdgoAp6aMkycbttik4hDoPJ +eAWaZo2UFs2MGoUbX9m4RzPqPuBHNFqoV6yRyS1K/3KWyxVVvamZY0Qgzmoi4coB +hRlTO6GDkF7u1YQ7eZi7pP7U8OcklfE= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/subj-2-cert.pem b/test/js/node/test/fixtures/x509-escaping/subj-2-cert.pem new file mode 100644 index 0000000000..e6a23dccdd --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/subj-2-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEyTCCArGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQHDB1Tb21l +d2hlcmUKQ049ZXZpbC5leGFtcGxlLmNvbTAeFw0yMTEyMjAxNDU3MzVaFw0zMTEy +MTgxNDU3MzVaMCgxJjAkBgNVBAcMHVNvbWV3aGVyZQpDTj1ldmlsLmV4YW1wbGUu +Y29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsRFndNLvRPU/5KOl +nAio4We7Y531cpZwOzNBBzsL3Yr4A+OngG9aJrKJy2oIla2axuxKWLjIbc/oN2L9 +XdJ7xb7/IHvVCHZzfBA0w8y6Sdymzah1Ea2ol7gQ6mt63WOCQWpAnLmB5dW49Tk3 +sO8ZdRVnNY3tOKwU0BkxSEXZiWWMnPWyMPVpGOprKHdMNTw3C4WUt3pof3mGi+Mw +EFq1YUH1s3+K2cxWiP2uZ9KO+WlJE7r8Qw0OdVdnelpElNymzp39iVvkCV387DTn +omAPQJ32OfXr6+BhHhvFWXRrlBt/bgwiFpgFE/HpYV16lavjXQanOlVDSwyW6gpj +MfxHKePBBzul+bl5tMVYmSFTzSM6ookYVbeJxX8D0Ga04GqtvrQ+/8w9chA+DtRY +ZQ5ebcB9je/qBtOh7BJbkHSz64+yHnaZ3hlSjLNO/A3aL+4+onGL/0WR1XrQ5a8w +wx4yyVsMcgFs3RnZIbTBj3egfYuE7Rfz1Nyd526S5+V3xARbuIyfsPuVr5OWutIB +dREcvziwTP3vLK6NrBASKadbTdcCVQWTrUyIuFVQ4cA0UFIsG9ndUXuxkO/pnM+Q +/9NasVukvsNCCq6cCVI0d5qWtDlPfCnylSZHsnhAS5BIQ3Zxkw6mfRP4nJBqLK1t +oAAGCoM15O9uXacU3aSxKLHw26cCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAEMEW +EElTS/lgeoWvTruGEqmpwS86NE+j+Ws+VnUXnjo2RSqs4tSICkBzJsi4g/WHNa5V +TzD42MOmyQTUGaJ96Cpq8VmL8pE0mYKo1wXsi8WonDgaw0Eup6v9ga5kHPfKJBvV +dqEP+upiAbYXxlISj+xgOVW5WBJ3tBic1Iyg/oOKlHwXYA0IKc1MOLlvh0EdVqj7 +2cYodO7nuAmeFLpf5RDtGTNMWt/whoqv+vUb5iy2pDdDNMJdoa0hT/L4E+ibl0ZA +7W/RKkcXJ0RlZMA7rYGjQ2/lasHvMniHlfLZd2UtChVgs8hY/b1PCLubyiz1peCj +Q8Y4VoveePnxfovTPvcvMxPbNiCLPJtsPhWq1KPbOyBpKBc/mJ6I5DmszQB16Jb2 +fq6RfrrXjC1C+vYN4KCUGPbS+J4eZ0a04C4OdSGED02YSOpLIBnfNRMDyXZQ6Hhd +sZSvyOAD3UhugEloCV9cnFKVglbXaW3k97xeYg/86udVPrgiAEn7u3Lsr9U1wZ2x +wFgE4js1IzeIvIZOk9wDQHPolUiPaZUvMZXfM7+i9X9qX9AgtUAxnO0y0U9zXrUB +Xjdtfddb4XAHdrPnuBkCb/75JeQ4JroP3t59iY0SFuQ0TH9YkOJULrw7oTqqmLo+ +PAFMiK1/kbmpVsT92k2WLjPgrAXe+lslQPwXBNM= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/subj-3-cert.pem b/test/js/node/test/fixtures/x509-escaping/subj-3-cert.pem new file mode 100644 index 0000000000..48bee70c9b --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/subj-3-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEzzCCAregAwIBAgIBATANBgkqhkiG9w0BAQsFADArMSkwJwYDVQQHDCBTb21l +d2hlcmUsIENOID0gZXZpbC5leGFtcGxlLmNvbTAeFw0yMTEyMjAxNDU3MzVaFw0z +MTEyMTgxNDU3MzVaMCsxKTAnBgNVBAcMIFNvbWV3aGVyZSwgQ04gPSBldmlsLmV4 +YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsRFndNLv +RPU/5KOlnAio4We7Y531cpZwOzNBBzsL3Yr4A+OngG9aJrKJy2oIla2axuxKWLjI +bc/oN2L9XdJ7xb7/IHvVCHZzfBA0w8y6Sdymzah1Ea2ol7gQ6mt63WOCQWpAnLmB +5dW49Tk3sO8ZdRVnNY3tOKwU0BkxSEXZiWWMnPWyMPVpGOprKHdMNTw3C4WUt3po +f3mGi+MwEFq1YUH1s3+K2cxWiP2uZ9KO+WlJE7r8Qw0OdVdnelpElNymzp39iVvk +CV387DTnomAPQJ32OfXr6+BhHhvFWXRrlBt/bgwiFpgFE/HpYV16lavjXQanOlVD +SwyW6gpjMfxHKePBBzul+bl5tMVYmSFTzSM6ookYVbeJxX8D0Ga04GqtvrQ+/8w9 +chA+DtRYZQ5ebcB9je/qBtOh7BJbkHSz64+yHnaZ3hlSjLNO/A3aL+4+onGL/0WR +1XrQ5a8wwx4yyVsMcgFs3RnZIbTBj3egfYuE7Rfz1Nyd526S5+V3xARbuIyfsPuV +r5OWutIBdREcvziwTP3vLK6NrBASKadbTdcCVQWTrUyIuFVQ4cA0UFIsG9ndUXux +kO/pnM+Q/9NasVukvsNCCq6cCVI0d5qWtDlPfCnylSZHsnhAS5BIQ3Zxkw6mfRP4 +nJBqLK1toAAGCoM15O9uXacU3aSxKLHw26cCAwEAATANBgkqhkiG9w0BAQsFAAOC +AgEAFvcwnV5K6KH4jvYFUccZDEVZ2WFuZsqJVD5N4nX5KgHmnSzyDYgHRRZ4oGiN +eTgi+3B6S5TPRTMLUaO7hnFxilnfr3HlhsQhGVh+Qb+ovyL1evsrCu8CzmmFMJs1 +bHm/ct/HzDfNgrx7HEZbrpesNjka05UWhIewA/64IkSMFoGbrjb35WINpcHQNgvQ +X5YnUTk3U+DyDHGeRvZ9dsYBXnK7Q+s6lbS1Bvl3G65SZq9fxqtxLnwloP5ms62j +r7OLdQ/IDYFu0v/HKkA9Ms/NJyKtoPUXYyiP0qQPq2A9lDRW07goCaR7WApmU4Sr +uYQVAPCFbEJGQtjUVUrmEdlEuNaiaMM7+iB5WEXaQ8M8gRX+4U7lbk7HsRSsHlDn +9/1sAOxrWAnCffoYSrUwruD8SKVCTBlkYs5pPSIkfz/yzwNq5u6ebe5ATJBjIv+H +N4nflcrY18oMAz694f+94RUFat/5wX+WsnNT4Av+bVz6Gv5nbGJGXurUArrne5F9 +G+ESYu2KuGIRhxrOrBIvZapv9lITlBm9t8kChBbR9YZC4dD0+lu72h4xH3iXeeBl +MFmP1mk8zxuIwH6H/bM70B5NAHEw4U5guthnRU5YSK5EpvXhNl/JqdSp8xskfYCM +62dhRqgQNL0HZxKJO61bn3XBvVKLPNpCqBD5KQsI0R4wevM= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/subj-4-cert.pem b/test/js/node/test/fixtures/x509-escaping/subj-4-cert.pem new file mode 100644 index 0000000000..c23922d991 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/subj-4-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEyTCCArGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQHDB1Tb21l +d2hlcmUvQ049ZXZpbC5leGFtcGxlLmNvbTAeFw0yMTEyMjAxNDU3MzVaFw0zMTEy +MTgxNDU3MzVaMCgxJjAkBgNVBAcMHVNvbWV3aGVyZS9DTj1ldmlsLmV4YW1wbGUu +Y29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsRFndNLvRPU/5KOl +nAio4We7Y531cpZwOzNBBzsL3Yr4A+OngG9aJrKJy2oIla2axuxKWLjIbc/oN2L9 +XdJ7xb7/IHvVCHZzfBA0w8y6Sdymzah1Ea2ol7gQ6mt63WOCQWpAnLmB5dW49Tk3 +sO8ZdRVnNY3tOKwU0BkxSEXZiWWMnPWyMPVpGOprKHdMNTw3C4WUt3pof3mGi+Mw +EFq1YUH1s3+K2cxWiP2uZ9KO+WlJE7r8Qw0OdVdnelpElNymzp39iVvkCV387DTn +omAPQJ32OfXr6+BhHhvFWXRrlBt/bgwiFpgFE/HpYV16lavjXQanOlVDSwyW6gpj +MfxHKePBBzul+bl5tMVYmSFTzSM6ookYVbeJxX8D0Ga04GqtvrQ+/8w9chA+DtRY +ZQ5ebcB9je/qBtOh7BJbkHSz64+yHnaZ3hlSjLNO/A3aL+4+onGL/0WR1XrQ5a8w +wx4yyVsMcgFs3RnZIbTBj3egfYuE7Rfz1Nyd526S5+V3xARbuIyfsPuVr5OWutIB +dREcvziwTP3vLK6NrBASKadbTdcCVQWTrUyIuFVQ4cA0UFIsG9ndUXuxkO/pnM+Q +/9NasVukvsNCCq6cCVI0d5qWtDlPfCnylSZHsnhAS5BIQ3Zxkw6mfRP4nJBqLK1t +oAAGCoM15O9uXacU3aSxKLHw26cCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAQD16 +wSsZodV3hk98VYDyXBuQdzrlF1zXm5n7Dx+ONGw62d3FRRaegbkwBfvUf7P+ZfR/ +qUFZQwWKYZ+hYos/gIvYuBRJSSg8nrGrHkp+AXIxQ6ZmgVAat3OnLdzG+k0Cras6 +vzRrEohL3JnXCBVZ+4MMnNrZFhGzQ9rHGJtrarkZ5NQMhH8VbfdtuKDpwS8O9mtI +MqoNTIViocqtBem8ZD5z+m9A5UT8DMKwL+gjDQQ3j/flfmAq5bcqZkkIrJol3mrp +4Ol1Hc4/tVMa1wsnEtYGWEOfBJqANY3m5IiEBHIyeP67NR68fdlZ+XFpdHNl5/LV +XwjGquv0jSE3CbKR1ez5sefn1fmCWVZi5mZV6O8jpT7Ztu1XL8jOxTxtCMKE6cCC +xgEL2HFG4JWeA/z5ZXT8U+4Bfiu1GXBMxF5LJc89DORTBRIWMR1IHca+nOb2zHNF +v4QOfqLKF+ko5D/ie9Xg1s49l6lI8NReg9NRRp2sc90Zxc0Pqz7wdNH2SMUC/+gR +kWhz77OhACeXpcRQVy0Bi64l5Or+05ZB2piK6OemcFUKIybKjxUbzuwZdrqj0vK6 +Tw1nemA1BCH8X+b1rz6kDKPycBAEdtMoRSFzbtZbdjBR1g0PLGeYn8rL2gsLMpaN +1XTCTb7BAAy0Ky4cpMduD+uYGbma9V4ER3RLdL8= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/subj-5-cert.pem b/test/js/node/test/fixtures/x509-escaping/subj-5-cert.pem new file mode 100644 index 0000000000..6c1c87e2ce --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/subj-5-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEyTCCArGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQHDB1Nw7xu +Y2hlblwKQ049ZXZpbC5leGFtcGxlLmNvbTAeFw0yMTEyMjAxNDU3MzVaFw0zMTEy +MTgxNDU3MzVaMCgxJjAkBgNVBAcMHU3DvG5jaGVuXApDTj1ldmlsLmV4YW1wbGUu +Y29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsRFndNLvRPU/5KOl +nAio4We7Y531cpZwOzNBBzsL3Yr4A+OngG9aJrKJy2oIla2axuxKWLjIbc/oN2L9 +XdJ7xb7/IHvVCHZzfBA0w8y6Sdymzah1Ea2ol7gQ6mt63WOCQWpAnLmB5dW49Tk3 +sO8ZdRVnNY3tOKwU0BkxSEXZiWWMnPWyMPVpGOprKHdMNTw3C4WUt3pof3mGi+Mw +EFq1YUH1s3+K2cxWiP2uZ9KO+WlJE7r8Qw0OdVdnelpElNymzp39iVvkCV387DTn +omAPQJ32OfXr6+BhHhvFWXRrlBt/bgwiFpgFE/HpYV16lavjXQanOlVDSwyW6gpj +MfxHKePBBzul+bl5tMVYmSFTzSM6ookYVbeJxX8D0Ga04GqtvrQ+/8w9chA+DtRY +ZQ5ebcB9je/qBtOh7BJbkHSz64+yHnaZ3hlSjLNO/A3aL+4+onGL/0WR1XrQ5a8w +wx4yyVsMcgFs3RnZIbTBj3egfYuE7Rfz1Nyd526S5+V3xARbuIyfsPuVr5OWutIB +dREcvziwTP3vLK6NrBASKadbTdcCVQWTrUyIuFVQ4cA0UFIsG9ndUXuxkO/pnM+Q +/9NasVukvsNCCq6cCVI0d5qWtDlPfCnylSZHsnhAS5BIQ3Zxkw6mfRP4nJBqLK1t +oAAGCoM15O9uXacU3aSxKLHw26cCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAipRw +3Q8C0CUYTQJlYTAdmATrboUFATpex+ZFhQgQPPWs/tUvf8zWU+DdDjFjrLNCY+ew +FaURBnNQ92AE3LVDayu3Jh6TMoHKMAnPOERaiMuHDoKr/T4JVk2vWSBck6aYbokl +7W7/ucMTVyPS9tLiuIwyJ+0dta+ucQSjIZj2RtCzsOtxdbUqt/7iTJrl8EjZGGbH +FTKSbFBY2mR9oFKhoyCaVV0Alw1//napqdzu93gNqZx3cXskA0T63GxyhjhVpFq8 +d1ILGB3yKAiIzc5epNKx8ZPSUddx7zK0FAXRtBGHcOTES3+kTljkxmXAFDGTrMk0 +fsWgKfDDkDEGaUHL43524HLnPUoQASdQ9Uk5r7TDkl/kATv5w+HpWKdd3sxcSH8m +UeUFCFdJbcOyqKfF7jz8kCe08Xt2sEW5tKZb4xWjI+mm01PCNeyCsaAw4OlSDUEm +63fCsXY/b+i0hOxdd/eusoq3B76ngOEGaEJ8jOvpxeyHuet9kDet5M48aQRE9S9x +HJWLL+80mFt4yiRHPUob/WP+4L7EnBjmiVBevEO0sptYLqymdRuCy4Ub4/QIQnNW +kFasltzL/WEe1TzpTNziqOk1jEHA06D5Euwy/mI+S0Y0uvFOYC+tVkspsCNikrTu +Fj0Lqyg5tqQJM3msSEfJvaJhUydaeIZp1Cr535Y= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/subj-6-cert.pem b/test/js/node/test/fixtures/x509-escaping/subj-6-cert.pem new file mode 100644 index 0000000000..82912d7c26 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/subj-6-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE0zCCArugAwIBAgIBATANBgkqhkiG9w0BAQsFADAtMSswEAYDVQQHDAlTb21l +d2hlcmUwFwYDVQQDDBBldmlsLmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoX +DTMxMTIxODE0NTczNVowLTErMBAGA1UEBwwJU29tZXdoZXJlMBcGA1UEAwwQZXZp +bC5leGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALER +Z3TS70T1P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4BvWiayictqCJWtmsbs +Sli4yG3P6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGtqJe4EOpret1jgkFq +QJy5geXVuPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1aRjqayh3TDU8NwuF +lLd6aH95hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMNDnVXZ3paRJTcps6d +/Ylb5Ald/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaYBRPx6WFdepWr410G +pzpVQ0sMluoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3icV/A9BmtOBqrb60 +Pv/MPXIQPg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4ZUoyzTvwN2i/uPqJx +i/9FkdV60OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tcnedukufld8QEW7iM +n7D7la+TlrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61MiLhVUOHANFBSLBvZ +3VF7sZDv6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUmR7J4QEuQSEN2cZMO +pn0T+JyQaiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAEwDQYJKoZIhvcNAQEL +BQADggIBAAdRC4tmZb5tukc4pIdnzRyrzNq3uefQNLcrZpZaCKAWvey+AFOZw88N +nnjUT0A3bXA2YJPKQtRaSJG+UBH3xgRNOM0ttvKYqmzZDt/ygzxRlTMt80AVVyMG +P06D5UUZHEX6aUchS/noDI5jewZy23jINEAzQv8B72r8WjV/LwjbJ1IoBg08gJhO +QQCfeDaJ0sAQCL1tdlwiS6Q3N6rkC3jLzBHCzXP0FN5OF5rxr6nlfHiTOuhTdodR +p/UrLVADdvpXq6SegbTvZ7/KwNWzzAmOEx2MAHFQKh46S1+RHQE3L7SV9dqV2XCe +OxfBPPXTy+AiceKhVL0+jhdI/VWIdhTHSCeFuzrGbrLQwWLCDZ5AZjS/JaBXuVGl +WILzz3ZG6ekdqMY/qG8weDEFv49f03MGWoX27uhkz4qtumLzrXEspzL7GwUfnDZo +zyF9Jo9vJVNmiz/N2DnUd0X5hdHUsjnN8vPN+3u5kkvfXTgT9wUrMgzECu/tyC92 +GAX0MqY6lKJwTT+pxkZPUNGMbP8c3BuO9NVGPUeOA+/4sgsws+V0TDF7umNk2nq3 +vCuS+QFZXAR4Ns2xgIOMH8XQjRZ4qSp3HsFNehOqSQrFvcgjMLo0RcgiwgReUMl+ +Pnhjk+V4ttEIUe3UswaRHD9moG4sgCfFk/bafwCvdKonD6mBETMa +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/subj-7-cert.pem b/test/js/node/test/fixtures/x509-escaping/subj-7-cert.pem new file mode 100644 index 0000000000..fd645da965 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/subj-7-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEzTCCArWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAqMSgwJgYDVQQHDB9Tb21l +d2hlcmUgKyBDTj1ldmlsLmV4YW1wbGUuY29tMB4XDTIxMTIyMDE0NTczNVoXDTMx +MTIxODE0NTczNVowKjEoMCYGA1UEBwwfU29tZXdoZXJlICsgQ049ZXZpbC5leGFt +cGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALERZ3TS70T1 +P+SjpZwIqOFnu2Od9XKWcDszQQc7C92K+APjp4BvWiayictqCJWtmsbsSli4yG3P +6Ddi/V3Se8W+/yB71Qh2c3wQNMPMukncps2odRGtqJe4EOpret1jgkFqQJy5geXV +uPU5N7DvGXUVZzWN7TisFNAZMUhF2YlljJz1sjD1aRjqayh3TDU8NwuFlLd6aH95 +hovjMBBatWFB9bN/itnMVoj9rmfSjvlpSRO6/EMNDnVXZ3paRJTcps6d/Ylb5Ald +/Ow056JgD0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaYBRPx6WFdepWr410GpzpVQ0sM +luoKYzH8RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3icV/A9BmtOBqrb60Pv/MPXIQ +Pg7UWGUOXm3AfY3v6gbToewSW5B0s+uPsh52md4ZUoyzTvwN2i/uPqJxi/9FkdV6 +0OWvMMMeMslbDHIBbN0Z2SG0wY93oH2LhO0X89Tcnedukufld8QEW7iMn7D7la+T +lrrSAXURHL84sEz97yyujawQEimnW03XAlUFk61MiLhVUOHANFBSLBvZ3VF7sZDv +6ZzPkP/TWrFbpL7DQgqunAlSNHealrQ5T3wp8pUmR7J4QEuQSEN2cZMOpn0T+JyQ +aiytbaAABgqDNeTvbl2nFN2ksSix8NunAgMBAAEwDQYJKoZIhvcNAQELBQADggIB +AAG8vjV7c4B4yKO2BDhufVjkmzot97SPf4qR0qJATAV+Iifm5D2YL/dr36kyvTiK +JoPU/0vztcnh5X75YzvEtD4xh5zg3FQdAEpGx4zZkNXkJt2syz3V3DFG9Te4GH3n +/a39z4yn2J2MG2uXj+TTSJR23ICAgqNkj4EtrwvOouAqLCR/yZuYaUM6ZPmEYrHM +5wwiMCheDgMUYvFhTIKAwalnQitCGQCFr5WvTHU/0oVn498miZEU5LPAIiuhIQoA +UI/tro47evU/Nli8WY9UImLbcWkbIS7MogtWhjDQXd80G3sX+9DpVO43S2Cf4shB +yXl49bvqITMXdurSQrNKbfQ5aLDmKno4Qjs9wZMmi2xhIKczuB4bdtQDsC0/LiSr +oydiSP9uxYatT6SedzgkypTOL/5qtuh14Z7aRio5s4WrIDDJ1RVlWJGffq4hF+j/ +cu5OHo4cyvN42+bnyYzAWpOE7h8Nmi0D14zvm1FE3FKVSlBZzScBBungVdJkchAP +4JleXVqfH5skLgMiYCa3qocfUEfeKTCVXJUxaPIvBILtcOYzx75B0izsVlsd/dr+ +DqoIKN9aMGyuKR0QZtmW97eCxaH6Dm7lVuym56hiQrT3J0PL2iU+LU1R9UfLE/pL +RjUWW/gbxxNq8dbFybiUM7Sj+6tWuVvLygA04lMeDIDq +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/subj-8-cert.pem b/test/js/node/test/fixtures/x509-escaping/subj-8-cert.pem new file mode 100644 index 0000000000..edd4b460b1 --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/subj-8-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADAlMRYwCQYDVQQHDAJMMTAJ +BgNVBAcMAkwyMQswCQYDVQQHDAJMMzAeFw0yMTEyMjAxNDU3MzVaFw0zMTEyMTgx +NDU3MzVaMCUxFjAJBgNVBAcMAkwxMAkGA1UEBwwCTDIxCzAJBgNVBAcMAkwzMIIC +IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsRFndNLvRPU/5KOlnAio4We7 +Y531cpZwOzNBBzsL3Yr4A+OngG9aJrKJy2oIla2axuxKWLjIbc/oN2L9XdJ7xb7/ +IHvVCHZzfBA0w8y6Sdymzah1Ea2ol7gQ6mt63WOCQWpAnLmB5dW49Tk3sO8ZdRVn +NY3tOKwU0BkxSEXZiWWMnPWyMPVpGOprKHdMNTw3C4WUt3pof3mGi+MwEFq1YUH1 +s3+K2cxWiP2uZ9KO+WlJE7r8Qw0OdVdnelpElNymzp39iVvkCV387DTnomAPQJ32 +OfXr6+BhHhvFWXRrlBt/bgwiFpgFE/HpYV16lavjXQanOlVDSwyW6gpjMfxHKePB +Bzul+bl5tMVYmSFTzSM6ookYVbeJxX8D0Ga04GqtvrQ+/8w9chA+DtRYZQ5ebcB9 +je/qBtOh7BJbkHSz64+yHnaZ3hlSjLNO/A3aL+4+onGL/0WR1XrQ5a8wwx4yyVsM +cgFs3RnZIbTBj3egfYuE7Rfz1Nyd526S5+V3xARbuIyfsPuVr5OWutIBdREcvziw +TP3vLK6NrBASKadbTdcCVQWTrUyIuFVQ4cA0UFIsG9ndUXuxkO/pnM+Q/9NasVuk +vsNCCq6cCVI0d5qWtDlPfCnylSZHsnhAS5BIQ3Zxkw6mfRP4nJBqLK1toAAGCoM1 +5O9uXacU3aSxKLHw26cCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAGNhY0vKd8Os9 +75+HHQH03BugatuIykpSu+tj8OYr2/7VLT76qUaKdkAZV0m9TiS8MitHZieEbig3 +EozQtYrTZQbiFjiV8FudPsmAXZxcz1TdE25mZykWe24FmZNdeMQmoVRZYbg3gb/M +sTEDbnV3DoW6X8LWMlitaBpisxg/LqHakATvj6Otvts8RFhI1c/JFx8THuY14Fj1 +sJ8eFdwebPK35V4ZNtH8bevVo9MvnUS290fF1WDC1dnjZ1zYqHT7sPoGbCFF4kne +TF2Ef12BgUNtgJKnXeEV5Gull4iOQS8qTkWCIm8jbz1+9ap8nqVcGn60bkwiMmgz +hNyBW7c31MvEfedfCwFma/uV1yMB2nGwX47TMnTTjwc5b2I/lOrFOfeh2JD9QVZF +XFKRsVXqCwa3aLc1fc93M9kEHzKWzGgMjYvJzZEGsoqTil22NmQXIG7jKjLth7zF +4Sc/qBDXsLaqUaWQveZ9U6suFYr9u2X7h3KkciFtsZPFK+AZGO07z/4nWEeo4frV +RyltN38BmJxwBSxNEZFBiMJ9AEmg2EhgBXJbEhN9XCwpW2EEp+M09AfcebzKjJ+h +3Q7AWlTPawz/PQzzunZzNMkq7/6Y/dIFg/Ak8RIPkMVb3xE9oD0wMWigyiK05UUI +832NnZXih3qq15MfVS4eTSeKrNcFt3c= +-----END CERTIFICATE----- diff --git a/test/js/node/test/fixtures/x509-escaping/subj-9-cert.pem b/test/js/node/test/fixtures/x509-escaping/subj-9-cert.pem new file mode 100644 index 0000000000..5490e2ea3e --- /dev/null +++ b/test/js/node/test/fixtures/x509-escaping/subj-9-cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIExzCCAq+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAnMQswCQYDVQQHDAJMMTEL +MAkGA1UEBwwCTDIxCzAJBgNVBAcMAkwzMB4XDTIxMTIyMDE0NTczNVoXDTMxMTIx +ODE0NTczNVowJzELMAkGA1UEBwwCTDExCzAJBgNVBAcMAkwyMQswCQYDVQQHDAJM +MzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALERZ3TS70T1P+SjpZwI +qOFnu2Od9XKWcDszQQc7C92K+APjp4BvWiayictqCJWtmsbsSli4yG3P6Ddi/V3S +e8W+/yB71Qh2c3wQNMPMukncps2odRGtqJe4EOpret1jgkFqQJy5geXVuPU5N7Dv +GXUVZzWN7TisFNAZMUhF2YlljJz1sjD1aRjqayh3TDU8NwuFlLd6aH95hovjMBBa +tWFB9bN/itnMVoj9rmfSjvlpSRO6/EMNDnVXZ3paRJTcps6d/Ylb5Ald/Ow056Jg +D0Cd9jn16+vgYR4bxVl0a5Qbf24MIhaYBRPx6WFdepWr410GpzpVQ0sMluoKYzH8 +RynjwQc7pfm5ebTFWJkhU80jOqKJGFW3icV/A9BmtOBqrb60Pv/MPXIQPg7UWGUO +Xm3AfY3v6gbToewSW5B0s+uPsh52md4ZUoyzTvwN2i/uPqJxi/9FkdV60OWvMMMe +MslbDHIBbN0Z2SG0wY93oH2LhO0X89Tcnedukufld8QEW7iMn7D7la+TlrrSAXUR +HL84sEz97yyujawQEimnW03XAlUFk61MiLhVUOHANFBSLBvZ3VF7sZDv6ZzPkP/T +WrFbpL7DQgqunAlSNHealrQ5T3wp8pUmR7J4QEuQSEN2cZMOpn0T+JyQaiytbaAA +BgqDNeTvbl2nFN2ksSix8NunAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAEeFRIyV +5PdD7Xipg3byNhcCH6I8gADM+Ipnxic93COfQrWCKd/lnsJzxml7VhyANScUTx44 +wkYs+kW9Xi/tEViVwrsFzlTB3YwaAYPiGNtr98B4JBUfLneHSh8IUeeMUnBeLt4O +eqo3ts38hCfY3B3E2FtV9nRBKu91ZwE+pInWftdTJ6pIkltr+t9kPbVFW72hYfQJ +rdtyzIiSkTnJElcvNcWtsqEmTMLewgZz/bjbZkQh/LXQDT7oepZBZ5Qb4F8kwytb +wGC/OFoByWyXYfuPWKb2obdnbb5xa1vg8rLVdVgY25q+VeNItBB/FSzf0Pnxd9od +jVVtzvby57A0IT7XpTu8RFAkuWmZp4FO5kDyXLNgsd6md/qeqcO5V7dY6MSKeIXw +nMYTBWuxOZPMw2RnxjcfkEdN/5sDuYHnzuizkH+OiwPPfs2qa4EETaxo5xxmTcy+ +pDh0GEOIgyazpJnncgG1k1ABOcHevRaCpm8NuXexkfpAHEORNfOflRkJDICXSUxv +5o2VjOhqj8gRqLvpGBW3hCxVM/Of2Fzdye0ldoDhzcW0WxjzmcjcC5EEEVSapwok +K5+ZvVFjqW2j619UICFf95tCtB025AzWWwVVQ9rlnCWL0MOrOwe66vYERG2MUYAD +jcB7FUOjXh2+3Gkh1PzXiXCQatDLhIVt9Vus +-----END CERTIFICATE----- diff --git a/test/js/node/test/parallel/.gitignore b/test/js/node/test/parallel/.gitignore index 874ae654ed..3a5f2a9153 100644 --- a/test/js/node/test/parallel/.gitignore +++ b/test/js/node/test/parallel/.gitignore @@ -1,6 +1,7 @@ # Not working yet: child-process-double-pipe.test.js child-process-exec-cwd.test.js +child-process-exec-timeout-expire.test.js child-process-spawn-controller.test.js child-process-stdio-inherit.test.js cluster-fork-env.test.js @@ -10,6 +11,7 @@ file-write-stream5.test.js filehandle-close.test.js fs-existssync-false.test.js fs-fmap.test.js +fs-read-stream-fd.test.js fs-readdir-ucs2.test.js fs-watch-recursive-add-file-to-new-folder.test.js fs-watch-recursive-symlink.test.js @@ -18,14 +20,18 @@ http-request-agent.test.js http2-connect-options.test.js https-server-connections-checking-leak.test.js module-circular-symlinks.test.js +module-prototype-mutation.test.js net-bind-twice.test.js net-listen-error.test.js net-server-close.test.js +net-write-fully-async-hex-string.test.js permission-fs-windows-path.test.js pipe-abstract-socket-http.test.js pipe-file-to-http.test.js process-ppid.test.js +require-invalid-package.test.js require-long-path.test.js +snapshot-dns-lookup-localhost.test.js trace-events-net-abstract-socket.test.js trace-events-worker-metadata-with-name.test.js windows-failed-heap-allocation.test.js @@ -33,6 +39,13 @@ worker-dns-terminate.test.js worker-esm-exit.test.js worker-message-port-wasm-module.test.js +# Failing on Windows: +pipe-head.test.js +http-client-response-domain.test.js +require-extensions-same-filename-as-dir-trailing-slash.test.js +fs-realpath-on-substed-drive.test.js +fs-symlink-dir-junction.test.js + # macOS not working yet node-dns.test.js @@ -43,3 +56,14 @@ npm* *changelog* permission* shadow-realm* +trace-events* +cli-node-options* +corepack* +eslint* +coverage* +buffer-zero-fill-cli* +icu-minimum-version.test.js +release-npm.test.js + +# Bad tests +tls-wrap-no-abort.test.js diff --git a/test/js/node/test/parallel/assert-esm-cjs-message-verify.test.js b/test/js/node/test/parallel/assert-esm-cjs-message-verify.test.js new file mode 100644 index 0000000000..93537273a8 --- /dev/null +++ b/test/js/node/test/parallel/assert-esm-cjs-message-verify.test.js @@ -0,0 +1,54 @@ +//#FILE: test-assert-esm-cjs-message-verify.js +//#SHA1: 3d120c4813c4051523045df80fc501e9921b878f +//----------------- +"use strict"; + +const { spawnPromisified } = require("../common"); +const tmpdir = require("../common/tmpdir"); +const assert = require("assert"); +const { writeFileSync, unlink } = require("fs"); +const { join } = require("path"); + +tmpdir.refresh(); + +const fileImports = { + cjs: 'const assert = require("assert");', + mjs: 'import assert from "assert";', +}; + +const fileNames = []; + +for (const [ext, header] of Object.entries(fileImports)) { + const fileName = `test-file.${ext}`; + // Store the generated filesnames in an array + fileNames.push(join(tmpdir.path, fileName)); + + writeFileSync(tmpdir.resolve(fileName), `${header}\nassert.ok(0 === 2);`); +} + +describe("ensure the assert.ok throwing similar error messages for esm and cjs files", () => { + const nodejsPath = process.execPath; + const errorsMessages = []; + + test("should return code 1 for each command", async () => { + for (const fileName of fileNames) { + const { stderr, code } = await spawnPromisified(nodejsPath, [fileName]); + expect(code).toBe(1); + // For each error message, filter the lines which will starts with AssertionError + errorsMessages.push(stderr.split("\n").find(s => s.startsWith("AssertionError"))); + } + }); + + afterAll(() => { + expect(errorsMessages).toHaveLength(2); + expect(errorsMessages[0]).toEqual(errorsMessages[1]); + + for (const fileName of fileNames) { + unlink(fileName, () => {}); + } + + tmpdir.refresh(); + }); +}); + +//<#END_FILE: test-assert-esm-cjs-message-verify.js diff --git a/test/js/node/test/parallel/buffer-failed-alloc-typed-arrays.test.js b/test/js/node/test/parallel/buffer-failed-alloc-typed-arrays.test.js index 376c5010a9..8dfcd1d03a 100644 --- a/test/js/node/test/parallel/buffer-failed-alloc-typed-arrays.test.js +++ b/test/js/node/test/parallel/buffer-failed-alloc-typed-arrays.test.js @@ -14,7 +14,7 @@ const SlowBuffer = require("buffer").SlowBuffer; // whether or not to zero-fill was not being reset, causing TypedArrays to // allocate incorrectly. -test("failed or zero-sized Buffer allocations should not affect typed arrays", () => { +test("failed or zero-sized Buffer allocations do not affect typed arrays", () => { const zeroArray = new Uint32Array(10).fill(0); const sizes = [1e20, 0, 0.1, -1, "a", undefined, null, NaN]; const allocators = [Buffer, SlowBuffer, Buffer.alloc, Buffer.allocUnsafe, Buffer.allocUnsafeSlow]; diff --git a/test/js/node/test/parallel/child-process-exec-env.test.js b/test/js/node/test/parallel/child-process-exec-env.test.js new file mode 100644 index 0000000000..1649fad830 --- /dev/null +++ b/test/js/node/test/parallel/child-process-exec-env.test.js @@ -0,0 +1,50 @@ +//#FILE: test-child-process-exec-env.js +//#SHA1: cba9b5f7a9d1ab7cd674bde00c1c4184470e4899 +//----------------- +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +"use strict"; +const { isWindows } = require("../common"); +const { exec } = require("child_process"); +const util = require("util"); + +const execPromise = util.promisify(exec); + +test("exec with custom environment", async () => { + let command, options; + + if (!isWindows) { + command = "/usr/bin/env"; + options = { env: { HELLO: "WORLD" } }; + } else { + command = "set"; + options = { env: { ...process.env, HELLO: "WORLD" } }; + } + + const { stdout, stderr } = await execPromise(command, options); + + expect(stdout).not.toBe(""); + expect(stdout).toContain("HELLO=WORLD"); + expect(stderr).toBe(""); +}); + +//<#END_FILE: test-child-process-exec-env.js diff --git a/test/js/node/test/parallel/child-process-exec-timeout-kill.test.js b/test/js/node/test/parallel/child-process-exec-timeout-kill.test.js new file mode 100644 index 0000000000..045b8c6c23 --- /dev/null +++ b/test/js/node/test/parallel/child-process-exec-timeout-kill.test.js @@ -0,0 +1,59 @@ +//#FILE: test-child-process-exec-timeout-kill.js +//#SHA1: 01bc25d258b4d8905a2387e9a08b9ceb8c38c141 +//----------------- +"use strict"; + +// Test exec() with both a timeout and a killSignal. + +const cp = require("child_process"); +const path = require("path"); + +const { kExpiringChildRunTime, kExpiringParentTimer } = require("../common/child_process"); + +const logAfterTime = time => { + setTimeout(() => { + console.log(`Logged after ${time}ms`); + }, time); +}; + +if (process.argv[2] === "child") { + logAfterTime(kExpiringChildRunTime); + process.exit(0); +} + +const cmd = `"${process.execPath}" "${__filename}" child`; + +test("exec with timeout and killSignal", done => { + // Test with a different kill signal. + cp.exec( + cmd, + { + timeout: kExpiringParentTimer, + killSignal: "SIGKILL", + }, + (err, stdout, stderr) => { + console.log("[stdout]", stdout.trim()); + console.log("[stderr]", stderr.trim()); + + expect(err.killed).toBe(true); + expect(err.code).toBeNull(); + expect(err.signal).toBe("SIGKILL"); + expect(err.cmd).toBe(cmd); + expect(stdout.trim()).toBe(""); + expect(stderr.trim()).toBe(""); + done(); + }, + ); +}); + +afterAll(() => { + // Clean up any stale processes + const { execSync } = require("child_process"); + try { + execSync(`pkill -f "${path.basename(__filename)}"`); + } catch (error) { + // Ignore errors, as there might not be any processes to kill + } +}); + +//<#END_FILE: test-child-process-exec-timeout-kill.js diff --git a/test/js/node/test/parallel/child-process-execfile-promisified-abortcontroller.test.js b/test/js/node/test/parallel/child-process-execfile-promisified-abortcontroller.test.js new file mode 100644 index 0000000000..acebc661e9 --- /dev/null +++ b/test/js/node/test/parallel/child-process-execfile-promisified-abortcontroller.test.js @@ -0,0 +1,57 @@ +//#FILE: test-child-process-execFile-promisified-abortController.js +//#SHA1: 133445acf9aaafea4be11eb7965f222c5827f2f3 +//----------------- +"use strict"; + +const { promisify } = require("util"); +const execFile = require("child_process").execFile; +const fixtures = require("../common/fixtures"); + +const echoFixture = fixtures.path("echo.js"); +const promisified = promisify(execFile); +const invalidArgTypeError = { + code: "ERR_INVALID_ARG_TYPE", + name: "TypeError", +}; + +test("Verify that the signal option works properly", async () => { + const ac = new AbortController(); + const signal = ac.signal; + const promise = promisified(process.execPath, [echoFixture, 0], { signal }); + + ac.abort(); + + await expect(promise).rejects.toThrow( + expect.objectContaining({ + name: "AbortError", + message: expect.any(String), + }), + ); +}); + +test("Verify that the signal option works properly when already aborted", async () => { + const signal = AbortSignal.abort(); + + await expect(promisified(process.execPath, [echoFixture, 0], { signal })).rejects.toThrow( + expect.objectContaining({ + name: "AbortError", + message: expect.any(String), + }), + ); +}); + +test("Verify that if something different than Abortcontroller.signal is passed, ERR_INVALID_ARG_TYPE is thrown", () => { + const signal = {}; + expect(() => { + promisified(process.execPath, [echoFixture, 0], { signal }); + }).toThrow(expect.objectContaining(invalidArgTypeError)); +}); + +test("Verify that if a string is passed as signal, ERR_INVALID_ARG_TYPE is thrown", () => { + const signal = "world!"; + expect(() => { + promisified(process.execPath, [echoFixture, 0], { signal }); + }).toThrow(expect.objectContaining(invalidArgTypeError)); +}); + +//<#END_FILE: test-child-process-execFile-promisified-abortController.js diff --git a/test/js/node/test/parallel/child-process-fork-abort-signal.test.js b/test/js/node/test/parallel/child-process-fork-abort-signal.test.js new file mode 100644 index 0000000000..f3c1dcfe65 --- /dev/null +++ b/test/js/node/test/parallel/child-process-fork-abort-signal.test.js @@ -0,0 +1,115 @@ +//#FILE: test-child-process-fork-abort-signal.js +//#SHA1: 4805d5dd4e3cb22ffd5a21fd9d92b6ccd6bc73cf +//----------------- +"use strict"; + +const fixtures = require("../common/fixtures"); +const { fork } = require("child_process"); + +test("aborting a forked child_process after calling fork", done => { + const ac = new AbortController(); + const { signal } = ac; + const cp = fork(fixtures.path("child-process-stay-alive-forever.js"), { + signal, + }); + cp.on("exit", (code, killSignal) => { + expect(code).toBeNull(); + expect(killSignal).toBe("SIGTERM"); + done(); + }); + cp.on("error", err => { + expect(err.name).toBe("AbortError"); + done(); + }); + process.nextTick(() => ac.abort()); +}); + +test("aborting with custom error", done => { + const ac = new AbortController(); + const { signal } = ac; + const cp = fork(fixtures.path("child-process-stay-alive-forever.js"), { + signal, + }); + cp.on("exit", (code, killSignal) => { + expect(code).toBeNull(); + expect(killSignal).toBe("SIGTERM"); + done(); + }); + cp.on("error", err => { + expect(err.name).toBe("AbortError"); + expect(err.cause.name).toBe("Error"); + expect(err.cause.message).toBe("boom"); + done(); + }); + process.nextTick(() => ac.abort(new Error("boom"))); +}); + +test("passing an already aborted signal to a forked child_process", done => { + const signal = AbortSignal.abort(); + const cp = fork(fixtures.path("child-process-stay-alive-forever.js"), { + signal, + }); + cp.on("exit", (code, killSignal) => { + expect(code).toBeNull(); + expect(killSignal).toBe("SIGTERM"); + done(); + }); + cp.on("error", err => { + expect(err.name).toBe("AbortError"); + done(); + }); +}); + +test("passing an aborted signal with custom error to a forked child_process", done => { + const signal = AbortSignal.abort(new Error("boom")); + const cp = fork(fixtures.path("child-process-stay-alive-forever.js"), { + signal, + }); + cp.on("exit", (code, killSignal) => { + expect(code).toBeNull(); + expect(killSignal).toBe("SIGTERM"); + done(); + }); + cp.on("error", err => { + expect(err.name).toBe("AbortError"); + expect(err.cause.name).toBe("Error"); + expect(err.cause.message).toBe("boom"); + done(); + }); +}); + +test("passing a different kill signal", done => { + const signal = AbortSignal.abort(); + const cp = fork(fixtures.path("child-process-stay-alive-forever.js"), { + signal, + killSignal: "SIGKILL", + }); + cp.on("exit", (code, killSignal) => { + expect(code).toBeNull(); + expect(killSignal).toBe("SIGKILL"); + done(); + }); + cp.on("error", err => { + expect(err.name).toBe("AbortError"); + done(); + }); +}); + +test("aborting a cp before close but after exit", done => { + const ac = new AbortController(); + const { signal } = ac; + const cp = fork(fixtures.path("child-process-stay-alive-forever.js"), { + signal, + }); + cp.on("exit", () => { + ac.abort(); + done(); + }); + cp.on("error", () => { + done(new Error("Should not have errored")); + }); + + setTimeout(() => cp.kill(), 1); +}); + +//<#END_FILE: test-child-process-fork-abort-signal.js diff --git a/test/js/node/test/parallel/child-process-fork-args.test.js b/test/js/node/test/parallel/child-process-fork-args.test.js new file mode 100644 index 0000000000..f2efa98aa5 --- /dev/null +++ b/test/js/node/test/parallel/child-process-fork-args.test.js @@ -0,0 +1,88 @@ +//#FILE: test-child-process-fork-args.js +//#SHA1: 172297ab2ed7887ced1b830b8c36d2d6a508deed +//----------------- +"use strict"; +const fixtures = require("../common/fixtures"); +const { fork } = require("child_process"); + +// This test check the arguments of `fork` method +// Refs: https://github.com/nodejs/node/issues/20749 +const expectedEnv = { foo: "bar" }; + +// Ensure that first argument `modulePath` must be provided +// and be of type string +test("fork modulePath argument must be a string", () => { + const invalidModulePath = [0, true, undefined, null, [], {}, () => {}, Symbol("t")]; + invalidModulePath.forEach(modulePath => { + expect(() => fork(modulePath)).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + name: "TypeError", + message: expect.stringMatching(/^The "modulePath" argument must be of type string/), + }), + ); + }); +}); + +test("fork with valid modulePath", done => { + const cp = fork(fixtures.path("child-process-echo-options.js")); + cp.on("exit", code => { + expect(code).toBe(0); + done(); + }); +}); + +// Ensure that the second argument of `fork` +// and `fork` should parse options +// correctly if args is undefined or null +test("fork second argument validation", () => { + const invalidSecondArgs = [0, true, () => {}, Symbol("t")]; + invalidSecondArgs.forEach(arg => { + expect(() => { + fork(fixtures.path("child-process-echo-options.js"), arg); + }).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + name: "TypeError", + }), + ); + }); +}); + +test("fork with valid second argument", async () => { + const argsLists = [undefined, null, []]; + + for (const args of argsLists) { + const cp = fork(fixtures.path("child-process-echo-options.js"), args, { + env: { ...process.env, ...expectedEnv }, + }); + + await new Promise(resolve => { + cp.on("message", ({ env }) => { + expect(env.foo).toBe(expectedEnv.foo); + }); + + cp.on("exit", code => { + expect(code).toBe(0); + resolve(); + }); + }); + } +}); + +// Ensure that the third argument should be type of object if provided +test("fork third argument must be an object if provided", () => { + const invalidThirdArgs = [0, true, () => {}, Symbol("t")]; + invalidThirdArgs.forEach(arg => { + expect(() => { + fork(fixtures.path("child-process-echo-options.js"), [], arg); + }).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + name: "TypeError", + }), + ); + }); +}); + +//<#END_FILE: test-child-process-fork-args.js diff --git a/test/js/node/test/parallel/child-process-fork-close.test.js b/test/js/node/test/parallel/child-process-fork-close.test.js new file mode 100644 index 0000000000..d7dd94759a --- /dev/null +++ b/test/js/node/test/parallel/child-process-fork-close.test.js @@ -0,0 +1,68 @@ +//#FILE: test-child-process-fork-close.js +//#SHA1: d196e4b4f06991be7c2a48169cb89b815c0f172b +//----------------- +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +"use strict"; +const { fork } = require("child_process"); +const path = require("path"); + +test("child process fork close events", async () => { + const cp = fork(path.resolve(__dirname, "../fixtures/child-process-message-and-exit.js")); + + let gotMessage = false; + let gotExit = false; + let gotClose = false; + + const messagePromise = new Promise(resolve => { + cp.on("message", message => { + expect(gotMessage).toBe(false); + expect(gotClose).toBe(false); + expect(message).toBe("hello"); + gotMessage = true; + resolve(); + }); + }); + + const exitPromise = new Promise(resolve => { + cp.on("exit", () => { + expect(gotExit).toBe(false); + expect(gotClose).toBe(false); + gotExit = true; + resolve(); + }); + }); + + const closePromise = new Promise(resolve => { + cp.on("close", () => { + expect(gotMessage).toBe(true); + expect(gotExit).toBe(true); + expect(gotClose).toBe(false); + gotClose = true; + resolve(); + }); + }); + + await Promise.all([messagePromise, exitPromise, closePromise]); +}); + +//<#END_FILE: test-child-process-fork-close.js diff --git a/test/js/node/test/parallel/child-process-fork-detached.test.js b/test/js/node/test/parallel/child-process-fork-detached.test.js new file mode 100644 index 0000000000..18c3f6a0cb --- /dev/null +++ b/test/js/node/test/parallel/child-process-fork-detached.test.js @@ -0,0 +1,31 @@ +//#FILE: test-child-process-fork-detached.js +//#SHA1: 289d7a5f7c5d58ae50a06e7427730c57d78fe39c +//----------------- +"use strict"; + +const { fork } = require("child_process"); +const path = require("path"); + +const fixturesPath = path.resolve(__dirname, "..", "fixtures"); + +test("fork detached child process", done => { + const nonPersistentNode = fork(path.join(fixturesPath, "parent-process-nonpersistent-fork.js"), [], { silent: true }); + + let childId = -1; + + nonPersistentNode.stdout.on("data", data => { + childId = parseInt(data, 10); + nonPersistentNode.kill(); + }); + + nonPersistentNode.on("exit", () => { + expect(childId).not.toBe(-1); + + // Killing the child process should not throw an error + expect(() => process.kill(childId)).not.toThrow(); + + done(); + }); +}); + +//<#END_FILE: test-child-process-fork-detached.js diff --git a/test/js/node/test/parallel/crypto-keygen-async-encrypted-private-key-der.test.js b/test/js/node/test/parallel/crypto-keygen-async-encrypted-private-key-der.test.js new file mode 100644 index 0000000000..01e5b30494 --- /dev/null +++ b/test/js/node/test/parallel/crypto-keygen-async-encrypted-private-key-der.test.js @@ -0,0 +1,54 @@ +//#FILE: test-crypto-keygen-async-encrypted-private-key-der.js +//#SHA1: 30f86c68619f3f24294d5f062eed48b13c116b0c +//----------------- +"use strict"; + +const crypto = require("crypto"); +const { assertApproximateSize, testEncryptDecrypt, testSignVerify } = require("../common/crypto"); + +// Test async RSA key generation with an encrypted private key, but encoded as DER. +test("RSA key generation with encrypted private key (DER)", async () => { + const { publicKey: publicKeyDER, privateKey: privateKeyDER } = await new Promise((resolve, reject) => { + crypto.generateKeyPair( + "rsa", + { + publicExponent: 0x10001, + modulusLength: 512, + publicKeyEncoding: { + type: "pkcs1", + format: "der", + }, + privateKeyEncoding: { + type: "pkcs8", + format: "der", + }, + }, + (err, publicKey, privateKey) => { + if (err) reject(err); + else resolve({ publicKey, privateKey }); + }, + ); + }); + + expect(Buffer.isBuffer(publicKeyDER)).toBe(true); + assertApproximateSize(publicKeyDER, 74); + + expect(Buffer.isBuffer(privateKeyDER)).toBe(true); + + const publicKey = { + key: publicKeyDER, + type: "pkcs1", + format: "der", + }; + const privateKey = { + key: privateKeyDER, + format: "der", + type: "pkcs8", + passphrase: "secret", + }; + + await testEncryptDecrypt(publicKey, privateKey); + await testSignVerify(publicKey, privateKey); +}); + +//<#END_FILE: test-crypto-keygen-async-encrypted-private-key-der.js diff --git a/test/js/node/test/parallel/crypto-keygen-async-explicit-elliptic-curve.test.js b/test/js/node/test/parallel/crypto-keygen-async-explicit-elliptic-curve.test.js new file mode 100644 index 0000000000..4d6f637147 --- /dev/null +++ b/test/js/node/test/parallel/crypto-keygen-async-explicit-elliptic-curve.test.js @@ -0,0 +1,50 @@ +//#FILE: test-crypto-keygen-async-explicit-elliptic-curve.js +//#SHA1: be1eabf816f52e5f53cb2535d47050b2552d21cd +//----------------- +"use strict"; + +const crypto = require("crypto"); + +// Skip the test if crypto support is not available +if (!crypto.generateKeyPair) { + test.skip("missing crypto support", () => {}); +} else { + const { generateKeyPair } = crypto; + + const { testSignVerify, spkiExp, sec1Exp } = require("../common/crypto"); + + // Test async explicit elliptic curve key generation, e.g. for ECDSA, + // with a SEC1 private key with paramEncoding explicit. + test("async explicit elliptic curve key generation", async () => { + await new Promise((resolve, reject) => { + generateKeyPair( + "ec", + { + namedCurve: "prime256v1", + paramEncoding: "explicit", + publicKeyEncoding: { + type: "spki", + format: "pem", + }, + privateKeyEncoding: { + type: "sec1", + format: "pem", + }, + }, + (err, publicKey, privateKey) => { + if (err) reject(err); + else resolve({ publicKey, privateKey }); + }, + ); + }).then(({ publicKey, privateKey }) => { + expect(typeof publicKey).toBe("string"); + expect(publicKey).toMatch(spkiExp); + expect(typeof privateKey).toBe("string"); + expect(privateKey).toMatch(sec1Exp); + + return testSignVerify(publicKey, privateKey); + }); + }); +} + +//<#END_FILE: test-crypto-keygen-async-explicit-elliptic-curve.js diff --git a/test/js/node/test/parallel/crypto-keygen-async-named-elliptic-curve.test.js b/test/js/node/test/parallel/crypto-keygen-async-named-elliptic-curve.test.js new file mode 100644 index 0000000000..8721a4551f --- /dev/null +++ b/test/js/node/test/parallel/crypto-keygen-async-named-elliptic-curve.test.js @@ -0,0 +1,51 @@ +//#FILE: test-crypto-keygen-async-named-elliptic-curve.js +//#SHA1: 77822175b9b2c2206ec4ab8a3e1182e3576b23bd +//----------------- +"use strict"; + +const crypto = require("crypto"); +const { testSignVerify } = require("../common/crypto"); + +if (!crypto.generateKeyPair) { + test.skip("missing crypto.generateKeyPair"); +} + +const spkiExp = + /^-----BEGIN PUBLIC KEY-----\n(?:[A-Za-z0-9+/=]{64}\n)*[A-Za-z0-9+/=]{1,64}\n-----END PUBLIC KEY-----\n$/; +const sec1Exp = + /^-----BEGIN EC PRIVATE KEY-----\n(?:[A-Za-z0-9+/=]{64}\n)*[A-Za-z0-9+/=]{1,64}\n-----END EC PRIVATE KEY-----\n$/; + +// Test async named elliptic curve key generation, e.g. for ECDSA, +// with a SEC1 private key. +test("async named elliptic curve key generation with SEC1 private key", async () => { + const { publicKey, privateKey } = await new Promise((resolve, reject) => { + crypto.generateKeyPair( + "ec", + { + namedCurve: "prime256v1", + paramEncoding: "named", + publicKeyEncoding: { + type: "spki", + format: "pem", + }, + privateKeyEncoding: { + type: "sec1", + format: "pem", + }, + }, + (err, publicKey, privateKey) => { + if (err) reject(err); + else resolve({ publicKey, privateKey }); + }, + ); + }); + + expect(typeof publicKey).toBe("string"); + expect(publicKey).toMatch(spkiExp); + expect(typeof privateKey).toBe("string"); + expect(privateKey).toMatch(sec1Exp); + + await testSignVerify(publicKey, privateKey); +}); + +//<#END_FILE: test-crypto-keygen-async-named-elliptic-curve.js diff --git a/test/js/node/test/parallel/crypto-keygen-missing-oid.test.js b/test/js/node/test/parallel/crypto-keygen-missing-oid.test.js new file mode 100644 index 0000000000..b91248c3a6 --- /dev/null +++ b/test/js/node/test/parallel/crypto-keygen-missing-oid.test.js @@ -0,0 +1,55 @@ +//#FILE: test-crypto-keygen-missing-oid.js +//#SHA1: ffcbc53b115cce8795ca1a0e73a533b04789a930 +//----------------- +"use strict"; + +const { generateKeyPair, generateKeyPairSync, getCurves } = require("crypto"); + +// This test creates EC key pairs on curves without associated OIDs. +// Specifying a key encoding should not crash. +test("EC key pairs on curves without associated OIDs", () => { + if (process.versions.openssl >= "1.1.1i") { + const curves = ["Oakley-EC2N-3", "Oakley-EC2N-4"]; + const availableCurves = getCurves(); + + for (const namedCurve of curves) { + if (!availableCurves.includes(namedCurve)) continue; + + const expectedErrorCode = process.versions.openssl.startsWith("3.") + ? "ERR_OSSL_MISSING_OID" + : "ERR_OSSL_EC_MISSING_OID"; + + const params = { + namedCurve, + publicKeyEncoding: { + format: "der", + type: "spki", + }, + }; + + expect(() => { + generateKeyPairSync("ec", params); + }).toThrow( + expect.objectContaining({ + code: expectedErrorCode, + message: expect.any(String), + }), + ); + + return new Promise(resolve => { + generateKeyPair("ec", params, err => { + expect(err).toMatchObject({ + code: expectedErrorCode, + message: expect.any(String), + }); + resolve(); + }); + }); + } + } else { + // Skip test if OpenSSL version is less than 1.1.1i + test.skip("OpenSSL version is less than 1.1.1i"); + } +}); + +//<#END_FILE: test-crypto-keygen-missing-oid.js diff --git a/test/js/node/test/parallel/crypto-keygen-sync.test.js b/test/js/node/test/parallel/crypto-keygen-sync.test.js new file mode 100644 index 0000000000..26d3a218fb --- /dev/null +++ b/test/js/node/test/parallel/crypto-keygen-sync.test.js @@ -0,0 +1,50 @@ +//#FILE: test-crypto-keygen-sync.js +//#SHA1: 57749dc903b0d5f9b64a3d61f313be6e5549323f +//----------------- +"use strict"; + +const crypto = require("crypto"); +const { + assertApproximateSize, + testEncryptDecrypt, + testSignVerify, + pkcs1PubExp, + pkcs8Exp, +} = require("../common/crypto"); + +// Skip the test if crypto support is not available +if (typeof crypto.generateKeyPairSync !== "function") { + test.skip("missing crypto support", () => {}); +} else { + // To make the test faster, we will only test sync key generation once and + // with a relatively small key. + test("generateKeyPairSync", () => { + const ret = crypto.generateKeyPairSync("rsa", { + publicExponent: 3, + modulusLength: 512, + publicKeyEncoding: { + type: "pkcs1", + format: "pem", + }, + privateKeyEncoding: { + type: "pkcs8", + format: "pem", + }, + }); + + expect(Object.keys(ret)).toHaveLength(2); + const { publicKey, privateKey } = ret; + + expect(typeof publicKey).toBe("string"); + expect(publicKey).toMatch(pkcs1PubExp); + assertApproximateSize(publicKey, 162); + expect(typeof privateKey).toBe("string"); + expect(privateKey).toMatch(pkcs8Exp); + assertApproximateSize(privateKey, 512); + + testEncryptDecrypt(publicKey, privateKey); + testSignVerify(publicKey, privateKey); + }); +} + +//<#END_FILE: test-crypto-keygen-sync.js diff --git a/test/js/node/test/parallel/fs-promises-readfile-empty.test.js b/test/js/node/test/parallel/fs-promises-readfile-empty.test.js new file mode 100644 index 0000000000..dc9d291e5f --- /dev/null +++ b/test/js/node/test/parallel/fs-promises-readfile-empty.test.js @@ -0,0 +1,27 @@ +//#FILE: test-fs-promises-readfile-empty.js +//#SHA1: 6fcec9b5d3c9617426d46c79fb79244bc236574b +//----------------- +"use strict"; + +const fs = require("fs").promises; +const path = require("path"); + +const fixturesPath = path.resolve(__dirname, "..", "fixtures"); +const fn = path.join(fixturesPath, "empty.txt"); + +test("fs.readFile on empty file", async () => { + const content = await fs.readFile(fn); + expect(content).toBeTruthy(); +}); + +test("fs.readFile on empty file with utf8 encoding", async () => { + const content = await fs.readFile(fn, "utf8"); + expect(content).toBe(""); +}); + +test("fs.readFile on empty file with options object", async () => { + const content = await fs.readFile(fn, { encoding: "utf8" }); + expect(content).toBe(""); +}); + +//<#END_FILE: test-fs-promises-readfile-empty.js diff --git a/test/js/node/test/parallel/fs-read-stream-fd-leak.test.js b/test/js/node/test/parallel/fs-read-stream-fd-leak.test.js new file mode 100644 index 0000000000..5c4e0dd55b --- /dev/null +++ b/test/js/node/test/parallel/fs-read-stream-fd-leak.test.js @@ -0,0 +1,66 @@ +//#FILE: test-fs-read-stream-fd-leak.js +//#SHA1: fc07b42f524d6a2f9743a5a7665c92096f58505b +//----------------- +"use strict"; + +const fs = require("fs"); +const path = require("path"); + +let openCount = 0; +const _fsopen = fs.open; +const _fsclose = fs.close; + +const loopCount = 50; +const totalCheck = 50; +const emptyTxt = path.join(__dirname, "../fixtures/empty.txt"); + +fs.open = function () { + openCount++; + return _fsopen.apply(null, arguments); +}; + +fs.close = function () { + openCount--; + return _fsclose.apply(null, arguments); +}; + +function testLeak(endFn) { + return new Promise(resolve => { + console.log(`testing for leaks from fs.createReadStream().${endFn}()...`); + + let i = 0; + let check = 0; + + function checkFunction() { + if (openCount !== 0 && check < totalCheck) { + check++; + setTimeout(checkFunction, 100); + return; + } + + expect(openCount).toBe(0); + openCount = 0; + resolve(); + } + + const interval = setInterval(() => { + const s = fs.createReadStream(emptyTxt); + s[endFn](); + + if (++i === loopCount) { + clearInterval(interval); + setTimeout(checkFunction, 100); + } + }, 2); + }); +} + +test("no leaked file descriptors using close()", async () => { + await testLeak("close"); +}, 10000); + +test("no leaked file descriptors using destroy()", async () => { + await testLeak("destroy"); +}, 10000); + +//<#END_FILE: test-fs-read-stream-fd-leak.js diff --git a/test/js/node/test/parallel/heap-prof-exec-argv.test.js b/test/js/node/test/parallel/heap-prof-exec-argv.test.js new file mode 100644 index 0000000000..aa64858dbb --- /dev/null +++ b/test/js/node/test/parallel/heap-prof-exec-argv.test.js @@ -0,0 +1,43 @@ +//#FILE: test-heap-prof-exec-argv.js +//#SHA1: 77c3a447116b06f03f52fd56efe928699ba6d60d +//----------------- +"use strict"; + +// Tests --heap-prof generates a heap profile from worker +// when execArgv is set. + +const fixtures = require("../common/fixtures"); +const assert = require("assert"); +const { spawnSync } = require("child_process"); +const tmpdir = require("../common/tmpdir"); +const { getHeapProfiles, verifyFrames } = require("../common/prof"); + +// Skip the test if inspector is disabled +const isInspectorEnabled = process.execArgv.some(arg => arg.startsWith("--inspect")); +if (!isInspectorEnabled) { + test.skip("Inspector is disabled", () => {}); +} else { + test("--heap-prof generates a heap profile from worker when execArgv is set", () => { + tmpdir.refresh(); + const output = spawnSync(process.execPath, [fixtures.path("workload", "allocation-worker-argv.js")], { + cwd: tmpdir.path, + env: { + ...process.env, + HEAP_PROF_INTERVAL: "128", + }, + }); + + if (output.status !== 0) { + console.log(output.stderr.toString()); + } + + expect(output.status).toBe(0); + + const profiles = getHeapProfiles(tmpdir.path); + expect(profiles.length).toBe(1); + + verifyFrames(output, profiles[0], "runAllocation"); + }); +} + +//<#END_FILE: test-heap-prof-exec-argv.js diff --git a/test/js/node/test/parallel/http-get-pipeline-problem.test.js b/test/js/node/test/parallel/http-get-pipeline-problem.test.js new file mode 100644 index 0000000000..ec0750f018 --- /dev/null +++ b/test/js/node/test/parallel/http-get-pipeline-problem.test.js @@ -0,0 +1,98 @@ +//#FILE: test-http-get-pipeline-problem.js +//#SHA1: 422a6c8ae8350bb70627efee734652421322b1bd +//----------------- +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +"use strict"; +// In previous versions of Node.js (e.g., 0.6.0), this sort of thing would halt +// after http.globalAgent.maxSockets number of files. +// See https://groups.google.com/forum/#!topic/nodejs-dev/V5fB69hFa9o +const fixtures = require("../common/fixtures"); +const http = require("http"); +const fs = require("fs"); +const tmpdir = require("../common/tmpdir"); + +http.globalAgent.maxSockets = 1; + +tmpdir.refresh(); + +const image = fixtures.readSync("/person.jpg"); + +console.log(`image.length = ${image.length}`); + +const total = 10; + +test("HTTP GET pipeline problem", async () => { + const server = http.createServer((req, res) => { + setTimeout(() => { + res.writeHead(200, { + "content-type": "image/jpeg", + connection: "close", + "content-length": image.length, + }); + res.end(image); + }, 1); + }); + + await new Promise(resolve => server.listen(0, resolve)); + + const serverAddress = server.address(); + + const requests = Array.from({ length: total }, (_, i) => { + return new Promise((resolve, reject) => { + const opts = { + port: serverAddress.port, + headers: { connection: "close" }, + }; + + http + .get(opts, res => { + console.error(`recv ${i}`); + const s = fs.createWriteStream(`${tmpdir.path}/${i}.jpg`); + res.pipe(s); + + s.on("finish", () => { + console.error(`done ${i}`); + resolve(); + }); + }) + .on("error", reject); + }); + }); + + await Promise.all(requests); + + // Check files + const files = fs.readdirSync(tmpdir.path); + expect(files.length).toBeGreaterThanOrEqual(total); + + for (let i = 0; i < total; i++) { + const fn = `${i}.jpg`; + expect(files).toContain(fn); + const stat = fs.statSync(`${tmpdir.path}/${fn}`); + expect(stat.size).toBe(image.length); + } + + server.close(); +}); + +//<#END_FILE: test-http-get-pipeline-problem.js diff --git a/test/js/node/test/parallel/http-url.parse-https.request.test.js b/test/js/node/test/parallel/http-url.parse-https.request.test.js new file mode 100644 index 0000000000..6b8a992569 --- /dev/null +++ b/test/js/node/test/parallel/http-url.parse-https.request.test.js @@ -0,0 +1,81 @@ +//#FILE: test-http-url.parse-https.request.js +//#SHA1: e9b9e39f28d5d2633f9444150977b748bc8995cb +//----------------- +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +"use strict"; + +const https = require("https"); +const url = require("url"); +const { readKey } = require("../common/fixtures"); + +let common; +try { + common = require("../common"); +} catch (e) { + // For Bun compatibility + common = { + hasCrypto: true, + skip: console.log, + }; +} + +if (!common.hasCrypto) { + common.skip("missing crypto"); + process.exit(0); +} + +// https options +const httpsOptions = { + key: readKey("agent1-key.pem"), + cert: readKey("agent1-cert.pem"), +}; + +function check(request) { + // Assert that I'm https + expect(request.socket._secureEstablished).toBeTruthy(); +} + +test("HTTPS request with URL object", done => { + const server = https.createServer(httpsOptions, function (request, response) { + // Run the check function + check(request); + response.writeHead(200, {}); + response.end("ok"); + server.close(); + }); + + server.listen(0, function () { + const testURL = url.parse(`https://localhost:${this.address().port}`); + testURL.rejectUnauthorized = false; + + // make the request + const clientRequest = https.request(testURL); + // Since there is a little magic with the agent + // make sure that the request uses the https.Agent + expect(clientRequest.agent).toBeInstanceOf(https.Agent); + clientRequest.end(); + done(); + }); +}); + +//<#END_FILE: test-http-url.parse-https.request.js diff --git a/test/js/node/test/parallel/https-agent.test.js b/test/js/node/test/parallel/https-agent.test.js new file mode 100644 index 0000000000..31b1e0ee25 --- /dev/null +++ b/test/js/node/test/parallel/https-agent.test.js @@ -0,0 +1,106 @@ +//#FILE: test-https-agent.js +//#SHA1: 1348abc863ae99725dd893838c95b42c5120a052 +//----------------- +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +"use strict"; + +const https = require("https"); +const { readKey } = require("../common/fixtures"); + +const options = { + key: readKey("agent1-key.pem"), + cert: readKey("agent1-cert.pem"), +}; + +const N = 4; +const M = 4; + +let server; +let responses = 0; + +beforeAll(() => { + if (!process.versions.openssl) { + return test.skip("missing crypto"); + } +}); + +beforeEach(() => { + return new Promise(resolve => { + server = https.createServer(options, (req, res) => { + res.writeHead(200); + res.end("hello world\n"); + }); + + server.listen(0, () => { + resolve(); + }); + }); +}); + +afterEach(() => { + return new Promise(resolve => { + server.close(() => { + resolve(); + }); + }); +}); + +test("HTTPS Agent handles multiple concurrent requests", async () => { + const makeRequests = i => { + return new Promise(resolve => { + setTimeout(() => { + const requests = Array.from( + { length: M }, + () => + new Promise(innerResolve => { + https + .get( + { + path: "/", + port: server.address().port, + rejectUnauthorized: false, + }, + function (res) { + res.resume(); + expect(res.statusCode).toBe(200); + responses++; + innerResolve(); + }, + ) + .on("error", e => { + throw e; + }); + }), + ); + Promise.all(requests).then(resolve); + }, i); + }); + }; + + const allRequests = Array.from({ length: N }, (_, i) => makeRequests(i)); + await Promise.all(allRequests); + + expect(responses).toBe(N * M); +}); + +//<#END_FILE: test-https-agent.js diff --git a/test/js/node/test/parallel/https-byteswritten.test.js b/test/js/node/test/parallel/https-byteswritten.test.js new file mode 100644 index 0000000000..c695fa7027 --- /dev/null +++ b/test/js/node/test/parallel/https-byteswritten.test.js @@ -0,0 +1,58 @@ +//#FILE: test-https-byteswritten.js +//#SHA1: 8b808da3e55de553190426095aee298ec7d5df36 +//----------------- +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +"use strict"; +const fixtures = require("../common/fixtures"); +const https = require("https"); + +const options = { + key: fixtures.readKey("agent1-key.pem"), + cert: fixtures.readKey("agent1-cert.pem"), +}; + +const body = "hello world\n"; + +test("HTTPS server bytesWritten", async () => { + const httpsServer = https.createServer(options, (req, res) => { + res.on("finish", () => { + expect(typeof req.connection.bytesWritten).toBe("number"); + expect(req.connection.bytesWritten).toBeGreaterThan(0); + httpsServer.close(); + }); + res.writeHead(200, { "Content-Type": "text/plain" }); + res.end(body); + }); + + await new Promise(resolve => { + httpsServer.listen(0, () => { + https.get({ + port: httpsServer.address().port, + rejectUnauthorized: false, + }); + resolve(); + }); + }); +}); + +//<#END_FILE: test-https-byteswritten.js diff --git a/test/js/node/test/parallel/https-foafssl.test.js b/test/js/node/test/parallel/https-foafssl.test.js new file mode 100644 index 0000000000..aac467af04 --- /dev/null +++ b/test/js/node/test/parallel/https-foafssl.test.js @@ -0,0 +1,114 @@ +//#FILE: test-https-foafssl.js +//#SHA1: 07ac711f5948207540af7366d06803f2675f04c7 +//----------------- +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +"use strict"; + +const { skip } = require("../common"); +const fixtures = require("../common/fixtures"); +const https = require("https"); +const { spawn } = require("child_process"); + +if (!process.versions.openssl) { + skip("missing crypto"); +} + +if (!process.env.NODE_OPENSSL_CERT) { + skip("node compiled without OpenSSL CLI."); +} + +const options = { + key: fixtures.readKey("rsa_private.pem"), + cert: fixtures.readKey("rsa_cert.crt"), + requestCert: true, + rejectUnauthorized: false, +}; + +const webIdUrl = "URI:http://example.com/#me"; +const modulus = fixtures.readKey("rsa_cert_foafssl_b.modulus", "ascii").replace(/\n/g, ""); +const exponent = fixtures.readKey("rsa_cert_foafssl_b.exponent", "ascii").replace(/\n/g, ""); + +const CRLF = "\r\n"; +const body = "hello world\n"; +let cert; + +test("HTTPS FOAFSSL", async () => { + const serverHandler = jest.fn((req, res) => { + console.log("got request"); + + cert = req.connection.getPeerCertificate(); + + expect(cert.subjectaltname).toBe(webIdUrl); + expect(cert.exponent).toBe(exponent); + expect(cert.modulus).toBe(modulus); + res.writeHead(200, { "content-type": "text/plain" }); + res.end(body, () => { + console.log("stream finished"); + }); + console.log("sent response"); + }); + + const server = https.createServer(options, serverHandler); + + await new Promise(resolve => { + server.listen(0, resolve); + }); + + const { port } = server.address(); + + const args = [ + "s_client", + "-quiet", + "-connect", + `127.0.0.1:${port}`, + "-cert", + fixtures.path("keys/rsa_cert_foafssl_b.crt"), + "-key", + fixtures.path("keys/rsa_private_b.pem"), + ]; + + const client = spawn(process.env.NODE_OPENSSL_CERT, args); + + client.stdout.on("data", data => { + console.log("response received"); + const message = data.toString(); + const contents = message.split(CRLF + CRLF).pop(); + expect(contents).toBe(body); + server.close(e => { + expect(e).toBeFalsy(); + console.log("server closed"); + }); + console.log("server.close() called"); + }); + + client.stdin.write("GET /\r\n\r\n"); + + await new Promise((resolve, reject) => { + client.on("error", reject); + client.on("close", resolve); + }); + + expect(serverHandler).toHaveBeenCalledTimes(1); +}); + +//<#END_FILE: test-https-foafssl.js diff --git a/test/js/node/test/parallel/https-socket-options.test.js b/test/js/node/test/parallel/https-socket-options.test.js new file mode 100644 index 0000000000..5e325acc5d --- /dev/null +++ b/test/js/node/test/parallel/https-socket-options.test.js @@ -0,0 +1,102 @@ +//#FILE: test-https-socket-options.js +//#SHA1: 8f63b3c65f69e8b766b159d148e681984c134477 +//----------------- +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +"use strict"; + +const fixtures = require("../common/fixtures"); +const https = require("https"); +const http = require("http"); + +const options = { + key: fixtures.readKey("agent1-key.pem"), + cert: fixtures.readKey("agent1-cert.pem"), +}; + +const body = "hello world\n"; + +test("HTTP server socket options", async () => { + const server_http = http.createServer((req, res) => { + console.log("got HTTP request"); + res.writeHead(200, { "content-type": "text/plain" }); + res.end(body); + }); + + await new Promise(resolve => { + server_http.listen(0, () => { + const req = http.request( + { + port: server_http.address().port, + rejectUnauthorized: false, + }, + res => { + server_http.close(); + res.resume(); + resolve(); + }, + ); + // These methods should exist on the request and get passed down to the socket + expect(req.setNoDelay).toBeDefined(); + expect(req.setTimeout).toBeDefined(); + expect(req.setSocketKeepAlive).toBeDefined(); + req.setNoDelay(true); + req.setTimeout(1000, () => {}); + req.setSocketKeepAlive(true, 1000); + req.end(); + }); + }); +}); + +test("HTTPS server socket options", async () => { + const server_https = https.createServer(options, (req, res) => { + console.log("got HTTPS request"); + res.writeHead(200, { "content-type": "text/plain" }); + res.end(body); + }); + + await new Promise(resolve => { + server_https.listen(0, () => { + const req = https.request( + { + port: server_https.address().port, + rejectUnauthorized: false, + }, + res => { + server_https.close(); + res.resume(); + resolve(); + }, + ); + // These methods should exist on the request and get passed down to the socket + expect(req.setNoDelay).toBeDefined(); + expect(req.setTimeout).toBeDefined(); + expect(req.setSocketKeepAlive).toBeDefined(); + req.setNoDelay(true); + req.setTimeout(1000, () => {}); + req.setSocketKeepAlive(true, 1000); + req.end(); + }); + }); +}); + +//<#END_FILE: test-https-socket-options.js diff --git a/test/js/node/test/parallel/jest.config.js b/test/js/node/test/parallel/jest.config.js new file mode 100644 index 0000000000..7f2c94ff64 --- /dev/null +++ b/test/js/node/test/parallel/jest.config.js @@ -0,0 +1,2 @@ +// So jest doesn't try to look up. +module.exports = {}; diff --git a/test/js/node/test/parallel/module-main-extension-lookup.test.js b/test/js/node/test/parallel/module-main-extension-lookup.test.js new file mode 100644 index 0000000000..741f721bc6 --- /dev/null +++ b/test/js/node/test/parallel/module-main-extension-lookup.test.js @@ -0,0 +1,23 @@ +//#FILE: test-module-main-extension-lookup.js +//#SHA1: d50be34ba21e1e14de5225ac5d93b6fe20505014 +//----------------- +"use strict"; + +const path = require("path"); +const { execFileSync } = require("child_process"); + +const node = process.argv[0]; + +test("ES modules extension lookup", () => { + const fixturesPath = path.resolve(__dirname, "..", "fixtures"); + + expect(() => { + execFileSync(node, [path.join(fixturesPath, "es-modules", "test-esm-ok.mjs")]); + }).not.toThrow(); + + expect(() => { + execFileSync(node, [path.join(fixturesPath, "es-modules", "noext")]); + }).not.toThrow(); +}); + +//<#END_FILE: test-module-main-extension-lookup.js diff --git a/test/js/node/test/parallel/net-autoselectfamily-attempt-timeout-default-value.test.js b/test/js/node/test/parallel/net-autoselectfamily-attempt-timeout-default-value.test.js new file mode 100644 index 0000000000..5b33636b4d --- /dev/null +++ b/test/js/node/test/parallel/net-autoselectfamily-attempt-timeout-default-value.test.js @@ -0,0 +1,13 @@ +//#FILE: test-net-autoselectfamily-attempt-timeout-default-value.js +//#SHA1: 028b16515c47d987e68ca138e753ed4d255f179c +//----------------- +"use strict"; + +const { platformTimeout } = require("../common"); +const { getDefaultAutoSelectFamilyAttemptTimeout } = require("net"); + +test("getDefaultAutoSelectFamilyAttemptTimeout returns the correct default value", () => { + expect(getDefaultAutoSelectFamilyAttemptTimeout()).toBe(platformTimeout(2500)); +}); + +//<#END_FILE: test-net-autoselectfamily-attempt-timeout-default-value.js diff --git a/test/js/node/test/parallel/process-chdir-errormessage.test.js b/test/js/node/test/parallel/process-chdir-errormessage.test.js new file mode 100644 index 0000000000..3703d4e1b9 --- /dev/null +++ b/test/js/node/test/parallel/process-chdir-errormessage.test.js @@ -0,0 +1,26 @@ +//#FILE: test-process-chdir-errormessage.js +//#SHA1: d0eee0a43892b20221d341b892fa425fe207c506 +//----------------- +"use strict"; + +// Skip test in workers where process.chdir is not available +if (typeof Worker !== "undefined") { + test.skip("process.chdir is not available in Workers"); +} else { + test("process.chdir throws correct error for non-existent directory", () => { + expect(() => { + process.chdir("does-not-exist"); + }).toThrow( + expect.objectContaining({ + name: "Error", + code: "ENOENT", + message: expect.stringMatching(/ENOENT: no such file or directory, chdir .+ -> 'does-not-exist'/), + path: process.cwd(), + syscall: "chdir", + dest: "does-not-exist", + }), + ); + }); +} + +//<#END_FILE: test-process-chdir-errormessage.js diff --git a/test/js/node/test/parallel/quic-internal-endpoint-options.test.js b/test/js/node/test/parallel/quic-internal-endpoint-options.test.js new file mode 100644 index 0000000000..9a5694dcfd --- /dev/null +++ b/test/js/node/test/parallel/quic-internal-endpoint-options.test.js @@ -0,0 +1,192 @@ +//#FILE: test-quic-internal-endpoint-options.js +//#SHA1: 089ba4358a2a9ed3c5463e59d205ee7854f26f30 +//----------------- +// Flags: --expose-internals +"use strict"; + +const common = require("../common"); +if (!common.hasQuic) common.skip("missing quic"); + +const { internalBinding } = require("internal/test/binding"); +const quic = internalBinding("quic"); + +quic.setCallbacks({ + onEndpointClose() {}, + onSessionNew() {}, + onSessionClose() {}, + onSessionDatagram() {}, + onSessionDatagramStatus() {}, + onSessionHandshake() {}, + onSessionPathValidation() {}, + onSessionTicket() {}, + onSessionVersionNegotiation() {}, + onStreamCreated() {}, + onStreamBlocked() {}, + onStreamClose() {}, + onStreamReset() {}, + onStreamHeaders() {}, + onStreamTrailers() {}, +}); + +test("Invalid Endpoint constructor arguments", () => { + expect(() => new quic.Endpoint()).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + message: expect.any(String), + }), + ); + + expect(() => new quic.Endpoint("a")).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + message: expect.any(String), + }), + ); + + expect(() => new quic.Endpoint(null)).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + message: expect.any(String), + }), + ); + + expect(() => new quic.Endpoint(false)).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + message: expect.any(String), + }), + ); +}); + +test("Default options work", () => { + expect(() => new quic.Endpoint({})).not.toThrow(); +}); + +const cases = [ + { + key: "retryTokenExpiration", + valid: [1, 10, 100, 1000, 10000, 10000n], + invalid: [-1, -1n, "a", null, false, true, {}, [], () => {}], + }, + { + key: "tokenExpiration", + valid: [1, 10, 100, 1000, 10000, 10000n], + invalid: [-1, -1n, "a", null, false, true, {}, [], () => {}], + }, + { + key: "maxConnectionsPerHost", + valid: [1, 10, 100, 1000, 10000, 10000n], + invalid: [-1, -1n, "a", null, false, true, {}, [], () => {}], + }, + { + key: "maxConnectionsTotal", + valid: [1, 10, 100, 1000, 10000, 10000n], + invalid: [-1, -1n, "a", null, false, true, {}, [], () => {}], + }, + { + key: "maxStatelessResetsPerHost", + valid: [1, 10, 100, 1000, 10000, 10000n], + invalid: [-1, -1n, "a", null, false, true, {}, [], () => {}], + }, + { + key: "addressLRUSize", + valid: [1, 10, 100, 1000, 10000, 10000n], + invalid: [-1, -1n, "a", null, false, true, {}, [], () => {}], + }, + { + key: "maxRetries", + valid: [1, 10, 100, 1000, 10000, 10000n], + invalid: [-1, -1n, "a", null, false, true, {}, [], () => {}], + }, + { + key: "maxPayloadSize", + valid: [1, 10, 100, 1000, 10000, 10000n], + invalid: [-1, -1n, "a", null, false, true, {}, [], () => {}], + }, + { + key: "unacknowledgedPacketThreshold", + valid: [1, 10, 100, 1000, 10000, 10000n], + invalid: [-1, -1n, "a", null, false, true, {}, [], () => {}], + }, + { + key: "validateAddress", + valid: [true, false, 0, 1, "a"], + invalid: [], + }, + { + key: "disableStatelessReset", + valid: [true, false, 0, 1, "a"], + invalid: [], + }, + { + key: "ipv6Only", + valid: [true, false, 0, 1, "a"], + invalid: [], + }, + { + key: "cc", + valid: [ + quic.CC_ALGO_RENO, + quic.CC_ALGO_CUBIC, + quic.CC_ALGO_BBR, + quic.CC_ALGO_BBR2, + quic.CC_ALGO_RENO_STR, + quic.CC_ALGO_CUBIC_STR, + quic.CC_ALGO_BBR_STR, + quic.CC_ALGO_BBR2_STR, + ], + invalid: [-1, 4, 1n, "a", null, false, true, {}, [], () => {}], + }, + { + key: "udpReceiveBufferSize", + valid: [0, 1, 2, 3, 4, 1000], + invalid: [-1, "a", null, false, true, {}, [], () => {}], + }, + { + key: "udpSendBufferSize", + valid: [0, 1, 2, 3, 4, 1000], + invalid: [-1, "a", null, false, true, {}, [], () => {}], + }, + { + key: "udpTTL", + valid: [0, 1, 2, 3, 4, 255], + invalid: [-1, 256, "a", null, false, true, {}, [], () => {}], + }, + { + key: "resetTokenSecret", + valid: [new Uint8Array(16), new Uint16Array(8), new Uint32Array(4)], + invalid: ["a", null, false, true, {}, [], () => {}, new Uint8Array(15), new Uint8Array(17), new ArrayBuffer(16)], + }, + { + key: "tokenSecret", + valid: [new Uint8Array(16), new Uint16Array(8), new Uint32Array(4)], + invalid: ["a", null, false, true, {}, [], () => {}, new Uint8Array(15), new Uint8Array(17), new ArrayBuffer(16)], + }, + { + // Unknown options are ignored entirely for any value type + key: "ignored", + valid: ["a", null, false, true, {}, [], () => {}], + invalid: [], + }, +]; + +for (const { key, valid, invalid } of cases) { + describe(`Endpoint option: ${key}`, () => { + test.each(valid)("valid value: %p", value => { + const options = { [key]: value }; + expect(() => new quic.Endpoint(options)).not.toThrow(); + }); + + test.each(invalid)("invalid value: %p", value => { + const options = { [key]: value }; + expect(() => new quic.Endpoint(options)).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_VALUE", + message: expect.any(String), + }), + ); + }); + }); +} + +//<#END_FILE: test-quic-internal-endpoint-options.js diff --git a/test/js/node/test/parallel/require-empty-main.test.js b/test/js/node/test/parallel/require-empty-main.test.js new file mode 100644 index 0000000000..93e53d4aed --- /dev/null +++ b/test/js/node/test/parallel/require-empty-main.test.js @@ -0,0 +1,31 @@ +//#FILE: test-require-empty-main.js +//#SHA1: 1c03cef0482df2bd119e42f418f54123675b532d +//----------------- +"use strict"; + +const path = require("path"); +const fixtures = require("../common/fixtures"); + +const where = fixtures.path("require-empty-main"); +const expected = path.join(where, "index.js"); + +const testRequireResolve = () => { + expect(require.resolve(where)).toBe(expected); + expect(require(where)).toBe(42); + expect(require.resolve(where)).toBe(expected); +}; + +test('A package.json with an empty "main" property should use index.js if present', testRequireResolve); + +test("require.resolve() should resolve to index.js for the same reason", testRequireResolve); + +test('Any "main" property that doesn\'t resolve to a file should result in index.js being used', testRequireResolve); + +test("Asynchronous test execution", done => { + setImmediate(() => { + testRequireResolve(); + done(); + }); +}); + +//<#END_FILE: test-require-empty-main.js diff --git a/test/js/node/test/parallel/require-extensions-main.test.js b/test/js/node/test/parallel/require-extensions-main.test.js new file mode 100644 index 0000000000..47dee39446 --- /dev/null +++ b/test/js/node/test/parallel/require-extensions-main.test.js @@ -0,0 +1,15 @@ +//#FILE: test-require-extensions-main.js +//#SHA1: c3dd50393bbc3eb542e40c67611fc48707ad3cba +//----------------- +"use strict"; + +const path = require("path"); + +test("require extensions main", () => { + const fixturesPath = path.join(__dirname, "..", "fixtures"); + const fixturesRequire = require(path.join(fixturesPath, "require-bin", "bin", "req.js")); + + expect(fixturesRequire).toBe(""); +}); + +//<#END_FILE: test-require-extensions-main.js diff --git a/test/js/node/test/parallel/signal-unregister.test.js b/test/js/node/test/parallel/signal-unregister.test.js new file mode 100644 index 0000000000..0f7b55ce66 --- /dev/null +++ b/test/js/node/test/parallel/signal-unregister.test.js @@ -0,0 +1,27 @@ +//#FILE: test-signal-unregister.js +//#SHA1: 44f7b12e1cb3d5e2bc94cb244f52d5a6a591d8f4 +//----------------- +"use strict"; + +const { spawn } = require("child_process"); +const path = require("path"); + +const fixturesPath = path.resolve(__dirname, "..", "fixtures"); + +test("Child process exits on SIGINT", () => { + const child = spawn(process.argv[0], [path.join(fixturesPath, "should_exit.js")]); + + return new Promise(resolve => { + child.stdout.once("data", () => { + child.kill("SIGINT"); + }); + + child.on("exit", (exitCode, signalCode) => { + expect(exitCode).toBeNull(); + expect(signalCode).toBe("SIGINT"); + resolve(); + }); + }); +}); + +//<#END_FILE: test-signal-unregister.js diff --git a/test/js/node/test/parallel/stream-preprocess.test.js b/test/js/node/test/parallel/stream-preprocess.test.js new file mode 100644 index 0000000000..8c5dd3cc8a --- /dev/null +++ b/test/js/node/test/parallel/stream-preprocess.test.js @@ -0,0 +1,68 @@ +//#FILE: test-stream-preprocess.js +//#SHA1: 4061428f95671f257c4a57a92d77c0dc63a1394a +//----------------- +"use strict"; + +const fs = require("fs"); +const rl = require("readline"); +const fixtures = require("../common/fixtures"); + +const BOM = "\uFEFF"; + +// Get the data using a non-stream way to compare with the streamed data. +const modelData = fixtures.readSync("file-to-read-without-bom.txt", "utf8"); +const modelDataFirstCharacter = modelData[0]; + +// Detect the number of forthcoming 'line' events for mustCall() 'expected' arg. +const lineCount = modelData.match(/\n/g).length; + +test("Ensure both without-bom and with-bom test files are textwise equal", () => { + expect(fixtures.readSync("file-to-read-with-bom.txt", "utf8")).toBe(`${BOM}${modelData}`); +}); + +test("An unjustified BOM stripping with a non-BOM character unshifted to a stream", done => { + const inputWithoutBOM = fs.createReadStream(fixtures.path("file-to-read-without-bom.txt"), "utf8"); + + inputWithoutBOM.once("readable", () => { + const maybeBOM = inputWithoutBOM.read(1); + expect(maybeBOM).toBe(modelDataFirstCharacter); + expect(maybeBOM).not.toBe(BOM); + + inputWithoutBOM.unshift(maybeBOM); + + let streamedData = ""; + rl.createInterface({ + input: inputWithoutBOM, + }) + .on("line", line => { + streamedData += `${line}\n`; + }) + .on("close", () => { + expect(streamedData).toBe(modelData); + done(); + }); + }); +}); + +test("A justified BOM stripping", done => { + const inputWithBOM = fs.createReadStream(fixtures.path("file-to-read-with-bom.txt"), "utf8"); + + inputWithBOM.once("readable", () => { + const maybeBOM = inputWithBOM.read(1); + expect(maybeBOM).toBe(BOM); + + let streamedData = ""; + rl.createInterface({ + input: inputWithBOM, + }) + .on("line", line => { + streamedData += `${line}\n`; + }) + .on("close", () => { + expect(streamedData).toBe(modelData); + done(); + }); + }); +}); + +//<#END_FILE: test-stream-preprocess.js diff --git a/test/js/node/test/parallel/tls-add-context.test.js b/test/js/node/test/parallel/tls-add-context.test.js new file mode 100644 index 0000000000..ca3d03c578 --- /dev/null +++ b/test/js/node/test/parallel/tls-add-context.test.js @@ -0,0 +1,93 @@ +//#FILE: test-tls-add-context.js +//#SHA1: 61f134fe8c8fb63a00278b2d70dfecf11efb5df9 +//----------------- +"use strict"; + +const crypto = require("crypto"); +const fixtures = require("../common/fixtures"); +const tls = require("tls"); + +// Skip test if crypto is not available +if (!crypto) { + test.skip("missing crypto", () => {}); +} else { + function loadPEM(n) { + return fixtures.readKey(`${n}.pem`); + } + + const serverOptions = { + key: loadPEM("agent2-key"), + cert: loadPEM("agent2-cert"), + ca: [loadPEM("ca2-cert")], + requestCert: true, + rejectUnauthorized: false, + }; + + let connections = 0; + + test("TLS add context", done => { + const server = tls.createServer(serverOptions, c => { + if (++connections === 3) { + server.close(); + } + if (c.servername === "unknowncontext") { + expect(c.authorized).toBe(false); + return; + } + expect(c.authorized).toBe(true); + }); + + const secureContext = { + key: loadPEM("agent1-key"), + cert: loadPEM("agent1-cert"), + ca: [loadPEM("ca1-cert")], + }; + server.addContext("context1", secureContext); + server.addContext("context2", tls.createSecureContext(secureContext)); + + const clientOptionsBase = { + key: loadPEM("agent1-key"), + cert: loadPEM("agent1-cert"), + ca: [loadPEM("ca1-cert")], + rejectUnauthorized: false, + }; + + server.listen(0, () => { + const client1 = tls.connect( + { + ...clientOptionsBase, + port: server.address().port, + servername: "context1", + }, + () => { + client1.end(); + }, + ); + + const client2 = tls.connect( + { + ...clientOptionsBase, + port: server.address().port, + servername: "context2", + }, + () => { + client2.end(); + }, + ); + + const client3 = tls.connect( + { + ...clientOptionsBase, + port: server.address().port, + servername: "unknowncontext", + }, + () => { + client3.end(); + done(); + }, + ); + }); + }); +} + +//<#END_FILE: test-tls-add-context.js diff --git a/test/js/node/test/parallel/tls-ca-concat.test.js b/test/js/node/test/parallel/tls-ca-concat.test.js new file mode 100644 index 0000000000..dcee3b9522 --- /dev/null +++ b/test/js/node/test/parallel/tls-ca-concat.test.js @@ -0,0 +1,39 @@ +//#FILE: test-tls-ca-concat.js +//#SHA1: 23b19f45d7777ee95a3c8d8ba4a727b149ea7409 +//----------------- +"use strict"; + +const fixtures = require("../common/fixtures"); + +// Check ca option can contain concatenated certs by prepending an unrelated +// non-CA cert and showing that agent6's CA root is still found. + +const { connect, keys } = require(fixtures.path("tls-connect")); + +test("ca option can contain concatenated certs", async () => { + await new Promise((resolve, reject) => { + connect( + { + client: { + checkServerIdentity: (servername, cert) => {}, + ca: `${keys.agent1.cert}\n${keys.agent6.ca}`, + }, + server: { + cert: keys.agent6.cert, + key: keys.agent6.key, + }, + }, + (err, pair, cleanup) => { + if (err) { + cleanup(); + reject(err); + } else { + cleanup(); + resolve(); + } + }, + ); + }); +}); + +//<#END_FILE: test-tls-ca-concat.js diff --git a/test/js/node/test/parallel/tls-client-abort.test.js b/test/js/node/test/parallel/tls-client-abort.test.js new file mode 100644 index 0000000000..4679c1f0e4 --- /dev/null +++ b/test/js/node/test/parallel/tls-client-abort.test.js @@ -0,0 +1,57 @@ +//#FILE: test-tls-client-abort.js +//#SHA1: e4f4d09f8de79ff5f4bdefcdaf1bbebb49f3cc16 +//----------------- +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +"use strict"; + +const tls = require("tls"); +const fs = require("fs"); +const path = require("path"); + +const hasCrypto = (() => { + try { + require("crypto"); + return true; + } catch { + return false; + } +})(); + +if (!hasCrypto) { + test.skip("missing crypto", () => {}); +} else { + test("TLS client abort", () => { + const cert = fs.readFileSync(path.join(__dirname, "..", "fixtures", "keys", "rsa_cert.crt")); + const key = fs.readFileSync(path.join(__dirname, "..", "fixtures", "keys", "rsa_private.pem")); + + const onConnect = jest.fn(); + const conn = tls.connect({ cert, key, port: 0 }, onConnect); + + conn.on("error", () => {}); // Expecting an error, but not testing its content + conn.destroy(); + + expect(onConnect).not.toHaveBeenCalled(); + }); +} + +//<#END_FILE: test-tls-client-abort.js diff --git a/test/js/node/test/parallel/tls-fast-writing.test.js b/test/js/node/test/parallel/tls-fast-writing.test.js new file mode 100644 index 0000000000..7656d5eb15 --- /dev/null +++ b/test/js/node/test/parallel/tls-fast-writing.test.js @@ -0,0 +1,97 @@ +//#FILE: test-tls-fast-writing.js +//#SHA1: 3a9ce4612ccf460fb5c0dfd4be6f8f5cad06c4a4 +//----------------- +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +"use strict"; +const fixtures = require("../common/fixtures"); +const tls = require("tls"); + +const options = { + key: fixtures.readKey("rsa_private.pem"), + cert: fixtures.readKey("rsa_cert.crt"), + ca: [fixtures.readKey("rsa_ca.crt")], +}; + +let gotChunk = false; +let gotDrain = false; + +function onconnection(conn) { + conn.on("data", function (c) { + if (!gotChunk) { + gotChunk = true; + console.log("ok - got chunk"); + } + + // Just some basic sanity checks. + expect(c.length).toBeGreaterThan(0); + expect(Buffer.isBuffer(c)).toBe(true); + + if (gotDrain) { + process.exit(0); + } + }); +} + +test("TLS fast writing", done => { + if (!process.versions.openssl) { + console.log("1..0 # Skipped: missing crypto"); + return done(); + } + + const server = tls.createServer(options, onconnection); + + server.listen(0, function () { + const chunk = Buffer.alloc(1024, "x"); + const opt = { port: this.address().port, rejectUnauthorized: false }; + const conn = tls.connect(opt, function () { + conn.on("drain", ondrain); + write(); + }); + + function ondrain() { + if (!gotDrain) { + gotDrain = true; + console.log("ok - got drain"); + } + if (gotChunk) { + process.exit(0); + } + write(); + } + + function write() { + // This needs to return false eventually + while (false !== conn.write(chunk)); + } + }); + + // Clean up + process.on("exit", () => { + server.close(); + expect(gotChunk).toBe(true); + expect(gotDrain).toBe(true); + done(); + }); +}); + +//<#END_FILE: test-tls-fast-writing.js diff --git a/test/js/node/test/parallel/tls-net-socket-keepalive.test.js b/test/js/node/test/parallel/tls-net-socket-keepalive.test.js new file mode 100644 index 0000000000..a0378791cc --- /dev/null +++ b/test/js/node/test/parallel/tls-net-socket-keepalive.test.js @@ -0,0 +1,80 @@ +//#FILE: test-tls-net-socket-keepalive.js +//#SHA1: 9ae6965b63d37c0f9cb2ab7d068d4da2a68b8b1f +//----------------- +"use strict"; + +const fixtures = require("../common/fixtures"); +const tls = require("tls"); +const net = require("net"); + +// This test ensures that when tls sockets are created with `allowHalfOpen`, +// they won't hang. +const key = fixtures.readKey("agent1-key.pem"); +const cert = fixtures.readKey("agent1-cert.pem"); +const ca = fixtures.readKey("ca1-cert.pem"); +const options = { + key, + cert, + ca: [ca], +}; + +test("TLS sockets with allowHalfOpen do not hang", done => { + const server = tls.createServer(options, conn => { + conn.write("hello", () => { + expect(true).toBe(true); // Equivalent to common.mustCall() + }); + conn.on("data", () => { + expect(true).toBe(true); // Equivalent to common.mustCall() + }); + conn.on("end", () => { + expect(true).toBe(true); // Equivalent to common.mustCall() + }); + conn.on("data", () => { + expect(true).toBe(true); // Equivalent to common.mustCall() + }); + conn.on("close", () => { + expect(true).toBe(true); // Equivalent to common.mustCall() + }); + conn.end(); + }); + + server.listen(0, () => { + const netSocket = new net.Socket({ + allowHalfOpen: true, + }); + + const socket = tls.connect({ + socket: netSocket, + rejectUnauthorized: false, + }); + + const { port, address } = server.address(); + + // Doing `net.Socket.connect()` after `tls.connect()` will make tls module + // wrap the socket in StreamWrap. + netSocket.connect({ + port, + address, + }); + + socket.on("secureConnect", () => { + expect(true).toBe(true); // Equivalent to common.mustCall() + }); + socket.on("end", () => { + expect(true).toBe(true); // Equivalent to common.mustCall() + }); + socket.on("data", () => { + expect(true).toBe(true); // Equivalent to common.mustCall() + }); + socket.on("close", () => { + expect(true).toBe(true); // Equivalent to common.mustCall() + server.close(); + done(); + }); + + socket.write("hello"); + socket.end(); + }); +}); + +//<#END_FILE: test-tls-net-socket-keepalive.js diff --git a/test/js/node/test/parallel/tls-peer-certificate-multi-keys.test.js b/test/js/node/test/parallel/tls-peer-certificate-multi-keys.test.js new file mode 100644 index 0000000000..d1cfe70e15 --- /dev/null +++ b/test/js/node/test/parallel/tls-peer-certificate-multi-keys.test.js @@ -0,0 +1,87 @@ +//#FILE: test-tls-peer-certificate-multi-keys.js +//#SHA1: d30d685d74ebea73274e19cea1a19a2b8cea5120 +//----------------- +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +"use strict"; + +const tls = require("tls"); +const fixtures = require("../common/fixtures"); + +const options = { + key: fixtures.readKey("rsa_private.pem"), + cert: fixtures.readKey("rsa_cert.crt"), +}; + +let server; + +beforeAll(() => { + if (!process.versions.openssl) { + return test.skip("missing crypto"); + } +}); + +afterAll(() => { + if (server) { + server.close(); + } +}); + +test("TLS peer certificate with multiple keys", async () => { + server = tls.createServer(options, cleartext => { + cleartext.end("World"); + }); + + const serverSecureConnectionPromise = new Promise(resolve => { + server.once("secureConnection", socket => { + const cert = socket.getCertificate(); + // The server's local cert is the client's peer cert. + expect(cert.subject.OU).toEqual(["Test TLS Certificate", "Engineering"]); + resolve(); + }); + }); + + await new Promise(resolve => { + server.listen(0, resolve); + }); + + const clientConnectionPromise = new Promise((resolve, reject) => { + const socket = tls.connect( + { + port: server.address().port, + rejectUnauthorized: false, + }, + () => { + const peerCert = socket.getPeerCertificate(); + expect(peerCert.subject.OU).toEqual(["Test TLS Certificate", "Engineering"]); + socket.end("Hello"); + resolve(); + }, + ); + + socket.on("error", reject); + }); + + await Promise.all([serverSecureConnectionPromise, clientConnectionPromise]); +}); + +//<#END_FILE: test-tls-peer-certificate-multi-keys.js diff --git a/test/js/node/test/parallel/tls-startcom-wosign-whitelist.test.js b/test/js/node/test/parallel/tls-startcom-wosign-whitelist.test.js new file mode 100644 index 0000000000..fde4c90e29 --- /dev/null +++ b/test/js/node/test/parallel/tls-startcom-wosign-whitelist.test.js @@ -0,0 +1,82 @@ +//#FILE: test-tls-startcom-wosign-whitelist.js +//#SHA1: 6742ecdeeaa94ca1efad850b021d5308b3077358 +//----------------- +"use strict"; + +const tls = require("tls"); +const fixtures = require("../common/fixtures"); + +function loadPEM(n) { + return fixtures.readKey(`${n}.pem`); +} + +const testCases = [ + { + // agent8 is signed by fake-startcom-root with notBefore of + // Oct 20 23:59:59 2016 GMT. It passes StartCom/WoSign check. + serverOpts: { + key: loadPEM("agent8-key"), + cert: loadPEM("agent8-cert"), + }, + clientOpts: { + ca: loadPEM("fake-startcom-root-cert"), + port: undefined, + rejectUnauthorized: true, + }, + errorCode: "CERT_REVOKED", + }, + { + // agent9 is signed by fake-startcom-root with notBefore of + // Oct 21 00:00:01 2016 GMT. It fails StartCom/WoSign check. + serverOpts: { + key: loadPEM("agent9-key"), + cert: loadPEM("agent9-cert"), + }, + clientOpts: { + ca: loadPEM("fake-startcom-root-cert"), + port: undefined, + rejectUnauthorized: true, + }, + errorCode: "CERT_REVOKED", + }, +]; + +describe("TLS StartCom/WoSign Whitelist", () => { + let finishedTests = 0; + + afterAll(() => { + expect(finishedTests).toBe(testCases.length); + }); + + testCases.forEach((tcase, index) => { + it(`should handle case ${index + 1} correctly`, async () => { + const server = tls.createServer(tcase.serverOpts, s => { + s.resume(); + }); + + await new Promise(resolve => { + server.listen(0, () => { + tcase.clientOpts.port = server.address().port; + const client = tls.connect(tcase.clientOpts); + + client.on("error", e => { + expect(e.code).toBe(tcase.errorCode); + server.close(resolve); + }); + + client.on("secureConnect", () => { + // agent8 can pass StartCom/WoSign check so that the secureConnect + // is established. + expect(tcase.errorCode).toBe("CERT_REVOKED"); + client.end(); + server.close(resolve); + }); + }); + }); + + finishedTests++; + }); + }); +}); + +//<#END_FILE: test-tls-startcom-wosign-whitelist.js diff --git a/test/js/node/test/parallel/tls-ticket-cluster.test.js b/test/js/node/test/parallel/tls-ticket-cluster.test.js new file mode 100644 index 0000000000..2def9c478c --- /dev/null +++ b/test/js/node/test/parallel/tls-ticket-cluster.test.js @@ -0,0 +1,153 @@ +//#FILE: test-tls-ticket-cluster.js +//#SHA1: a65d425111990ee164b458fd373b9f5bb083f6df +//----------------- +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +"use strict"; + +const tls = require("tls"); +const cluster = require("cluster"); +const fixtures = require("../common/fixtures"); + +const workerCount = 4; +const expectedReqCount = 16; + +if (!process.env.NODE_SKIP_NO_CRYPTO_TEST) { + test("skip if missing crypto", () => { + const hasCrypto = typeof process.versions.openssl === "string"; + if (!hasCrypto) { + console.log("1..0 # Skipped: missing crypto"); + } + expect(hasCrypto).toBe(true); + }); +} + +if (cluster.isPrimary) { + let listeningCount = 0; + let reusedCount = 0; + let reqCount = 0; + let lastSession = null; + let workerPort = null; + + function shoot() { + console.error("[primary] connecting", workerPort, "session?", !!lastSession); + const c = tls + .connect( + workerPort, + { + session: lastSession, + rejectUnauthorized: false, + }, + () => { + c.on("end", c.end); + }, + ) + .on("close", () => { + // Wait for close to shoot off another connection. We don't want to shoot + // until a new session is allocated, if one will be. The new session is + // not guaranteed on secureConnect (it depends on TLS1.2 vs TLS1.3), but + // it is guaranteed to happen before the connection is closed. + if (++reqCount === expectedReqCount) { + Object.keys(cluster.workers).forEach(function (id) { + cluster.workers[id].send("die"); + }); + } else { + shoot(); + } + }) + .once("session", session => { + expect(lastSession).toBeFalsy(); + lastSession = session; + }); + + c.resume(); // See close_notify comment in server + } + + function fork() { + const worker = cluster.fork(); + worker.on("message", ({ msg, port }) => { + console.error("[primary] got %j", msg); + if (msg === "reused") { + ++reusedCount; + } else if (msg === "listening" && ++listeningCount === workerCount) { + workerPort = port; + shoot(); + } + }); + + worker.on("exit", () => { + console.error("[primary] worker died"); + }); + } + + test("cluster primary", () => { + for (let i = 0; i < workerCount; i++) { + fork(); + } + + process.on("exit", () => { + expect(reqCount).toBe(expectedReqCount); + expect(reusedCount + 1).toBe(reqCount); + }); + }); +} else { + const key = fixtures.readKey("rsa_private.pem"); + const cert = fixtures.readKey("rsa_cert.crt"); + + const options = { key, cert }; + + const server = tls.createServer(options, c => { + console.error("[worker] connection reused?", c.isSessionReused()); + if (c.isSessionReused()) { + process.send({ msg: "reused" }); + } else { + process.send({ msg: "not-reused" }); + } + // Used to just .end(), but that means client gets close_notify before + // NewSessionTicket. Send data until that problem is solved. + c.end("x"); + }); + + server.listen(0, () => { + const { port } = server.address(); + process.send({ + msg: "listening", + port, + }); + }); + + process.on("message", function listener(msg) { + console.error("[worker] got %j", msg); + if (msg === "die") { + server.close(() => { + console.error("[worker] server close"); + process.exit(); + }); + } + }); + + process.on("exit", () => { + console.error("[worker] exit"); + }); +} + +//<#END_FILE: test-tls-ticket-cluster.js diff --git a/test/js/node/test/parallel/tls-transport-destroy-after-own-gc.test.js b/test/js/node/test/parallel/tls-transport-destroy-after-own-gc.test.js new file mode 100644 index 0000000000..1f7c20dda3 --- /dev/null +++ b/test/js/node/test/parallel/tls-transport-destroy-after-own-gc.test.js @@ -0,0 +1,39 @@ +//#FILE: test-tls-transport-destroy-after-own-gc.js +//#SHA1: e2ef35ad88444196d24664e93fb9efdad050c876 +//----------------- +// Flags: --expose-gc +"use strict"; + +// Regression test for https://github.com/nodejs/node/issues/17475 +// Unfortunately, this tests only "works" reliably when checked with valgrind or +// a similar tool. + +const { TLSSocket } = require("tls"); +const makeDuplexPair = require("../common/duplexpair"); + +test("TLSSocket destruction after garbage collection", done => { + if (!process.versions.openssl) { + done(); + return; + } + + let { clientSide } = makeDuplexPair(); + + let clientTLS = new TLSSocket(clientSide, { isServer: false }); + let clientTLSHandle = clientTLS._handle; // eslint-disable-line no-unused-vars + + setImmediate(() => { + clientTLS = null; + global.gc(); + clientTLSHandle = null; + global.gc(); + setImmediate(() => { + clientSide = null; + global.gc(); + // If we've reached this point without crashing, the test has passed + done(); + }); + }); +}); + +//<#END_FILE: test-tls-transport-destroy-after-own-gc.js diff --git a/test/js/node/test/parallel/tls-zero-clear-in.test.js b/test/js/node/test/parallel/tls-zero-clear-in.test.js new file mode 100644 index 0000000000..26283f4311 --- /dev/null +++ b/test/js/node/test/parallel/tls-zero-clear-in.test.js @@ -0,0 +1,81 @@ +//#FILE: test-tls-zero-clear-in.js +//#SHA1: 6014fd3aa5a294b4e8594a32f0eb8e7b3c206213 +//----------------- +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +"use strict"; + +const tls = require("tls"); +const { readKey } = require("../common/fixtures"); + +if (!process.versions.openssl) { + test.skip("missing crypto"); +} + +const cert = readKey("rsa_cert.crt"); +const key = readKey("rsa_private.pem"); + +test("SSL_write() call with 0 bytes should not be treated as error", done => { + const server = tls.createServer( + { + cert, + key, + }, + c => { + // Nop + setTimeout(() => { + c.end(); + server.close(); + }, 20); + }, + ); + + server.listen(0, () => { + const conn = tls.connect( + { + cert: cert, + key: key, + rejectUnauthorized: false, + port: server.address().port, + }, + () => { + setTimeout(() => { + conn.destroy(); + }, 20); + }, + ); + + // SSL_write() call's return value, when called 0 bytes, should not be + // treated as error. + conn.end(""); + + conn.on("error", () => { + done(new Error("Unexpected error event")); + }); + + setTimeout(() => { + done(); + }, 100); + }); +}); + +//<#END_FILE: test-tls-zero-clear-in.js diff --git a/test/js/node/test/parallel/whatwg-url-custom-searchparams-entries.test.js b/test/js/node/test/parallel/whatwg-url-custom-searchparams-entries.test.js new file mode 100644 index 0000000000..8d7bd72648 --- /dev/null +++ b/test/js/node/test/parallel/whatwg-url-custom-searchparams-entries.test.js @@ -0,0 +1,62 @@ +//#FILE: test-whatwg-url-custom-searchparams-entries.js +//#SHA1: 4ba98b18a2f44b46ac4e6e0ee5179e97083100be +//----------------- +"use strict"; + +// Tests below are not from WPT. +test("URLSearchParams entries", () => { + const params = new URLSearchParams("a=b&c=d"); + const entries = params.entries(); + + expect(typeof entries[Symbol.iterator]).toBe("function"); + expect(entries[Symbol.iterator]()).toBe(entries); + + expect(entries.next()).toEqual({ + value: ["a", "b"], + done: false, + }); + + expect(entries.next()).toEqual({ + value: ["c", "d"], + done: false, + }); + + expect(entries.next()).toEqual({ + value: undefined, + done: true, + }); + + expect(entries.next()).toEqual({ + value: undefined, + done: true, + }); +}); + +test("entries.next() throws with invalid this", () => { + const params = new URLSearchParams("a=b&c=d"); + const entries = params.entries(); + + expect(() => { + entries.next.call(undefined); + }).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_THIS", + name: "TypeError", + message: expect.any(String), + }), + ); +}); + +test("params.entries() throws with invalid this", () => { + expect(() => { + URLSearchParams.prototype.entries.call(undefined); + }).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_THIS", + name: "TypeError", + message: expect.any(String), + }), + ); +}); + +//<#END_FILE: test-whatwg-url-custom-searchparams-entries.js diff --git a/test/js/node/test/parallel/whatwg-url-custom-searchparams-foreach.test.js b/test/js/node/test/parallel/whatwg-url-custom-searchparams-foreach.test.js new file mode 100644 index 0000000000..233a679a00 --- /dev/null +++ b/test/js/node/test/parallel/whatwg-url-custom-searchparams-foreach.test.js @@ -0,0 +1,21 @@ +//#FILE: test-whatwg-url-custom-searchparams-foreach.js +//#SHA1: affe74306c7fdeb688aadc771c4d7d5b769fc236 +//----------------- +"use strict"; + +// Tests below are not from WPT. + +test('URLSearchParams.forEach called with invalid "this"', () => { + const params = new URLSearchParams(); + expect(() => { + params.forEach.call(undefined); + }).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_THIS", + name: "TypeError", + message: expect.any(String), + }), + ); +}); + +//<#END_FILE: test-whatwg-url-custom-searchparams-foreach.js diff --git a/test/js/node/test/parallel/whatwg-url-custom-searchparams-keys.test.js b/test/js/node/test/parallel/whatwg-url-custom-searchparams-keys.test.js new file mode 100644 index 0000000000..0b4a13ea30 --- /dev/null +++ b/test/js/node/test/parallel/whatwg-url-custom-searchparams-keys.test.js @@ -0,0 +1,66 @@ +//#FILE: test-whatwg-url-custom-searchparams-keys.js +//#SHA1: 06abe929cfe842fcdd80b44cee8a0092358e5fdf +//----------------- +"use strict"; + +// Tests below are not from WPT. + +describe("URLSearchParams keys", () => { + let params; + let keys; + + beforeEach(() => { + params = new URLSearchParams("a=b&c=d"); + keys = params.keys(); + }); + + test("keys iterator is a function and returns self", () => { + expect(typeof keys[Symbol.iterator]).toBe("function"); + expect(keys[Symbol.iterator]()).toBe(keys); + }); + + test("keys iterator returns correct values", () => { + expect(keys.next()).toEqual({ + value: "a", + done: false, + }); + expect(keys.next()).toEqual({ + value: "c", + done: false, + }); + expect(keys.next()).toEqual({ + value: undefined, + done: true, + }); + expect(keys.next()).toEqual({ + value: undefined, + done: true, + }); + }); + + test("keys.next() throws with invalid this", () => { + expect(() => { + keys.next.call(undefined); + }).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_THIS", + name: "TypeError", + message: expect.any(String), + }), + ); + }); + + test("params.keys() throws with invalid this", () => { + expect(() => { + params.keys.call(undefined); + }).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_THIS", + name: "TypeError", + message: expect.any(String), + }), + ); + }); +}); + +//<#END_FILE: test-whatwg-url-custom-searchparams-keys.js diff --git a/test/js/node/test/parallel/whatwg-url-custom-searchparams-stringifier.test.js b/test/js/node/test/parallel/whatwg-url-custom-searchparams-stringifier.test.js new file mode 100644 index 0000000000..94028430ba --- /dev/null +++ b/test/js/node/test/parallel/whatwg-url-custom-searchparams-stringifier.test.js @@ -0,0 +1,30 @@ +//#FILE: test-whatwg-url-custom-searchparams-stringifier.js +//#SHA1: 588663b1cad21e26a4b8e25c0659d204a5d96542 +//----------------- +"use strict"; + +// Tests below are not from WPT. + +test("URLSearchParams toString called with invalid this", () => { + const params = new URLSearchParams(); + expect(() => { + params.toString.call(undefined); + }).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_THIS", + name: "TypeError", + message: expect.any(String), + }), + ); +}); + +// The URLSearchParams stringifier mutates the base URL using +// different percent-encoding rules than the URL itself. +test("URLSearchParams stringifier mutates base URL with different percent-encoding", () => { + const myUrl = new URL("https://example.org?foo=~bar"); + expect(myUrl.search).toBe("?foo=~bar"); + myUrl.searchParams.sort(); + expect(myUrl.search).toBe("?foo=%7Ebar"); +}); + +//<#END_FILE: test-whatwg-url-custom-searchparams-stringifier.js diff --git a/test/js/node/test/parallel/whatwg-url-custom-searchparams-values.test.js b/test/js/node/test/parallel/whatwg-url-custom-searchparams-values.test.js new file mode 100644 index 0000000000..5b7d88801c --- /dev/null +++ b/test/js/node/test/parallel/whatwg-url-custom-searchparams-values.test.js @@ -0,0 +1,52 @@ +//#FILE: test-whatwg-url-custom-searchparams-values.js +//#SHA1: 7df0ccf30363d589199bb3f71c68e5559e9e4f59 +//----------------- +"use strict"; + +// Tests below are not from WPT. + +test("URLSearchParams values() method", () => { + const params = new URLSearchParams("a=b&c=d"); + const values = params.values(); + + expect(typeof values[Symbol.iterator]).toBe("function"); + expect(values[Symbol.iterator]()).toBe(values); + expect(values.next()).toEqual({ + value: "b", + done: false, + }); + expect(values.next()).toEqual({ + value: "d", + done: false, + }); + expect(values.next()).toEqual({ + value: undefined, + done: true, + }); + expect(values.next()).toEqual({ + value: undefined, + done: true, + }); + + expect(() => { + values.next.call(undefined); + }).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_THIS", + name: "TypeError", + message: expect.any(String), + }), + ); + + expect(() => { + params.values.call(undefined); + }).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_THIS", + name: "TypeError", + message: expect.any(String), + }), + ); +}); + +//<#END_FILE: test-whatwg-url-custom-searchparams-values.js diff --git a/test/js/node/test/parallel/whatwg-url-custom-searchparams.test.js b/test/js/node/test/parallel/whatwg-url-custom-searchparams.test.js new file mode 100644 index 0000000000..7de337086e --- /dev/null +++ b/test/js/node/test/parallel/whatwg-url-custom-searchparams.test.js @@ -0,0 +1,191 @@ +//#FILE: test-whatwg-url-custom-searchparams.js +//#SHA1: 8308ed9fc341a1caaadcf01653bd49b96cebf599 +//----------------- +"use strict"; + +// Tests below are not from WPT. + +const assert = require("assert"); +const fixtures = require("../common/fixtures"); + +const serialized = + "a=a&a=1&a=true&a=undefined&a=null&a=%EF%BF%BD" + + "&a=%EF%BF%BD&a=%F0%9F%98%80&a=%EF%BF%BD%EF%BF%BD" + + "&a=%5Bobject+Object%5D"; +const values = ["a", 1, true, undefined, null, "\uD83D", "\uDE00", "\uD83D\uDE00", "\uDE00\uD83D", {}]; +const normalizedValues = [ + "a", + "1", + "true", + "undefined", + "null", + "\uFFFD", + "\uFFFD", + "\uD83D\uDE00", + "\uFFFD\uFFFD", + "[object Object]", +]; + +describe("WHATWG URL Custom SearchParams", () => { + let m, sp; + + beforeEach(() => { + m = new URL("http://example.org"); + sp = m.searchParams; + }); + + it("should not modify own symbols when accessing searchParams", () => { + const ownSymbolsBeforeGetterAccess = Object.getOwnPropertySymbols(m); + expect(sp).toBeDefined(); + expect(Object.getOwnPropertySymbols(m)).toEqual(ownSymbolsBeforeGetterAccess); + }); + + it("should initialize with empty search params", () => { + expect(sp.toString()).toBe(""); + expect(m.search).toBe(""); + }); + + it("should handle setting and deleting search params", () => { + expect(sp.has("a")).toBe(false); + values.forEach(i => sp.set("a", i)); + expect(sp.has("a")).toBe(true); + expect(sp.get("a")).toBe("[object Object]"); + sp.delete("a"); + expect(sp.has("a")).toBe(false); + }); + + it("should handle appending search params", () => { + m.search = ""; + expect(sp.toString()).toBe(""); + + values.forEach(i => sp.append("a", i)); + expect(sp.has("a")).toBe(true); + expect(sp.getAll("a").length).toBe(values.length); + expect(sp.get("a")).toBe("a"); + + expect(sp.toString()).toBe(serialized); + expect(m.search).toBe(`?${serialized}`); + }); + + it("should update URL components when modifying search params", () => { + sp.delete("a"); + values.forEach(i => sp.append("a", i)); + expect(m.href).toBe(`http://example.org/?${serialized}`); + expect(m.toString()).toBe(`http://example.org/?${serialized}`); + expect(m.toJSON()).toBe(`http://example.org/?${serialized}`); + }); + + it("should clear search params when setting href or search", () => { + sp.delete("a"); + values.forEach(i => sp.append("a", i)); + m.href = "http://example.org"; + expect(m.href).toBe("http://example.org/"); + expect(sp.size).toBe(0); + + values.forEach(i => sp.append("a", i)); + m.search = ""; + expect(m.href).toBe("http://example.org/"); + expect(sp.size).toBe(0); + }); + + it("should update URL components when modifying pathname or hash", () => { + sp.delete("a"); + values.forEach(i => sp.append("a", i)); + m.pathname = "/test"; + expect(m.href).toBe(`http://example.org/test?${serialized}`); + m.pathname = ""; + + sp.delete("a"); + values.forEach(i => sp.append("a", i)); + m.hash = "#test"; + expect(m.href).toBe(`http://example.org/?${serialized}#test`); + m.hash = ""; + }); + + it("should have correct iteration behavior", () => { + expect(sp[Symbol.iterator]).toBe(sp.entries); + + sp.delete("a"); + values.forEach(i => sp.append("a", i)); + + let n = 0; + for (const [key, val] of sp) { + expect(key).toBe("a"); + expect(val).toBe(normalizedValues[n]); + n++; + } + + n = 0; + for (const key of sp.keys()) { + expect(key).toBe("a"); + n++; + } + + n = 0; + for (const val of sp.values()) { + expect(val).toBe(normalizedValues[n]); + n++; + } + + n = 0; + sp.forEach(function (val, key, obj) { + expect(this).toBeUndefined(); + expect(key).toBe("a"); + expect(val).toBe(normalizedValues[n]); + expect(obj).toBe(sp); + n++; + }); + + sp.forEach(function () { + expect(this).toBe(m); + }, m); + }); + + it("should throw for invalid forEach arguments", () => { + expect(() => sp.forEach()).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + name: "TypeError", + }), + ); + expect(() => sp.forEach(1)).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + name: "TypeError", + }), + ); + }); + + it("should handle setting search directly", () => { + m.search = "?a=a&b=b"; + expect(sp.toString()).toBe("a=a&b=b"); + }); + + it("should pass URL search params tests", () => { + const tests = require(fixtures.path("url-searchparams.js")); + + for (const [input, expected, parsed] of tests) { + if (input[0] !== "?") { + const sp = new URLSearchParams(input); + expect(String(sp)).toBe(expected); + expect(Array.from(sp)).toEqual(parsed); + + m.search = input; + expect(String(m.searchParams)).toBe(expected); + expect(Array.from(m.searchParams)).toEqual(parsed); + } + + { + const sp = new URLSearchParams(`?${input}`); + expect(String(sp)).toBe(expected); + expect(Array.from(sp)).toEqual(parsed); + + m.search = `?${input}`; + expect(String(m.searchParams)).toBe(expected); + expect(Array.from(m.searchParams)).toEqual(parsed); + } + } + }); +}); + +//<#END_FILE: test-whatwg-url-custom-searchparams.js diff --git a/test/js/node/test/parallel/worker-cjs-workerdata.test.js b/test/js/node/test/parallel/worker-cjs-workerdata.test.js new file mode 100644 index 0000000000..0c0158346e --- /dev/null +++ b/test/js/node/test/parallel/worker-cjs-workerdata.test.js @@ -0,0 +1,21 @@ +//#FILE: test-worker-cjs-workerdata.js +//#SHA1: 8e5d70084de66c757d227df54612de48d1048ad3 +//----------------- +"use strict"; +const fixtures = require("../common/fixtures"); +const { Worker } = require("worker_threads"); + +const workerData = "Hello from main thread"; + +test("Worker with CJS module and workerData", done => { + const worker = new Worker(fixtures.path("worker-data.cjs"), { + workerData, + }); + + worker.on("message", message => { + expect(message).toBe(workerData); + done(); + }); +}); + +//<#END_FILE: test-worker-cjs-workerdata.js diff --git a/test/js/node/test/parallel/worker-esmodule.test.js b/test/js/node/test/parallel/worker-esmodule.test.js new file mode 100644 index 0000000000..e08d58041a --- /dev/null +++ b/test/js/node/test/parallel/worker-esmodule.test.js @@ -0,0 +1,20 @@ +//#FILE: test-worker-esmodule.js +//#SHA1: a40c6a55aa2fe45203bec4808e0d53efed2fa4e4 +//----------------- +"use strict"; + +const fixtures = require("../common/fixtures"); +const { Worker } = require("worker_threads"); + +test("Worker can load ES module", () => { + const w = new Worker(fixtures.path("worker-script.mjs")); + + return new Promise(resolve => { + w.on("message", message => { + expect(message).toBe("Hello, world!"); + resolve(); + }); + }); +}); + +//<#END_FILE: test-worker-esmodule.js diff --git a/test/js/node/test/parallel/worker-mjs-workerdata.test.js b/test/js/node/test/parallel/worker-mjs-workerdata.test.js new file mode 100644 index 0000000000..d3bfe6d442 --- /dev/null +++ b/test/js/node/test/parallel/worker-mjs-workerdata.test.js @@ -0,0 +1,22 @@ +//#FILE: test-worker-mjs-workerdata.js +//#SHA1: c4df37cd769b399dd8245d29bed7f385f1adb472 +//----------------- +"use strict"; + +const fixtures = require("../common/fixtures"); +const { Worker } = require("worker_threads"); + +const workerData = "Hello from main thread"; + +test("Worker with workerData in MJS", done => { + const worker = new Worker(fixtures.path("worker-data.mjs"), { + workerData, + }); + + worker.on("message", message => { + expect(message).toBe(workerData); + done(); + }); +}); + +//<#END_FILE: test-worker-mjs-workerdata.js diff --git a/test/js/node/test/parallel/worker-terminate-http2-respond-with-file.test.js b/test/js/node/test/parallel/worker-terminate-http2-respond-with-file.test.js new file mode 100644 index 0000000000..c317604d79 --- /dev/null +++ b/test/js/node/test/parallel/worker-terminate-http2-respond-with-file.test.js @@ -0,0 +1,51 @@ +//#FILE: test-worker-terminate-http2-respond-with-file.js +//#SHA1: e8ce958ee3283a8ec8c83acc27cc3a02824ebfb7 +//----------------- +"use strict"; + +const http2 = require("http2"); +const makeDuplexPair = require("../common/duplexpair"); +const { Worker, isMainThread } = require("worker_threads"); + +// This is a variant of test-http2-generic-streams-sendfile for checking +// that Workers can be terminated during a .respondWithFile() operation. + +if (isMainThread) { + test("Worker can be terminated during respondWithFile operation", () => { + const worker = new Worker(__filename); + expect(worker).toBeDefined(); + }); +} else { + test("HTTP/2 server responds with file", done => { + const server = http2.createServer(); + server.on("stream", (stream, headers) => { + stream.respondWithFile(process.execPath); // Use a large-ish file. + }); + + const { clientSide, serverSide } = makeDuplexPair(); + server.emit("connection", serverSide); + + const client = http2.connect("http://localhost:80", { + createConnection: () => clientSide, + }); + + const req = client.request(); + + req.on("response", headers => { + expect(headers[":status"]).toBe(200); + }); + + req.on("data", () => { + process.exit(); + done(); + }); + + req.on("end", () => { + done.fail("Request should not end"); + }); + + req.end(); + }); +} + +//<#END_FILE: test-worker-terminate-http2-respond-with-file.js