feat: harden community production foundation through story 1.5

This commit is contained in:
2026-08-14 00:21:59 +03:00
parent c30461cc92
commit f6fc2e5c9b
161 changed files with 16758 additions and 2515 deletions
+13 -99
View File
@@ -1,8 +1,4 @@
use std::{
ffi::OsString,
sync::{Mutex, MutexGuard},
time::Duration,
};
use std::time::Duration;
use crank_core::{
CacheBackend, CacheScope, CacheStoreError, CachedHeader, CachedResponse,
@@ -17,62 +13,29 @@ use crank_runtime::{
};
use serde_json::json;
const CACHE_ENV_NAMES: [&str; 3] = [
"CRANK_CACHE_BACKEND",
"CRANK_CACHE_URL",
"CRANK_CACHE_DEFAULT_TTL_MS",
];
static CACHE_ENV_LOCK: Mutex<()> = Mutex::new(());
#[test]
fn defaults_to_in_memory_cache_without_url() {
let config = RuntimeCacheConfig::default();
assert_eq!(config.backend, CacheBackend::Memory);
assert_eq!(config.url, None);
assert_eq!(config.default_ttl_ms, None);
}
#[test]
fn treats_blank_optional_cache_values_as_unset() {
let _env = IsolatedCacheEnv::new();
unsafe {
std::env::set_var("CRANK_CACHE_URL", " ");
std::env::set_var("CRANK_CACHE_DEFAULT_TTL_MS", " ");
}
let config = RuntimeCacheConfig::from_env().unwrap();
assert_eq!(config.backend, CacheBackend::Memory);
assert_eq!(config.url, None);
assert_eq!(config.default_ttl_ms, None);
}
#[test]
fn loads_valkey_config_from_env() {
let _env = IsolatedCacheEnv::new();
unsafe {
std::env::set_var("CRANK_CACHE_BACKEND", "valkey");
std::env::set_var("CRANK_CACHE_URL", "redis://cache:6379/0");
std::env::set_var("CRANK_CACHE_DEFAULT_TTL_MS", "15000");
}
let config = RuntimeCacheConfig::from_env().unwrap();
fn accepts_validated_valkey_values() {
let config = RuntimeCacheConfig::try_new(
CacheBackend::Valkey,
Some("redis://cache:6379/0".to_owned()),
)
.unwrap();
assert_eq!(config.backend, CacheBackend::Valkey);
assert_eq!(config.url.as_deref(), Some("redis://cache:6379/0"));
assert_eq!(config.default_ttl_ms, Some(15_000));
}
#[test]
fn rejects_external_backend_without_url() {
let _env = IsolatedCacheEnv::new();
unsafe {
std::env::set_var("CRANK_CACHE_BACKEND", "redis");
std::env::remove_var("CRANK_CACHE_URL");
}
let error = RuntimeCacheConfig::from_env().unwrap_err();
let error = RuntimeCacheConfig::try_new(CacheBackend::Redis, None).unwrap_err();
assert!(matches!(
error,
@@ -83,59 +46,11 @@ fn rejects_external_backend_without_url() {
}
#[test]
fn rejects_zero_ttl() {
let _env = IsolatedCacheEnv::new();
unsafe {
std::env::set_var("CRANK_CACHE_DEFAULT_TTL_MS", "0");
}
let error = RuntimeCacheConfig::from_env().unwrap_err();
assert!(matches!(
error,
RuntimeCacheConfigError::ZeroTtl {
name: "CRANK_CACHE_DEFAULT_TTL_MS"
}
));
}
struct IsolatedCacheEnv {
_lock: MutexGuard<'static, ()>,
previous: Vec<(&'static str, Option<OsString>)>,
}
impl IsolatedCacheEnv {
fn new() -> Self {
let lock = CACHE_ENV_LOCK
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
let previous = CACHE_ENV_NAMES
.iter()
.map(|name| (*name, std::env::var_os(name)))
.collect();
for name in CACHE_ENV_NAMES {
unsafe {
std::env::remove_var(name);
}
}
Self {
_lock: lock,
previous,
}
}
}
impl Drop for IsolatedCacheEnv {
fn drop(&mut self) {
for (name, value) in &self.previous {
unsafe {
match value {
Some(value) => std::env::set_var(name, value),
None => std::env::remove_var(name),
}
}
}
}
fn rejects_url_for_memory_backend() {
let error =
RuntimeCacheConfig::try_new(CacheBackend::Memory, Some("redis://cache:6379".to_owned()))
.unwrap_err();
assert!(matches!(error, RuntimeCacheConfigError::UnexpectedUrl));
}
#[tokio::test]
@@ -410,7 +325,6 @@ fn runtime_cache_stores_report_missing_external_url() {
let future = RuntimeCacheStores::from_config(&RuntimeCacheConfig {
backend: CacheBackend::Valkey,
url: None,
default_ttl_ms: None,
});
let runtime = tokio::runtime::Runtime::new().unwrap();