use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)]
pub struct UpdateCheckConfig {
#[serde(default = "default_enabled")]
pub enabled: bool,
#[serde(default = "default_endpoint")]
pub endpoint: String,
#[serde(default = "default_timeout_ms")]
pub timeout_ms: u64,
}
fn default_enabled() -> bool {
true
}
fn default_endpoint() -> String {
"https://velesdb.com/api/check".to_string()
}
fn default_timeout_ms() -> u64 {
2000
}
impl Default for UpdateCheckConfig {
fn default() -> Self {
Self {
enabled: default_enabled(),
endpoint: default_endpoint(),
timeout_ms: default_timeout_ms(),
}
}
}
impl UpdateCheckConfig {
#[must_use]
pub fn is_enabled(&self) -> bool {
if let Ok(val) = std::env::var("VELESDB_NO_UPDATE_CHECK") {
if is_truthy(&val) {
return false;
}
}
if let Ok(val) = std::env::var("VELESDB_UPDATE_CHECK") {
return is_truthy(&val);
}
self.enabled
}
}
fn is_truthy(val: &str) -> bool {
!matches!(val.to_lowercase().as_str(), "0" | "false" | "no" | "off")
}
#[cfg(test)]
mod tests {
use super::*;
use serial_test::serial;
struct EnvVarGuard {
key: &'static str,
previous: Option<String>,
}
impl EnvVarGuard {
fn set(key: &'static str, value: &str) -> Self {
let previous = std::env::var(key).ok();
std::env::set_var(key, value);
Self { key, previous }
}
fn unset(key: &'static str) -> Self {
let previous = std::env::var(key).ok();
std::env::remove_var(key);
Self { key, previous }
}
}
impl Drop for EnvVarGuard {
fn drop(&mut self) {
match self.previous.take() {
Some(value) => std::env::set_var(self.key, value),
None => std::env::remove_var(self.key),
}
}
}
#[test]
fn test_env_var_guard_restores_on_unwind() {
const KEY: &str = "VELESDB_TEST_ENV_GUARD_PROBE";
std::env::set_var(KEY, "original");
let result = std::panic::catch_unwind(|| {
let _guard = EnvVarGuard::set(KEY, "overridden");
assert_eq!(std::env::var(KEY).as_deref(), Ok("overridden"));
panic!("simulated assertion failure");
});
assert!(result.is_err());
assert_eq!(
std::env::var(KEY).as_deref(),
Ok("original"),
"a panicking test must not leak its environment override to the rest \
of the process"
);
std::env::remove_var(KEY);
}
#[test]
#[serial(env)]
fn test_env_var_disables_update_check() {
let _no_check = EnvVarGuard::set("VELESDB_NO_UPDATE_CHECK", "1");
let config = UpdateCheckConfig::default();
assert!(!config.is_enabled());
}
#[test]
#[serial(env)]
fn test_env_var_overrides_config() {
let _no_check = EnvVarGuard::set("VELESDB_NO_UPDATE_CHECK", "1");
let config = UpdateCheckConfig {
enabled: true, ..Default::default()
};
assert!(!config.is_enabled()); }
#[test]
#[serial(env)]
fn test_config_disabled() {
let _no_check = EnvVarGuard::unset("VELESDB_NO_UPDATE_CHECK");
let _check = EnvVarGuard::unset("VELESDB_UPDATE_CHECK");
let config = UpdateCheckConfig {
enabled: false,
..Default::default()
};
assert!(!config.is_enabled());
}
#[test]
#[serial(env)]
fn test_default_enabled() {
let _no_check = EnvVarGuard::unset("VELESDB_NO_UPDATE_CHECK");
let _check = EnvVarGuard::unset("VELESDB_UPDATE_CHECK");
let config = UpdateCheckConfig::default();
assert!(config.is_enabled());
}
#[test]
fn test_default_endpoint() {
let config = UpdateCheckConfig::default();
assert_eq!(config.endpoint, "https://velesdb.com/api/check");
}
#[test]
fn test_default_timeout() {
let config = UpdateCheckConfig::default();
assert_eq!(config.timeout_ms, 2000);
}
}