mirror of
https://github.com/denoland/deno.git
synced 2024-11-25 15:29:32 -05:00
chore(tests): add .use_symlinked_temp_dir()
to TestBuilder
(#19435)
This allows easily using a symlinked temporary directory, which is useful for debugging issues locally that happen on the CI with a symlinked temporary directory. For example: ```rs let context = TestContextBuilder::new() .use_temp_cwd() .use_symlinked_temp_dir() // add this .build(); ```
This commit is contained in:
parent
168eb8e01d
commit
f182c8af87
3 changed files with 85 additions and 11 deletions
|
@ -31,6 +31,7 @@ pub struct TestContextBuilder {
|
||||||
use_http_server: bool,
|
use_http_server: bool,
|
||||||
use_temp_cwd: bool,
|
use_temp_cwd: bool,
|
||||||
use_separate_deno_dir: bool,
|
use_separate_deno_dir: bool,
|
||||||
|
use_symlinked_temp_dir: bool,
|
||||||
/// Copies the files at the specified directory in the "testdata" directory
|
/// Copies the files at the specified directory in the "testdata" directory
|
||||||
/// to the temp folder and runs the test from there. This is useful when
|
/// to the temp folder and runs the test from there. This is useful when
|
||||||
/// the test creates files in the testdata directory (ex. a node_modules folder)
|
/// the test creates files in the testdata directory (ex. a node_modules folder)
|
||||||
|
@ -59,6 +60,18 @@ impl TestContextBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Causes the temp directory to be symlinked to a target directory
|
||||||
|
/// which is useful for debugging issues that only show up on the CI.
|
||||||
|
///
|
||||||
|
/// Note: This method is not actually deprecated, it's just the CI
|
||||||
|
/// does this by default so there's no need to check in any code that
|
||||||
|
/// uses this into the repo. This is just for debugging purposes.
|
||||||
|
#[deprecated]
|
||||||
|
pub fn use_symlinked_temp_dir(mut self) -> Self {
|
||||||
|
self.use_symlinked_temp_dir = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// By default, the temp_dir and the deno_dir will be shared.
|
/// By default, the temp_dir and the deno_dir will be shared.
|
||||||
/// In some cases, that might cause an issue though, so calling
|
/// In some cases, that might cause an issue though, so calling
|
||||||
/// this will use a separate directory for the deno dir and the
|
/// this will use a separate directory for the deno dir and the
|
||||||
|
@ -110,6 +123,11 @@ impl TestContextBuilder {
|
||||||
} else {
|
} else {
|
||||||
deno_dir.clone()
|
deno_dir.clone()
|
||||||
};
|
};
|
||||||
|
let temp_dir = if self.use_symlinked_temp_dir {
|
||||||
|
TempDir::new_symlinked(temp_dir)
|
||||||
|
} else {
|
||||||
|
temp_dir
|
||||||
|
};
|
||||||
let testdata_dir = if let Some(temp_copy_dir) = &self.copy_temp_dir {
|
let testdata_dir = if let Some(temp_copy_dir) = &self.copy_temp_dir {
|
||||||
let test_data_path = testdata_path().join(temp_copy_dir);
|
let test_data_path = testdata_path().join(temp_copy_dir);
|
||||||
let temp_copy_dir = temp_dir.path().join(temp_copy_dir);
|
let temp_copy_dir = temp_dir.path().join(temp_copy_dir);
|
||||||
|
|
|
@ -616,7 +616,7 @@ impl LspClient {
|
||||||
config: Value,
|
config: Value,
|
||||||
) {
|
) {
|
||||||
let mut builder = InitializeParamsBuilder::new();
|
let mut builder = InitializeParamsBuilder::new();
|
||||||
builder.set_root_uri(self.context.deno_dir().uri());
|
builder.set_root_uri(self.context.temp_dir().uri());
|
||||||
do_build(&mut builder);
|
do_build(&mut builder);
|
||||||
self.write_request("initialize", builder.build());
|
self.write_request("initialize", builder.build());
|
||||||
self.write_notification("initialized", json!({}));
|
self.write_notification("initialized", json!({}));
|
||||||
|
|
|
@ -2,11 +2,46 @@
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use lsp_types::Url;
|
use lsp_types::Url;
|
||||||
|
|
||||||
|
enum TempDirInner {
|
||||||
|
TempDir(tempfile::TempDir),
|
||||||
|
Path(PathBuf),
|
||||||
|
Symlinked {
|
||||||
|
symlink: Arc<TempDirInner>,
|
||||||
|
target: Arc<TempDirInner>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TempDirInner {
|
||||||
|
pub fn path(&self) -> &Path {
|
||||||
|
match self {
|
||||||
|
Self::Path(path) => path.as_path(),
|
||||||
|
Self::TempDir(dir) => dir.path(),
|
||||||
|
Self::Symlinked { symlink, .. } => symlink.path(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn target_path(&self) -> &Path {
|
||||||
|
match self {
|
||||||
|
TempDirInner::Symlinked { target, .. } => target.target_path(),
|
||||||
|
_ => self.path(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TempDirInner {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Self::Path(path) = self {
|
||||||
|
_ = fs::remove_dir_all(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// For creating temporary directories in tests.
|
/// For creating temporary directories in tests.
|
||||||
///
|
///
|
||||||
/// This was done because `tempfiles::TempDir` was very slow on Windows.
|
/// This was done because `tempfiles::TempDir` was very slow on Windows.
|
||||||
|
@ -14,7 +49,7 @@ use lsp_types::Url;
|
||||||
/// Note: Do not use this in actual code as this does not protect against
|
/// Note: Do not use this in actual code as this does not protect against
|
||||||
/// "insecure temporary file" security vulnerabilities.
|
/// "insecure temporary file" security vulnerabilities.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TempDir(Arc<tempfile::TempDir>);
|
pub struct TempDir(Arc<TempDirInner>);
|
||||||
|
|
||||||
impl Default for TempDir {
|
impl Default for TempDir {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -35,6 +70,23 @@ impl TempDir {
|
||||||
Self::new_inner(&std::env::temp_dir(), Some(prefix))
|
Self::new_inner(&std::env::temp_dir(), Some(prefix))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_with_path(path: &Path) -> Self {
|
||||||
|
Self(Arc::new(TempDirInner::Path(path.to_path_buf())))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_symlinked(target: TempDir) -> Self {
|
||||||
|
let target_path = target.path();
|
||||||
|
let path = target_path.parent().unwrap().join(format!(
|
||||||
|
"{}_symlinked",
|
||||||
|
target_path.file_name().unwrap().to_str().unwrap()
|
||||||
|
));
|
||||||
|
target.symlink_dir(target.path(), &path);
|
||||||
|
TempDir(Arc::new(TempDirInner::Symlinked {
|
||||||
|
target: target.0,
|
||||||
|
symlink: Self::new_with_path(&path).0,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new temporary directory with the given prefix as part of its name, if specified.
|
/// Create a new temporary directory with the given prefix as part of its name, if specified.
|
||||||
fn new_inner(parent_dir: &Path, prefix: Option<&str>) -> Self {
|
fn new_inner(parent_dir: &Path, prefix: Option<&str>) -> Self {
|
||||||
let mut builder = tempfile::Builder::new();
|
let mut builder = tempfile::Builder::new();
|
||||||
|
@ -42,7 +94,7 @@ impl TempDir {
|
||||||
let dir = builder
|
let dir = builder
|
||||||
.tempdir_in(parent_dir)
|
.tempdir_in(parent_dir)
|
||||||
.expect("Failed to create a temporary directory");
|
.expect("Failed to create a temporary directory");
|
||||||
Self(dir.into())
|
Self(Arc::new(TempDirInner::TempDir(dir)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uri(&self) -> Url {
|
pub fn uri(&self) -> Url {
|
||||||
|
@ -50,35 +102,39 @@ impl TempDir {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path(&self) -> &Path {
|
pub fn path(&self) -> &Path {
|
||||||
let inner = &self.0;
|
self.0.path()
|
||||||
inner.path()
|
}
|
||||||
|
|
||||||
|
/// The resolved final target path if this is a symlink.
|
||||||
|
pub fn target_path(&self) -> &Path {
|
||||||
|
self.0.target_path()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_dir_all(&self, path: impl AsRef<Path>) {
|
pub fn create_dir_all(&self, path: impl AsRef<Path>) {
|
||||||
fs::create_dir_all(self.path().join(path)).unwrap();
|
fs::create_dir_all(self.target_path().join(path)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_file(&self, path: impl AsRef<Path>) {
|
pub fn remove_file(&self, path: impl AsRef<Path>) {
|
||||||
fs::remove_file(self.path().join(path)).unwrap();
|
fs::remove_file(self.target_path().join(path)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_dir_all(&self, path: impl AsRef<Path>) {
|
pub fn remove_dir_all(&self, path: impl AsRef<Path>) {
|
||||||
fs::remove_dir_all(self.path().join(path)).unwrap();
|
fs::remove_dir_all(self.target_path().join(path)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_to_string(&self, path: impl AsRef<Path>) -> String {
|
pub fn read_to_string(&self, path: impl AsRef<Path>) -> String {
|
||||||
let file_path = self.path().join(path);
|
let file_path = self.target_path().join(path);
|
||||||
fs::read_to_string(&file_path)
|
fs::read_to_string(&file_path)
|
||||||
.with_context(|| format!("Could not find file: {}", file_path.display()))
|
.with_context(|| format!("Could not find file: {}", file_path.display()))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rename(&self, from: impl AsRef<Path>, to: impl AsRef<Path>) {
|
pub fn rename(&self, from: impl AsRef<Path>, to: impl AsRef<Path>) {
|
||||||
fs::rename(self.path().join(from), self.path().join(to)).unwrap();
|
fs::rename(self.target_path().join(from), self.path().join(to)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(&self, path: impl AsRef<Path>, text: impl AsRef<str>) {
|
pub fn write(&self, path: impl AsRef<Path>, text: impl AsRef<str>) {
|
||||||
fs::write(self.path().join(path), text.as_ref()).unwrap();
|
fs::write(self.target_path().join(path), text.as_ref()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn symlink_dir(
|
pub fn symlink_dir(
|
||||||
|
|
Loading…
Reference in a new issue