This commit moves all of the caching support that currently lives in `wasmtime-environ` into a `wasmtime-cache` crate and makes it optional. The goal here is to slim down the `wasmtime-environ` crate and clearly separate boundaries where caching is a standalone and optional feature, not intertwined with other crates.
526 lines
14 KiB
Rust
526 lines
14 KiB
Rust
use super::CacheConfig;
|
|
use std::fs;
|
|
use std::path::PathBuf;
|
|
use std::time::Duration;
|
|
use tempfile::{self, TempDir};
|
|
|
|
// note: config loading during validation creates cache directory to canonicalize its path,
|
|
// that's why these function and macro always use custom cache directory
|
|
// note: tempdir removes directory when being dropped, so we need to return it to the caller,
|
|
// so the paths are valid
|
|
pub fn test_prolog() -> (TempDir, PathBuf, PathBuf) {
|
|
let _ = pretty_env_logger::try_init();
|
|
let temp_dir = tempfile::tempdir().expect("Can't create temporary directory");
|
|
let cache_dir = temp_dir.path().join("cache-dir");
|
|
let config_path = temp_dir.path().join("cache-config.toml");
|
|
(temp_dir, cache_dir, config_path)
|
|
}
|
|
|
|
macro_rules! load_config {
|
|
($config_path:ident, $content_fmt:expr, $cache_dir:ident) => {{
|
|
let config_path = &$config_path;
|
|
let content = format!(
|
|
$content_fmt,
|
|
cache_dir = toml::to_string_pretty(&format!("{}", $cache_dir.display())).unwrap()
|
|
);
|
|
fs::write(config_path, content).expect("Failed to write test config file");
|
|
CacheConfig::from_file(Some(config_path)).unwrap()
|
|
}};
|
|
}
|
|
|
|
macro_rules! bad_config {
|
|
($config_path:ident, $content_fmt:expr, $cache_dir:ident) => {{
|
|
let config_path = &$config_path;
|
|
let content = format!(
|
|
$content_fmt,
|
|
cache_dir = toml::to_string_pretty(&format!("{}", $cache_dir.display())).unwrap()
|
|
);
|
|
fs::write(config_path, content).expect("Failed to write test config file");
|
|
assert!(CacheConfig::from_file(Some(config_path)).is_err());
|
|
}};
|
|
}
|
|
|
|
// test without macros to test being disabled
|
|
#[test]
|
|
fn test_disabled() {
|
|
let dir = tempfile::tempdir().expect("Can't create temporary directory");
|
|
let config_path = dir.path().join("cache-config.toml");
|
|
let config_content = "[cache]\n\
|
|
enabled = false\n";
|
|
fs::write(&config_path, config_content).expect("Failed to write test config file");
|
|
let conf = CacheConfig::from_file(Some(&config_path)).unwrap();
|
|
assert!(!conf.enabled());
|
|
}
|
|
|
|
#[test]
|
|
fn test_unrecognized_settings() {
|
|
let (_td, cd, cp) = test_prolog();
|
|
bad_config!(
|
|
cp,
|
|
"unrecognized-setting = 42\n\
|
|
[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}",
|
|
cd
|
|
);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
unrecognized-setting = 42",
|
|
cd
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_all_settings() {
|
|
let (_td, cd, cp) = test_prolog();
|
|
let conf = load_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
worker-event-queue-size = '16'\n\
|
|
baseline-compression-level = 3\n\
|
|
optimized-compression-level = 20\n\
|
|
optimized-compression-usage-counter-threshold = '256'\n\
|
|
cleanup-interval = '1h'\n\
|
|
optimizing-compression-task-timeout = '30m'\n\
|
|
allowed-clock-drift-for-files-from-future = '1d'\n\
|
|
file-count-soft-limit = '65536'\n\
|
|
files-total-size-soft-limit = '512Mi'\n\
|
|
file-count-limit-percent-if-deleting = '70%'\n\
|
|
files-total-size-limit-percent-if-deleting = '70%'",
|
|
cd
|
|
);
|
|
check_conf(&conf, &cd);
|
|
|
|
let conf = load_config!(
|
|
cp,
|
|
// added some white spaces
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
worker-event-queue-size = ' 16\t'\n\
|
|
baseline-compression-level = 3\n\
|
|
optimized-compression-level =\t 20\n\
|
|
optimized-compression-usage-counter-threshold = '256'\n\
|
|
cleanup-interval = ' 1h'\n\
|
|
optimizing-compression-task-timeout = '30 m'\n\
|
|
allowed-clock-drift-for-files-from-future = '1\td'\n\
|
|
file-count-soft-limit = '\t \t65536\t'\n\
|
|
files-total-size-soft-limit = '512\t\t Mi '\n\
|
|
file-count-limit-percent-if-deleting = '70\t%'\n\
|
|
files-total-size-limit-percent-if-deleting = ' 70 %'",
|
|
cd
|
|
);
|
|
check_conf(&conf, &cd);
|
|
|
|
fn check_conf(conf: &CacheConfig, cd: &PathBuf) {
|
|
assert!(conf.enabled());
|
|
assert_eq!(
|
|
conf.directory(),
|
|
&fs::canonicalize(cd).expect("canonicalize failed")
|
|
);
|
|
assert_eq!(conf.worker_event_queue_size(), 0x10);
|
|
assert_eq!(conf.baseline_compression_level(), 3);
|
|
assert_eq!(conf.optimized_compression_level(), 20);
|
|
assert_eq!(conf.optimized_compression_usage_counter_threshold(), 0x100);
|
|
assert_eq!(conf.cleanup_interval(), Duration::from_secs(60 * 60));
|
|
assert_eq!(
|
|
conf.optimizing_compression_task_timeout(),
|
|
Duration::from_secs(30 * 60)
|
|
);
|
|
assert_eq!(
|
|
conf.allowed_clock_drift_for_files_from_future(),
|
|
Duration::from_secs(60 * 60 * 24)
|
|
);
|
|
assert_eq!(conf.file_count_soft_limit(), 0x10_000);
|
|
assert_eq!(conf.files_total_size_soft_limit(), 512 * (1u64 << 20));
|
|
assert_eq!(conf.file_count_limit_percent_if_deleting(), 70);
|
|
assert_eq!(conf.files_total_size_limit_percent_if_deleting(), 70);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_compression_level_settings() {
|
|
let (_td, cd, cp) = test_prolog();
|
|
let conf = load_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
baseline-compression-level = 1\n\
|
|
optimized-compression-level = 21",
|
|
cd
|
|
);
|
|
assert!(conf.enabled());
|
|
assert_eq!(conf.baseline_compression_level(), 1);
|
|
assert_eq!(conf.optimized_compression_level(), 21);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
baseline-compression-level = -1\n\
|
|
optimized-compression-level = 21",
|
|
cd
|
|
);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
baseline-compression-level = 15\n\
|
|
optimized-compression-level = 10",
|
|
cd
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_si_prefix_settings() {
|
|
let (_td, cd, cp) = test_prolog();
|
|
let conf = load_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
worker-event-queue-size = '42'\n\
|
|
optimized-compression-usage-counter-threshold = '4K'\n\
|
|
file-count-soft-limit = '3M'",
|
|
cd
|
|
);
|
|
assert!(conf.enabled());
|
|
assert_eq!(conf.worker_event_queue_size(), 42);
|
|
assert_eq!(conf.optimized_compression_usage_counter_threshold(), 4_000);
|
|
assert_eq!(conf.file_count_soft_limit(), 3_000_000);
|
|
|
|
let conf = load_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
worker-event-queue-size = '2K'\n\
|
|
optimized-compression-usage-counter-threshold = '4444T'\n\
|
|
file-count-soft-limit = '1P'",
|
|
cd
|
|
);
|
|
assert!(conf.enabled());
|
|
assert_eq!(conf.worker_event_queue_size(), 2_000);
|
|
assert_eq!(
|
|
conf.optimized_compression_usage_counter_threshold(),
|
|
4_444_000_000_000_000
|
|
);
|
|
assert_eq!(conf.file_count_soft_limit(), 1_000_000_000_000_000);
|
|
|
|
// different errors
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
worker-event-queue-size = '2g'",
|
|
cd
|
|
);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
file-count-soft-limit = 1",
|
|
cd
|
|
);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
file-count-soft-limit = '-31337'",
|
|
cd
|
|
);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
file-count-soft-limit = '3.14M'",
|
|
cd
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_disk_space_settings() {
|
|
let (_td, cd, cp) = test_prolog();
|
|
let conf = load_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
files-total-size-soft-limit = '76'",
|
|
cd
|
|
);
|
|
assert!(conf.enabled());
|
|
assert_eq!(conf.files_total_size_soft_limit(), 76);
|
|
|
|
let conf = load_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
files-total-size-soft-limit = '42 Mi'",
|
|
cd
|
|
);
|
|
assert!(conf.enabled());
|
|
assert_eq!(conf.files_total_size_soft_limit(), 42 * (1u64 << 20));
|
|
|
|
let conf = load_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
files-total-size-soft-limit = '2 Gi'",
|
|
cd
|
|
);
|
|
assert!(conf.enabled());
|
|
assert_eq!(conf.files_total_size_soft_limit(), 2 * (1u64 << 30));
|
|
|
|
let conf = load_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
files-total-size-soft-limit = '31337 Ti'",
|
|
cd
|
|
);
|
|
assert!(conf.enabled());
|
|
assert_eq!(conf.files_total_size_soft_limit(), 31337 * (1u64 << 40));
|
|
|
|
let conf = load_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
files-total-size-soft-limit = '7 Pi'",
|
|
cd
|
|
);
|
|
assert!(conf.enabled());
|
|
assert_eq!(conf.files_total_size_soft_limit(), 7 * (1u64 << 50));
|
|
|
|
let conf = load_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
files-total-size-soft-limit = '7M'",
|
|
cd
|
|
);
|
|
assert!(conf.enabled());
|
|
assert_eq!(conf.files_total_size_soft_limit(), 7_000_000);
|
|
|
|
// different errors
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
files-total-size-soft-limit = '7 mi'",
|
|
cd
|
|
);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
files-total-size-soft-limit = 1",
|
|
cd
|
|
);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
files-total-size-soft-limit = '-31337'",
|
|
cd
|
|
);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
files-total-size-soft-limit = '3.14Ki'",
|
|
cd
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_duration_settings() {
|
|
let (_td, cd, cp) = test_prolog();
|
|
let conf = load_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
cleanup-interval = '100s'\n\
|
|
optimizing-compression-task-timeout = '3m'\n\
|
|
allowed-clock-drift-for-files-from-future = '4h'",
|
|
cd
|
|
);
|
|
assert!(conf.enabled());
|
|
assert_eq!(conf.cleanup_interval(), Duration::from_secs(100));
|
|
assert_eq!(
|
|
conf.optimizing_compression_task_timeout(),
|
|
Duration::from_secs(3 * 60)
|
|
);
|
|
assert_eq!(
|
|
conf.allowed_clock_drift_for_files_from_future(),
|
|
Duration::from_secs(4 * 60 * 60)
|
|
);
|
|
|
|
let conf = load_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
cleanup-interval = '2d'\n\
|
|
optimizing-compression-task-timeout = '333 m'",
|
|
cd
|
|
);
|
|
assert!(conf.enabled());
|
|
assert_eq!(
|
|
conf.cleanup_interval(),
|
|
Duration::from_secs(2 * 24 * 60 * 60)
|
|
);
|
|
assert_eq!(
|
|
conf.optimizing_compression_task_timeout(),
|
|
Duration::from_secs(333 * 60)
|
|
);
|
|
|
|
// different errors
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
optimizing-compression-task-timeout = '333'",
|
|
cd
|
|
);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
optimizing-compression-task-timeout = 333",
|
|
cd
|
|
);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
optimizing-compression-task-timeout = '10 M'",
|
|
cd
|
|
);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
optimizing-compression-task-timeout = '10 min'",
|
|
cd
|
|
);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
optimizing-compression-task-timeout = '-10s'",
|
|
cd
|
|
);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
optimizing-compression-task-timeout = '1.5m'",
|
|
cd
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_percent_settings() {
|
|
let (_td, cd, cp) = test_prolog();
|
|
let conf = load_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
file-count-limit-percent-if-deleting = '62%'\n\
|
|
files-total-size-limit-percent-if-deleting = '23 %'",
|
|
cd
|
|
);
|
|
assert!(conf.enabled());
|
|
assert_eq!(conf.file_count_limit_percent_if_deleting(), 62);
|
|
assert_eq!(conf.files_total_size_limit_percent_if_deleting(), 23);
|
|
|
|
// different errors
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
files-total-size-limit-percent-if-deleting = '23'",
|
|
cd
|
|
);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
files-total-size-limit-percent-if-deleting = '22.5%'",
|
|
cd
|
|
);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
files-total-size-limit-percent-if-deleting = '0.5'",
|
|
cd
|
|
);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
files-total-size-limit-percent-if-deleting = '-1%'",
|
|
cd
|
|
);
|
|
|
|
bad_config!(
|
|
cp,
|
|
"[cache]\n\
|
|
enabled = true\n\
|
|
directory = {cache_dir}\n\
|
|
files-total-size-limit-percent-if-deleting = '101%'",
|
|
cd
|
|
);
|
|
}
|