Files
uv/crates/uv/tests/cache_prune.rs
T
konsti e6103dcab1 Deduplicate test command creation (#4512)
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.
2024-06-25 22:06:54 +00:00

131 lines
3.4 KiB
Rust

#![cfg(all(feature = "python", feature = "pypi"))]
use std::process::Command;
use anyhow::Result;
use assert_cmd::prelude::*;
use assert_fs::prelude::*;
use common::uv_snapshot;
use crate::common::{get_bin, TestContext};
mod common;
/// Create a `cache prune` command with options shared across scenarios.
fn prune_command(context: &TestContext) -> Command {
let mut command = Command::new(get_bin());
command.arg("cache").arg("prune");
context.add_shared_args(&mut command);
command
}
/// `cache prune` should be a no-op if there's nothing out-of-date in the cache.
#[test]
fn prune_no_op() -> Result<()> {
let context = TestContext::new("3.12");
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("anyio")?;
// Install a requirement, to populate the cache.
context
.pip_sync()
.arg("requirements.txt")
.assert()
.success();
uv_snapshot!(context.filters(), prune_command(&context).arg("--verbose"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
DEBUG uv [VERSION] ([COMMIT] DATE)
Pruning cache at: [CACHE_DIR]/
No unused entries found
"###);
Ok(())
}
/// `cache prune` should remove any stale top-level directories from the cache.
#[test]
fn prune_stale_directory() -> Result<()> {
let context = TestContext::new("3.12");
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("anyio")?;
// Install a requirement, to populate the cache.
context
.pip_sync()
.arg("requirements.txt")
.assert()
.success();
// Add a stale directory to the cache.
let simple = context.cache_dir.child("simple-v4");
simple.create_dir_all()?;
uv_snapshot!(context.filters(), prune_command(&context).arg("--verbose"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
DEBUG uv [VERSION] ([COMMIT] DATE)
Pruning cache at: [CACHE_DIR]/
DEBUG Removing dangling cache entry: [CACHE_DIR]/simple-v4
Removed 1 directory
"###);
Ok(())
}
/// `cache prune` should remove any stale symlink from the cache.
#[test]
fn prune_stale_symlink() -> Result<()> {
let context = TestContext::new("3.12");
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("anyio")?;
// Install a requirement, to populate the cache.
context
.pip_sync()
.arg("requirements.txt")
.assert()
.success();
// Remove the wheels directory, causing the symlink to become stale.
let wheels = context.cache_dir.child("wheels-v1");
fs_err::remove_dir_all(wheels)?;
let filters: Vec<_> = context
.filters()
.into_iter()
.chain([
// The cache entry does not have a stable key, so we filter it out
(
r"\[CACHE_DIR\](\\|\/)(.+)(\\|\/).*",
"[CACHE_DIR]/$2/[ENTRY]",
),
])
.collect();
uv_snapshot!(filters, prune_command(&context).arg("--verbose"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
DEBUG uv [VERSION] ([COMMIT] DATE)
Pruning cache at: [CACHE_DIR]/
DEBUG Removing dangling cache entry: [CACHE_DIR]/archive-v0/[ENTRY]
Removed 44 files ([SIZE])
"###);
Ok(())
}