use anyhow::Result;
use assert_cmd::prelude::*;
use assert_fs::prelude::*;
use uv_cache::Cache;
use uv_static::EnvVars;
use uv_test::uv_snapshot;
#[test]
fn clean_all() -> Result<()> {
let context = uv_test::test_context!("3.12");
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("typing-extensions\niniconfig")?;
context
.pip_sync()
.arg("requirements.txt")
.assert()
.success();
uv_snapshot!(context.with_filtered_counts().filters(), context.clean().arg("--verbose"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
DEBUG Searching for user configuration in: `[UV_USER_CONFIG_DIR]/uv.toml`
DEBUG uv [VERSION] ([COMMIT] DATE)
Clearing cache at: [CACHE_DIR]/
Removed [N] files ([SIZE])
");
Ok(())
}
#[test]
fn clear_all_alias() -> Result<()> {
let context = uv_test::test_context!("3.12");
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("typing-extensions\niniconfig")?;
context
.pip_sync()
.arg("requirements.txt")
.assert()
.success();
let mut command = context.command();
command.arg("cache").arg("clear").arg("--verbose");
uv_snapshot!(context.with_filtered_counts().filters(), command, @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
DEBUG Searching for user configuration in: `[UV_USER_CONFIG_DIR]/uv.toml`
DEBUG uv [VERSION] ([COMMIT] DATE)
Clearing cache at: [CACHE_DIR]/
Removed [N] files ([SIZE])
");
Ok(())
}
#[tokio::test]
async fn clean_force() -> Result<()> {
let context = uv_test::test_context!("3.12").with_filtered_counts();
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("typing-extensions\niniconfig")?;
context
.pip_sync()
.arg("requirements.txt")
.assert()
.success();
uv_snapshot!(context.filters(), context.clean().arg("--verbose").arg("--force"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
DEBUG Searching for user configuration in: `[UV_USER_CONFIG_DIR]/uv.toml`
DEBUG uv [VERSION] ([COMMIT] DATE)
Clearing cache at: [CACHE_DIR]/
Removed [N] files ([SIZE])
");
context
.pip_sync()
.arg("requirements.txt")
.assert()
.success();
let _cache = uv_cache::Cache::from_path(context.cache_dir.path())
.with_exclusive_lock()
.await;
uv_snapshot!(context.filters(), context.clean().arg("--verbose").arg("--force"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
DEBUG Searching for user configuration in: `[UV_USER_CONFIG_DIR]/uv.toml`
DEBUG uv [VERSION] ([COMMIT] DATE)
DEBUG Lock is busy for `[CACHE_DIR]/`
DEBUG Cache is currently in use, proceeding due to `--force`
Clearing cache at: [CACHE_DIR]/
Removed [N] files ([SIZE])
");
Ok(())
}
#[test]
fn clean_package_pypi() -> Result<()> {
let context = uv_test::test_context!("3.12");
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("anyio\niniconfig")?;
context
.pip_sync()
.arg("requirements.txt")
.assert()
.success();
let rkyv = context
.cache_dir
.child("simple-v21")
.child("pypi")
.child("iniconfig.rkyv");
assert!(
rkyv.exists(),
"Expected the `.rkyv` file to exist for `iniconfig`"
);
let filters: Vec<_> = context
.filters()
.into_iter()
.chain([
(
r"\[CACHE_DIR\](\\|\/)(.+)(\\|\/).*",
"[CACHE_DIR]/$2/[ENTRY]",
),
("Removed \\d+ files?", "Removed [N] files"),
])
.collect();
uv_snapshot!(&filters, context.clean().arg("--verbose").arg("iniconfig"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
DEBUG Searching for user configuration in: `[UV_USER_CONFIG_DIR]/uv.toml`
DEBUG uv [VERSION] ([COMMIT] DATE)
DEBUG Removing dangling cache entry: [CACHE_DIR]/archive-v0/[ENTRY]
Removed [N] files ([SIZE])
");
assert!(
!rkyv.exists(),
"Expected the `.rkyv` file to be removed for `iniconfig`"
);
uv_snapshot!(&filters, context.prune().arg("--verbose"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
DEBUG Searching for user configuration in: `[UV_USER_CONFIG_DIR]/uv.toml`
DEBUG uv [VERSION] ([COMMIT] DATE)
Pruning cache at: [CACHE_DIR]/
No unused entries found
");
Ok(())
}
#[test]
fn clean_package_index() -> Result<()> {
let context = uv_test::test_context!("3.12");
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("anyio\niniconfig")?;
context
.pip_sync()
.arg("requirements.txt")
.arg("--index-url")
.arg("https://test.pypi.org/simple")
.assert()
.success();
let rkyv = context
.cache_dir
.child("simple-v21")
.child("index")
.child("e8208120cae3ba69")
.child("iniconfig.rkyv");
assert!(
rkyv.exists(),
"Expected the `.rkyv` file to exist for `iniconfig`"
);
let filters: Vec<_> = context
.filters()
.into_iter()
.chain([
(
r"\[CACHE_DIR\](\\|\/)(.+)(\\|\/).*",
"[CACHE_DIR]/$2/[ENTRY]",
),
("Removed \\d+ files?", "Removed [N] files"),
])
.collect();
uv_snapshot!(&filters, context.clean().arg("--verbose").arg("iniconfig"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
DEBUG Searching for user configuration in: `[UV_USER_CONFIG_DIR]/uv.toml`
DEBUG uv [VERSION] ([COMMIT] DATE)
DEBUG Removing dangling cache entry: [CACHE_DIR]/archive-v0/[ENTRY]
Removed [N] files ([SIZE])
");
assert!(
!rkyv.exists(),
"Expected the `.rkyv` file to be removed for `iniconfig`"
);
Ok(())
}
#[tokio::test]
async fn cache_timeout() {
let context = uv_test::test_context!("3.12");
let _cache = Cache::from_path(context.cache_dir.path())
.with_exclusive_lock()
.await;
uv_snapshot!(context.filters(), context.clean().env(EnvVars::UV_LOCK_TIMEOUT, "1"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
Cache is currently in-use, waiting for other uv processes to finish (use `--force` to override)
error: Timeout ([TIME]) when waiting for lock on `[CACHE_DIR]/` at `[CACHE_DIR]/.lock`, is another uv process running? You can set `UV_LOCK_TIMEOUT` to increase the timeout.
");
}
#[cfg(windows)]
#[test]
fn clean_handles_verbatim_paths() -> Result<()> {
let context = uv_test::test_context!("3.12");
fs_err::remove_dir_all(&context.cache_dir)?;
let uwsgi_shard = context
.cache_dir
.child("sdists-v9")
.child("pypi")
.child("uwsgi")
.child("2.0.31")
.child("QxDIp0qpjbsWjWURKmegK")
.child("src")
.child("core");
uwsgi_shard.create_dir_all()?;
let invalid_path = uwsgi_shard.child("logging.").to_path_buf();
let invalid_file = uv_fs::verbatim_path(invalid_path.as_path());
fs_err::write(&invalid_file, b"")?;
let remove_err = fs_err::remove_file(&invalid_path).expect_err("expected to fail");
assert_eq!(remove_err.kind(), std::io::ErrorKind::NotFound);
uv_snapshot!(context.filters(), context.clean().arg("--verbose"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
DEBUG Searching for user configuration in: `[UV_USER_CONFIG_DIR]/uv.toml`
DEBUG uv [VERSION] ([COMMIT] DATE)
Clearing cache at: [CACHE_DIR]/
Removed 2 files
");
Ok(())
}