1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-23 15:16:54 -05:00
denoland-deno/cli/tests/integration/mod.rs

1398 lines
39 KiB
Rust
Raw Normal View History

// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use crate::itest;
use deno_core::url;
use deno_runtime::deno_fetch::reqwest;
use deno_runtime::deno_net::ops_tls::TlsStream;
use deno_runtime::deno_tls::rustls;
use deno_runtime::deno_tls::rustls_pemfile;
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 test_util as util;
use test_util::TempDir;
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()
}
}
);
2021-08-11 11:38:07 -04:00
#[macro_export]
macro_rules! itest_flaky(
($name:ident {$( $key:ident: $value:expr,)*}) => {
#[flaky_test::flaky_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 = "bench_tests.rs"]
mod bench;
#[path = "bundle_tests.rs"]
mod bundle;
#[path = "cache_tests.rs"]
mod cache;
#[path = "check_tests.rs"]
mod check;
#[path = "compat_tests.rs"]
mod compat;
#[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 = "task_tests.rs"]
mod task;
#[path = "test_tests.rs"]
mod test;
#[path = "upgrade_tests.rs"]
mod upgrade;
2022-02-16 13:14:19 -05:00
#[path = "vendor_tests.rs"]
mod vendor;
#[path = "watcher_tests.rs"]
mod watcher;
#[path = "worker_tests.rs"]
mod worker;
#[test]
fn help_flag() {
let status = util::deno_cmd()
.current_dir(util::testdata_path())
.arg("--help")
.spawn()
.unwrap()
.wait()
.unwrap();
assert!(status.success());
}
#[test]
fn version_short_flag() {
let status = util::deno_cmd()
.current_dir(util::testdata_path())
.arg("-V")
.spawn()
.unwrap()
.wait()
.unwrap();
assert!(status.success());
}
#[test]
fn version_long_flag() {
let status = util::deno_cmd()
.current_dir(util::testdata_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();
let module_url =
url::Url::parse("http://localhost:4545/006_url_imports.ts").unwrap();
let output = Command::new(util::deno_exe_path())
.env("DENO_DIR", deno_dir.path())
.current_dir(util::testdata_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::testdata_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::testdata_path().join("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();
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::testdata_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::testdata_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();
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::testdata_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::testdata_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();
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::testdata_path())
.env("NO_COLOR", "1")
.env("DENO_FUTURE_CHECK", "1")
.arg("run")
.arg("--check")
.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::testdata_path())
.env("NO_COLOR", "1")
.env("DENO_FUTURE_CHECK", "1")
.arg("run")
.arg("--check")
.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::testdata_path().join("017_import_redirect.ts");
assert!(redirect_ts.is_file());
let mut cmd = Command::new(e.clone());
cmd.env("DENO_DIR", deno_dir.path());
cmd.env("DENO_FUTURE_CHECK", "1");
let mut initial = cmd
.current_dir(util::testdata_path())
.arg("run")
.arg("--check")
.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());
cmd.env("DENO_FUTURE_CHECK", "1");
let output = cmd
.current_dir(util::testdata_path())
.arg("run")
.arg("--check")
.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::testdata_path().join("002_hello.ts");
assert!(hello_ts.is_file());
let deno_dir = TempDir::new();
let mut initial = util::deno_cmd_with_deno_dir(&deno_dir)
.current_dir(util::testdata_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)
.current_dir(util::testdata_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!(
dbg!(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::testdata_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::testdata_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::testdata_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"));
}
itest!(error_cause {
args: "run error_cause.ts",
output: "error_cause.ts.out",
exit_code: 1,
});
itest!(error_cause_recursive {
args: "run error_cause_recursive.ts",
output: "error_cause_recursive.ts.out",
exit_code: 1,
});
2021-08-11 11:38:07 -04:00
itest_flaky!(cafile_url_imports {
2021-08-11 05:52:52 -04:00
args: "run --quiet --reload --cert tls/RootCA.pem cafile_url_imports.ts",
output: "cafile_url_imports.ts.out",
http_server: true,
});
2021-08-11 11:38:07 -04:00
itest_flaky!(cafile_ts_fetch {
2021-08-11 05:52:52 -04:00
args:
"run --quiet --reload --allow-net --cert tls/RootCA.pem cafile_ts_fetch.ts",
output: "cafile_ts_fetch.ts.out",
http_server: true,
});
2021-08-11 11:38:07 -04:00
itest_flaky!(cafile_eval {
args: "eval --cert tls/RootCA.pem fetch('https://localhost:5545/cafile_ts_fetch.ts.out').then(r=>r.text()).then(t=>console.log(t.trimEnd()))",
2021-08-11 05:52:52 -04:00
output: "cafile_ts_fetch.ts.out",
http_server: true,
});
2021-08-11 11:38:07 -04:00
itest_flaky!(cafile_info {
2021-08-11 05:52:52 -04:00
args:
"info --quiet --cert tls/RootCA.pem https://localhost:5545/cafile_info.ts",
2021-08-11 05:52:52 -04:00
output: "cafile_info.ts.out",
http_server: true,
});
2021-08-11 11:38:07 -04:00
itest_flaky!(cafile_url_imports_unsafe_ssl {
args: "run --quiet --reload --unsafely-ignore-certificate-errors=localhost cafile_url_imports.ts",
output: "cafile_url_imports_unsafe_ssl.ts.out",
http_server: true,
});
2021-08-11 11:38:07 -04:00
itest_flaky!(cafile_ts_fetch_unsafe_ssl {
args:
"run --quiet --reload --allow-net --unsafely-ignore-certificate-errors cafile_ts_fetch.ts",
output: "cafile_ts_fetch_unsafe_ssl.ts.out",
http_server: true,
});
2021-08-10 10:22:21 -04:00
itest!(deno_land_unsafe_ssl {
args:
"run --quiet --reload --allow-net --unsafely-ignore-certificate-errors=deno.land deno_land_unsafe_ssl.ts",
output: "deno_land_unsafe_ssl.ts.out",
});
itest!(localhost_unsafe_ssl {
args:
"run --quiet --reload --allow-net --unsafely-ignore-certificate-errors=deno.land cafile_url_imports.ts",
output: "localhost_unsafe_ssl.ts.out",
http_server: true,
exit_code: 1,
});
2021-08-11 11:38:07 -04:00
#[flaky_test::flaky_test]
fn cafile_env_fetch() {
use deno_core::url::Url;
let _g = util::http_server();
let deno_dir = TempDir::new();
let module_url =
Url::parse("https://localhost:5545/cafile_url_imports.ts").unwrap();
let cafile = util::testdata_path().join("tls/RootCA.pem");
let output = Command::new(util::deno_exe_path())
.env("DENO_DIR", deno_dir.path())
.env("DENO_CERT", cafile)
.current_dir(util::testdata_path())
.arg("cache")
.arg(module_url.to_string())
.output()
.expect("Failed to spawn script");
assert!(output.status.success());
}
2021-08-11 11:38:07 -04:00
#[flaky_test::flaky_test]
fn cafile_fetch() {
use deno_core::url::Url;
let _g = util::http_server();
let deno_dir = TempDir::new();
let module_url =
Url::parse("http://localhost:4545/cafile_url_imports.ts").unwrap();
let cafile = util::testdata_path().join("tls/RootCA.pem");
let output = Command::new(util::deno_exe_path())
.env("DENO_DIR", deno_dir.path())
.current_dir(util::testdata_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, "");
}
2021-08-11 11:38:07 -04:00
#[flaky_test::flaky_test]
fn cafile_install_remote_module() {
let _g = util::http_server();
let temp_dir = TempDir::new();
let bin_dir = temp_dir.path().join("bin");
std::fs::create_dir(&bin_dir).unwrap();
let deno_dir = TempDir::new();
let cafile = util::testdata_path().join("tls/RootCA.pem");
let install_output = Command::new(util::deno_exe_path())
.env("DENO_DIR", deno_dir.path())
.current_dir(util::testdata_path())
.arg("install")
.arg("--cert")
.arg(cafile)
.arg("--root")
.arg(temp_dir.path())
.arg("-n")
.arg("echo_test")
.arg("https://localhost:5545/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"));
}
2021-08-11 11:38:07 -04:00
#[flaky_test::flaky_test]
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/subdir/mod1.ts";
let cafile = util::testdata_path().join("tls/RootCA.pem");
let t = TempDir::new();
let bundle = t.path().join("mod1.bundle.js");
let mut deno = util::deno_cmd()
.current_dir(util::testdata_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::testdata_path())
.env("DENO_FUTURE_CHECK", "1")
.arg("run")
.arg("--check")
.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::testdata_path().join("websocket_test.ts");
let root_ca = util::testdata_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());
}
#[test]
fn websocketstream() {
let _g = util::http_server();
let script = util::testdata_path().join("websocketstream_test.ts");
let root_ca = util::testdata_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());
}
#[test]
fn websocket_server_multi_field_connection_header() {
let script = util::testdata_path()
.join("websocket_server_multi_field_connection_header_test.ts");
let root_ca = util::testdata_path().join("tls/RootCA.pem");
let mut child = util::deno_cmd()
.arg("run")
.arg("--unstable")
.arg("--allow-net")
.arg("--cert")
.arg(root_ca)
.arg(script)
.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 req = http::request::Builder::new()
.header(http::header::CONNECTION, "keep-alive, Upgrade")
.uri("ws://localhost:4319")
.body(())
.unwrap();
assert!(
deno_runtime::deno_websocket::tokio_tungstenite::tungstenite::connect(req)
.is_ok()
);
assert!(child.wait().unwrap().success());
}
// TODO(bartlomieju): this should use `deno run`, not `deno test`; but the
// test hangs then. https://github.com/denoland/deno/issues/14283
#[test]
#[ignore]
fn websocket_server_idletimeout() {
let script = util::testdata_path().join("websocket_server_idletimeout.ts");
let root_ca = util::testdata_path().join("tls/RootCA.pem");
let mut child = util::deno_cmd()
.arg("test")
.arg("--unstable")
.arg("--allow-net")
.arg("--cert")
.arg(root_ca)
.arg(script)
.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 req = http::request::Builder::new()
.uri("ws://localhost:4509")
.body(())
.unwrap();
let (_ws, _request) =
deno_runtime::deno_websocket::tokio_tungstenite::tungstenite::connect(req)
.unwrap();
assert!(child.wait().unwrap().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::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 NS record
let rdata = RData::NS(Name::from_str("ns1.ns.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::NS),
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(
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::testdata_path())
.env("NO_COLOR", "1")
.env("DENO_FUTURE_CHECK", "1")
.arg("run")
.arg("--check")
.arg("--allow-net")
.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::testdata_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::testdata_path())
.env("NO_COLOR", "1")
.env("DENO_FUTURE_CHECK", "1")
.arg("run")
.arg("--check")
.arg("--allow-net=127.0.0.1:4553")
.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::testdata_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::testdata_path())
.env("NO_COLOR", "1")
.env("DENO_FUTURE_CHECK", "1")
.arg("run")
.arg("--check")
.arg("--allow-net=deno.land")
.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::testdata_path())
.env("NO_COLOR", "1")
.env("DENO_FUTURE_CHECK", "1")
.arg("run")
.arg("--check")
.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 output = util::deno_cmd()
.arg("test")
.arg("--doc")
.arg(util::root_path().join("cli/dts/lib.deno.ns.d.ts"))
.output()
.unwrap();
println!("stdout: {}", String::from_utf8(output.stdout).unwrap());
println!("stderr: {}", String::from_utf8(output.stderr).unwrap());
assert!(output.status.success());
}
#[test]
fn typecheck_declarations_unstable() {
let output = util::deno_cmd()
.arg("test")
.arg("--doc")
.arg("--unstable")
.arg(util::root_path().join("cli/dts/lib.deno.unstable.d.ts"))
.output()
.unwrap();
println!("stdout: {}", String::from_utf8(output.stdout).unwrap());
println!("stderr: {}", String::from_utf8(output.stderr).unwrap());
assert!(output.status.success());
}
#[test]
fn typecheck_core() {
let deno_dir = TempDir::new();
let test_file = deno_dir.path().join("test_deno_core_types.ts");
std::fs::write(
&test_file,
format!(
"import \"{}\";",
deno_core::resolve_path(
util::root_path()
.join("core/lib.deno_core.d.ts")
.to_str()
.unwrap()
)
.unwrap()
),
)
.unwrap();
let output = util::deno_cmd_with_deno_dir(&deno_dir)
.arg("run")
.arg(test_file.to_str().unwrap())
.output()
.unwrap();
println!("stdout: {}", String::from_utf8(output.stdout).unwrap());
println!("stderr: {}", String::from_utf8(output.stderr).unwrap());
assert!(output.status.success());
}
#[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());
}
#[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("--no-prompt")
.arg("-A")
.arg(util::tests_path().join("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());
}
#[test]
fn basic_auth_tokens() {
let _g = util::http_server();
let output = util::deno_cmd()
.current_dir(util::root_path())
.arg("run")
.arg("http://127.0.0.1:4554/001_hello.js")
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
.unwrap()
.wait_with_output()
.unwrap();
assert!(!output.status.success());
let stdout_str = std::str::from_utf8(&output.stdout).unwrap().trim();
assert!(stdout_str.is_empty());
let stderr_str = std::str::from_utf8(&output.stderr).unwrap().trim();
eprintln!("{}", stderr_str);
assert!(stderr_str
.contains("Module not found \"http://127.0.0.1:4554/001_hello.js\"."));
let output = util::deno_cmd()
.current_dir(util::root_path())
.arg("run")
.arg("http://127.0.0.1:4554/001_hello.js")
.env("DENO_AUTH_TOKENS", "testuser123:testpassabc@127.0.0.1:4554")
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
.unwrap()
.wait_with_output()
.unwrap();
let stderr_str = std::str::from_utf8(&output.stderr).unwrap().trim();
eprintln!("{}", stderr_str);
assert!(output.status.success());
let stdout_str = std::str::from_utf8(&output.stdout).unwrap().trim();
assert_eq!(util::strip_ansi_codes(stdout_str), "Hello World");
}
#[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::testdata_path())
.arg("run")
.arg("--unstable")
.arg("--quiet")
.arg("--allow-net")
.arg("--allow-read")
.arg("./listen_tls_alpn.ts")
.arg("4504")
.stdout(std::process::Stdio::piped())
.spawn()
.unwrap();
let stdout = child.stdout.as_mut().unwrap();
let mut msg = [0; 5];
let read = stdout.read(&mut msg).unwrap();
assert_eq!(read, 5);
assert_eq!(&msg, b"READY");
let mut reader = &mut BufReader::new(Cursor::new(include_bytes!(
"../testdata/tls/RootCA.crt"
)));
let certs = rustls_pemfile::certs(&mut reader).unwrap();
let mut root_store = rustls::RootCertStore::empty();
root_store.add_parsable_certificates(&certs);
let mut cfg = rustls::ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_store)
.with_no_client_auth();
cfg.alpn_protocols.push(b"foobar".to_vec());
let cfg = Arc::new(cfg);
let hostname = rustls::ServerName::try_from("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 (_, rustls_connection) = tls_stream.get_ref();
let alpn = rustls_connection.alpn_protocol().unwrap();
assert_eq!(alpn, b"foobar");
let status = child.wait().unwrap();
assert!(status.success());
})
.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::testdata_path())
.arg("run")
.arg("--unstable")
.arg("--quiet")
.arg("--allow-net")
.arg("--allow-read")
.arg("./listen_tls_alpn_fail.ts")
.arg("4505")
.stdout(std::process::Stdio::piped())
.spawn()
.unwrap();
let stdout = child.stdout.as_mut().unwrap();
let mut msg = [0; 5];
let read = stdout.read(&mut msg).unwrap();
assert_eq!(read, 5);
assert_eq!(&msg, b"READY");
let mut reader = &mut BufReader::new(Cursor::new(include_bytes!(
"../testdata/tls/RootCA.crt"
)));
let certs = rustls_pemfile::certs(&mut reader).unwrap();
let mut root_store = rustls::RootCertStore::empty();
root_store.add_parsable_certificates(&certs);
let mut cfg = rustls::ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_store)
.with_no_client_auth();
cfg.alpn_protocols.push(b"boofar".to_vec());
let cfg = Arc::new(cfg);
let hostname = rustls::ServerName::try_from("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_err();
let (_, rustls_connection) = tls_stream.get_ref();
assert!(rustls_connection.alpn_protocol().is_none());
let status = child.wait().unwrap();
assert!(status.success());
})
.await;
}
#[tokio::test]
async fn http2_request_url() {
// 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::testdata_path())
.arg("run")
.arg("--unstable")
.arg("--quiet")
.arg("--allow-net")
.arg("--allow-read")
.arg("./http2_request_url.ts")
.arg("4506")
.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 cert = reqwest::Certificate::from_pem(include_bytes!(
"../testdata/tls/RootCA.crt"
))
.unwrap();
let client = reqwest::Client::builder()
.add_root_certificate(cert)
.http2_prior_knowledge()
.build()
.unwrap();
let res = client.get("http://127.0.0.1:4506").send().await.unwrap();
assert_eq!(200, res.status());
let body = res.text().await.unwrap();
assert_eq!(body, "http://127.0.0.1:4506/");
child.kill().unwrap();
child.wait().unwrap();
})
.await;
}