1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 23:34:47 -05:00
denoland-deno/tests/integration/cert_tests.rs

302 lines
8.5 KiB
Rust
Raw Normal View History

// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
refactor: split integration tests from CLI (part 1) (#22308) This PR separates integration tests from CLI tests into a new project named `cli_tests`. This is a prerequisite for an integration test runner that can work with either the CLI binary in the current project, or one that is built ahead of time. ## Background Rust does not have the concept of artifact dependencies yet (https://github.com/rust-lang/cargo/issues/9096). Because of this, the only way we can ensure a binary is built before running associated tests is by hanging tests off the crate with the binary itself. Unfortunately this means that to run those tests, you _must_ build the binary and in the case of the deno executable that might be a 10 minute wait in release mode. ## Implementation To allow for tests to run with and without the requirement that the binary is up-to-date, we split the integration tests into a project of their own. As these tests would not require the binary to build itself before being run as-is, we add a stub integration `[[test]]` target in the `cli` project that invokes these tests using `cargo test`. The stub test runner we add has `harness = false` so that we can get access to a `main` function. This `main` function's sole job is to `execvp` the command `cargo test -p deno_cli`, effectively "calling" another cargo target. This ensures that the deno executable is always correctly rebuilt before running the stub test runner from `cli`, and gets us closer to be able to run the entire integration test suite on arbitrary deno executables (and therefore split the build into multiple phases). The new `cli_tests` project lives within `cli` to avoid a large PR. In later PRs, the test data will be split from the `cli` project. As there are a few thousand files, it'll be better to do this as a completely separate PR to avoid noise.
2024-02-09 15:33:05 -05:00
use deno_tls::rustls;
use deno_tls::rustls_pemfile;
use deno_tls::rustls_tokio_stream::TlsStream;
use std::io::BufReader;
use std::io::Cursor;
use std::io::Read;
use std::sync::Arc;
use test_util as util;
use test_util::itest;
use test_util::itest_flaky;
refactor: split integration tests from CLI (part 1) (#22308) This PR separates integration tests from CLI tests into a new project named `cli_tests`. This is a prerequisite for an integration test runner that can work with either the CLI binary in the current project, or one that is built ahead of time. ## Background Rust does not have the concept of artifact dependencies yet (https://github.com/rust-lang/cargo/issues/9096). Because of this, the only way we can ensure a binary is built before running associated tests is by hanging tests off the crate with the binary itself. Unfortunately this means that to run those tests, you _must_ build the binary and in the case of the deno executable that might be a 10 minute wait in release mode. ## Implementation To allow for tests to run with and without the requirement that the binary is up-to-date, we split the integration tests into a project of their own. As these tests would not require the binary to build itself before being run as-is, we add a stub integration `[[test]]` target in the `cli` project that invokes these tests using `cargo test`. The stub test runner we add has `harness = false` so that we can get access to a `main` function. This `main` function's sole job is to `execvp` the command `cargo test -p deno_cli`, effectively "calling" another cargo target. This ensures that the deno executable is always correctly rebuilt before running the stub test runner from `cli`, and gets us closer to be able to run the entire integration test suite on arbitrary deno executables (and therefore split the build into multiple phases). The new `cli_tests` project lives within `cli` to avoid a large PR. In later PRs, the test data will be split from the `cli` project. As there are a few thousand files, it'll be better to do this as a completely separate PR to avoid noise.
2024-02-09 15:33:05 -05:00
use url::Url;
use util::testdata_path;
use util::TestContext;
itest_flaky!(cafile_url_imports {
args: "run --quiet --reload --cert tls/RootCA.pem cert/cafile_url_imports.ts",
output: "cert/cafile_url_imports.ts.out",
http_server: true,
});
itest_flaky!(cafile_ts_fetch {
args:
"run --quiet --reload --allow-net --cert tls/RootCA.pem cert/cafile_ts_fetch.ts",
output: "cert/cafile_ts_fetch.ts.out",
http_server: true,
});
itest_flaky!(cafile_eval {
args: "eval --cert tls/RootCA.pem fetch('https://localhost:5545/cert/cafile_ts_fetch.ts.out').then(r=>r.text()).then(t=>console.log(t.trimEnd()))",
output: "cert/cafile_ts_fetch.ts.out",
http_server: true,
});
itest_flaky!(cafile_info {
args:
"info --quiet --cert tls/RootCA.pem https://localhost:5545/cert/cafile_info.ts",
output: "cert/cafile_info.ts.out",
http_server: true,
});
itest_flaky!(cafile_url_imports_unsafe_ssl {
args: "run --quiet --reload --unsafely-ignore-certificate-errors=localhost cert/cafile_url_imports.ts",
output: "cert/cafile_url_imports_unsafe_ssl.ts.out",
http_server: true,
});
itest_flaky!(cafile_ts_fetch_unsafe_ssl {
args:
"run --quiet --reload --allow-net --unsafely-ignore-certificate-errors cert/cafile_ts_fetch.ts",
output: "cert/cafile_ts_fetch_unsafe_ssl.ts.out",
http_server: true,
});
// TODO(bartlomieju): reenable, this test was flaky on macOS CI during 1.30.3 release
// itest!(deno_land_unsafe_ssl {
// args:
// "run --quiet --reload --allow-net --unsafely-ignore-certificate-errors=deno.land cert/deno_land_unsafe_ssl.ts",
// output: "cert/deno_land_unsafe_ssl.ts.out",
// });
itest!(ip_address_unsafe_ssl {
args:
"run --quiet --reload --allow-net --unsafely-ignore-certificate-errors=1.1.1.1 cert/ip_address_unsafe_ssl.ts",
output: "cert/ip_address_unsafe_ssl.ts.out",
});
itest!(localhost_unsafe_ssl {
args: "run --quiet --reload --allow-net --unsafely-ignore-certificate-errors=deno.land cert/cafile_url_imports.ts",
output: "cert/localhost_unsafe_ssl.ts.out",
http_server: true,
exit_code: 1,
});
#[flaky_test::flaky_test]
fn cafile_env_fetch() {
let module_url =
Url::parse("https://localhost:5545/cert/cafile_url_imports.ts").unwrap();
let context = TestContext::with_http_server();
let cafile = testdata_path().join("tls/RootCA.pem");
context
.new_command()
.args(format!("cache {module_url}"))
.env("DENO_CERT", cafile)
.run()
.assert_exit_code(0)
.skip_output_check();
}
#[flaky_test::flaky_test]
fn cafile_fetch() {
let module_url =
Url::parse("http://localhost:4545/cert/cafile_url_imports.ts").unwrap();
let context = TestContext::with_http_server();
let cafile = testdata_path().join("tls/RootCA.pem");
context
.new_command()
.args(format!("cache --quiet --cert {} {}", cafile, module_url,))
.run()
.assert_exit_code(0)
.assert_matches_text("");
}
#[test]
fn cafile_compile() {
let context = TestContext::with_http_server();
let temp_dir = context.temp_dir().path();
let output_exe = if cfg!(windows) {
temp_dir.join("cert.exe")
} else {
temp_dir.join("cert")
};
let output = context.new_command()
.args(format!("compile --quiet --cert ./tls/RootCA.pem --allow-net --output {} ./cert/cafile_ts_fetch.ts", output_exe))
.run();
output.skip_output_check();
context
.new_command()
.name(output_exe)
.run()
.assert_matches_text("[WILDCARD]\nHello\n");
}
#[flaky_test::flaky_test]
fn cafile_install_remote_module() {
let context = TestContext::with_http_server();
let temp_dir = context.temp_dir();
let bin_dir = temp_dir.path().join("bin");
bin_dir.create_dir_all();
let cafile = util::testdata_path().join("tls/RootCA.pem");
let install_output = context
.new_command()
.args_vec([
"install",
"--cert",
&cafile.to_string_lossy(),
"--root",
&temp_dir.path().to_string_lossy(),
"-n",
"echo_test",
"https://localhost:5545/echo.ts",
])
.split_output()
.run();
println!("{}", install_output.stdout());
eprintln!("{}", install_output.stderr());
install_output.assert_exit_code(0);
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 = context
.new_command()
.name(echo_test_path)
.args("foo")
.env("PATH", util::target_dir())
.run();
output.assert_matches_text("[WILDCARD]foo");
}
#[flaky_test::flaky_test]
fn cafile_bundle_remote_exports() {
let context = TestContext::with_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 = context.temp_dir();
let bundle = t.path().join("mod1.bundle.js");
context
.new_command()
.args_vec([
"bundle",
"--cert",
&cafile.to_string_lossy(),
mod1,
&bundle.to_string_lossy(),
])
.run()
.skip_output_check()
.assert_exit_code(0);
assert!(bundle.is_file());
// Now we try to use that bundle from another module.
let test = t.path().join("test.js");
test.write(
"import { printHello3 } from \"./mod1.bundle.js\";
printHello3();",
);
context
.new_command()
.args_vec(["run", "--quiet", "--check", &test.to_string_lossy()])
.run()
.assert_matches_text("[WILDCARD]Hello\n")
.assert_exit_code(0);
}
#[tokio::test]
async fn listen_tls_alpn() {
let mut child = util::deno_cmd()
.current_dir(util::testdata_path())
.arg("run")
.arg("--unstable")
.arg("--quiet")
.arg("--allow-net")
.arg("--allow-read")
.arg("./cert/listen_tls_alpn.ts")
.arg("4504")
.stdout_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, None);
let handshake = tls_stream.handshake().await.unwrap();
assert_eq!(handshake.alpn, Some(b"foobar".to_vec()));
let status = child.wait().unwrap();
assert!(status.success());
}
#[tokio::test]
async fn listen_tls_alpn_fail() {
let mut child = util::deno_cmd()
.current_dir(util::testdata_path())
.arg("run")
.arg("--unstable")
.arg("--quiet")
.arg("--allow-net")
.arg("--allow-read")
.arg("./cert/listen_tls_alpn_fail.ts")
.arg("4505")
.stdout_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, None);
tls_stream.handshake().await.unwrap_err();
let status = child.wait().unwrap();
assert!(status.success());
}