mirror of
https://github.com/denoland/deno.git
synced 2024-12-28 10:09:20 -05:00
38a7128cdd
This commits moves implementation of net related APIs available on "Deno" namespace to "deno_net" extension. Following APIs were moved: - Deno.listen() - Deno.connect() - Deno.listenTls() - Deno.serveHttp() - Deno.shutdown() - Deno.resolveDns() - Deno.listenDatagram() - Deno.startTls() - Deno.Conn - Deno.Listener - Deno.DatagramConn
1092 lines
31 KiB
Rust
1092 lines
31 KiB
Rust
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
|
|
|
use crate::itest;
|
|
use deno_core::url;
|
|
use deno_runtime::deno_net::ops_tls::rustls;
|
|
use deno_runtime::deno_net::ops_tls::webpki;
|
|
use deno_runtime::deno_net::ops_tls::TlsStream;
|
|
use std::fs;
|
|
use std::io::BufReader;
|
|
use std::io::Cursor;
|
|
use std::io::{Read, Write};
|
|
use std::process::Command;
|
|
use std::sync::Arc;
|
|
use tempfile::TempDir;
|
|
use test_util as util;
|
|
use tokio::task::LocalSet;
|
|
|
|
#[macro_export]
|
|
macro_rules! itest(
|
|
($name:ident {$( $key:ident: $value:expr,)*}) => {
|
|
#[test]
|
|
fn $name() {
|
|
(test_util::CheckOutputIntegrationTest {
|
|
$(
|
|
$key: $value,
|
|
)*
|
|
.. Default::default()
|
|
}).run()
|
|
}
|
|
}
|
|
);
|
|
|
|
// These files have `_tests.rs` suffix to make it easier to tell which file is
|
|
// the test (ex. `lint_tests.rs`) and which is the implementation (ex. `lint.rs`)
|
|
// when both are open, especially for two tabs in VS Code
|
|
|
|
#[path = "bundle_tests.rs"]
|
|
mod bundle;
|
|
#[path = "cache_tests.rs"]
|
|
mod cache;
|
|
#[path = "compile_tests.rs"]
|
|
mod compile;
|
|
#[path = "coverage_tests.rs"]
|
|
mod coverage;
|
|
#[path = "doc_tests.rs"]
|
|
mod doc;
|
|
#[path = "eval_tests.rs"]
|
|
mod eval;
|
|
#[path = "fmt_tests.rs"]
|
|
mod fmt;
|
|
#[path = "info_tests.rs"]
|
|
mod info;
|
|
#[path = "inspector_tests.rs"]
|
|
mod inspector;
|
|
#[path = "install_tests.rs"]
|
|
mod install;
|
|
#[path = "lint_tests.rs"]
|
|
mod lint;
|
|
#[path = "lsp_tests.rs"]
|
|
mod lsp;
|
|
#[path = "repl_tests.rs"]
|
|
mod repl;
|
|
#[path = "run_tests.rs"]
|
|
mod run;
|
|
#[path = "test_tests.rs"]
|
|
mod test;
|
|
#[path = "upgrade_tests.rs"]
|
|
mod upgrade;
|
|
#[path = "watcher_tests.rs"]
|
|
mod watcher;
|
|
#[path = "worker_tests.rs"]
|
|
mod worker;
|
|
|
|
#[test]
|
|
fn help_flag() {
|
|
let status = util::deno_cmd()
|
|
.current_dir(util::root_path())
|
|
.arg("--help")
|
|
.spawn()
|
|
.unwrap()
|
|
.wait()
|
|
.unwrap();
|
|
assert!(status.success());
|
|
}
|
|
|
|
#[test]
|
|
fn version_short_flag() {
|
|
let status = util::deno_cmd()
|
|
.current_dir(util::root_path())
|
|
.arg("-V")
|
|
.spawn()
|
|
.unwrap()
|
|
.wait()
|
|
.unwrap();
|
|
assert!(status.success());
|
|
}
|
|
|
|
#[test]
|
|
fn version_long_flag() {
|
|
let status = util::deno_cmd()
|
|
.current_dir(util::root_path())
|
|
.arg("--version")
|
|
.spawn()
|
|
.unwrap()
|
|
.wait()
|
|
.unwrap();
|
|
assert!(status.success());
|
|
}
|
|
|
|
itest!(types {
|
|
args: "types",
|
|
output: "types.out",
|
|
});
|
|
|
|
#[test]
|
|
fn cache_test() {
|
|
let _g = util::http_server();
|
|
let deno_dir = TempDir::new().expect("tempdir fail");
|
|
let module_url =
|
|
url::Url::parse("http://localhost:4545/cli/tests/006_url_imports.ts")
|
|
.unwrap();
|
|
let output = Command::new(util::deno_exe_path())
|
|
.env("DENO_DIR", deno_dir.path())
|
|
.current_dir(util::root_path())
|
|
.arg("cache")
|
|
.arg("-L")
|
|
.arg("debug")
|
|
.arg(module_url.to_string())
|
|
.output()
|
|
.expect("Failed to spawn script");
|
|
assert!(output.status.success());
|
|
|
|
let out = std::str::from_utf8(&output.stderr).unwrap();
|
|
// Check if file and dependencies are written successfully
|
|
assert!(out.contains("host.writeFile(\"deno://subdir/print_hello.js\")"));
|
|
assert!(out.contains("host.writeFile(\"deno://subdir/mod2.js\")"));
|
|
assert!(out.contains("host.writeFile(\"deno://006_url_imports.js\")"));
|
|
|
|
let prg = util::deno_exe_path();
|
|
let output = Command::new(&prg)
|
|
.env("DENO_DIR", deno_dir.path())
|
|
.env("HTTP_PROXY", "http://nil")
|
|
.env("NO_COLOR", "1")
|
|
.current_dir(util::root_path())
|
|
.arg("run")
|
|
.arg(module_url.to_string())
|
|
.output()
|
|
.expect("Failed to spawn script");
|
|
|
|
let str_output = std::str::from_utf8(&output.stdout).unwrap();
|
|
|
|
let module_output_path =
|
|
util::root_path().join("cli/tests/006_url_imports.ts.out");
|
|
let mut module_output = String::new();
|
|
let mut module_output_file = fs::File::open(module_output_path).unwrap();
|
|
module_output_file
|
|
.read_to_string(&mut module_output)
|
|
.unwrap();
|
|
|
|
assert_eq!(module_output, str_output);
|
|
}
|
|
|
|
#[test]
|
|
fn cache_invalidation_test() {
|
|
let deno_dir = TempDir::new().expect("tempdir fail");
|
|
let fixture_path = deno_dir.path().join("fixture.ts");
|
|
{
|
|
let mut file = std::fs::File::create(fixture_path.clone())
|
|
.expect("could not create fixture");
|
|
file
|
|
.write_all(b"console.log(\"42\");")
|
|
.expect("could not write fixture");
|
|
}
|
|
let output = Command::new(util::deno_exe_path())
|
|
.env("DENO_DIR", deno_dir.path())
|
|
.current_dir(util::root_path())
|
|
.arg("run")
|
|
.arg(fixture_path.to_str().unwrap())
|
|
.output()
|
|
.expect("Failed to spawn script");
|
|
assert!(output.status.success());
|
|
let actual = std::str::from_utf8(&output.stdout).unwrap();
|
|
assert_eq!(actual, "42\n");
|
|
{
|
|
let mut file = std::fs::File::create(fixture_path.clone())
|
|
.expect("could not create fixture");
|
|
file
|
|
.write_all(b"console.log(\"43\");")
|
|
.expect("could not write fixture");
|
|
}
|
|
let output = Command::new(util::deno_exe_path())
|
|
.env("DENO_DIR", deno_dir.path())
|
|
.current_dir(util::root_path())
|
|
.arg("run")
|
|
.arg(fixture_path.to_str().unwrap())
|
|
.output()
|
|
.expect("Failed to spawn script");
|
|
assert!(output.status.success());
|
|
let actual = std::str::from_utf8(&output.stdout).unwrap();
|
|
assert_eq!(actual, "43\n");
|
|
}
|
|
|
|
#[test]
|
|
fn cache_invalidation_test_no_check() {
|
|
let deno_dir = TempDir::new().expect("tempdir fail");
|
|
let fixture_path = deno_dir.path().join("fixture.ts");
|
|
{
|
|
let mut file = std::fs::File::create(fixture_path.clone())
|
|
.expect("could not create fixture");
|
|
file
|
|
.write_all(b"console.log(\"42\");")
|
|
.expect("could not write fixture");
|
|
}
|
|
let output = Command::new(util::deno_exe_path())
|
|
.env("DENO_DIR", deno_dir.path())
|
|
.current_dir(util::root_path())
|
|
.arg("run")
|
|
.arg("--no-check")
|
|
.arg(fixture_path.to_str().unwrap())
|
|
.output()
|
|
.expect("Failed to spawn script");
|
|
assert!(output.status.success());
|
|
let actual = std::str::from_utf8(&output.stdout).unwrap();
|
|
assert_eq!(actual, "42\n");
|
|
{
|
|
let mut file = std::fs::File::create(fixture_path.clone())
|
|
.expect("could not create fixture");
|
|
file
|
|
.write_all(b"console.log(\"43\");")
|
|
.expect("could not write fixture");
|
|
}
|
|
let output = Command::new(util::deno_exe_path())
|
|
.env("DENO_DIR", deno_dir.path())
|
|
.current_dir(util::root_path())
|
|
.arg("run")
|
|
.arg("--no-check")
|
|
.arg(fixture_path.to_str().unwrap())
|
|
.output()
|
|
.expect("Failed to spawn script");
|
|
assert!(output.status.success());
|
|
let actual = std::str::from_utf8(&output.stdout).unwrap();
|
|
assert_eq!(actual, "43\n");
|
|
}
|
|
|
|
#[test]
|
|
fn ts_dependency_recompilation() {
|
|
let t = TempDir::new().expect("tempdir fail");
|
|
let ats = t.path().join("a.ts");
|
|
|
|
std::fs::write(
|
|
&ats,
|
|
"
|
|
import { foo } from \"./b.ts\";
|
|
|
|
function print(str: string): void {
|
|
console.log(str);
|
|
}
|
|
|
|
print(foo);",
|
|
)
|
|
.unwrap();
|
|
|
|
let bts = t.path().join("b.ts");
|
|
std::fs::write(
|
|
&bts,
|
|
"
|
|
export const foo = \"foo\";",
|
|
)
|
|
.unwrap();
|
|
|
|
let output = util::deno_cmd()
|
|
.current_dir(util::root_path())
|
|
.env("NO_COLOR", "1")
|
|
.arg("run")
|
|
.arg(&ats)
|
|
.output()
|
|
.expect("failed to spawn script");
|
|
|
|
let stdout_output = std::str::from_utf8(&output.stdout).unwrap().trim();
|
|
let stderr_output = std::str::from_utf8(&output.stderr).unwrap().trim();
|
|
|
|
assert!(stdout_output.ends_with("foo"));
|
|
assert!(stderr_output.starts_with("Check"));
|
|
|
|
// Overwrite contents of b.ts and run again
|
|
std::fs::write(
|
|
&bts,
|
|
"
|
|
export const foo = 5;",
|
|
)
|
|
.expect("error writing file");
|
|
|
|
let output = util::deno_cmd()
|
|
.current_dir(util::root_path())
|
|
.env("NO_COLOR", "1")
|
|
.arg("run")
|
|
.arg(&ats)
|
|
.output()
|
|
.expect("failed to spawn script");
|
|
|
|
let stdout_output = std::str::from_utf8(&output.stdout).unwrap().trim();
|
|
let stderr_output = std::str::from_utf8(&output.stderr).unwrap().trim();
|
|
|
|
// error: TS2345 [ERROR]: Argument of type '5' is not assignable to parameter of type 'string'.
|
|
assert!(stderr_output.contains("TS2345"));
|
|
assert!(!output.status.success());
|
|
assert!(stdout_output.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn ts_no_recheck_on_redirect() {
|
|
let deno_dir = util::new_deno_dir();
|
|
let e = util::deno_exe_path();
|
|
|
|
let redirect_ts = util::root_path().join("cli/tests/017_import_redirect.ts");
|
|
assert!(redirect_ts.is_file());
|
|
let mut cmd = Command::new(e.clone());
|
|
cmd.env("DENO_DIR", deno_dir.path());
|
|
let mut initial = cmd
|
|
.current_dir(util::root_path())
|
|
.arg("run")
|
|
.arg(redirect_ts.clone())
|
|
.spawn()
|
|
.expect("failed to span script");
|
|
let status_initial =
|
|
initial.wait().expect("failed to wait for child process");
|
|
assert!(status_initial.success());
|
|
|
|
let mut cmd = Command::new(e);
|
|
cmd.env("DENO_DIR", deno_dir.path());
|
|
let output = cmd
|
|
.current_dir(util::root_path())
|
|
.arg("run")
|
|
.arg(redirect_ts)
|
|
.output()
|
|
.expect("failed to spawn script");
|
|
|
|
assert!(std::str::from_utf8(&output.stderr).unwrap().is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn ts_reload() {
|
|
let hello_ts = util::root_path().join("cli/tests/002_hello.ts");
|
|
assert!(hello_ts.is_file());
|
|
|
|
let deno_dir = TempDir::new().expect("tempdir fail");
|
|
let mut initial = util::deno_cmd_with_deno_dir(deno_dir.path())
|
|
.current_dir(util::root_path())
|
|
.arg("cache")
|
|
.arg(&hello_ts)
|
|
.spawn()
|
|
.expect("failed to spawn script");
|
|
let status_initial =
|
|
initial.wait().expect("failed to wait for child process");
|
|
assert!(status_initial.success());
|
|
|
|
let output = util::deno_cmd_with_deno_dir(deno_dir.path())
|
|
.current_dir(util::root_path())
|
|
.arg("cache")
|
|
.arg("--reload")
|
|
.arg("-L")
|
|
.arg("debug")
|
|
.arg(&hello_ts)
|
|
.output()
|
|
.expect("failed to spawn script");
|
|
|
|
// check the output of the the bundle program.
|
|
let output_path = hello_ts.canonicalize().unwrap();
|
|
assert!(std::str::from_utf8(&output.stderr)
|
|
.unwrap()
|
|
.trim()
|
|
.contains(&format!(
|
|
"host.getSourceFile(\"{}\", Latest)",
|
|
url::Url::from_file_path(&output_path).unwrap().as_str()
|
|
)));
|
|
}
|
|
|
|
#[test]
|
|
fn timeout_clear() {
|
|
// https://github.com/denoland/deno/issues/7599
|
|
|
|
use std::time::Duration;
|
|
use std::time::Instant;
|
|
|
|
let source_code = r#"
|
|
const handle = setTimeout(() => {
|
|
console.log("timeout finish");
|
|
}, 10000);
|
|
clearTimeout(handle);
|
|
console.log("finish");
|
|
"#;
|
|
|
|
let mut p = util::deno_cmd()
|
|
.current_dir(util::tests_path())
|
|
.arg("run")
|
|
.arg("-")
|
|
.stdin(std::process::Stdio::piped())
|
|
.spawn()
|
|
.unwrap();
|
|
let stdin = p.stdin.as_mut().unwrap();
|
|
stdin.write_all(source_code.as_bytes()).unwrap();
|
|
let start = Instant::now();
|
|
let status = p.wait().unwrap();
|
|
let end = Instant::now();
|
|
assert!(status.success());
|
|
// check that program did not run for 10 seconds
|
|
// for timeout to clear
|
|
assert!(end - start < Duration::new(10, 0));
|
|
}
|
|
|
|
#[test]
|
|
fn compiler_api() {
|
|
let status = util::deno_cmd()
|
|
.current_dir(util::tests_path())
|
|
.arg("test")
|
|
.arg("--unstable")
|
|
.arg("--reload")
|
|
.arg("--allow-read")
|
|
.arg("compiler_api_test.ts")
|
|
.spawn()
|
|
.unwrap()
|
|
.wait()
|
|
.unwrap();
|
|
assert!(status.success());
|
|
}
|
|
|
|
#[test]
|
|
fn broken_stdout() {
|
|
let (reader, writer) = os_pipe::pipe().unwrap();
|
|
// drop the reader to create a broken pipe
|
|
drop(reader);
|
|
|
|
let output = util::deno_cmd()
|
|
.current_dir(util::root_path())
|
|
.arg("eval")
|
|
.arg("console.log(3.14)")
|
|
.stdout(writer)
|
|
.stderr(std::process::Stdio::piped())
|
|
.spawn()
|
|
.unwrap()
|
|
.wait_with_output()
|
|
.unwrap();
|
|
|
|
assert!(!output.status.success());
|
|
let stderr = std::str::from_utf8(output.stderr.as_ref()).unwrap().trim();
|
|
assert!(stderr.contains("Uncaught BrokenPipe"));
|
|
assert!(!stderr.contains("panic"));
|
|
}
|
|
|
|
// TODO(lucacasonato): reenable these tests once we figure out what is wrong with cafile tests
|
|
// itest!(cafile_url_imports {
|
|
// args: "run --quiet --reload --cert tls/RootCA.pem cafile_url_imports.ts",
|
|
// output: "cafile_url_imports.ts.out",
|
|
// http_server: true,
|
|
// });
|
|
|
|
// itest!(cafile_ts_fetch {
|
|
// args:
|
|
// "run --quiet --reload --allow-net --cert tls/RootCA.pem cafile_ts_fetch.ts",
|
|
// output: "cafile_ts_fetch.ts.out",
|
|
// http_server: true,
|
|
// });
|
|
|
|
// itest!(cafile_eval {
|
|
// args: "eval --cert tls/RootCA.pem fetch('https://localhost:5545/cli/tests/cafile_ts_fetch.ts.out').then(r=>r.text()).then(t=>console.log(t.trimEnd()))",
|
|
// output: "cafile_ts_fetch.ts.out",
|
|
// http_server: true,
|
|
// });
|
|
|
|
// itest!(cafile_info {
|
|
// args:
|
|
// "info --quiet --cert tls/RootCA.pem https://localhost:5545/cli/tests/cafile_info.ts",
|
|
// output: "cafile_info.ts.out",
|
|
// http_server: true,
|
|
// });
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn cafile_env_fetch() {
|
|
use deno_core::url::Url;
|
|
let _g = util::http_server();
|
|
let deno_dir = TempDir::new().expect("tempdir fail");
|
|
let module_url =
|
|
Url::parse("https://localhost:5545/cli/tests/cafile_url_imports.ts")
|
|
.unwrap();
|
|
let cafile = util::root_path().join("cli/tests/tls/RootCA.pem");
|
|
let output = Command::new(util::deno_exe_path())
|
|
.env("DENO_DIR", deno_dir.path())
|
|
.env("DENO_CERT", cafile)
|
|
.current_dir(util::root_path())
|
|
.arg("cache")
|
|
.arg(module_url.to_string())
|
|
.output()
|
|
.expect("Failed to spawn script");
|
|
assert!(output.status.success());
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn cafile_fetch() {
|
|
use deno_core::url::Url;
|
|
let _g = util::http_server();
|
|
let deno_dir = TempDir::new().expect("tempdir fail");
|
|
let module_url =
|
|
Url::parse("http://localhost:4545/cli/tests/cafile_url_imports.ts")
|
|
.unwrap();
|
|
let cafile = util::root_path().join("cli/tests/tls/RootCA.pem");
|
|
let output = Command::new(util::deno_exe_path())
|
|
.env("DENO_DIR", deno_dir.path())
|
|
.current_dir(util::root_path())
|
|
.arg("cache")
|
|
.arg("--cert")
|
|
.arg(cafile)
|
|
.arg(module_url.to_string())
|
|
.output()
|
|
.expect("Failed to spawn script");
|
|
assert!(output.status.success());
|
|
let out = std::str::from_utf8(&output.stdout).unwrap();
|
|
assert_eq!(out, "");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn cafile_install_remote_module() {
|
|
let _g = util::http_server();
|
|
let temp_dir = TempDir::new().expect("tempdir fail");
|
|
let bin_dir = temp_dir.path().join("bin");
|
|
std::fs::create_dir(&bin_dir).unwrap();
|
|
let deno_dir = TempDir::new().expect("tempdir fail");
|
|
let cafile = util::root_path().join("cli/tests/tls/RootCA.pem");
|
|
|
|
let install_output = Command::new(util::deno_exe_path())
|
|
.env("DENO_DIR", deno_dir.path())
|
|
.current_dir(util::root_path())
|
|
.arg("install")
|
|
.arg("--cert")
|
|
.arg(cafile)
|
|
.arg("--root")
|
|
.arg(temp_dir.path())
|
|
.arg("-n")
|
|
.arg("echo_test")
|
|
.arg("https://localhost:5545/cli/tests/echo.ts")
|
|
.output()
|
|
.expect("Failed to spawn script");
|
|
println!("{}", std::str::from_utf8(&install_output.stdout).unwrap());
|
|
eprintln!("{}", std::str::from_utf8(&install_output.stderr).unwrap());
|
|
assert!(install_output.status.success());
|
|
|
|
let mut echo_test_path = bin_dir.join("echo_test");
|
|
if cfg!(windows) {
|
|
echo_test_path = echo_test_path.with_extension("cmd");
|
|
}
|
|
assert!(echo_test_path.exists());
|
|
|
|
let output = Command::new(echo_test_path)
|
|
.current_dir(temp_dir.path())
|
|
.arg("foo")
|
|
.env("PATH", util::target_dir())
|
|
.output()
|
|
.expect("failed to spawn script");
|
|
let stdout = std::str::from_utf8(&output.stdout).unwrap().trim();
|
|
assert!(stdout.ends_with("foo"));
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn cafile_bundle_remote_exports() {
|
|
let _g = util::http_server();
|
|
|
|
// First we have to generate a bundle of some remote module that has exports.
|
|
let mod1 = "https://localhost:5545/cli/tests/subdir/mod1.ts";
|
|
let cafile = util::root_path().join("cli/tests/tls/RootCA.pem");
|
|
let t = TempDir::new().expect("tempdir fail");
|
|
let bundle = t.path().join("mod1.bundle.js");
|
|
let mut deno = util::deno_cmd()
|
|
.current_dir(util::root_path())
|
|
.arg("bundle")
|
|
.arg("--cert")
|
|
.arg(cafile)
|
|
.arg(mod1)
|
|
.arg(&bundle)
|
|
.spawn()
|
|
.expect("failed to spawn script");
|
|
let status = deno.wait().expect("failed to wait for the child process");
|
|
assert!(status.success());
|
|
assert!(bundle.is_file());
|
|
|
|
// Now we try to use that bundle from another module.
|
|
let test = t.path().join("test.js");
|
|
std::fs::write(
|
|
&test,
|
|
"
|
|
import { printHello3 } from \"./mod1.bundle.js\";
|
|
printHello3(); ",
|
|
)
|
|
.expect("error writing file");
|
|
|
|
let output = util::deno_cmd()
|
|
.current_dir(util::root_path())
|
|
.arg("run")
|
|
.arg(&test)
|
|
.output()
|
|
.expect("failed to spawn script");
|
|
// check the output of the test.ts program.
|
|
assert!(std::str::from_utf8(&output.stdout)
|
|
.unwrap()
|
|
.trim()
|
|
.ends_with("Hello"));
|
|
assert_eq!(output.stderr, b"");
|
|
}
|
|
|
|
#[test]
|
|
fn websocket() {
|
|
let _g = util::http_server();
|
|
|
|
let script = util::tests_path().join("websocket_test.ts");
|
|
let root_ca = util::tests_path().join("tls/RootCA.pem");
|
|
let status = util::deno_cmd()
|
|
.arg("test")
|
|
.arg("--unstable")
|
|
.arg("--allow-net")
|
|
.arg("--cert")
|
|
.arg(root_ca)
|
|
.arg(script)
|
|
.spawn()
|
|
.unwrap()
|
|
.wait()
|
|
.unwrap();
|
|
|
|
assert!(status.success());
|
|
}
|
|
|
|
#[cfg(not(windows))]
|
|
#[test]
|
|
fn set_raw_should_not_panic_on_no_tty() {
|
|
let output = util::deno_cmd()
|
|
.arg("eval")
|
|
.arg("--unstable")
|
|
.arg("Deno.setRaw(Deno.stdin.rid, true)")
|
|
// stdin set to piped so it certainly does not refer to TTY
|
|
.stdin(std::process::Stdio::piped())
|
|
// stderr is piped so we can capture output.
|
|
.stderr(std::process::Stdio::piped())
|
|
.spawn()
|
|
.unwrap()
|
|
.wait_with_output()
|
|
.unwrap();
|
|
assert!(!output.status.success());
|
|
let stderr = std::str::from_utf8(&output.stderr).unwrap().trim();
|
|
assert!(stderr.contains("BadResource"));
|
|
}
|
|
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
async fn test_resolve_dns() {
|
|
use std::collections::BTreeMap;
|
|
use std::net::Ipv4Addr;
|
|
use std::net::Ipv6Addr;
|
|
use std::net::SocketAddr;
|
|
use std::str::FromStr;
|
|
use std::sync::Arc;
|
|
use std::sync::RwLock;
|
|
use std::time::Duration;
|
|
use tokio::net::TcpListener;
|
|
use tokio::net::UdpSocket;
|
|
use tokio::sync::oneshot;
|
|
use trust_dns_client::rr::LowerName;
|
|
use trust_dns_client::rr::RecordType;
|
|
use trust_dns_client::rr::RrKey;
|
|
use trust_dns_server::authority::Catalog;
|
|
use trust_dns_server::authority::ZoneType;
|
|
use trust_dns_server::proto::rr::rdata::mx::MX;
|
|
use trust_dns_server::proto::rr::rdata::soa::SOA;
|
|
use trust_dns_server::proto::rr::rdata::srv::SRV;
|
|
use trust_dns_server::proto::rr::rdata::txt::TXT;
|
|
use trust_dns_server::proto::rr::record_data::RData;
|
|
use trust_dns_server::proto::rr::resource::Record;
|
|
use trust_dns_server::proto::rr::Name;
|
|
use trust_dns_server::proto::rr::RecordSet;
|
|
use trust_dns_server::store::in_memory::InMemoryAuthority;
|
|
use trust_dns_server::ServerFuture;
|
|
|
|
const DNS_PORT: u16 = 4553;
|
|
|
|
// Setup DNS server for testing
|
|
async fn run_dns_server(tx: oneshot::Sender<()>) {
|
|
let catalog = {
|
|
let records = {
|
|
let mut map = BTreeMap::new();
|
|
let lookup_name = "www.example.com".parse::<Name>().unwrap();
|
|
let lookup_name_lower = LowerName::new(&lookup_name);
|
|
|
|
// Inserts SOA record
|
|
let soa = SOA::new(
|
|
Name::from_str("net").unwrap(),
|
|
Name::from_str("example").unwrap(),
|
|
0,
|
|
i32::MAX,
|
|
i32::MAX,
|
|
i32::MAX,
|
|
0,
|
|
);
|
|
let rdata = RData::SOA(soa);
|
|
let record = Record::from_rdata(Name::new(), u32::MAX, rdata);
|
|
let record_set = RecordSet::from(record);
|
|
map
|
|
.insert(RrKey::new(Name::root().into(), RecordType::SOA), record_set);
|
|
|
|
// Inserts A record
|
|
let rdata = RData::A(Ipv4Addr::new(1, 2, 3, 4));
|
|
let record = Record::from_rdata(lookup_name.clone(), u32::MAX, rdata);
|
|
let record_set = RecordSet::from(record);
|
|
map.insert(
|
|
RrKey::new(lookup_name_lower.clone(), RecordType::A),
|
|
record_set,
|
|
);
|
|
|
|
// Inserts AAAA record
|
|
let rdata = RData::AAAA(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8));
|
|
let record = Record::from_rdata(lookup_name.clone(), u32::MAX, rdata);
|
|
let record_set = RecordSet::from(record);
|
|
map.insert(
|
|
RrKey::new(lookup_name_lower.clone(), RecordType::AAAA),
|
|
record_set,
|
|
);
|
|
|
|
// Inserts ANAME record
|
|
let rdata = RData::ANAME(Name::from_str("aname.com").unwrap());
|
|
let record = Record::from_rdata(lookup_name.clone(), u32::MAX, rdata);
|
|
let record_set = RecordSet::from(record);
|
|
map.insert(
|
|
RrKey::new(lookup_name_lower.clone(), RecordType::ANAME),
|
|
record_set,
|
|
);
|
|
|
|
// Inserts CNAME record
|
|
let rdata = RData::CNAME(Name::from_str("cname.com").unwrap());
|
|
let record =
|
|
Record::from_rdata(Name::from_str("foo").unwrap(), u32::MAX, rdata);
|
|
let record_set = RecordSet::from(record);
|
|
map.insert(
|
|
RrKey::new(lookup_name_lower.clone(), RecordType::CNAME),
|
|
record_set,
|
|
);
|
|
|
|
// Inserts MX record
|
|
let rdata = RData::MX(MX::new(0, Name::from_str("mx.com").unwrap()));
|
|
let record = Record::from_rdata(lookup_name.clone(), u32::MAX, rdata);
|
|
let record_set = RecordSet::from(record);
|
|
map.insert(
|
|
RrKey::new(lookup_name_lower.clone(), RecordType::MX),
|
|
record_set,
|
|
);
|
|
|
|
// Inserts PTR record
|
|
let rdata = RData::PTR(Name::from_str("ptr.com").unwrap());
|
|
let record = Record::from_rdata(
|
|
Name::from_str("5.6.7.8").unwrap(),
|
|
u32::MAX,
|
|
rdata,
|
|
);
|
|
let record_set = RecordSet::from(record);
|
|
map.insert(
|
|
RrKey::new("5.6.7.8".parse().unwrap(), RecordType::PTR),
|
|
record_set,
|
|
);
|
|
|
|
// Inserts SRV record
|
|
let rdata = RData::SRV(SRV::new(
|
|
0,
|
|
100,
|
|
1234,
|
|
Name::from_str("srv.com").unwrap(),
|
|
));
|
|
let record = Record::from_rdata(
|
|
Name::from_str("_Service._TCP.example.com").unwrap(),
|
|
u32::MAX,
|
|
rdata,
|
|
);
|
|
let record_set = RecordSet::from(record);
|
|
map.insert(
|
|
RrKey::new(lookup_name_lower.clone(), RecordType::SRV),
|
|
record_set,
|
|
);
|
|
|
|
// Inserts TXT record
|
|
let rdata =
|
|
RData::TXT(TXT::new(vec!["foo".to_string(), "bar".to_string()]));
|
|
let record = Record::from_rdata(lookup_name, u32::MAX, rdata);
|
|
let record_set = RecordSet::from(record);
|
|
map.insert(RrKey::new(lookup_name_lower, RecordType::TXT), record_set);
|
|
|
|
map
|
|
};
|
|
|
|
let authority = Box::new(Arc::new(RwLock::new(
|
|
InMemoryAuthority::new(
|
|
Name::from_str("com").unwrap(),
|
|
records,
|
|
ZoneType::Primary,
|
|
false,
|
|
)
|
|
.unwrap(),
|
|
)));
|
|
let mut c = Catalog::new();
|
|
c.upsert(Name::root().into(), authority);
|
|
c
|
|
};
|
|
|
|
let mut server_fut = ServerFuture::new(catalog);
|
|
let socket_addr = SocketAddr::from(([127, 0, 0, 1], DNS_PORT));
|
|
let tcp_listener = TcpListener::bind(socket_addr).await.unwrap();
|
|
let udp_socket = UdpSocket::bind(socket_addr).await.unwrap();
|
|
server_fut.register_socket(udp_socket);
|
|
server_fut.register_listener(tcp_listener, Duration::from_secs(2));
|
|
|
|
// Notifies that the DNS server is ready
|
|
tx.send(()).unwrap();
|
|
|
|
server_fut.block_until_done().await.unwrap();
|
|
}
|
|
|
|
let (ready_tx, ready_rx) = oneshot::channel();
|
|
let dns_server_fut = run_dns_server(ready_tx);
|
|
let handle = tokio::spawn(dns_server_fut);
|
|
|
|
// Waits for the DNS server to be ready
|
|
ready_rx.await.unwrap();
|
|
|
|
// Pass: `--allow-net`
|
|
{
|
|
let output = util::deno_cmd()
|
|
.current_dir(util::tests_path())
|
|
.env("NO_COLOR", "1")
|
|
.arg("run")
|
|
.arg("--allow-net")
|
|
.arg("--unstable")
|
|
.arg("resolve_dns.ts")
|
|
.stdout(std::process::Stdio::piped())
|
|
.stderr(std::process::Stdio::piped())
|
|
.spawn()
|
|
.unwrap()
|
|
.wait_with_output()
|
|
.unwrap();
|
|
let err = String::from_utf8_lossy(&output.stderr);
|
|
let out = String::from_utf8_lossy(&output.stdout);
|
|
assert!(output.status.success());
|
|
assert!(err.starts_with("Check file"));
|
|
|
|
let expected =
|
|
std::fs::read_to_string(util::tests_path().join("resolve_dns.ts.out"))
|
|
.unwrap();
|
|
assert_eq!(expected, out);
|
|
}
|
|
|
|
// Pass: `--allow-net=127.0.0.1:4553`
|
|
{
|
|
let output = util::deno_cmd()
|
|
.current_dir(util::tests_path())
|
|
.env("NO_COLOR", "1")
|
|
.arg("run")
|
|
.arg("--allow-net=127.0.0.1:4553")
|
|
.arg("--unstable")
|
|
.arg("resolve_dns.ts")
|
|
.stdout(std::process::Stdio::piped())
|
|
.stderr(std::process::Stdio::piped())
|
|
.spawn()
|
|
.unwrap()
|
|
.wait_with_output()
|
|
.unwrap();
|
|
let err = String::from_utf8_lossy(&output.stderr);
|
|
let out = String::from_utf8_lossy(&output.stdout);
|
|
assert!(output.status.success());
|
|
assert!(err.starts_with("Check file"));
|
|
|
|
let expected =
|
|
std::fs::read_to_string(util::tests_path().join("resolve_dns.ts.out"))
|
|
.unwrap();
|
|
assert_eq!(expected, out);
|
|
}
|
|
|
|
// Permission error: `--allow-net=deno.land`
|
|
{
|
|
let output = util::deno_cmd()
|
|
.current_dir(util::tests_path())
|
|
.env("NO_COLOR", "1")
|
|
.arg("run")
|
|
.arg("--allow-net=deno.land")
|
|
.arg("--unstable")
|
|
.arg("resolve_dns.ts")
|
|
.stdout(std::process::Stdio::piped())
|
|
.stderr(std::process::Stdio::piped())
|
|
.spawn()
|
|
.unwrap()
|
|
.wait_with_output()
|
|
.unwrap();
|
|
let err = String::from_utf8_lossy(&output.stderr);
|
|
let out = String::from_utf8_lossy(&output.stdout);
|
|
assert!(!output.status.success());
|
|
assert!(err.starts_with("Check file"));
|
|
assert!(err.contains(r#"error: Uncaught (in promise) PermissionDenied: Requires net access to "127.0.0.1:4553""#));
|
|
assert!(out.is_empty());
|
|
}
|
|
|
|
// Permission error: no permission specified
|
|
{
|
|
let output = util::deno_cmd()
|
|
.current_dir(util::tests_path())
|
|
.env("NO_COLOR", "1")
|
|
.arg("run")
|
|
.arg("--unstable")
|
|
.arg("resolve_dns.ts")
|
|
.stdout(std::process::Stdio::piped())
|
|
.stderr(std::process::Stdio::piped())
|
|
.spawn()
|
|
.unwrap()
|
|
.wait_with_output()
|
|
.unwrap();
|
|
let err = String::from_utf8_lossy(&output.stderr);
|
|
let out = String::from_utf8_lossy(&output.stdout);
|
|
assert!(!output.status.success());
|
|
assert!(err.starts_with("Check file"));
|
|
assert!(err.contains(r#"error: Uncaught (in promise) PermissionDenied: Requires net access to "127.0.0.1:4553""#));
|
|
assert!(out.is_empty());
|
|
}
|
|
|
|
handle.abort();
|
|
}
|
|
|
|
#[test]
|
|
fn typecheck_declarations_ns() {
|
|
let status = util::deno_cmd()
|
|
.arg("test")
|
|
.arg("--doc")
|
|
.arg(util::root_path().join("cli/dts/lib.deno.ns.d.ts"))
|
|
.spawn()
|
|
.unwrap()
|
|
.wait()
|
|
.unwrap();
|
|
assert!(status.success());
|
|
}
|
|
|
|
#[test]
|
|
fn typecheck_declarations_unstable() {
|
|
let status = util::deno_cmd()
|
|
.arg("test")
|
|
.arg("--doc")
|
|
.arg("--unstable")
|
|
.arg(util::root_path().join("cli/dts/lib.deno.unstable.d.ts"))
|
|
.spawn()
|
|
.unwrap()
|
|
.wait()
|
|
.unwrap();
|
|
assert!(status.success());
|
|
}
|
|
|
|
#[test]
|
|
fn js_unit_tests_lint() {
|
|
let status = util::deno_cmd()
|
|
.arg("lint")
|
|
.arg("--unstable")
|
|
.arg(util::root_path().join("cli/tests/unit"))
|
|
.spawn()
|
|
.unwrap()
|
|
.wait()
|
|
.unwrap();
|
|
assert!(status.success());
|
|
}
|
|
|
|
#[test]
|
|
fn js_unit_tests() {
|
|
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")
|
|
.arg("--unstable")
|
|
.arg("--location=http://js-unit-tests/foo/bar")
|
|
.arg("-A")
|
|
.arg("cli/tests/unit")
|
|
.spawn()
|
|
.expect("failed to spawn script");
|
|
|
|
let status = deno.wait().expect("failed to wait for the child process");
|
|
assert_eq!(Some(0), status.code());
|
|
assert!(status.success());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn listen_tls_alpn() {
|
|
// TLS streams require the presence of an ambient local task set to gracefully
|
|
// close dropped connections in the background.
|
|
LocalSet::new()
|
|
.run_until(async {
|
|
let mut child = util::deno_cmd()
|
|
.current_dir(util::root_path())
|
|
.arg("run")
|
|
.arg("--unstable")
|
|
.arg("--quiet")
|
|
.arg("--allow-net")
|
|
.arg("--allow-read")
|
|
.arg("./cli/tests/listen_tls_alpn.ts")
|
|
.arg("4504")
|
|
.stdout(std::process::Stdio::piped())
|
|
.spawn()
|
|
.unwrap();
|
|
let stdout = child.stdout.as_mut().unwrap();
|
|
let mut buffer = [0; 5];
|
|
let read = stdout.read(&mut buffer).unwrap();
|
|
assert_eq!(read, 5);
|
|
let msg = std::str::from_utf8(&buffer).unwrap();
|
|
assert_eq!(msg, "READY");
|
|
|
|
let mut cfg = rustls::ClientConfig::new();
|
|
let reader =
|
|
&mut BufReader::new(Cursor::new(include_bytes!("../tls/RootCA.crt")));
|
|
cfg.root_store.add_pem_file(reader).unwrap();
|
|
cfg.alpn_protocols.push("foobar".as_bytes().to_vec());
|
|
let cfg = Arc::new(cfg);
|
|
|
|
let hostname =
|
|
webpki::DNSNameRef::try_from_ascii_str("localhost").unwrap();
|
|
|
|
let tcp_stream = tokio::net::TcpStream::connect("localhost:4504")
|
|
.await
|
|
.unwrap();
|
|
let mut tls_stream =
|
|
TlsStream::new_client_side(tcp_stream, &cfg, hostname);
|
|
tls_stream.handshake().await.unwrap();
|
|
let (_, session) = tls_stream.get_ref();
|
|
|
|
let alpn = session.get_alpn_protocol().unwrap();
|
|
assert_eq!(std::str::from_utf8(alpn).unwrap(), "foobar");
|
|
|
|
child.kill().unwrap();
|
|
child.wait().unwrap();
|
|
})
|
|
.await;
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn listen_tls_alpn_fail() {
|
|
// TLS streams require the presence of an ambient local task set to gracefully
|
|
// close dropped connections in the background.
|
|
LocalSet::new()
|
|
.run_until(async {
|
|
let mut child = util::deno_cmd()
|
|
.current_dir(util::root_path())
|
|
.arg("run")
|
|
.arg("--unstable")
|
|
.arg("--quiet")
|
|
.arg("--allow-net")
|
|
.arg("--allow-read")
|
|
.arg("./cli/tests/listen_tls_alpn.ts")
|
|
.arg("4505")
|
|
.stdout(std::process::Stdio::piped())
|
|
.spawn()
|
|
.unwrap();
|
|
let stdout = child.stdout.as_mut().unwrap();
|
|
let mut buffer = [0; 5];
|
|
let read = stdout.read(&mut buffer).unwrap();
|
|
assert_eq!(read, 5);
|
|
let msg = std::str::from_utf8(&buffer).unwrap();
|
|
assert_eq!(msg, "READY");
|
|
|
|
let mut cfg = rustls::ClientConfig::new();
|
|
let reader =
|
|
&mut BufReader::new(Cursor::new(include_bytes!("../tls/RootCA.crt")));
|
|
cfg.root_store.add_pem_file(reader).unwrap();
|
|
cfg.alpn_protocols.push("boofar".as_bytes().to_vec());
|
|
let cfg = Arc::new(cfg);
|
|
|
|
let hostname =
|
|
webpki::DNSNameRef::try_from_ascii_str("localhost").unwrap();
|
|
|
|
let tcp_stream = tokio::net::TcpStream::connect("localhost:4505")
|
|
.await
|
|
.unwrap();
|
|
let mut tls_stream =
|
|
TlsStream::new_client_side(tcp_stream, &cfg, hostname);
|
|
tls_stream.handshake().await.unwrap();
|
|
let (_, session) = tls_stream.get_ref();
|
|
|
|
assert!(session.get_alpn_protocol().is_none());
|
|
|
|
child.kill().unwrap();
|
|
child.wait().unwrap();
|
|
})
|
|
.await;
|
|
}
|