From 612226de8e2fe3068d981866242bacedfceb9734 Mon Sep 17 00:00:00 2001 From: Matt Mastracci Date: Mon, 22 May 2023 13:35:59 -0600 Subject: chore(cli): One Rust test per JS and Node unit test file (#19199) This runs our `js_unit_tests` and `node_unit_tests` in parallel, one rust test per JS unit test file. Some of our JS tests don't like running in parallel due to port requirements, so this also makes those use a specific port-per-file. This does not attempt to make the node-compat tests work. --- cli/tests/integration/js_unit_tests.rs | 177 +++++++++++++++++--- cli/tests/integration/node_unit_tests.rs | 150 ++++++++++++++++- cli/tests/unit/fetch_test.ts | 26 +-- cli/tests/unit/net_test.ts | 100 +++++------ cli/tests/unit/resources_test.ts | 6 +- cli/tests/unit/serve_test.ts | 166 +++++++++--------- cli/tests/unit/streams_deprecated.ts | 16 -- cli/tests/unit_node/crypto/crypto_cipher_test.ts | 186 +++++++++++++++++++++ cli/tests/unit_node/crypto/crypto_hash_test.ts | 24 +++ cli/tests/unit_node/crypto/crypto_key_test.ts | 204 +++++++++++++++++++++++ cli/tests/unit_node/crypto/crypto_sign_test.ts | 91 ++++++++++ cli/tests/unit_node/crypto_cipher_test.ts | 186 --------------------- cli/tests/unit_node/crypto_hash.ts | 24 --- cli/tests/unit_node/crypto_key.ts | 204 ----------------------- cli/tests/unit_node/crypto_sign_test.ts | 91 ---------- 15 files changed, 958 insertions(+), 693 deletions(-) delete mode 100644 cli/tests/unit/streams_deprecated.ts create mode 100644 cli/tests/unit_node/crypto/crypto_cipher_test.ts create mode 100644 cli/tests/unit_node/crypto/crypto_hash_test.ts create mode 100644 cli/tests/unit_node/crypto/crypto_key_test.ts create mode 100644 cli/tests/unit_node/crypto/crypto_sign_test.ts delete mode 100644 cli/tests/unit_node/crypto_cipher_test.ts delete mode 100644 cli/tests/unit_node/crypto_hash.ts delete mode 100644 cli/tests/unit_node/crypto_key.ts delete mode 100644 cli/tests/unit_node/crypto_sign_test.ts (limited to 'cli') diff --git a/cli/tests/integration/js_unit_tests.rs b/cli/tests/integration/js_unit_tests.rs index 793f66b1e..4d6ef3675 100644 --- a/cli/tests/integration/js_unit_tests.rs +++ b/cli/tests/integration/js_unit_tests.rs @@ -1,27 +1,113 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. - +use std::io::BufRead; +use std::io::BufReader; +use std::process::Stdio; +use std::time::Duration; +use std::time::Instant; use test_util as util; -#[test] -fn js_unit_tests_lint() { - let status = util::deno_cmd() - .arg("lint") - .arg("--unstable") - .arg(util::tests_path().join("unit")) - .spawn() - .unwrap() - .wait() - .unwrap(); - assert!(status.success()); -} +util::unit_test_factory!( + js_unit_test, + "tests/unit", + "*.ts", + [ + abort_controller_test, + blob_test, + body_test, + broadcast_channel_test, + buffer_test, + build_test, + cache_api_test, + chmod_test, + chown_test, + command_test, + console_test, + copy_file_test, + custom_event_test, + dir_test, + dom_exception_test, + error_stack_test, + error_test, + esnext_test, + event_target_test, + event_test, + fetch_test, + ffi_test, + file_test, + filereader_test, + files_test, + flock_test, + fs_events_test, + get_random_values_test, + globals_test, + headers_test, + http_test, + internals_test, + intl_test, + io_test, + kv_test, + link_test, + make_temp_test, + message_channel_test, + metrics_test, + mkdir_test, + navigator_test, + net_test, + network_interfaces_test, + opcall_test, + os_test, + path_from_url_test, + performance_test, + permissions_test, + process_test, + progressevent_test, + promise_hooks_test, + read_dir_test, + read_file_test, + read_link_test, + read_text_file_test, + real_path_test, + ref_unref_test, + remove_test, + rename_test, + request_test, + resources_test, + response_test, + serve_test, + signal_test, + stat_test, + stdio_test, + structured_clone_test, + symlink_test, + sync_test, + test_util, + testing_test, + text_encoding_test, + timers_test, + tls_test, + truncate_test, + tty_color_test, + tty_test, + umask_test, + url_search_params_test, + url_test, + urlpattern_test, + utime_test, + version_test, + wasm_test, + webcrypto_test, + websocket_test, + webstorage_test, + worker_permissions_test, + worker_types, + write_file_test, + write_text_file_test, + ] +); -#[test] -fn js_unit_tests() { +fn js_unit_test(test: String) { let _g = util::http_server(); - // Note that the unit tests are not safe for concurrency and must be run with a concurrency limit - // of one because there are some chdir tests in there. - // TODO(caspervonb) split these tests into two groups: parallel and serial. let mut deno = util::deno_cmd() .current_dir(util::root_path()) .arg("test") @@ -29,11 +115,58 @@ fn js_unit_tests() { .arg("--location=http://js-unit-tests/foo/bar") .arg("--no-prompt") .arg("-A") - .arg(util::tests_path().join("unit")) + .arg(util::tests_path().join("unit").join(format!("{test}.ts"))) + .stderr(Stdio::piped()) + .stdout(Stdio::piped()) .spawn() .expect("failed to spawn script"); - let status = deno.wait().expect("failed to wait for the child process"); + let now = Instant::now(); + let stdout = deno.stdout.take().unwrap(); + let test_name = test.clone(); + let stdout = std::thread::spawn(move || { + let reader = BufReader::new(stdout); + for line in reader.lines() { + if let Ok(line) = line { + println!("[{test_name} {:0>6.2}] {line}", now.elapsed().as_secs_f32()); + } else { + break; + } + } + }); + + let now = Instant::now(); + let stderr = deno.stderr.take().unwrap(); + let test_name = test.clone(); + let stderr = std::thread::spawn(move || { + let reader = BufReader::new(stderr); + for line in reader.lines() { + if let Ok(line) = line { + eprintln!("[{test_name} {:0>6.2}] {line}", now.elapsed().as_secs_f32()); + } else { + break; + } + } + }); + + const PER_TEST_TIMEOUT: Duration = Duration::from_secs(2 * 60); + + let now = Instant::now(); + let status = loop { + if now.elapsed() > PER_TEST_TIMEOUT { + // Last-ditch kill + _ = deno.kill(); + panic!("Test {test} failed to complete in time"); + } + if let Some(status) = deno + .try_wait() + .expect("failed to wait for the child process") + { + break status; + } + std::thread::sleep(Duration::from_millis(100)); + }; + #[cfg(unix)] assert_eq!( std::os::unix::process::ExitStatusExt::signal(&status), @@ -41,5 +174,9 @@ fn js_unit_tests() { "Deno should not have died with a signal" ); assert_eq!(Some(0), status.code(), "Deno should have exited cleanly"); + + stdout.join().unwrap(); + stderr.join().unwrap(); + assert!(status.success()); } diff --git a/cli/tests/integration/node_unit_tests.rs b/cli/tests/integration/node_unit_tests.rs index d2a6f6ec8..2cde51552 100644 --- a/cli/tests/integration/node_unit_tests.rs +++ b/cli/tests/integration/node_unit_tests.rs @@ -1,12 +1,80 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. - +use std::io::BufRead; +use std::io::BufReader; +use std::process::Stdio; +use std::time::Duration; +use std::time::Instant; use test_util as util; -#[test] -fn node_unit_tests() { +util::unit_test_factory!( + node_unit_test, + "tests/unit_node", + "**/*_test.ts", + [ + _fs_access_test = _fs / _fs_access_test, + _fs_appendFile_test = _fs / _fs_appendFile_test, + _fs_chmod_test = _fs / _fs_chmod_test, + _fs_chown_test = _fs / _fs_chown_test, + _fs_close_test = _fs / _fs_close_test, + _fs_copy_test = _fs / _fs_copy_test, + _fs_dir_test = _fs / _fs_dir_test, + _fs_exists_test = _fs / _fs_exists_test, + _fs_fdatasync_test = _fs / _fs_fdatasync_test, + _fs_fstat_test = _fs / _fs_fstat_test, + _fs_fsync_test = _fs / _fs_fsync_test, + _fs_ftruncate_test = _fs / _fs_ftruncate_test, + _fs_futimes_test = _fs / _fs_futimes_test, + _fs_link_test = _fs / _fs_link_test, + _fs_lstat_test = _fs / _fs_lstat_test, + _fs_mkdir_test = _fs / _fs_mkdir_test, + _fs_mkdtemp_test = _fs / _fs_mkdtemp_test, + _fs_opendir_test = _fs / _fs_opendir_test, + _fs_readFile_test = _fs / _fs_readFile_test, + _fs_readdir_test = _fs / _fs_readdir_test, + _fs_readlink_test = _fs / _fs_readlink_test, + _fs_realpath_test = _fs / _fs_realpath_test, + _fs_rename_test = _fs / _fs_rename_test, + _fs_rm_test = _fs / _fs_rm_test, + _fs_rmdir_test = _fs / _fs_rmdir_test, + _fs_stat_test = _fs / _fs_stat_test, + _fs_symlink_test = _fs / _fs_symlink_test, + _fs_truncate_test = _fs / _fs_truncate_test, + _fs_unlink_test = _fs / _fs_unlink_test, + _fs_utimes_test = _fs / _fs_utimes_test, + _fs_watch_test = _fs / _fs_watch_test, + _fs_write_test = _fs / _fs_write_test, + async_hooks_test, + child_process_test, + crypto_cipher_test = crypto / crypto_cipher_test, + crypto_hash_test = crypto / crypto_hash_test, + crypto_key_test = crypto / crypto_key_test, + crypto_sign_test = crypto / crypto_sign_test, + fs_test, + http_test, + _randomBytes_test = internal / _randomBytes_test, + _randomFill_test = internal / _randomFill_test, + _randomInt_test = internal / _randomInt_test, + pbkdf2_test = internal / pbkdf2_test, + scrypt_test = internal / scrypt_test, + module_test, + process_test, + querystring_test, + readline_test, + string_decoder_test, + timers_test, + tls_test, + tty_test, + util_test, + v8_test, + worker_threads_test + ] +); + +fn node_unit_test(test: String) { let _g = util::http_server(); - let mut deno = util::deno_cmd() + let mut deno = util::deno_cmd(); + let mut deno = deno .current_dir(util::root_path()) .arg("test") .arg("--unstable") @@ -14,12 +82,78 @@ fn node_unit_tests() { // but this shouldn't be necessary. tls.connect currently doesn't // pass hostname option correctly and it causes cert errors. .arg("--unsafely-ignore-certificate-errors") - .arg("-A") - .arg(util::tests_path().join("unit_node")) + .arg("-A"); + // Parallel tests for crypto + if test.starts_with("crypto/") { + deno = deno.arg("--parallel"); + } + let mut deno = deno + .arg( + util::tests_path() + .join("unit_node") + .join(format!("{test}.ts")), + ) + .stderr(Stdio::piped()) + .stdout(Stdio::piped()) .spawn() .expect("failed to spawn script"); - let status = deno.wait().expect("failed to wait for the child process"); - assert_eq!(Some(0), status.code()); + let now = Instant::now(); + let stdout = deno.stdout.take().unwrap(); + let test_name = test.clone(); + let stdout = std::thread::spawn(move || { + let reader = BufReader::new(stdout); + for line in reader.lines() { + if let Ok(line) = line { + println!("[{test_name} {:0>6.2}] {line}", now.elapsed().as_secs_f32()); + } else { + break; + } + } + }); + + let now = Instant::now(); + let stderr = deno.stderr.take().unwrap(); + let test_name = test.clone(); + let stderr = std::thread::spawn(move || { + let reader = BufReader::new(stderr); + for line in reader.lines() { + if let Ok(line) = line { + eprintln!("[{test_name} {:0>6.2}] {line}", now.elapsed().as_secs_f32()); + } else { + break; + } + } + }); + + const PER_TEST_TIMEOUT: Duration = Duration::from_secs(5 * 60); + + let now = Instant::now(); + let status = loop { + if now.elapsed() > PER_TEST_TIMEOUT { + // Last-ditch kill + _ = deno.kill(); + panic!("Test {test} failed to complete in time"); + } + if let Some(status) = deno + .try_wait() + .expect("failed to wait for the child process") + { + break status; + } + std::thread::sleep(Duration::from_millis(100)); + }; + + #[cfg(unix)] + assert_eq!( + std::os::unix::process::ExitStatusExt::signal(&status), + None, + "Deno should not have died with a signal" + ); + assert_eq!(Some(0), status.code(), "Deno should have exited cleanly"); + + stdout.join().unwrap(); + stderr.join().unwrap(); + assert!(status.success()); } diff --git a/cli/tests/unit/fetch_test.ts b/cli/tests/unit/fetch_test.ts index 08689a2a0..db553f14d 100644 --- a/cli/tests/unit/fetch_test.ts +++ b/cli/tests/unit/fetch_test.ts @@ -10,6 +10,8 @@ import { } from "./test_util.ts"; import { Buffer } from "../../../test_util/std/io/buffer.ts"; +const listenPort = 4504; + Deno.test( { permissions: { net: true } }, async function fetchRequiresOneArgument() { @@ -639,7 +641,7 @@ Deno.test( permissions: { net: true }, }, async function fetchRequest() { - const addr = "127.0.0.1:4501"; + const addr = `127.0.0.1:${listenPort}`; const bufPromise = bufferServer(addr); const response = await fetch(`http://${addr}/blah`, { method: "POST", @@ -673,7 +675,7 @@ Deno.test( permissions: { net: true }, }, async function fetchRequestAcceptHeaders() { - const addr = "127.0.0.1:4501"; + const addr = `127.0.0.1:${listenPort}`; const bufPromise = bufferServer(addr); const response = await fetch(`http://${addr}/blah`, { method: "POST", @@ -705,7 +707,7 @@ Deno.test( permissions: { net: true }, }, async function fetchPostBodyString() { - const addr = "127.0.0.1:4511"; + const addr = `127.0.0.1:${listenPort}`; const bufPromise = bufferServer(addr); const body = "hello world"; const response = await fetch(`http://${addr}/blah`, { @@ -743,7 +745,7 @@ Deno.test( permissions: { net: true }, }, async function fetchPostBodyTypedArray() { - const addr = "127.0.0.1:4503"; + const addr = `127.0.0.1:${listenPort}`; const bufPromise = bufferServer(addr); const bodyStr = "hello world"; const body = new TextEncoder().encode(bodyStr); @@ -781,7 +783,7 @@ Deno.test( permissions: { net: true }, }, async function fetchUserSetContentLength() { - const addr = "127.0.0.1:4501"; + const addr = `127.0.0.1:${listenPort}`; const bufPromise = bufferServer(addr); const response = await fetch(`http://${addr}/blah`, { method: "POST", @@ -812,7 +814,7 @@ Deno.test( permissions: { net: true }, }, async function fetchUserSetTransferEncoding() { - const addr = "127.0.0.1:4501"; + const addr = `127.0.0.1:${listenPort}`; const bufPromise = bufferServer(addr); const response = await fetch(`http://${addr}/blah`, { method: "POST", @@ -1158,7 +1160,7 @@ Deno.test( permissions: { net: true }, }, async function fetchPostBodyReadableStream() { - const addr = "127.0.0.1:4511"; + const addr = `127.0.0.1:${listenPort}`; const bufPromise = bufferServer(addr); const stream = new TransformStream(); const writer = stream.writable.getWriter(); @@ -1217,7 +1219,7 @@ Deno.test( async function fetchFilterOutCustomHostHeader(): Promise< void > { - const addr = "127.0.0.1:4511"; + const addr = `127.0.0.1:${listenPort}`; const [hostname, port] = addr.split(":"); const listener = Deno.listen({ hostname, @@ -1717,7 +1719,7 @@ Deno.test( async function fetchWithInvalidContentLengthAndTransferEncoding(): Promise< void > { - const addr = "127.0.0.1:4516"; + const addr = `127.0.0.1:${listenPort}`; const data = "a".repeat(10 << 10); const body = new TextEncoder().encode( @@ -1749,7 +1751,7 @@ Deno.test( async function fetchWithInvalidContentLength(): Promise< void > { - const addr = "127.0.0.1:4517"; + const addr = `127.0.0.1:${listenPort}`; const data = "a".repeat(10 << 10); const body = new TextEncoder().encode( @@ -1777,7 +1779,7 @@ Deno.test( async function fetchWithInvalidContentLength(): Promise< void > { - const addr = "127.0.0.1:4518"; + const addr = `127.0.0.1:${listenPort}`; const data = "a".repeat(10 << 10); const contentLength = data.length / 2; @@ -1804,7 +1806,7 @@ Deno.test( async function fetchWithInvalidContentLength(): Promise< void > { - const addr = "127.0.0.1:4519"; + const addr = `127.0.0.1:${listenPort}`; const data = "a".repeat(10 << 10); const contentLength = data.length * 2; diff --git a/cli/tests/unit/net_test.ts b/cli/tests/unit/net_test.ts index 935a6f846..32250bbd0 100644 --- a/cli/tests/unit/net_test.ts +++ b/cli/tests/unit/net_test.ts @@ -12,6 +12,10 @@ import { } from "./test_util.ts"; import { join } from "../../../test_util/std/path/mod.ts"; +// Since these tests may run in parallel, ensure this port is unique to this file +const listenPort = 4503; +const listenPort2 = 4504; + let isCI: boolean; try { isCI = Deno.env.get("CI") !== undefined; @@ -20,10 +24,10 @@ try { } Deno.test({ permissions: { net: true } }, function netTcpListenClose() { - const listener = Deno.listen({ hostname: "127.0.0.1", port: 3500 }); + const listener = Deno.listen({ hostname: "127.0.0.1", port: listenPort }); assert(listener.addr.transport === "tcp"); assertEquals(listener.addr.hostname, "127.0.0.1"); - assertEquals(listener.addr.port, 3500); + assertEquals(listener.addr.port, listenPort); assertNotEquals(listener.rid, 0); listener.close(); }); @@ -35,12 +39,12 @@ Deno.test( function netUdpListenClose() { const socket = Deno.listenDatagram({ hostname: "127.0.0.1", - port: 3500, + port: listenPort, transport: "udp", }); assert(socket.addr.transport === "udp"); assertEquals(socket.addr.hostname, "127.0.0.1"); - assertEquals(socket.addr.port, 3500); + assertEquals(socket.addr.port, listenPort); socket.close(); }, ); @@ -127,7 +131,7 @@ Deno.test( permissions: { net: true }, }, async function netTcpCloseWhileAccept() { - const listener = Deno.listen({ port: 4501 }); + const listener = Deno.listen({ port: listenPort }); const p = listener.accept(); listener.close(); // TODO(piscisaureus): the error type should be `Interrupted` here, which @@ -212,22 +216,22 @@ Deno.test( ); Deno.test({ permissions: { net: true } }, async function netTcpDialListen() { - const listener = Deno.listen({ port: 3500 }); + const listener = Deno.listen({ port: listenPort }); listener.accept().then( async (conn) => { assert(conn.remoteAddr != null); assert(conn.localAddr.transport === "tcp"); assertEquals(conn.localAddr.hostname, "127.0.0.1"); - assertEquals(conn.localAddr.port, 3500); + assertEquals(conn.localAddr.port, listenPort); await conn.write(new Uint8Array([1, 2, 3])); conn.close(); }, ); - const conn = await Deno.connect({ hostname: "127.0.0.1", port: 3500 }); + const conn = await Deno.connect({ hostname: "127.0.0.1", port: listenPort }); assert(conn.remoteAddr.transport === "tcp"); assertEquals(conn.remoteAddr.hostname, "127.0.0.1"); - assertEquals(conn.remoteAddr.port, 3500); + assertEquals(conn.remoteAddr.port, listenPort); assert(conn.localAddr != null); const buf = new Uint8Array(1024); const readResult = await conn.read(buf); @@ -247,23 +251,23 @@ Deno.test({ permissions: { net: true } }, async function netTcpDialListen() { }); Deno.test({ permissions: { net: true } }, async function netTcpSetNoDelay() { - const listener = Deno.listen({ port: 3500 }); + const listener = Deno.listen({ port: listenPort }); listener.accept().then( async (conn) => { assert(conn.remoteAddr != null); assert(conn.localAddr.transport === "tcp"); assertEquals(conn.localAddr.hostname, "127.0.0.1"); - assertEquals(conn.localAddr.port, 3500); + assertEquals(conn.localAddr.port, listenPort); await conn.write(new Uint8Array([1, 2, 3])); conn.close(); }, ); - const conn = await Deno.connect({ hostname: "127.0.0.1", port: 3500 }); + const conn = await Deno.connect({ hostname: "127.0.0.1", port: listenPort }); conn.setNoDelay(true); assert(conn.remoteAddr.transport === "tcp"); assertEquals(conn.remoteAddr.hostname, "127.0.0.1"); - assertEquals(conn.remoteAddr.port, 3500); + assertEquals(conn.remoteAddr.port, listenPort); assert(conn.localAddr != null); const buf = new Uint8Array(1024); const readResult = await conn.read(buf); @@ -283,23 +287,23 @@ Deno.test({ permissions: { net: true } }, async function netTcpSetNoDelay() { }); Deno.test({ permissions: { net: true } }, async function netTcpSetKeepAlive() { - const listener = Deno.listen({ port: 3500 }); + const listener = Deno.listen({ port: listenPort }); listener.accept().then( async (conn) => { assert(conn.remoteAddr != null); assert(conn.localAddr.transport === "tcp"); assertEquals(conn.localAddr.hostname, "127.0.0.1"); - assertEquals(conn.localAddr.port, 3500); + assertEquals(conn.localAddr.port, listenPort); await conn.write(new Uint8Array([1, 2, 3])); conn.close(); }, ); - const conn = await Deno.connect({ hostname: "127.0.0.1", port: 3500 }); + const conn = await Deno.connect({ hostname: "127.0.0.1", port: listenPort }); conn.setKeepAlive(true); assert(conn.remoteAddr.transport === "tcp"); assertEquals(conn.remoteAddr.hostname, "127.0.0.1"); - assertEquals(conn.remoteAddr.port, 3500); + assertEquals(conn.remoteAddr.port, listenPort); assert(conn.localAddr != null); const buf = new Uint8Array(1024); const readResult = await conn.read(buf); @@ -360,14 +364,14 @@ Deno.test( Deno.test( { permissions: { net: true } }, async function netUdpSendReceive() { - const alice = Deno.listenDatagram({ port: 3500, transport: "udp" }); + const alice = Deno.listenDatagram({ port: listenPort, transport: "udp" }); assert(alice.addr.transport === "udp"); - assertEquals(alice.addr.port, 3500); + assertEquals(alice.addr.port, listenPort); assertEquals(alice.addr.hostname, "127.0.0.1"); - const bob = Deno.listenDatagram({ port: 4501, transport: "udp" }); + const bob = Deno.listenDatagram({ port: listenPort2, transport: "udp" }); assert(bob.addr.transport === "udp"); - assertEquals(bob.addr.port, 4501); + assertEquals(bob.addr.port, listenPort2); assertEquals(bob.addr.hostname, "127.0.0.1"); const sent = new Uint8Array([1, 2, 3]); @@ -377,7 +381,7 @@ Deno.test( const [recvd, remote] = await bob.receive(); assert(remote.transport === "udp"); - assertEquals(remote.port, 3500); + assertEquals(remote.port, listenPort); assertEquals(recvd.length, 3); assertEquals(1, recvd[0]); assertEquals(2, recvd[1]); @@ -393,18 +397,18 @@ Deno.test( // Must bind sender to an address that can send to the broadcast address on MacOS. // Macos will give us error 49 when sending the broadcast packet if we omit hostname here. const alice = Deno.listenDatagram({ - port: 3500, + port: listenPort, transport: "udp", hostname: "0.0.0.0", }); const bob = Deno.listenDatagram({ - port: 4501, + port: listenPort, transport: "udp", hostname: "0.0.0.0", }); assert(bob.addr.transport === "udp"); - assertEquals(bob.addr.port, 4501); + assertEquals(bob.addr.port, listenPort); assertEquals(bob.addr.hostname, "0.0.0.0"); const broadcastAddr = { ...bob.addr, hostname: "255.255.255.255" }; @@ -415,7 +419,7 @@ Deno.test( assertEquals(byteLength, 3); const [recvd, remote] = await bob.receive(); assert(remote.transport === "udp"); - assertEquals(remote.port, 3500); + assertEquals(remote.port, listenPort); assertEquals(recvd.length, 3); assertEquals(1, recvd[0]); assertEquals(2, recvd[1]); @@ -563,9 +567,9 @@ Deno.test( Deno.test( { permissions: { net: true } }, async function netUdpConcurrentSendReceive() { - const socket = Deno.listenDatagram({ port: 3500, transport: "udp" }); + const socket = Deno.listenDatagram({ port: listenPort, transport: "udp" }); assert(socket.addr.transport === "udp"); - assertEquals(socket.addr.port, 3500); + assertEquals(socket.addr.port, listenPort); assertEquals(socket.addr.hostname, "127.0.0.1"); const recvPromise = socket.receive(); @@ -588,7 +592,7 @@ Deno.test( { permissions: { net: true } }, async function netUdpBorrowMutError() { const socket = Deno.listenDatagram({ - port: 4501, + port: listenPort, transport: "udp", }); // Panic happened on second send: BorrowMutError @@ -761,7 +765,7 @@ Deno.test( Deno.test( { permissions: { net: true } }, async function netListenAsyncIterator() { - const addr = { hostname: "127.0.0.1", port: 3500 }; + const addr = { hostname: "127.0.0.1", port: listenPort }; const listener = Deno.listen(addr); const runAsyncIterator = async () => { for await (const conn of listener) { @@ -794,7 +798,7 @@ Deno.test( permissions: { net: true }, }, async function netCloseWriteSuccess() { - const addr = { hostname: "127.0.0.1", port: 3500 }; + const addr = { hostname: "127.0.0.1", port: listenPort }; const listener = Deno.listen(addr); const closeDeferred = deferred(); listener.accept().then(async (conn) => { @@ -850,7 +854,7 @@ Deno.test( } } - const addr = { hostname: "127.0.0.1", port: 3500 }; + const addr = { hostname: "127.0.0.1", port: listenPort }; const listener = Deno.listen(addr); const listenerPromise = iteratorReq(listener); const connectionPromise = (async () => { @@ -898,13 +902,13 @@ Deno.test( Deno.test({ permissions: { net: true } }, async function whatwgStreams() { (async () => { - const listener = Deno.listen({ hostname: "127.0.0.1", port: 3500 }); + const listener = Deno.listen({ hostname: "127.0.0.1", port: listenPort }); const conn = await listener.accept(); await conn.readable.pipeTo(conn.writable); listener.close(); })(); - const conn = await Deno.connect({ hostname: "127.0.0.1", port: 3500 }); + const conn = await Deno.connect({ hostname: "127.0.0.1", port: listenPort }); const reader = conn.readable.getReader(); const writer = conn.writable.getWriter(); const encoder = new TextEncoder(); @@ -957,7 +961,7 @@ Deno.test( async function netListenUnref() { const [statusCode, _output] = await execCode(` async function main() { - const listener = Deno.listen({ port: 3500 }); + const listener = Deno.listen({ port: ${listenPort} }); listener.unref(); await listener.accept(); // This doesn't block the program from exiting } @@ -972,14 +976,14 @@ Deno.test( async function netListenUnref() { const [statusCode, _output] = await execCode(` async function main() { - const listener = Deno.listen({ port: 3500 }); + const listener = Deno.listen({ port: ${listenPort} }); await listener.accept(); listener.unref(); await listener.accept(); // The program exits here throw new Error(); // The program doesn't reach here } main(); - const conn = await Deno.connect({ port: 3500 }); + const conn = await Deno.connect({ port: ${listenPort} }); conn.close(); `); assertEquals(statusCode, 0); @@ -991,7 +995,7 @@ Deno.test( async function netListenUnrefAndRef() { const p = execCode2(` async function main() { - const listener = Deno.listen({ port: 3500 }); + const listener = Deno.listen({ port: ${listenPort} }); listener.unref(); listener.ref(); // This restores 'ref' state of listener console.log("started"); @@ -1001,7 +1005,7 @@ Deno.test( main(); `); await p.waitStdoutText("started"); - const conn = await Deno.connect({ port: 3500 }); + const conn = await Deno.connect({ port: listenPort }); conn.close(); const [statusCode, output] = await p.finished(); assertEquals(statusCode, 0); @@ -1013,7 +1017,7 @@ Deno.test( { permissions: { net: true } }, async function netListenUnrefConcurrentAccept() { const timer = setTimeout(() => {}, 1000); - const listener = Deno.listen({ port: 3500 }); + const listener = Deno.listen({ port: listenPort }); listener.accept().catch(() => {}); listener.unref(); // Unref'd listener still causes Busy error @@ -1044,12 +1048,12 @@ Deno.test({ Deno.test( { permissions: { net: true, read: true, run: true } }, async function netConnUnref() { - const listener = Deno.listen({ port: 3500 }); + const listener = Deno.listen({ port: listenPort }); const intervalId = setInterval(() => {}); // This keeps event loop alive. const program = execCode(` async function main() { - const conn = await Deno.connect({ port: 3500 }); + const conn = await Deno.connect({ port: ${listenPort} }); conn.unref(); await conn.read(new Uint8Array(10)); // The program exits here throw new Error(); // The program doesn't reach here @@ -1068,12 +1072,12 @@ Deno.test( Deno.test( { permissions: { net: true, read: true, run: true } }, async function netConnUnrefReadable() { - const listener = Deno.listen({ port: 3500 }); + const listener = Deno.listen({ port: listenPort }); const intervalId = setInterval(() => {}); // This keeps event loop alive. const program = execCode(` async function main() { - const conn = await Deno.connect({ port: 3500 }); + const conn = await Deno.connect({ port: ${listenPort} }); conn.unref(); const reader = conn.readable.getReader(); await reader.read(); // The program exits here @@ -1093,7 +1097,7 @@ Deno.test( Deno.test({ permissions: { net: true } }, async function netTcpReuseAddr() { const listener1 = Deno.listen({ hostname: "127.0.0.1", - port: 3500, + port: listenPort, }); listener1.accept().then( (conn) => { @@ -1101,7 +1105,7 @@ Deno.test({ permissions: { net: true } }, async function netTcpReuseAddr() { }, ); - const conn1 = await Deno.connect({ hostname: "127.0.0.1", port: 3500 }); + const conn1 = await Deno.connect({ hostname: "127.0.0.1", port: listenPort }); const buf1 = new Uint8Array(1024); await conn1.read(buf1); listener1.close(); @@ -1109,7 +1113,7 @@ Deno.test({ permissions: { net: true } }, async function netTcpReuseAddr() { const listener2 = Deno.listen({ hostname: "127.0.0.1", - port: 3500, + port: listenPort, }); listener2.accept().then( @@ -1118,7 +1122,7 @@ Deno.test({ permissions: { net: true } }, async function netTcpReuseAddr() { }, ); - const conn2 = await Deno.connect({ hostname: "127.0.0.1", port: 3500 }); + const conn2 = await Deno.connect({ hostname: "127.0.0.1", port: listenPort }); const buf2 = new Uint8Array(1024); await conn2.read(buf2); diff --git a/cli/tests/unit/resources_test.ts b/cli/tests/unit/resources_test.ts index 2d1f2fd75..4a55f05a7 100644 --- a/cli/tests/unit/resources_test.ts +++ b/cli/tests/unit/resources_test.ts @@ -1,6 +1,8 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. import { assert, assertEquals, assertThrows } from "./test_util.ts"; +const listenPort = 4505; + Deno.test(function resourcesCloseBadArgs() { assertThrows(() => { Deno.close((null as unknown) as number); @@ -16,8 +18,8 @@ Deno.test(function resourcesStdio() { }); Deno.test({ permissions: { net: true } }, async function resourcesNet() { - const listener = Deno.listen({ port: 4501 }); - const dialerConn = await Deno.connect({ port: 4501 }); + const listener = Deno.listen({ port: listenPort }); + const dialerConn = await Deno.connect({ port: listenPort }); const listenerConn = await listener.accept(); const res = Deno.resources(); diff --git a/cli/tests/unit/serve_test.ts b/cli/tests/unit/serve_test.ts index c26d3f751..d3faac78d 100644 --- a/cli/tests/unit/serve_test.ts +++ b/cli/tests/unit/serve_test.ts @@ -14,6 +14,9 @@ import { fail, } from "./test_util.ts"; +// Since these tests may run in parallel, ensure this port is unique to this file +const servePort = 4502; + const { upgradeHttpRaw, addTrailers, @@ -42,18 +45,18 @@ Deno.test(async function httpServerShutsDownPortBeforeResolving() { const server = Deno.serve({ handler: (_req) => new Response("ok"), - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), }); await listeningPromise; - assertThrows(() => Deno.listen({ port: 4501 })); + assertThrows(() => Deno.listen({ port: servePort })); ac.abort(); await server.finished; - const listener = Deno.listen({ port: 4501 }); + const listener = Deno.listen({ port: servePort }); listener!.close(); }); @@ -79,14 +82,14 @@ Deno.test(async function httpServerCanResolveHostnames() { const server = Deno.serve({ handler: (_req) => new Response("ok"), hostname: "localhost", - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), }); await listeningPromise; - const resp = await fetch("http://localhost:4501/", { + const resp = await fetch(`http://localhost:${servePort}/`, { headers: { "connection": "close" }, }); const text = await resp.text(); @@ -102,7 +105,7 @@ Deno.test(async function httpServerRejectsOnAddrInUse() { const server = Deno.serve({ handler: (_req) => new Response("ok"), hostname: "localhost", - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), @@ -114,7 +117,7 @@ Deno.test(async function httpServerRejectsOnAddrInUse() { Deno.serve({ handler: (_req) => new Response("ok"), hostname: "localhost", - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), @@ -135,20 +138,20 @@ Deno.test({ permissions: { net: true } }, async function httpServerBasic() { // FIXME(bartlomieju): // make sure that request can be inspected console.log(request); - assertEquals(new URL(request.url).href, "http://127.0.0.1:4501/"); + assertEquals(new URL(request.url).href, `http://127.0.0.1:${servePort}/`); assertEquals(await request.text(), ""); assertEquals(remoteAddr.hostname, "127.0.0.1"); promise.resolve(); return new Response("Hello World", { headers: { "foo": "bar" } }); }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), }); await listeningPromise; - const resp = await fetch("http://127.0.0.1:4501/", { + const resp = await fetch(`http://127.0.0.1:${servePort}/`, { headers: { "connection": "close" }, }); await promise; @@ -173,7 +176,7 @@ Deno.test({ permissions: { net: true } }, async function httpServerOnError() { await new Promise((r) => setTimeout(r, 100)); throw "fail"; }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: () => { @@ -182,14 +185,14 @@ Deno.test({ permissions: { net: true } }, async function httpServerOnError() { }); await listeningPromise; - const resp = await fetch("http://127.0.0.1:4501/", { + const resp = await fetch(`http://127.0.0.1:${servePort}/`, { headers: { "connection": "close" }, }); const text = await resp.text(); ac.abort(); await server; - assertEquals(text, "failed: http://127.0.0.1:4501/"); + assertEquals(text, `failed: http://127.0.0.1:${servePort}/`); }); Deno.test( @@ -208,7 +211,7 @@ Deno.test( await new Promise((r) => setTimeout(r, 100)); throw "fail"; }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: () => { @@ -217,7 +220,7 @@ Deno.test( }); await listeningPromise; - const resp = await fetch("http://127.0.0.1:4501/", { + const resp = await fetch(`http://127.0.0.1:${servePort}/`, { headers: { "connection": "close" }, }); const text = await resp.text(); @@ -234,7 +237,7 @@ Deno.test({ permissions: { net: true } }, async function httpServerOverload1() { const listeningPromise = deferred(); const server = Deno.serve({ - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), @@ -242,14 +245,14 @@ Deno.test({ permissions: { net: true } }, async function httpServerOverload1() { // FIXME(bartlomieju): // make sure that request can be inspected console.log(request); - assertEquals(new URL(request.url).href, "http://127.0.0.1:4501/"); + assertEquals(new URL(request.url).href, `http://127.0.0.1:${servePort}/`); assertEquals(await request.text(), ""); promise.resolve(); return new Response("Hello World", { headers: { "foo": "bar" } }); }); await listeningPromise; - const resp = await fetch("http://127.0.0.1:4501/", { + const resp = await fetch(`http://127.0.0.1:${servePort}/`, { headers: { "connection": "close" }, }); await promise; @@ -269,7 +272,7 @@ Deno.test({ permissions: { net: true } }, async function httpServerOverload2() { const listeningPromise = deferred(); const server = Deno.serve({ - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), @@ -277,14 +280,14 @@ Deno.test({ permissions: { net: true } }, async function httpServerOverload2() { // FIXME(bartlomieju): // make sure that request can be inspected console.log(request); - assertEquals(new URL(request.url).href, "http://127.0.0.1:4501/"); + assertEquals(new URL(request.url).href, `http://127.0.0.1:${servePort}/`); assertEquals(await request.text(), ""); promise.resolve(); return new Response("Hello World", { headers: { "foo": "bar" } }); }); await listeningPromise; - const resp = await fetch("http://127.0.0.1:4501/", { + const resp = await fetch(`http://127.0.0.1:${servePort}/`, { headers: { "connection": "close" }, }); await promise; @@ -387,14 +390,14 @@ Deno.test( promise.resolve(); return new Response(""); }, - port: 2333, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), }); await listeningPromise; - const conn = await Deno.connect({ port: 2333 }); + const conn = await Deno.connect({ port: servePort }); // Send GET request with a body + content-length. const encoder = new TextEncoder(); const body = @@ -525,18 +528,18 @@ Deno.test( promise.resolve(); return new Response("", { headers: {} }); }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), }); await listeningPromise; - const conn = await Deno.connect({ port: 4501 }); + const conn = await Deno.connect({ port: servePort }); // Send GET request with a body + content-length. const encoder = new TextEncoder(); const body = - `GET / HTTP/1.1\r\nHost: 127.0.0.1:4501\r\nContent-Length: 5\r\n\r\n12345`; + `GET / HTTP/1.1\r\nHost: 127.0.0.1:${servePort}\r\nContent-Length: 5\r\n\r\n12345`; const writeResult = await conn.write(encoder.encode(body)); assertEquals(body.length, writeResult); @@ -590,14 +593,14 @@ function createStreamTest(count: number, delay: number, action: string) { handler: (_request) => { return new Response(makeStream(count, delay)); }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), }); await listeningPromise; - const resp = await fetch("http://127.0.0.1:4501/"); + const resp = await fetch(`http://127.0.0.1:${servePort}/`); const text = await resp.text(); ac.abort(); @@ -643,14 +646,14 @@ Deno.test( assertEquals("hello world", reqBody); return new Response("yo"); }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), }); await listeningPromise; - const resp = await fetch("http://127.0.0.1:4501/", { + const resp = await fetch(`http://127.0.0.1:${servePort}/`, { body: stream.readable, method: "POST", headers: { "connection": "close" }, @@ -667,13 +670,13 @@ Deno.test({ permissions: { net: true } }, async function httpServerClose() { const listeningPromise = deferred(); const server = Deno.serve({ handler: () => new Response("ok"), - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), }); await listeningPromise; - const client = await Deno.connect({ port: 4501 }); + const client = await Deno.connect({ port: servePort }); client.close(); ac.abort(); await server; @@ -692,13 +695,13 @@ Deno.test({ permissions: { net: true } }, async function httpServerCloseGet() { responsePromise.resolve(); return new Response("ok"); }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), }); await listeningPromise; - const conn = await Deno.connect({ port: 4501 }); + const conn = await Deno.connect({ port: servePort }); const encoder = new TextEncoder(); const body = `GET / HTTP/1.1\r\nHost: example.domain\r\nConnection: close\r\n\r\n`; @@ -719,14 +722,14 @@ Deno.test( const listeningPromise = deferred(); const server = Deno.serve({ handler: () => new Response(new Blob([])), - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), }); await listeningPromise; - const resp = await fetch("http://127.0.0.1:4501/"); + const resp = await fetch(`http://127.0.0.1:${servePort}/`); const respBody = await resp.text(); assertEquals("", respBody); @@ -754,7 +757,7 @@ Deno.test( }); return new Response(body); }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: (err) => { @@ -768,7 +771,7 @@ Deno.test( }); await listeningPromise; - const resp = await fetch("http://127.0.0.1:4501/"); + const resp = await fetch(`http://127.0.0.1:${servePort}/`); // Incorrectly implemented reader ReadableStream should reject. assertStringIncludes(await resp.text(), "Failed to execute 'enqueue'"); await errorPromise; @@ -833,7 +836,7 @@ Deno.test({ permissions: { net: true } }, async function httpServerWebSocket() { }; return response; }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), @@ -841,7 +844,7 @@ Deno.test({ permissions: { net: true } }, async function httpServerWebSocket() { await listeningPromise; const def = deferred(); - const ws = new WebSocket("ws://localhost:4501"); + const ws = new WebSocket(`ws://localhost:${servePort}`); ws.onmessage = (m) => assertEquals(m.data, "foo"); ws.onerror = (e) => { console.error(e); @@ -887,7 +890,7 @@ Deno.test( conn.close(); return response; }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), @@ -895,7 +898,7 @@ Deno.test( await listeningPromise; - const conn = await Deno.connect({ port: 4501 }); + const conn = await Deno.connect({ port: servePort }); await conn.write( new TextEncoder().encode( "GET / HTTP/1.1\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\r\nUpgrade data", @@ -962,7 +965,7 @@ Deno.test( }; return response; }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), @@ -970,7 +973,7 @@ Deno.test( await listeningPromise; const def = deferred(); - const ws = new WebSocket("ws://localhost:4501"); + const ws = new WebSocket(`ws://localhost:${servePort}`); ws.onmessage = (m) => assertEquals(m.data, "foo"); ws.onerror = (e) => { console.error(e); @@ -999,7 +1002,7 @@ Deno.test( socket.onopen = () => socket.close(); return response; }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), @@ -1007,7 +1010,7 @@ Deno.test( await listeningPromise; const def = deferred(); - const ws = new WebSocket("ws://localhost:4501"); + const ws = new WebSocket(`ws://localhost:${servePort}`); ws.onerror = (e) => { console.error(e); fail(); @@ -1041,7 +1044,7 @@ Deno.test( }; return response; }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), @@ -1049,8 +1052,9 @@ Deno.test( await listeningPromise; const def = deferred(); - const ws = new WebSocket("ws://localhost:4501"); - ws.onmessage = (m) => assertEquals(m.data, "http://localhost:4501/"); + const ws = new WebSocket(`ws://localhost:${servePort}`); + ws.onmessage = (m) => + assertEquals(m.data, `http://localhost:${servePort}/`); ws.onerror = (e) => { console.error(e); fail(); @@ -1078,14 +1082,14 @@ Deno.test( promise.resolve(); return new Response(""); }, - port: 2333, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), }); await listeningPromise; - const conn = await Deno.connect({ port: 2333 }); + const conn = await Deno.connect({ port: servePort }); // Send GET request with a body + content-length. const encoder = new TextEncoder(); const smthElse = "x".repeat(16 * 1024 + 256); @@ -1118,14 +1122,14 @@ Deno.test( promise.resolve(); return new Response(""); }, - port: 2333, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), }); await listeningPromise; - const conn = await Deno.connect({ port: 2333 }); + const conn = await Deno.connect({ port: servePort }); // Send GET request with a body + content-length. const encoder = new TextEncoder(); const smthElse = "x".repeat(16 * 1024 + 256); @@ -1161,14 +1165,14 @@ Deno.test( promise.resolve(); return new Response(""); }, - port: 2333, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), }); await listeningPromise; - const conn = await Deno.connect({ port: 2333 }); + const conn = await Deno.connect({ port: servePort }); // Send GET request with a body + connection: close. const encoder = new TextEncoder(); const body = @@ -1191,7 +1195,7 @@ Deno.test( const ac = new AbortController(); const server = Deno.serve( - { port: 2333, signal: ac.signal }, + { port: servePort, signal: ac.signal }, (request) => { assert(request.body); @@ -1203,7 +1207,7 @@ Deno.test( const ts = new TransformStream(); const writable = ts.writable.getWriter(); - const resp = await fetch("http://127.0.0.1:2333/", { + const resp = await fetch(`http://127.0.0.1:${servePort}/`, { method: "POST", body: ts.readable, }); @@ -1255,7 +1259,7 @@ Deno.test( const w = new BufWriter(conn); const r = new BufReader(conn); - const body = `GET / HTTP/1.1\r\nHost: 127.0.0.1:4501\r\n\r\n`; + const body = `GET / HTTP/1.1\r\nHost: 127.0.0.1:${servePort}\r\n\r\n`; const writeResult = await w.write(encoder.encode(body)); assertEquals(body.length, writeResult); await w.flush(); @@ -1313,7 +1317,7 @@ Deno.test( promise.resolve(); return new Response(periodicStream()); }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), @@ -1321,7 +1325,7 @@ Deno.test( await listeningPromise; // start a client - const clientConn = await Deno.connect({ port: 4501 }); + const clientConn = await Deno.connect({ port: servePort }); const r1 = await writeRequest(clientConn); assertEquals(r1, "0\n1\n2\n"); @@ -1345,16 +1349,16 @@ Deno.test( promise.resolve(); return new Response("hello", { headers: { "X-Header-Test": "Æ" } }); }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), }); await listeningPromise; - const clientConn = await Deno.connect({ port: 4501 }); + const clientConn = await Deno.connect({ port: servePort }); const requestText = - "GET / HTTP/1.1\r\nHost: 127.0.0.1:4501\r\nX-Header-Test: á\r\n\r\n"; + `GET / HTTP/1.1\r\nHost: 127.0.0.1:${servePort}\r\nX-Header-Test: á\r\n\r\n`; const requestBytes = new Uint8Array(requestText.length); for (let i = 0; i < requestText.length; i++) { requestBytes[i] = requestText.charCodeAt(i); @@ -1388,19 +1392,19 @@ Deno.test( const server = Deno.serve({ handler: async (request) => { // FIXME: - // assertEquals(new URL(request.url).href, "http://127.0.0.1:4501/"); + // assertEquals(new URL(request.url).href, `http://127.0.0.1:${servePort}/`); assertEquals(await request.text(), ""); promise.resolve(); return new Response("11"); }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), }); await listeningPromise; - const clientConn = await Deno.connect({ port: 4501 }); + const clientConn = await Deno.connect({ port: servePort }); async function writeRequest(conn: Deno.Conn) { const encoder = new TextEncoder(); @@ -1408,7 +1412,7 @@ Deno.test( const w = new BufWriter(conn); const r = new BufReader(conn); const body = - `CONNECT 127.0.0.1:4501 HTTP/1.1\r\nHost: 127.0.0.1:4501\r\n\r\n`; + `CONNECT 127.0.0.1:${servePort} HTTP/1.1\r\nHost: 127.0.0.1:${servePort}\r\n\r\n`; const writeResult = await w.write(encoder.encode(body)); assertEquals(body.length, writeResult); await w.flush(); @@ -1446,7 +1450,7 @@ Deno.test( promise.resolve(); return new Response("ok"); }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), @@ -1454,7 +1458,7 @@ Deno.test( }); await listeningPromise; - const resp = await fetch("http://127.0.0.1:4501/", { + const resp = await fetch(`http://127.0.0.1:${servePort}/`, { headers: [ ["connection", "close"], ["cookie", "foo=bar"], @@ -1482,21 +1486,20 @@ Deno.test( const ac = new AbortController(); const hostname = "localhost"; - const port = 4501; const server = Deno.serve({ handler: () => { promise.resolve(); return new Response("ok"); }, - port: port, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), }); await listeningPromise; - const url = `http://${hostname}:${port}/`; + const url = `http://${hostname}:${servePort}/`; const args = ["-X", "DELETE", url]; const { success } = await new Deno.Command("curl", { args, @@ -1525,13 +1528,13 @@ Deno.test( promise.resolve(); return new Response(new Uint8Array([128])); }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), }); await listeningPromise; - const resp = await fetch("http://localhost:4501/"); + const resp = await fetch(`http://localhost:${servePort}/`); await promise; @@ -2211,12 +2214,11 @@ Deno.test( const ac = new AbortController(); const listeningPromise = deferred(); const hostname = "127.0.0.1"; - const port = 4501; const server = Deno.serve({ handler: () => new Response("Hello World"), hostname, - port, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), @@ -2227,7 +2229,7 @@ Deno.test( await listeningPromise; const caCert = Deno.readTextFileSync("cli/tests/testdata/tls/RootCA.pem"); const client = Deno.createHttpClient({ caCerts: [caCert] }); - const resp = await fetch(`https://localhost:${port}/`, { + const resp = await fetch(`https://localhost:${servePort}/`, { client, headers: { "connection": "close" }, }); @@ -2332,7 +2334,7 @@ Deno.test( const ac = new AbortController(); const server = Deno.serve({ handler: (_request) => new Response(null, { status: 204 }), - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), @@ -2340,7 +2342,7 @@ Deno.test( try { await listeningPromise; - const resp = await fetch("http://127.0.0.1:4501/", { + const resp = await fetch(`http://127.0.0.1:${servePort}/`, { method: "GET", headers: { "connection": "close" }, }); @@ -2641,7 +2643,7 @@ Deno.test( const server = Deno.serve({ handler: (_req) => new Response("ok"), hostname: "localhost", - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), @@ -2940,7 +2942,7 @@ Deno.test( addTrailers(response, [["baz", "why"]]); return response; }, - port: 4501, + port: servePort, signal: ac.signal, onListen: onListen(listeningPromise), onError: createOnErrorCb(ac), @@ -2948,7 +2950,7 @@ Deno.test( // We don't have a great way to access this right now, so just fetch the trailers with cURL const [_, stderr] = await curlRequestWithStdErr([ - "http://localhost:4501/path", + `http://localhost:${servePort}/path`, "-v", "--http2", "--http2-prior-knowledge", diff --git a/cli/tests/unit/streams_deprecated.ts b/cli/tests/unit/streams_deprecated.ts deleted file mode 100644 index 04dbfa3fb..000000000 --- a/cli/tests/unit/streams_deprecated.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -import { assertEquals } from "./test_util.ts"; - -Deno.test(async function symlinkSyncPerm() { - const rs = new ReadableStream({ - start(controller) { - controller.enqueue("hello "); - controller.enqueue("deno"); - controller.close(); - }, - }); - - for await (const chunk of rs.getIterator()) { - assertEquals(typeof chunk, "string"); - } -}); diff --git a/cli/tests/unit_node/crypto/crypto_cipher_test.ts b/cli/tests/unit_node/crypto/crypto_cipher_test.ts new file mode 100644 index 000000000..a8a5130cf --- /dev/null +++ b/cli/tests/unit_node/crypto/crypto_cipher_test.ts @@ -0,0 +1,186 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +import crypto from "node:crypto"; +import { Buffer } from "node:buffer"; +import { Readable } from "node:stream"; +import { buffer, text } from "node:stream/consumers"; +import { + assertEquals, + assertThrows, +} from "../../../../test_util/std/testing/asserts.ts"; + +const rsaPrivateKey = Deno.readTextFileSync( + new URL("../testdata/rsa_private.pem", import.meta.url), +); +const rsaPublicKey = Deno.readTextFileSync( + new URL("../testdata/rsa_public.pem", import.meta.url), +); + +const input = new TextEncoder().encode("hello world"); + +function zeros(length: number): Uint8Array { + return new Uint8Array(length); +} + +Deno.test({ + name: "rsa public encrypt and private decrypt", + fn() { + const encrypted = crypto.publicEncrypt(Buffer.from(rsaPublicKey), input); + const decrypted = crypto.privateDecrypt( + Buffer.from(rsaPrivateKey), + Buffer.from(encrypted), + ); + assertEquals(decrypted, input); + }, +}); + +Deno.test({ + name: "rsa private encrypt and private decrypt", + fn() { + const encrypted = crypto.privateEncrypt(rsaPrivateKey, input); + const decrypted = crypto.privateDecrypt( + rsaPrivateKey, + Buffer.from(encrypted), + ); + assertEquals(decrypted, input); + }, +}); + +Deno.test({ + name: "rsa public decrypt fail", + fn() { + const encrypted = crypto.publicEncrypt(rsaPublicKey, input); + assertThrows(() => + crypto.publicDecrypt(rsaPublicKey, Buffer.from(encrypted)) + ); + }, +}); + +Deno.test({ + name: "createCipheriv - multiple chunk inputs", + fn() { + const cipher = crypto.createCipheriv( + "aes-128-cbc", + new Uint8Array(16), + new Uint8Array(16), + ); + assertEquals( + cipher.update(new Uint8Array(16), undefined, "hex"), + "66e94bd4ef8a2c3b884cfa59ca342b2e", + ); + assertEquals( + cipher.update(new Uint8Array(19), undefined, "hex"), + "f795bd4a52e29ed713d313fa20e98dbc", + ); + assertEquals( + cipher.update(new Uint8Array(55), undefined, "hex"), + "a10cf66d0fddf3405370b4bf8df5bfb347c78395e0d8ae2194da0a90abc9888a94ee48f6c78fcd518a941c3896102cb1", + ); + assertEquals(cipher.final("hex"), "e11901dde4a2f99fe4efc707e48c6aed"); + }, +}); + +Deno.test({ + name: "createCipheriv - algorithms", + fn() { + const table = [ + [ + ["aes-128-cbc", 16, 16], + "66e94bd4ef8a2c3b884cfa59ca342b2ef795bd4a52e29ed713d313fa20e98dbca10cf66d0fddf3405370b4bf8df5bfb3", + "d5f65ecda64511e9d3d12206411ffd72", + ], + [ + ["aes-128-ecb", 16, 0], + "66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e", + "baf823258ca2e6994f638daa3515e986", + ], + ] as const; + for ( + const [[alg, keyLen, ivLen], expectedUpdate, expectedFinal] of table + ) { + const cipher = crypto.createCipheriv(alg, zeros(keyLen), zeros(ivLen)); + assertEquals(cipher.update(zeros(50), undefined, "hex"), expectedUpdate); + assertEquals(cipher.final("hex"), expectedFinal); + } + }, +}); + +Deno.test({ + name: "createCipheriv - input encoding", + fn() { + const cipher = crypto.createCipheriv( + "aes-128-cbc", + new Uint8Array(16), + new Uint8Array(16), + ); + assertEquals( + cipher.update("hello, world! hello, world!", "utf-8", "hex"), + "ca7df4d74f51b77a7440ead38343ab0f", + ); + assertEquals(cipher.final("hex"), "d0da733dec1fa61125c80a6f97e6166e"); + }, +}); + +Deno.test({ + name: "createCipheriv - transform stream", + async fn() { + const result = await buffer( + Readable.from("foo".repeat(15)).pipe(crypto.createCipheriv( + "aes-128-cbc", + new Uint8Array(16), + new Uint8Array(16), + )), + ); + // deno-fmt-ignore + assertEquals([...result], [ + 129, 19, 202, 142, 137, 51, 23, 53, 198, 33, + 214, 125, 17, 5, 128, 57, 162, 217, 220, 53, + 172, 51, 85, 113, 71, 250, 44, 156, 80, 4, + 158, 92, 185, 173, 67, 47, 255, 71, 78, 187, + 80, 206, 42, 5, 34, 104, 1, 54 + ]); + }, +}); + +Deno.test({ + name: "createDecipheriv - algorithms", + fn() { + const table = [ + [ + ["aes-128-cbc", 16, 16], + "66e94bd4ef8a2c3b884cfa59ca342b2ef795bd4a52e29ed713d313fa20e98dbca10cf66d0fddf3405370b4bf8df5bfb347c78395e0d8ae2194da0a90abc9888a94ee48f6c78fcd518a941c3896102cb1e11901dde4a2f99fe4efc707e48c6aed", + ], + [ + ["aes-128-ecb", 16, 0], + "66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2ec29a917cbaf72fa9bc32129bb0d17663", + ], + ] as const; + for ( + const [[alg, keyLen, ivLen], input] of table + ) { + const cipher = crypto.createDecipheriv(alg, zeros(keyLen), zeros(ivLen)); + assertEquals(cipher.update(input, "hex"), Buffer.alloc(80)); + assertEquals(cipher.final(), Buffer.alloc(10)); + } + }, +}); + +Deno.test({ + name: "createDecipheriv - transform stream", + async fn() { + const stream = Readable.from([ + // deno-fmt-ignore + new Uint8Array([ + 129, 19, 202, 142, 137, 51, 23, 53, 198, 33, + 214, 125, 17, 5, 128, 57, 162, 217, 220, 53, + 172, 51, 85, 113, 71, 250, 44, 156, 80, 4, + 158, 92, 185, 173, 67, 47, 255, 71, 78, 187, + 80, 206, 42, 5, 34, 104, 1, 54 + ]), + ]).pipe(crypto.createDecipheriv( + "aes-128-cbc", + new Uint8Array(16), + new Uint8Array(16), + )); + assertEquals(await text(stream), "foo".repeat(15)); + }, +}); diff --git a/cli/tests/unit_node/crypto/crypto_hash_test.ts b/cli/tests/unit_node/crypto/crypto_hash_test.ts new file mode 100644 index 000000000..679577770 --- /dev/null +++ b/cli/tests/unit_node/crypto/crypto_hash_test.ts @@ -0,0 +1,24 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +import { createHash, createHmac } from "node:crypto"; +import { assertEquals } from "../../../../test_util/std/testing/asserts.ts"; + +// https://github.com/denoland/deno/issues/18140 +Deno.test({ + name: "createHmac digest", + fn() { + assertEquals( + createHmac("sha256", "secret").update("hello").digest("hex"), + "88aab3ede8d3adf94d26ab90d3bafd4a2083070c3bcce9c014ee04a443847c0b", + ); + }, +}); + +Deno.test({ + name: "createHash digest", + fn() { + assertEquals( + createHash("sha256").update("hello").digest("hex"), + "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + ); + }, +}); diff --git a/cli/tests/unit_node/crypto/crypto_key_test.ts b/cli/tests/unit_node/crypto/crypto_key_test.ts new file mode 100644 index 000000000..672c9fa7f --- /dev/null +++ b/cli/tests/unit_node/crypto/crypto_key_test.ts @@ -0,0 +1,204 @@ +// deno-lint-ignore-file no-explicit-any + +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +import { + createSecretKey, + generateKeyPair, + generateKeyPairSync, + KeyObject, + randomBytes, +} from "node:crypto"; +import { promisify } from "node:util"; +import { Buffer } from "node:buffer"; +import { + assertEquals, + assertThrows, +} from "../../../../test_util/std/testing/asserts.ts"; +import { createHmac } from "node:crypto"; + +const generateKeyPairAsync = promisify( + ( + type: any, + options: any, + callback: ( + err: Error | null, + key: { publicKey: KeyObject; privateKey: KeyObject }, + ) => void, + ) => + generateKeyPair( + type, + options, + (err: Error | null, publicKey: KeyObject, privateKey: KeyObject) => { + callback(err, { publicKey, privateKey }); + }, + ), +); + +Deno.test({ + name: "create secret key", + fn() { + const key = createSecretKey(Buffer.alloc(0)); + assertEquals(key.type, "secret"); + assertEquals(key.asymmetricKeyType, undefined); + assertEquals(key.symmetricKeySize, 0); + }, +}); + +Deno.test({ + name: "export secret key", + fn() { + const material = Buffer.from(randomBytes(32)); + const key = createSecretKey(material); + assertEquals(Buffer.from(key.export()), material); + }, +}); + +Deno.test({ + name: "export jwk secret key", + fn() { + const material = Buffer.from("secret"); + const key = createSecretKey(material); + assertEquals(key.export({ format: "jwk" }), { + kty: "oct", + k: "c2VjcmV0", + }); + }, +}); + +Deno.test({ + name: "createHmac with secret key", + fn() { + const key = createSecretKey(Buffer.from("secret")); + assertEquals( + createHmac("sha256", key).update("hello").digest().toString("hex"), + "88aab3ede8d3adf94d26ab90d3bafd4a2083070c3bcce9c014ee04a443847c0b", + ); + }, +}); + +for (const type of ["rsa", "rsa-pss", "dsa"]) { + for (const modulusLength of [2048, 3072]) { + Deno.test({ + name: `generate ${type} key`, + fn() { + const { publicKey, privateKey } = generateKeyPairSync(type as any, { + modulusLength, + }); + + assertEquals(publicKey.type, "public"); + assertEquals(privateKey.type, "private"); + }, + }); + + Deno.test({ + name: `generate ${type} key async`, + async fn() { + const x = await generateKeyPairAsync(type as any, { + modulusLength, + }); + const { publicKey, privateKey } = x; + assertEquals(publicKey.type, "public"); + assertEquals(privateKey.type, "private"); + }, + }); + } +} + +for (const namedCurve of ["P-384", "P-256"]) { + Deno.test({ + name: `generate ec key ${namedCurve}`, + fn() { + const { publicKey, privateKey } = generateKeyPairSync("ec", { + namedCurve, + }); + + assertEquals(publicKey.type, "public"); + assertEquals(privateKey.type, "private"); + }, + }); + + Deno.test({ + name: `generate ec key ${namedCurve} async`, + async fn() { + const { publicKey, privateKey } = await generateKeyPairAsync("ec", { + namedCurve, + }); + + assertEquals(publicKey.type, "public"); + assertEquals(privateKey.type, "private"); + }, + }); + + Deno.test({ + name: `generate ec key ${namedCurve} paramEncoding=explicit fails`, + fn() { + assertThrows(() => { + // @ts-ignore: @types/node is broken? + generateKeyPairSync("ec", { + namedCurve, + paramEncoding: "explicit", + }); + }); + }, + }); +} + +for ( + const groupName of ["modp5", "modp14", "modp15", "modp16", "modp17", "modp18"] +) { + Deno.test({ + name: `generate dh key ${groupName}`, + fn() { + // @ts-ignore: @types/node is broken? + const { publicKey, privateKey } = generateKeyPairSync("dh", { + group: groupName, + }); + + assertEquals(publicKey.type, "public"); + assertEquals(privateKey.type, "private"); + }, + }); + + Deno.test({ + name: `generate dh key ${groupName} async`, + async fn() { + // @ts-ignore: @types/node is broken? + const { publicKey, privateKey } = await generateKeyPairAsync("dh", { + group: groupName, + }); + + assertEquals(publicKey.type, "public"); + assertEquals(privateKey.type, "private"); + }, + }); +} + +for (const primeLength of [1024, 2048, 4096]) { + Deno.test({ + name: `generate dh key ${primeLength}`, + fn() { + // @ts-ignore: @types/node is broken? + const { publicKey, privateKey } = generateKeyPairSync("dh", { + primeLength, + generator: 2, + }); + + assertEquals(publicKey.type, "public"); + assertEquals(privateKey.type, "private"); + }, + }); + + Deno.test({ + name: `generate dh key ${primeLength} async`, + async fn() { + // @ts-ignore: @types/node is broken? + const { publicKey, privateKey } = await generateKeyPairAsync("dh", { + primeLength, + generator: 2, + }); + + assertEquals(publicKey.type, "public"); + assertEquals(privateKey.type, "private"); + }, + }); +} diff --git a/cli/tests/unit_node/crypto/crypto_sign_test.ts b/cli/tests/unit_node/crypto/crypto_sign_test.ts new file mode 100644 index 000000000..9988ed71c --- /dev/null +++ b/cli/tests/unit_node/crypto/crypto_sign_test.ts @@ -0,0 +1,91 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. + +import { + assert, + assertEquals, +} from "../../../../test_util/std/testing/asserts.ts"; +import { createSign, createVerify, sign, verify } from "node:crypto"; +import { Buffer } from "node:buffer"; + +const rsaPrivatePem = Buffer.from( + await Deno.readFile( + new URL("../testdata/rsa_private.pem", import.meta.url), + ), +); +const rsaPublicPem = Buffer.from( + await Deno.readFile( + new URL("../testdata/rsa_public.pem", import.meta.url), + ), +); + +const table = [ + { + algorithms: ["sha224", "RSA-SHA224"], + signature: + "7ad162b288bd7f4ba9b8a31295ad4136d143a5fd11eb99a72379dc9b53e3e8b5c1b7c9dd8a3864a1f626d921e550c48056982bd8fe7e75333885311b5515de1ecbbfcc6a1dd930f422dff87bfceb7eb38882ac6b4fd9dea9efd462776775976e81b1d677f8db41f5ac8686abfa9838069125be939c59e404aa50550872d84befb8b5f6ce2dd051c62a8ba268f876b6f17a27af43b79938222e4ab8b90c4f5540d0f8b02508ef3e68279d685746956b924f00c92438b7981a3cfcb1e2a97305402d381ea62aeaa803f8707961bc3e10a258352e210772e9846ca4024e3dc0a956a50d6db1c03d2943826cc98c6f36d7bafacf1c94b6c438c7664c300a3be172b1", + }, + { + algorithms: ["sha256", "RSA-SHA256"], + signature: + "080313284d7398e1e0e27f6e44f198ceecedddc801e81af63a867d9245ad744e29018099c9ac3c27061c33cabfe27af1db38f44bac09cdcd2c4ab3b00a2a3020f68368f2239db5f911a2dbb7ea2dee322ca7d26d0c88d197482ca4aa1c29ac87b9e6c20075dc974ae71d2d76d2a5b2a15bd541033519465c3aea815cc73b0f1c3ffeedcfb93d6788416623789f86786870d23e86b982ab0df157d7a596097bd3cca3e752f3f47eff4b83754296868b52bc8ff741492dc8a401fe6dc035569e45d1fa1a71c8988d3aadce68fb1bf5c3e756c586af20c8e75c037436ff4c8389e6ce9d943ef7e2566977b84577272181fcec403077cc29e7db1166fff900b36a1d", + }, + { + algorithms: ["sha384", "RSA-SHA384"], + signature: + "2f77a5b7ac0168efd652c30ecb082075f3de30629e9c1f51b7e7e671f24b5c3a2606bb72159a217438220fc7aaba887d4b817e3f43fe0cc8f840747368df8cd65ec760c21a3f9296d01caedc80a335030e31d31ac451277fc4bcc1679c168b2c3185dfee21286514113c080af5238a61a677b03777344f476f25053108588aa6bdc02a6138c6b59a20de4d11e3d668482f17e748e75747f83c0512206283acfc64ed0ad963dddc9ec24589cfd459ee806b8e0e67b93cea16651e967762a5deef890f438ffb9db39247469289db06e2ed7fe262aa1df4ab9607e5b5219a17ddc9694283a61bf8643f58fd702f2c5d3b2d53dc7f36bb5e96461174d376950d6d19", + }, + { + algorithms: ["sha512", "RSA-SHA512"], + signature: + "072e20a433f255ab2f7e5e9ce69255d5c6d7c15a36af75c8389b9672c41abc6a9532fbd057d9d64270bb2483d3c9923f8f419fba4b59b838dcda82a1322009d245c06e2802a74febaea9cebc0b7f46f8761331c5f52ffb650245b5aefefcc604f209b44f6560fe45370cb239d236622e5f72fbb45377f08a0c733e16a8f15830897679ad4349d2e2e5e50a99796820302f4f47881ed444aede56a6d3330b71acaefc4218ae2e4a3bdfbb0c9432ffc5e5bac8c168278b2205d68a5d6905ccbb91282d519c11eccca52d42c86787de492b2a89679dce98cd14c37b0c183af8427e7a1ec86b1ed3f9b5bebf83f1ef81eb18748e69c716a0f263a8598fe627158647", + }, +]; + +const data = Buffer.from("some data to sign"); + +Deno.test({ + name: + "crypto.Sign|sign - RSA PEM with SHA224, SHA256, SHA384, SHA512 digests", + fn() { + for (const testCase of table) { + for (const algorithm of testCase.algorithms) { + assertEquals( + createSign(algorithm) + .update(data) + .sign(rsaPrivatePem, "hex"), + testCase.signature, + ); + assertEquals( + sign(algorithm, data, rsaPrivatePem), + Buffer.from(testCase.signature, "hex"), + ); + } + } + }, +}); + +Deno.test({ + name: + "crypto.Verify|verify - RSA PEM with SHA224, SHA256, SHA384, SHA512 digests", + fn() { + for (const testCase of table) { + for (const algorithm of testCase.algorithms) { + assert( + createVerify(algorithm).update(data).verify( + rsaPublicPem, + testCase.signature, + "hex", + ), + ); + assert( + verify( + algorithm, + data, + rsaPublicPem, + Buffer.from(testCase.signature, "hex"), + ), + ); + } + } + }, +}); diff --git a/cli/tests/unit_node/crypto_cipher_test.ts b/cli/tests/unit_node/crypto_cipher_test.ts deleted file mode 100644 index 2c8cca256..000000000 --- a/cli/tests/unit_node/crypto_cipher_test.ts +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -import crypto from "node:crypto"; -import { Buffer } from "node:buffer"; -import { Readable } from "node:stream"; -import { buffer, text } from "node:stream/consumers"; -import { - assertEquals, - assertThrows, -} from "../../../test_util/std/testing/asserts.ts"; - -const rsaPrivateKey = Deno.readTextFileSync( - new URL("./testdata/rsa_private.pem", import.meta.url), -); -const rsaPublicKey = Deno.readTextFileSync( - new URL("./testdata/rsa_public.pem", import.meta.url), -); - -const input = new TextEncoder().encode("hello world"); - -function zeros(length: number): Uint8Array { - return new Uint8Array(length); -} - -Deno.test({ - name: "rsa public encrypt and private decrypt", - fn() { - const encrypted = crypto.publicEncrypt(Buffer.from(rsaPublicKey), input); - const decrypted = crypto.privateDecrypt( - Buffer.from(rsaPrivateKey), - Buffer.from(encrypted), - ); - assertEquals(decrypted, input); - }, -}); - -Deno.test({ - name: "rsa private encrypt and private decrypt", - fn() { - const encrypted = crypto.privateEncrypt(rsaPrivateKey, input); - const decrypted = crypto.privateDecrypt( - rsaPrivateKey, - Buffer.from(encrypted), - ); - assertEquals(decrypted, input); - }, -}); - -Deno.test({ - name: "rsa public decrypt fail", - fn() { - const encrypted = crypto.publicEncrypt(rsaPublicKey, input); - assertThrows(() => - crypto.publicDecrypt(rsaPublicKey, Buffer.from(encrypted)) - ); - }, -}); - -Deno.test({ - name: "createCipheriv - multiple chunk inputs", - fn() { - const cipher = crypto.createCipheriv( - "aes-128-cbc", - new Uint8Array(16), - new Uint8Array(16), - ); - assertEquals( - cipher.update(new Uint8Array(16), undefined, "hex"), - "66e94bd4ef8a2c3b884cfa59ca342b2e", - ); - assertEquals( - cipher.update(new Uint8Array(19), undefined, "hex"), - "f795bd4a52e29ed713d313fa20e98dbc", - ); - assertEquals( - cipher.update(new Uint8Array(55), undefined, "hex"), - "a10cf66d0fddf3405370b4bf8df5bfb347c78395e0d8ae2194da0a90abc9888a94ee48f6c78fcd518a941c3896102cb1", - ); - assertEquals(cipher.final("hex"), "e11901dde4a2f99fe4efc707e48c6aed"); - }, -}); - -Deno.test({ - name: "createCipheriv - algorithms", - fn() { - const table = [ - [ - ["aes-128-cbc", 16, 16], - "66e94bd4ef8a2c3b884cfa59ca342b2ef795bd4a52e29ed713d313fa20e98dbca10cf66d0fddf3405370b4bf8df5bfb3", - "d5f65ecda64511e9d3d12206411ffd72", - ], - [ - ["aes-128-ecb", 16, 0], - "66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e", - "baf823258ca2e6994f638daa3515e986", - ], - ] as const; - for ( - const [[alg, keyLen, ivLen], expectedUpdate, expectedFinal] of table - ) { - const cipher = crypto.createCipheriv(alg, zeros(keyLen), zeros(ivLen)); - assertEquals(cipher.update(zeros(50), undefined, "hex"), expectedUpdate); - assertEquals(cipher.final("hex"), expectedFinal); - } - }, -}); - -Deno.test({ - name: "createCipheriv - input encoding", - fn() { - const cipher = crypto.createCipheriv( - "aes-128-cbc", - new Uint8Array(16), - new Uint8Array(16), - ); - assertEquals( - cipher.update("hello, world! hello, world!", "utf-8", "hex"), - "ca7df4d74f51b77a7440ead38343ab0f", - ); - assertEquals(cipher.final("hex"), "d0da733dec1fa61125c80a6f97e6166e"); - }, -}); - -Deno.test({ - name: "createCipheriv - transform stream", - async fn() { - const result = await buffer( - Readable.from("foo".repeat(15)).pipe(crypto.createCipheriv( - "aes-128-cbc", - new Uint8Array(16), - new Uint8Array(16), - )), - ); - // deno-fmt-ignore - assertEquals([...result], [ - 129, 19, 202, 142, 137, 51, 23, 53, 198, 33, - 214, 125, 17, 5, 128, 57, 162, 217, 220, 53, - 172, 51, 85, 113, 71, 250, 44, 156, 80, 4, - 158, 92, 185, 173, 67, 47, 255, 71, 78, 187, - 80, 206, 42, 5, 34, 104, 1, 54 - ]); - }, -}); - -Deno.test({ - name: "createDecipheriv - algorithms", - fn() { - const table = [ - [ - ["aes-128-cbc", 16, 16], - "66e94bd4ef8a2c3b884cfa59ca342b2ef795bd4a52e29ed713d313fa20e98dbca10cf66d0fddf3405370b4bf8df5bfb347c78395e0d8ae2194da0a90abc9888a94ee48f6c78fcd518a941c3896102cb1e11901dde4a2f99fe4efc707e48c6aed", - ], - [ - ["aes-128-ecb", 16, 0], - "66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2ec29a917cbaf72fa9bc32129bb0d17663", - ], - ] as const; - for ( - const [[alg, keyLen, ivLen], input] of table - ) { - const cipher = crypto.createDecipheriv(alg, zeros(keyLen), zeros(ivLen)); - assertEquals(cipher.update(input, "hex"), Buffer.alloc(80)); - assertEquals(cipher.final(), Buffer.alloc(10)); - } - }, -}); - -Deno.test({ - name: "createDecipheriv - transform stream", - async fn() { - const stream = Readable.from([ - // deno-fmt-ignore - new Uint8Array([ - 129, 19, 202, 142, 137, 51, 23, 53, 198, 33, - 214, 125, 17, 5, 128, 57, 162, 217, 220, 53, - 172, 51, 85, 113, 71, 250, 44, 156, 80, 4, - 158, 92, 185, 173, 67, 47, 255, 71, 78, 187, - 80, 206, 42, 5, 34, 104, 1, 54 - ]), - ]).pipe(crypto.createDecipheriv( - "aes-128-cbc", - new Uint8Array(16), - new Uint8Array(16), - )); - assertEquals(await text(stream), "foo".repeat(15)); - }, -}); diff --git a/cli/tests/unit_node/crypto_hash.ts b/cli/tests/unit_node/crypto_hash.ts deleted file mode 100644 index fae66e024..000000000 --- a/cli/tests/unit_node/crypto_hash.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -import { createHash, createHmac } from "node:crypto"; -import { assertEquals } from "../../../test_util/std/testing/asserts.ts"; - -// https://github.com/denoland/deno/issues/18140 -Deno.test({ - name: "createHmac digest", - fn() { - assertEquals( - createHmac("sha256", "secret").update("hello").digest("hex"), - "88aab3ede8d3adf94d26ab90d3bafd4a2083070c3bcce9c014ee04a443847c0b", - ); - }, -}); - -Deno.test({ - name: "createHash digest", - fn() { - assertEquals( - createHash("sha256").update("hello").digest("hex"), - "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", - ); - }, -}); diff --git a/cli/tests/unit_node/crypto_key.ts b/cli/tests/unit_node/crypto_key.ts deleted file mode 100644 index 49d81003f..000000000 --- a/cli/tests/unit_node/crypto_key.ts +++ /dev/null @@ -1,204 +0,0 @@ -// deno-lint-ignore-file no-explicit-any - -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -import { - createSecretKey, - generateKeyPair, - generateKeyPairSync, - KeyObject, - randomBytes, -} from "node:crypto"; -import { promisify } from "node:util"; -import { Buffer } from "node:buffer"; -import { - assertEquals, - assertThrows, -} from "../../../test_util/std/testing/asserts.ts"; -import { createHmac } from "node:crypto"; - -const generateKeyPairAsync = promisify( - ( - type: any, - options: any, - callback: ( - err: Error | null, - key: { publicKey: KeyObject; privateKey: KeyObject }, - ) => void, - ) => - generateKeyPair( - type, - options, - (err: Error | null, publicKey: KeyObject, privateKey: KeyObject) => { - callback(err, { publicKey, privateKey }); - }, - ), -); - -Deno.test({ - name: "create secret key", - fn() { - const key = createSecretKey(Buffer.alloc(0)); - assertEquals(key.type, "secret"); - assertEquals(key.asymmetricKeyType, undefined); - assertEquals(key.symmetricKeySize, 0); - }, -}); - -Deno.test({ - name: "export secret key", - fn() { - const material = Buffer.from(randomBytes(32)); - const key = createSecretKey(material); - assertEquals(Buffer.from(key.export()), material); - }, -}); - -Deno.test({ - name: "export jwk secret key", - fn() { - const material = Buffer.from("secret"); - const key = createSecretKey(material); - assertEquals(key.export({ format: "jwk" }), { - kty: "oct", - k: "c2VjcmV0", - }); - }, -}); - -Deno.test({ - name: "createHmac with secret key", - fn() { - const key = createSecretKey(Buffer.from("secret")); - assertEquals( - createHmac("sha256", key).update("hello").digest().toString("hex"), - "88aab3ede8d3adf94d26ab90d3bafd4a2083070c3bcce9c014ee04a443847c0b", - ); - }, -}); - -for (const type of ["rsa", "rsa-pss", "dsa"]) { - for (const modulusLength of [2048, 3072]) { - Deno.test({ - name: `generate ${type} key`, - fn() { - const { publicKey, privateKey } = generateKeyPairSync(type as any, { - modulusLength, - }); - - assertEquals(publicKey.type, "public"); - assertEquals(privateKey.type, "private"); - }, - }); - - Deno.test({ - name: `generate ${type} key async`, - async fn() { - const x = await generateKeyPairAsync(type as any, { - modulusLength, - }); - const { publicKey, privateKey } = x; - assertEquals(publicKey.type, "public"); - assertEquals(privateKey.type, "private"); - }, - }); - } -} - -for (const namedCurve of ["P-384", "P-256"]) { - Deno.test({ - name: `generate ec key ${namedCurve}`, - fn() { - const { publicKey, privateKey } = generateKeyPairSync("ec", { - namedCurve, - }); - - assertEquals(publicKey.type, "public"); - assertEquals(privateKey.type, "private"); - }, - }); - - Deno.test({ - name: `generate ec key ${namedCurve} async`, - async fn() { - const { publicKey, privateKey } = await generateKeyPairAsync("ec", { - namedCurve, - }); - - assertEquals(publicKey.type, "public"); - assertEquals(privateKey.type, "private"); - }, - }); - - Deno.test({ - name: `generate ec key ${namedCurve} paramEncoding=explicit fails`, - fn() { - assertThrows(() => { - // @ts-ignore: @types/node is broken? - generateKeyPairSync("ec", { - namedCurve, - paramEncoding: "explicit", - }); - }); - }, - }); -} - -for ( - const groupName of ["modp5", "modp14", "modp15", "modp16", "modp17", "modp18"] -) { - Deno.test({ - name: `generate dh key ${groupName}`, - fn() { - // @ts-ignore: @types/node is broken? - const { publicKey, privateKey } = generateKeyPairSync("dh", { - group: groupName, - }); - - assertEquals(publicKey.type, "public"); - assertEquals(privateKey.type, "private"); - }, - }); - - Deno.test({ - name: `generate dh key ${groupName} async`, - async fn() { - // @ts-ignore: @types/node is broken? - const { publicKey, privateKey } = await generateKeyPairAsync("dh", { - group: groupName, - }); - - assertEquals(publicKey.type, "public"); - assertEquals(privateKey.type, "private"); - }, - }); -} - -for (const primeLength of [1024, 2048, 4096]) { - Deno.test({ - name: `generate dh key ${primeLength}`, - fn() { - // @ts-ignore: @types/node is broken? - const { publicKey, privateKey } = generateKeyPairSync("dh", { - primeLength, - generator: 2, - }); - - assertEquals(publicKey.type, "public"); - assertEquals(privateKey.type, "private"); - }, - }); - - Deno.test({ - name: `generate dh key ${primeLength} async`, - async fn() { - // @ts-ignore: @types/node is broken? - const { publicKey, privateKey } = await generateKeyPairAsync("dh", { - primeLength, - generator: 2, - }); - - assertEquals(publicKey.type, "public"); - assertEquals(privateKey.type, "private"); - }, - }); -} diff --git a/cli/tests/unit_node/crypto_sign_test.ts b/cli/tests/unit_node/crypto_sign_test.ts deleted file mode 100644 index 9d346e7d0..000000000 --- a/cli/tests/unit_node/crypto_sign_test.ts +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. - -import { - assert, - assertEquals, -} from "../../../test_util/std/testing/asserts.ts"; -import { createSign, createVerify, sign, verify } from "node:crypto"; -import { Buffer } from "node:buffer"; - -const rsaPrivatePem = Buffer.from( - await Deno.readFile( - new URL("./testdata/rsa_private.pem", import.meta.url), - ), -); -const rsaPublicPem = Buffer.from( - await Deno.readFile( - new URL("./testdata/rsa_public.pem", import.meta.url), - ), -); - -const table = [ - { - algorithms: ["sha224", "RSA-SHA224"], - signature: - "7ad162b288bd7f4ba9b8a31295ad4136d143a5fd11eb99a72379dc9b53e3e8b5c1b7c9dd8a3864a1f626d921e550c48056982bd8fe7e75333885311b5515de1ecbbfcc6a1dd930f422dff87bfceb7eb38882ac6b4fd9dea9efd462776775976e81b1d677f8db41f5ac8686abfa9838069125be939c59e404aa50550872d84befb8b5f6ce2dd051c62a8ba268f876b6f17a27af43b79938222e4ab8b90c4f5540d0f8b02508ef3e68279d685746956b924f00c92438b7981a3cfcb1e2a97305402d381ea62aeaa803f8707961bc3e10a258352e210772e9846ca4024e3dc0a956a50d6db1c03d2943826cc98c6f36d7bafacf1c94b6c438c7664c300a3be172b1", - }, - { - algorithms: ["sha256", "RSA-SHA256"], - signature: - "080313284d7398e1e0e27f6e44f198ceecedddc801e81af63a867d9245ad744e29018099c9ac3c27061c33cabfe27af1db38f44bac09cdcd2c4ab3b00a2a3020f68368f2239db5f911a2dbb7ea2dee322ca7d26d0c88d197482ca4aa1c29ac87b9e6c20075dc974ae71d2d76d2a5b2a15bd541033519465c3aea815cc73b0f1c3ffeedcfb93d6788416623789f86786870d23e86b982ab0df157d7a596097bd3cca3e752f3f47eff4b83754296868b52bc8ff741492dc8a401fe6dc035569e45d1fa1a71c8988d3aadce68fb1bf5c3e756c586af20c8e75c037436ff4c8389e6ce9d943ef7e2566977b84577272181fcec403077cc29e7db1166fff900b36a1d", - }, - { - algorithms: ["sha384", "RSA-SHA384"], - signature: - "2f77a5b7ac0168efd652c30ecb082075f3de30629e9c1f51b7e7e671f24b5c3a2606bb72159a217438220fc7aaba887d4b817e3f43fe0cc8f840747368df8cd65ec760c21a3f9296d01caedc80a335030e31d31ac451277fc4bcc1679c168b2c3185dfee21286514113c080af5238a61a677b03777344f476f25053108588aa6bdc02a6138c6b59a20de4d11e3d668482f17e748e75747f83c0512206283acfc64ed0ad963dddc9ec24589cfd459ee806b8e0e67b93cea16651e967762a5deef890f438ffb9db39247469289db06e2ed7fe262aa1df4ab9607e5b5219a17ddc9694283a61bf8643f58fd702f2c5d3b2d53dc7f36bb5e96461174d376950d6d19", - }, - { - algorithms: ["sha512", "RSA-SHA512"], - signature: - "072e20a433f255ab2f7e5e9ce69255d5c6d7c15a36af75c8389b9672c41abc6a9532fbd057d9d64270bb2483d3c9923f8f419fba4b59b838dcda82a1322009d245c06e2802a74febaea9cebc0b7f46f8761331c5f52ffb650245b5aefefcc604f209b44f6560fe45370cb239d236622e5f72fbb45377f08a0c733e16a8f15830897679ad4349d2e2e5e50a99796820302f4f47881ed444aede56a6d3330b71acaefc4218ae2e4a3bdfbb0c9432ffc5e5bac8c168278b2205d68a5d6905ccbb91282d519c11eccca52d42c86787de492b2a89679dce98cd14c37b0c183af8427e7a1ec86b1ed3f9b5bebf83f1ef81eb18748e69c716a0f263a8598fe627158647", - }, -]; - -const data = Buffer.from("some data to sign"); - -Deno.test({ - name: - "crypto.Sign|sign - RSA PEM with SHA224, SHA256, SHA384, SHA512 digests", - fn() { - for (const testCase of table) { - for (const algorithm of testCase.algorithms) { - assertEquals( - createSign(algorithm) - .update(data) - .sign(rsaPrivatePem, "hex"), - testCase.signature, - ); - assertEquals( - sign(algorithm, data, rsaPrivatePem), - Buffer.from(testCase.signature, "hex"), - ); - } - } - }, -}); - -Deno.test({ - name: - "crypto.Verify|verify - RSA PEM with SHA224, SHA256, SHA384, SHA512 digests", - fn() { - for (const testCase of table) { - for (const algorithm of testCase.algorithms) { - assert( - createVerify(algorithm).update(data).verify( - rsaPublicPem, - testCase.signature, - "hex", - ), - ); - assert( - verify( - algorithm, - data, - rsaPublicPem, - Buffer.from(testCase.signature, "hex"), - ), - ); - } - } - }, -}); -- cgit v1.2.3