mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-04 19:08:04 +00:00

This PR refactors the command creation in the test suite to remove the duplication. **1)** We add the same set of test stubbing args to almost any uv invocation in the tests: ```rust command .arg("--cache-dir") .arg(self.cache_dir.path()) .env("VIRTUAL_ENV", self.venv.as_os_str()) .env("UV_NO_WRAP", "1") .env("HOME", self.home_dir.as_os_str()) .env("UV_TOOLCHAIN_DIR", "") .env("UV_TEST_PYTHON_PATH", &self.python_path()) .current_dir(self.temp_dir.path()); if cfg!(all(windows, debug_assertions)) { // TODO(konstin): Reduce stack usage in debug mode enough that the tests pass with the // default windows stack of 1MB command.env("UV_STACK_SIZE", (8 * 1024 * 1024).to_string()); } ``` Centralizing these into a `TestContext::add_shared_args` method removes them from everywhere. **2)** Prefix all `TextContext` methods of the pip interface with `pip_`. This is now necessary due to `uv sync` vs. `uv pip sync`. **3)** Move command creation in the various test files into dedicated functions or methods to avoid repeating the arguments. Except for error message tests, there should be at most one `Command::new(get_bin())` call per test file. `EXCLUDE_NEWER` is exclusively used in `TestContext`. --- I'm considering adding a `TestCommand` on top of these changes (in another PR) that holds a reference to the `TextContext`, has `add_shared_args` as a method and uses `Fn(Self) -> Self` instead of `Fn(&mut Self) -> Self` for methods to improved chaining.
510 lines
14 KiB
Rust
510 lines
14 KiB
Rust
use std::env;
|
|
use std::path::{Path, PathBuf};
|
|
use std::process::Command;
|
|
|
|
use anyhow::Result;
|
|
use assert_cmd::assert::OutputAssertExt;
|
|
|
|
use crate::common::{copy_dir_ignore, uv_snapshot, TestContext};
|
|
|
|
mod common;
|
|
|
|
/// `pip install --preview -e <current dir>`
|
|
fn install_workspace(context: &TestContext, current_dir: &Path) -> Command {
|
|
let mut command = context.pip_install();
|
|
command.arg("--preview").arg("-e").arg(current_dir);
|
|
command
|
|
}
|
|
|
|
fn workspaces_dir() -> PathBuf {
|
|
env::current_dir()
|
|
.unwrap()
|
|
.parent()
|
|
.unwrap()
|
|
.parent()
|
|
.unwrap()
|
|
.join("scripts")
|
|
.join("workspaces")
|
|
}
|
|
|
|
#[test]
|
|
fn test_albatross_in_examples_bird_feeder() {
|
|
let context = TestContext::new("3.12");
|
|
let current_dir = workspaces_dir()
|
|
.join("albatross-in-example")
|
|
.join("examples")
|
|
.join("bird-feeder");
|
|
|
|
uv_snapshot!(context.filters(), install_workspace(&context, ¤t_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Resolved 4 packages in [TIME]
|
|
Prepared 4 packages in [TIME]
|
|
Installed 4 packages in [TIME]
|
|
+ anyio==4.3.0
|
|
+ bird-feeder==1.0.0 (from file://[WORKSPACE]/scripts/workspaces/albatross-in-example/examples/bird-feeder)
|
|
+ idna==3.6
|
|
+ sniffio==1.3.1
|
|
"###
|
|
);
|
|
|
|
context.assert_file(current_dir.join("check_installed_bird_feeder.py"));
|
|
uv_snapshot!(context.filters(), install_workspace(&context, ¤t_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Audited 1 package in [TIME]
|
|
"###
|
|
);
|
|
|
|
context.assert_file(current_dir.join("check_installed_bird_feeder.py"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_albatross_in_examples() {
|
|
let context = TestContext::new("3.12");
|
|
let current_dir = workspaces_dir().join("albatross-in-example");
|
|
|
|
uv_snapshot!(context.filters(), install_workspace(&context, ¤t_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Resolved 2 packages in [TIME]
|
|
Prepared 2 packages in [TIME]
|
|
Installed 2 packages in [TIME]
|
|
+ albatross==0.1.0 (from file://[WORKSPACE]/scripts/workspaces/albatross-in-example)
|
|
+ tqdm==4.66.2
|
|
"###
|
|
);
|
|
|
|
context.assert_file(current_dir.join("check_installed_albatross.py"));
|
|
uv_snapshot!(context.filters(), install_workspace(&context, ¤t_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Audited 1 package in [TIME]
|
|
"###
|
|
);
|
|
|
|
context.assert_file(current_dir.join("check_installed_albatross.py"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_albatross_just_project() {
|
|
let context = TestContext::new("3.12");
|
|
let current_dir = workspaces_dir().join("albatross-just-project");
|
|
|
|
uv_snapshot!(context.filters(), install_workspace(&context, ¤t_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Resolved 2 packages in [TIME]
|
|
Prepared 2 packages in [TIME]
|
|
Installed 2 packages in [TIME]
|
|
+ albatross==0.1.0 (from file://[WORKSPACE]/scripts/workspaces/albatross-just-project)
|
|
+ tqdm==4.66.2
|
|
"###
|
|
);
|
|
|
|
context.assert_file(current_dir.join("check_installed_albatross.py"));
|
|
uv_snapshot!(context.filters(), install_workspace(&context, ¤t_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Audited 1 package in [TIME]
|
|
"###
|
|
);
|
|
|
|
context.assert_file(current_dir.join("check_installed_albatross.py"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_albatross_project_in_excluded() {
|
|
let context = TestContext::new("3.12");
|
|
let current_dir = workspaces_dir()
|
|
.join("albatross-project-in-excluded")
|
|
.join("excluded")
|
|
.join("bird-feeder");
|
|
|
|
uv_snapshot!(context.filters(), install_workspace(&context, ¤t_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Resolved 4 packages in [TIME]
|
|
Prepared 4 packages in [TIME]
|
|
Installed 4 packages in [TIME]
|
|
+ anyio==4.3.0
|
|
+ bird-feeder==1.0.0 (from file://[WORKSPACE]/scripts/workspaces/albatross-project-in-excluded/excluded/bird-feeder)
|
|
+ idna==3.6
|
|
+ sniffio==1.3.1
|
|
"###
|
|
);
|
|
|
|
context.assert_file(current_dir.join("check_installed_bird_feeder.py"));
|
|
uv_snapshot!(context.filters(), install_workspace(&context, ¤t_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Audited 1 package in [TIME]
|
|
"###
|
|
);
|
|
|
|
context.assert_file(current_dir.join("check_installed_bird_feeder.py"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_albatross_root_workspace() {
|
|
let context = TestContext::new("3.12");
|
|
let current_dir = workspaces_dir().join("albatross-root-workspace");
|
|
|
|
uv_snapshot!(context.filters(), install_workspace(&context, ¤t_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Resolved 7 packages in [TIME]
|
|
Prepared 7 packages in [TIME]
|
|
Installed 7 packages in [TIME]
|
|
+ albatross==0.1.0 (from file://[WORKSPACE]/scripts/workspaces/albatross-root-workspace)
|
|
+ anyio==4.3.0
|
|
+ bird-feeder==1.0.0 (from file://[WORKSPACE]/scripts/workspaces/albatross-root-workspace/packages/bird-feeder)
|
|
+ idna==3.6
|
|
+ seeds==1.0.0 (from file://[WORKSPACE]/scripts/workspaces/albatross-root-workspace/packages/seeds)
|
|
+ sniffio==1.3.1
|
|
+ tqdm==4.66.2
|
|
"###
|
|
);
|
|
|
|
context.assert_file(current_dir.join("check_installed_albatross.py"));
|
|
uv_snapshot!(context.filters(), install_workspace(&context, ¤t_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Audited 1 package in [TIME]
|
|
"###
|
|
);
|
|
|
|
context.assert_file(current_dir.join("check_installed_albatross.py"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_albatross_root_workspace_bird_feeder() {
|
|
let context = TestContext::new("3.12");
|
|
let current_dir = workspaces_dir()
|
|
.join("albatross-root-workspace")
|
|
.join("packages")
|
|
.join("bird-feeder");
|
|
|
|
uv_snapshot!(context.filters(), install_workspace(&context, ¤t_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Resolved 5 packages in [TIME]
|
|
Prepared 5 packages in [TIME]
|
|
Installed 5 packages in [TIME]
|
|
+ anyio==4.3.0
|
|
+ bird-feeder==1.0.0 (from file://[WORKSPACE]/scripts/workspaces/albatross-root-workspace/packages/bird-feeder)
|
|
+ idna==3.6
|
|
+ seeds==1.0.0 (from file://[WORKSPACE]/scripts/workspaces/albatross-root-workspace/packages/seeds)
|
|
+ sniffio==1.3.1
|
|
"###
|
|
);
|
|
|
|
context.assert_file(current_dir.join("check_installed_bird_feeder.py"));
|
|
uv_snapshot!(context.filters(), install_workspace(&context, ¤t_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Audited 1 package in [TIME]
|
|
"###
|
|
);
|
|
|
|
context.assert_file(current_dir.join("check_installed_bird_feeder.py"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_albatross_root_workspace_albatross() {
|
|
let context = TestContext::new("3.12");
|
|
let current_dir = workspaces_dir()
|
|
.join("albatross-root-workspace")
|
|
.join("packages")
|
|
.join("bird-feeder");
|
|
|
|
uv_snapshot!(context.filters(), install_workspace(&context, ¤t_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Resolved 5 packages in [TIME]
|
|
Prepared 5 packages in [TIME]
|
|
Installed 5 packages in [TIME]
|
|
+ anyio==4.3.0
|
|
+ bird-feeder==1.0.0 (from file://[WORKSPACE]/scripts/workspaces/albatross-root-workspace/packages/bird-feeder)
|
|
+ idna==3.6
|
|
+ seeds==1.0.0 (from file://[WORKSPACE]/scripts/workspaces/albatross-root-workspace/packages/seeds)
|
|
+ sniffio==1.3.1
|
|
"###
|
|
);
|
|
|
|
context.assert_file(current_dir.join("check_installed_albatross.py"));
|
|
uv_snapshot!(context.filters(), install_workspace(&context, ¤t_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Audited 1 package in [TIME]
|
|
"###
|
|
);
|
|
|
|
context.assert_file(current_dir.join("check_installed_albatross.py"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_albatross_virtual_workspace() {
|
|
let context = TestContext::new("3.12");
|
|
let current_dir = workspaces_dir()
|
|
.join("albatross-virtual-workspace")
|
|
.join("packages")
|
|
.join("bird-feeder");
|
|
|
|
uv_snapshot!(context.filters(), install_workspace(&context, ¤t_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Resolved 5 packages in [TIME]
|
|
Prepared 5 packages in [TIME]
|
|
Installed 5 packages in [TIME]
|
|
+ anyio==4.3.0
|
|
+ bird-feeder==1.0.0 (from file://[WORKSPACE]/scripts/workspaces/albatross-virtual-workspace/packages/bird-feeder)
|
|
+ idna==3.6
|
|
+ seeds==1.0.0 (from file://[WORKSPACE]/scripts/workspaces/albatross-virtual-workspace/packages/seeds)
|
|
+ sniffio==1.3.1
|
|
"###
|
|
);
|
|
|
|
context.assert_file(current_dir.join("check_installed_bird_feeder.py"));
|
|
uv_snapshot!(context.filters(), install_workspace(&context, ¤t_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Audited 1 package in [TIME]
|
|
"###
|
|
);
|
|
|
|
context.assert_file(current_dir.join("check_installed_bird_feeder.py"));
|
|
}
|
|
|
|
/// Check that `uv run --package` works in a virtual workspace.
|
|
#[test]
|
|
fn test_uv_run_with_package_virtual_workspace() -> Result<()> {
|
|
let context = TestContext::new("3.12");
|
|
let work_dir = context.temp_dir.join("albatross-virtual-workspace");
|
|
|
|
copy_dir_ignore(
|
|
workspaces_dir().join("albatross-virtual-workspace"),
|
|
&work_dir,
|
|
)?;
|
|
|
|
let mut filters = context.filters();
|
|
filters.push((
|
|
r"Using Python 3.12.\[X\] interpreter at: .*",
|
|
"Using Python 3.12.[X] interpreter at: [PYTHON]",
|
|
));
|
|
|
|
uv_snapshot!(filters, context
|
|
.run()
|
|
.arg("--preview")
|
|
.arg("--package")
|
|
.arg("bird-feeder")
|
|
.arg("packages/bird-feeder/check_installed_bird_feeder.py")
|
|
.current_dir(&work_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
Success
|
|
|
|
----- stderr -----
|
|
Using Python 3.12.[X] interpreter at: [PYTHON]
|
|
Creating virtualenv at: .venv
|
|
Resolved 8 packages in [TIME]
|
|
Prepared 5 packages in [TIME]
|
|
Installed 5 packages in [TIME]
|
|
+ anyio==4.3.0
|
|
+ bird-feeder==1.0.0 (from file://[TEMP_DIR]/albatross-virtual-workspace/packages/bird-feeder)
|
|
+ idna==3.6
|
|
+ seeds==1.0.0 (from file://[TEMP_DIR]/albatross-virtual-workspace/packages/seeds)
|
|
+ sniffio==1.3.1
|
|
"###
|
|
);
|
|
|
|
uv_snapshot!(context.filters(), universal_windows_filters=true, context
|
|
.run()
|
|
.arg("--preview")
|
|
.arg("--package")
|
|
.arg("albatross")
|
|
.arg("packages/albatross/check_installed_albatross.py")
|
|
.current_dir(&work_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
Success
|
|
|
|
----- stderr -----
|
|
Resolved 8 packages in [TIME]
|
|
Prepared 2 packages in [TIME]
|
|
Installed 2 packages in [TIME]
|
|
+ albatross==0.1.0 (from file://[TEMP_DIR]/albatross-virtual-workspace/packages/albatross)
|
|
+ tqdm==4.66.2
|
|
"###
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Check that `uv run --package` works in a root workspace.
|
|
#[test]
|
|
fn test_uv_run_with_package_root_workspace() -> Result<()> {
|
|
let context = TestContext::new("3.12");
|
|
let work_dir = context.temp_dir.join("albatross-root-workspace");
|
|
|
|
copy_dir_ignore(workspaces_dir().join("albatross-root-workspace"), &work_dir)?;
|
|
|
|
let mut filters = context.filters();
|
|
filters.push((
|
|
r"Using Python 3.12.\[X\] interpreter at: .*",
|
|
"Using Python 3.12.[X] interpreter at: [PYTHON]",
|
|
));
|
|
|
|
uv_snapshot!(filters, context
|
|
.run()
|
|
.arg("--preview")
|
|
.arg("--package")
|
|
.arg("bird-feeder")
|
|
.arg("packages/bird-feeder/check_installed_bird_feeder.py")
|
|
.current_dir(&work_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
Success
|
|
|
|
----- stderr -----
|
|
Using Python 3.12.[X] interpreter at: [PYTHON]
|
|
Creating virtualenv at: .venv
|
|
Resolved 8 packages in [TIME]
|
|
Prepared 5 packages in [TIME]
|
|
Installed 5 packages in [TIME]
|
|
+ anyio==4.3.0
|
|
+ bird-feeder==1.0.0 (from file://[TEMP_DIR]/albatross-root-workspace/packages/bird-feeder)
|
|
+ idna==3.6
|
|
+ seeds==1.0.0 (from file://[TEMP_DIR]/albatross-root-workspace/packages/seeds)
|
|
+ sniffio==1.3.1
|
|
"###
|
|
);
|
|
|
|
uv_snapshot!(context.filters(), universal_windows_filters=true, context
|
|
.run()
|
|
.arg("--preview")
|
|
.arg("--package")
|
|
.arg("albatross")
|
|
.arg("check_installed_albatross.py")
|
|
.current_dir(&work_dir), @r###"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
Success
|
|
|
|
----- stderr -----
|
|
Resolved 8 packages in [TIME]
|
|
Prepared 2 packages in [TIME]
|
|
Installed 2 packages in [TIME]
|
|
+ albatross==0.1.0 (from file://[TEMP_DIR]/albatross-root-workspace)
|
|
+ tqdm==4.66.2
|
|
"###
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Check that the resolution is the same no matter where in the workspace we are.
|
|
fn workspace_lock_idempotence(workspace: &str, subdirectories: &[&str]) -> Result<()> {
|
|
let mut shared_lock = None;
|
|
|
|
for dir in subdirectories {
|
|
let context = TestContext::new("3.12");
|
|
let work_dir = context.temp_dir.join(workspace);
|
|
|
|
copy_dir_ignore(workspaces_dir().join(workspace), &work_dir)?;
|
|
|
|
context
|
|
.lock()
|
|
.arg("--preview")
|
|
.current_dir(&work_dir.join(dir))
|
|
.assert()
|
|
.success();
|
|
|
|
let lock = fs_err::read_to_string(work_dir.join("uv.lock"))?;
|
|
// Check the lockfile is the same for all resolutions.
|
|
if let Some(shared_lock) = &shared_lock {
|
|
assert_eq!(shared_lock, &lock);
|
|
} else {
|
|
shared_lock = Some(lock);
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Check that the resolution is the same no matter where in the workspace we are.
|
|
#[test]
|
|
fn workspace_lock_idempotence_root_workspace() -> Result<()> {
|
|
workspace_lock_idempotence(
|
|
"albatross-root-workspace",
|
|
&[".", "packages/bird-feeder", "packages/seeds"],
|
|
)?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Check that the resolution is the same no matter where in the workspace we are, and that locking
|
|
/// works even if there is no root project.
|
|
#[test]
|
|
fn workspace_lock_idempotence_virtual_workspace() -> Result<()> {
|
|
workspace_lock_idempotence(
|
|
"albatross-virtual-workspace",
|
|
&[
|
|
".",
|
|
"packages/albatross",
|
|
"packages/bird-feeder",
|
|
"packages/seeds",
|
|
],
|
|
)?;
|
|
Ok(())
|
|
}
|