diff options
Diffstat (limited to 'cli/tests/integration/mod.rs')
-rw-r--r-- | cli/tests/integration/mod.rs | 1092 |
1 files changed, 1092 insertions, 0 deletions
diff --git a/cli/tests/integration/mod.rs b/cli/tests/integration/mod.rs new file mode 100644 index 000000000..fab2f20a5 --- /dev/null +++ b/cli/tests/integration/mod.rs @@ -0,0 +1,1092 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use crate::itest; +use deno_core::url; +use deno_runtime::ops::tls::rustls; +use deno_runtime::ops::tls::webpki; +use deno_runtime::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; +} |