mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 17:34:47 -05:00
test: add private npm registry (#23510)
This commit adds a "private npm registry" to the test server. This registry requires to send an appropriate Authorization header. Towards https://github.com/denoland/deno/issues/16105
This commit is contained in:
parent
aff7a64544
commit
90a167a1a2
2 changed files with 135 additions and 42 deletions
|
@ -3,9 +3,11 @@
|
|||
use deno_core::serde_json;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::serde_json::Value;
|
||||
use deno_fetch::reqwest;
|
||||
use pretty_assertions::assert_eq;
|
||||
use test_util as util;
|
||||
use test_util::itest;
|
||||
use url::Url;
|
||||
use util::assert_contains;
|
||||
use util::env_vars_for_npm_tests;
|
||||
use util::http_server;
|
||||
|
@ -3081,3 +3083,29 @@ fn run_cjs_in_node_modules_folder() {
|
|||
.run()
|
||||
.assert_matches_text("hi\n");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_private_npm_registry() {
|
||||
let _server = http_server();
|
||||
|
||||
// For now just check that private server rejects requests without proper
|
||||
// auth header.
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let url =
|
||||
Url::parse("http://127.0.0.1:4252/npm/registry/@denotest/bin/0.5.0")
|
||||
.unwrap();
|
||||
|
||||
let req = reqwest::Request::new(reqwest::Method::GET, url.clone());
|
||||
let resp = client.execute(req).await.unwrap();
|
||||
assert_eq!(resp.status(), reqwest::StatusCode::UNAUTHORIZED);
|
||||
|
||||
let mut req = reqwest::Request::new(reqwest::Method::GET, url.clone());
|
||||
req.headers_mut().insert(
|
||||
reqwest::header::AUTHORIZATION,
|
||||
reqwest::header::HeaderValue::from_static("Bearer private-reg-token"),
|
||||
);
|
||||
let resp = client.execute(req).await.unwrap();
|
||||
assert_eq!(resp.status(), reqwest::StatusCode::OK);
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@ const H2_GRPC_PORT: u16 = 4246;
|
|||
const H2S_GRPC_PORT: u16 = 4247;
|
||||
const REGISTRY_SERVER_PORT: u16 = 4250;
|
||||
const PROVENANCE_MOCK_SERVER_PORT: u16 = 4251;
|
||||
const PRIVATE_NPM_REGISTRY_1_PORT: u16 = 4252;
|
||||
|
||||
// Use the single-threaded scheduler. The hyper server is used as a point of
|
||||
// comparison for the (single-threaded!) benchmarks in cli/bench. We're not
|
||||
|
@ -130,6 +131,8 @@ pub async fn run_all_servers() {
|
|||
let registry_server_fut = registry::registry_server(REGISTRY_SERVER_PORT);
|
||||
let provenance_mock_server_fut =
|
||||
registry::provenance_mock_server(PROVENANCE_MOCK_SERVER_PORT);
|
||||
let private_npm_registry_1_server_fut =
|
||||
wrap_private_npm_registry1(PRIVATE_NPM_REGISTRY_1_PORT);
|
||||
|
||||
let server_fut = async {
|
||||
futures::join!(
|
||||
|
@ -158,6 +161,7 @@ pub async fn run_all_servers() {
|
|||
h2_grpc_server_fut,
|
||||
registry_server_fut,
|
||||
provenance_mock_server_fut,
|
||||
private_npm_registry_1_server_fut,
|
||||
)
|
||||
}
|
||||
.boxed_local();
|
||||
|
@ -1087,49 +1091,9 @@ async fn main_server(
|
|||
}
|
||||
|
||||
// serve npm registry files
|
||||
if let Some(suffix) = req
|
||||
.uri()
|
||||
.path()
|
||||
.strip_prefix("/npm/registry/@denotest/")
|
||||
.or_else(|| req.uri().path().strip_prefix("/npm/registry/@denotest%2f"))
|
||||
if let Some(resp) = try_serve_npm_registry(&req, file_path.clone()).await
|
||||
{
|
||||
// serve all requests to /npm/registry/@deno using the file system
|
||||
// at that path
|
||||
match handle_custom_npm_registry_path(suffix) {
|
||||
Ok(Some(response)) => return Ok(response),
|
||||
Ok(None) => {} // ignore, not found
|
||||
Err(err) => {
|
||||
return Response::builder()
|
||||
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
||||
.body(string_body(&format!("{err:#}")))
|
||||
.map_err(|e| e.into());
|
||||
}
|
||||
}
|
||||
} else if req.uri().path().starts_with("/npm/registry/") {
|
||||
// otherwise, serve based on registry.json and tgz files
|
||||
let is_tarball = req.uri().path().ends_with(".tgz");
|
||||
if !is_tarball {
|
||||
file_path.push("registry.json");
|
||||
}
|
||||
if let Ok(file) = tokio::fs::read(&file_path).await {
|
||||
let file_resp = custom_headers(req.uri().path(), file);
|
||||
return Ok(file_resp);
|
||||
} else if should_download_npm_packages() {
|
||||
if let Err(err) =
|
||||
download_npm_registry_file(req.uri(), &file_path, is_tarball).await
|
||||
{
|
||||
return Response::builder()
|
||||
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
||||
.body(string_body(&format!("{err:#}")))
|
||||
.map_err(|e| e.into());
|
||||
};
|
||||
|
||||
// serve the file
|
||||
if let Ok(file) = tokio::fs::read(&file_path).await {
|
||||
let file_resp = custom_headers(req.uri().path(), file);
|
||||
return Ok(file_resp);
|
||||
}
|
||||
}
|
||||
return resp;
|
||||
} else if let Some(suffix) = req.uri().path().strip_prefix("/deno_std/") {
|
||||
let file_path = std_path().join(suffix);
|
||||
if let Ok(file) = tokio::fs::read(&file_path).await {
|
||||
|
@ -1154,6 +1118,51 @@ async fn main_server(
|
|||
};
|
||||
}
|
||||
|
||||
const PRIVATE_NPM_REGISTRY_AUTH_TOKEN: &str = "private-reg-token";
|
||||
|
||||
async fn wrap_private_npm_registry1(port: u16) {
|
||||
let npm_registry_addr = SocketAddr::from(([127, 0, 0, 1], port));
|
||||
run_server(
|
||||
ServerOptions {
|
||||
addr: npm_registry_addr,
|
||||
kind: ServerKind::Auto,
|
||||
error_msg: "HTTP server error",
|
||||
},
|
||||
private_npm_registry1,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn private_npm_registry1(
|
||||
req: Request<hyper::body::Incoming>,
|
||||
) -> Result<Response<UnsyncBoxBody<Bytes, Infallible>>, anyhow::Error> {
|
||||
let auth = req
|
||||
.headers()
|
||||
.get("authorization")
|
||||
.and_then(|x| x.to_str().ok())
|
||||
.unwrap_or_default();
|
||||
if auth != format!("Bearer {}", PRIVATE_NPM_REGISTRY_AUTH_TOKEN) {
|
||||
return Ok(
|
||||
Response::builder()
|
||||
.status(StatusCode::UNAUTHORIZED)
|
||||
.body(empty_body())
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
let mut file_path = testdata_path().to_path_buf();
|
||||
file_path.push(&req.uri().path()[1..].replace("%2f", "/"));
|
||||
|
||||
if let Some(resp) = try_serve_npm_registry(&req, file_path).await {
|
||||
return resp;
|
||||
}
|
||||
|
||||
Response::builder()
|
||||
.status(StatusCode::NOT_FOUND)
|
||||
.body(empty_body())
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn handle_custom_npm_registry_path(
|
||||
path: &str,
|
||||
) -> Result<Option<Response<UnsyncBoxBody<Bytes, Infallible>>>, anyhow::Error> {
|
||||
|
@ -1186,6 +1195,62 @@ fn should_download_npm_packages() -> bool {
|
|||
std::env::var("DENO_TEST_UTIL_UPDATE_NPM") == Ok("1".to_string())
|
||||
}
|
||||
|
||||
async fn try_serve_npm_registry(
|
||||
req: &Request<hyper::body::Incoming>,
|
||||
mut file_path: PathBuf,
|
||||
) -> Option<Result<Response<UnsyncBoxBody<Bytes, Infallible>>, anyhow::Error>> {
|
||||
if let Some(suffix) = req
|
||||
.uri()
|
||||
.path()
|
||||
.strip_prefix("/npm/registry/@denotest/")
|
||||
.or_else(|| req.uri().path().strip_prefix("/npm/registry/@denotest%2f"))
|
||||
{
|
||||
// serve all requests to /npm/registry/@deno using the file system
|
||||
// at that path
|
||||
match handle_custom_npm_registry_path(suffix) {
|
||||
Ok(Some(response)) => return Some(Ok(response)),
|
||||
Ok(None) => {} // ignore, not found
|
||||
Err(err) => {
|
||||
return Some(
|
||||
Response::builder()
|
||||
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
||||
.body(string_body(&format!("{err:#}")))
|
||||
.map_err(|e| e.into()),
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if req.uri().path().starts_with("/npm/registry/") {
|
||||
// otherwise, serve based on registry.json and tgz files
|
||||
let is_tarball = req.uri().path().ends_with(".tgz");
|
||||
if !is_tarball {
|
||||
file_path.push("registry.json");
|
||||
}
|
||||
if let Ok(file) = tokio::fs::read(&file_path).await {
|
||||
let file_resp = custom_headers(req.uri().path(), file);
|
||||
return Some(Ok(file_resp));
|
||||
} else if should_download_npm_packages() {
|
||||
if let Err(err) =
|
||||
download_npm_registry_file(req.uri(), &file_path, is_tarball).await
|
||||
{
|
||||
return Some(
|
||||
Response::builder()
|
||||
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
||||
.body(string_body(&format!("{err:#}")))
|
||||
.map_err(|e| e.into()),
|
||||
);
|
||||
};
|
||||
|
||||
// serve the file
|
||||
if let Ok(file) = tokio::fs::read(&file_path).await {
|
||||
let file_resp = custom_headers(req.uri().path(), file);
|
||||
return Some(Ok(file_resp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
async fn download_npm_registry_file(
|
||||
uri: &hyper::Uri,
|
||||
file_path: &PathBuf,
|
||||
|
|
Loading…
Add table
Reference in a new issue