env: centralize NOMOS/POL env var parsing

This commit is contained in:
andrussal 2025-12-18 18:19:38 +01:00
parent 4a47024a11
commit 027fd598a7
18 changed files with 184 additions and 59 deletions

8
Cargo.lock generated
View File

@ -7215,6 +7215,7 @@ dependencies = [
"rand 0.8.5",
"serde",
"subnetworks-assignations",
"testing-framework-env",
"thiserror 2.0.17",
"time",
"tracing",
@ -7252,11 +7253,16 @@ dependencies = [
"serde_yaml",
"tempfile",
"testing-framework-config",
"testing-framework-env",
"thiserror 2.0.17",
"tokio",
"tracing",
]
[[package]]
name = "testing-framework-env"
version = "0.1.0"
[[package]]
name = "testing-framework-runner-compose"
version = "0.1.0"
@ -7275,6 +7281,7 @@ dependencies = [
"tempfile",
"tera",
"testing-framework-core",
"testing-framework-env",
"tests",
"thiserror 2.0.17",
"tokio",
@ -7299,6 +7306,7 @@ dependencies = [
"serde_yaml",
"tempfile",
"testing-framework-core",
"testing-framework-env",
"thiserror 2.0.17",
"tokio",
"tracing",

View File

@ -8,6 +8,7 @@ members = [
"testing-framework/deployers/compose",
"testing-framework/deployers/k8s",
"testing-framework/deployers/local",
"testing-framework/env",
"testing-framework/tools/cfgsync",
"testing-framework/workflows",
]
@ -33,6 +34,7 @@ all = "allow"
# Local testing framework crates
testing-framework-config = { default-features = false, path = "testing-framework/configs" }
testing-framework-core = { default-features = false, path = "testing-framework/core" }
testing-framework-env = { default-features = false, path = "testing-framework/env" }
testing-framework-runner-compose = { default-features = false, path = "testing-framework/deployers/compose" }
testing-framework-runner-k8s = { default-features = false, path = "testing-framework/deployers/k8s" }
testing-framework-runner-local = { default-features = false, path = "testing-framework/deployers/local" }

View File

@ -41,6 +41,7 @@ num-bigint = { version = "0.4", default-features = false }
rand = { workspace = true }
serde = { workspace = true, features = ["derive"] }
subnetworks-assignations = { workspace = true }
testing-framework-env = { workspace = true }
thiserror = { workspace = true }
time = { version = "0.3", default-features = true }
tracing = { workspace = true }

View File

@ -1,18 +1,16 @@
use std::{env, net::Ipv4Addr, ops::Mul as _, sync::LazyLock, time::Duration};
use std::{net::Ipv4Addr, ops::Mul as _, sync::LazyLock, time::Duration};
use nomos_core::sdp::ProviderId;
use nomos_libp2p::{Multiaddr, PeerId, multiaddr};
use testing_framework_env as tf_env;
pub mod nodes;
pub mod timeouts;
pub mod topology;
static IS_SLOW_TEST_ENV: LazyLock<bool> =
LazyLock::new(|| env::var("SLOW_TEST_ENV").is_ok_and(|s| s == "true"));
static IS_SLOW_TEST_ENV: LazyLock<bool> = LazyLock::new(tf_env::slow_test_env);
pub static IS_DEBUG_TRACING: LazyLock<bool> = LazyLock::new(|| {
env::var("NOMOS_TESTS_TRACING").is_ok_and(|val| val.eq_ignore_ascii_case("true"))
});
pub static IS_DEBUG_TRACING: LazyLock<bool> = LazyLock::new(tf_env::debug_tracing);
const SLOW_ENV_TIMEOUT_MULTIPLIER: u32 = 2;

View File

@ -18,6 +18,7 @@ use nomos_node::NomosDaMembership;
use num_bigint::BigUint;
use rand::random;
use subnetworks_assignations::{MembershipCreator as _, MembershipHandler as _};
use testing_framework_env as tf_env;
use thiserror::Error;
use tracing::warn;
@ -50,7 +51,7 @@ fn canonicalize_params_path(mut path: PathBuf) -> PathBuf {
}
fn resolve_global_params_path() -> String {
if let Ok(path) = env::var("NOMOS_KZGRS_PARAMS_PATH") {
if let Some(path) = tf_env::nomos_kzgrs_params_path() {
return canonicalize_params_path(PathBuf::from(path))
.to_string_lossy()
.to_string();

View File

@ -1,10 +1,11 @@
use std::{env, time::Duration};
use std::time::Duration;
use nomos_libp2p::{
IdentifySettings, KademliaSettings, Multiaddr, NatSettings, ed25519, gossipsub,
};
use nomos_node::config::network::serde::{BackendSettings, Config, SwarmConfig};
use nomos_utils::net::get_available_udp_port;
use testing_framework_env as tf_env;
use thiserror::Error;
use crate::node_address_from_port;
@ -46,7 +47,7 @@ fn default_swarm_config() -> SwarmConfig {
}
fn nat_settings(port: u16) -> NatSettings {
if env::var("NOMOS_USE_AUTONAT").is_ok() {
if tf_env::nomos_use_autonat() {
return NatSettings::default();
}

View File

@ -1,5 +1,3 @@
use std::{env, path::PathBuf};
use nomos_tracing::{
logging::{local::FileConfig, loki::LokiConfig},
metrics::otlp::OtlpMetricsConfig,
@ -8,6 +6,7 @@ use nomos_tracing::{
use nomos_tracing_service::{
ConsoleLayer, FilterLayer, LoggerLayer, MetricsLayer, TracingLayer, TracingSettings,
};
use testing_framework_env as tf_env;
use tracing::Level;
use crate::IS_DEBUG_TRACING;
@ -65,11 +64,11 @@ impl GeneralTracingConfig {
}
fn otlp_tracing_endpoint() -> Option<String> {
env::var("NOMOS_OTLP_ENDPOINT").ok()
tf_env::nomos_otlp_endpoint()
}
fn otlp_metrics_endpoint() -> Option<String> {
env::var("NOMOS_OTLP_METRICS_ENDPOINT").ok()
tf_env::nomos_otlp_metrics_endpoint()
}
#[must_use]
@ -103,8 +102,7 @@ fn apply_file_logger_override(
mut cfg: GeneralTracingConfig,
node_index: usize,
) -> GeneralTracingConfig {
if let Ok(dir) = std::env::var("NOMOS_LOG_DIR") {
let directory = PathBuf::from(dir);
if let Some(directory) = tf_env::nomos_log_dir() {
cfg.tracing_settings.logger = LoggerLayer::File(FileConfig {
directory,
prefix: Some(format!("nomos-node-{node_index}").into()),
@ -115,26 +113,23 @@ fn apply_file_logger_override(
}
fn file_log_level() -> Level {
env::var("NOMOS_LOG_LEVEL")
.ok()
tf_env::nomos_log_level()
.and_then(|raw| raw.parse::<Level>().ok())
.unwrap_or(Level::INFO)
}
fn file_filter_override() -> Option<nomos_tracing::filter::envfilter::EnvFilterConfig> {
env::var("NOMOS_LOG_FILTER")
.ok()
.map(|raw| nomos_tracing::filter::envfilter::EnvFilterConfig {
filters: raw
.split(',')
.filter_map(|pair| {
let mut parts = pair.splitn(2, '=');
let target = parts.next()?.trim().to_string();
let level = parts.next()?.trim().to_string();
(!target.is_empty() && !level.is_empty()).then_some((target, level))
})
.collect(),
})
tf_env::nomos_log_filter().map(|raw| nomos_tracing::filter::envfilter::EnvFilterConfig {
filters: raw
.split(',')
.filter_map(|pair| {
let mut parts = pair.splitn(2, '=');
let target = parts.next()?.trim().to_string();
let level = parts.next()?.trim().to_string();
(!target.is_empty() && !level.is_empty()).then_some((target, level))
})
.collect(),
})
}
fn maybe_disable_otlp_layers(mut cfg: GeneralTracingConfig) -> GeneralTracingConfig {

View File

@ -44,6 +44,7 @@ serde_with = { workspace = true }
serde_yaml = { workspace = true }
tempfile = { workspace = true }
testing-framework-config = { workspace = true }
testing-framework-env = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["macros", "process", "rt-multi-thread", "time"] }
tracing = { workspace = true }

View File

@ -1,4 +1,6 @@
use std::{env, time::Duration};
use std::time::Duration;
use testing_framework_env as tf_env;
/// Default cfgsync port used across runners.
pub const DEFAULT_CFGSYNC_PORT: u16 = 4400;
@ -38,14 +40,11 @@ pub const DEFAULT_BLEND_NETWORK_PORT: u16 = 4401;
/// Resolve cfgsync port from `NOMOS_CFGSYNC_PORT`, falling back to the default.
pub fn cfgsync_port() -> u16 {
env::var("NOMOS_CFGSYNC_PORT")
.ok()
.and_then(|v| v.parse::<u16>().ok())
.unwrap_or(DEFAULT_CFGSYNC_PORT)
tf_env::nomos_cfgsync_port().unwrap_or(DEFAULT_CFGSYNC_PORT)
}
/// Resolve container KZG path from `NOMOS_KZG_CONTAINER_PATH`, falling back to
/// the default.
pub fn kzg_container_path() -> String {
env::var("NOMOS_KZG_CONTAINER_PATH").unwrap_or_else(|_| DEFAULT_KZG_CONTAINER_PATH.to_string())
tf_env::nomos_kzg_container_path().unwrap_or_else(|| DEFAULT_KZG_CONTAINER_PATH.to_string())
}

View File

@ -1,13 +1,13 @@
use std::{
env,
fs::{self, File},
io,
path::{Path, PathBuf},
path::Path,
};
use nomos_tracing::logging::local::FileConfig;
use serde::Serialize;
use serde_yaml::Value;
use testing_framework_env as tf_env;
use tracing::debug;
use crate::nodes::common::config::injection::normalize_ed25519_sigs;
@ -20,8 +20,7 @@ where
{
debug!(prefix, base_dir = %base_dir.display(), "configuring node logging");
if let Ok(env_dir) = env::var("NOMOS_LOG_DIR") {
let log_dir = PathBuf::from(env_dir);
if let Some(log_dir) = tf_env::nomos_log_dir() {
let _ = fs::create_dir_all(&log_dir);
set_logger(FileConfig {

View File

@ -7,10 +7,10 @@ use std::sync::LazyLock;
pub use api_client::{ApiClient, ApiClientError};
use tempfile::TempDir;
use testing_framework_env as tf_env;
pub(crate) const LOGS_PREFIX: &str = "__logs";
static KEEP_NODE_TEMPDIRS: LazyLock<bool> =
LazyLock::new(|| std::env::var("NOMOS_TESTS_KEEP_LOGS").is_ok());
static KEEP_NODE_TEMPDIRS: LazyLock<bool> = LazyLock::new(tf_env::nomos_tests_keep_logs);
pub(crate) fn create_tempdir() -> std::io::Result<TempDir> {
// It's easier to use the current location instead of OS-default tempfile

View File

@ -23,6 +23,7 @@ serde = { workspace = true, features = ["derive"] }
tempfile = { workspace = true }
tera = "1.19"
testing-framework-core = { path = "../../core" }
testing-framework-env = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["macros", "net", "process", "rt-multi-thread", "sync", "time"] }
tracing = { workspace = true }

View File

@ -8,6 +8,7 @@ use testing_framework_core::{
constants::{DEFAULT_CFGSYNC_PORT, kzg_container_path},
topology::generation::{GeneratedNodeConfig, GeneratedTopology},
};
use testing_framework_env as tf_env;
use crate::docker::platform::{host_gateway_entry, resolve_image};
@ -180,12 +181,11 @@ fn default_extra_hosts() -> Vec<String> {
}
fn base_environment(cfgsync_port: u16) -> Vec<EnvEntry> {
let pol_mode = std::env::var("POL_PROOF_DEV_MODE").unwrap_or_else(|_| "true".to_string());
let rust_log = std::env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string());
let nomos_log_level = std::env::var("NOMOS_LOG_LEVEL").unwrap_or_else(|_| "info".to_string());
let time_backend = std::env::var("NOMOS_TIME_BACKEND").unwrap_or_else(|_| "monotonic".into());
let kzg_path =
std::env::var("NOMOS_KZGRS_PARAMS_PATH").unwrap_or_else(|_| kzg_container_path());
let pol_mode = tf_env::pol_proof_dev_mode().unwrap_or_else(|| "true".to_string());
let rust_log = tf_env::rust_log().unwrap_or_else(|| "info".to_string());
let nomos_log_level = tf_env::nomos_log_level().unwrap_or_else(|| "info".to_string());
let time_backend = tf_env::nomos_time_backend().unwrap_or_else(|| "monotonic".into());
let kzg_path = tf_env::nomos_kzgrs_params_path().unwrap_or_else(kzg_container_path);
vec![
EnvEntry::new("POL_PROOF_DEV_MODE", pol_mode),
EnvEntry::new("RUST_LOG", rust_log),

View File

@ -1,12 +1,13 @@
use std::env;
use testing_framework_env as tf_env;
use tracing::debug;
/// Select the compose image and optional platform, honoring
/// NOMOS_TESTNET_IMAGE.
pub fn resolve_image() -> (String, Option<String>) {
let image = env::var("NOMOS_TESTNET_IMAGE")
.unwrap_or_else(|_| String::from("logos-blockchain-testing:local"));
let image = tf_env::nomos_testnet_image()
.unwrap_or_else(|| String::from("logos-blockchain-testing:local"));
let platform = (image == "ghcr.io/logos-co/nomos:testnet").then(|| "linux/amd64".to_owned());
debug!(image, platform = ?platform, "resolved compose image");
(image, platform)

View File

@ -24,6 +24,7 @@ serde = { version = "1", features = ["derive"] }
serde_yaml = { workspace = true }
tempfile = { workspace = true }
testing-framework-core = { path = "../../core" }
testing-framework-env = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["macros", "net", "process", "rt-multi-thread", "sync", "time"] }
tracing = { workspace = true }

View File

@ -15,6 +15,7 @@ use testing_framework_core::{
scenario::cfgsync::{apply_topology_overrides, load_cfgsync_template, render_cfgsync_yaml},
topology::generation::GeneratedTopology,
};
use testing_framework_env as tf_env;
use thiserror::Error;
use tracing::{debug, info, warn};
@ -81,7 +82,7 @@ pub enum KzgMode {
}
fn kzg_mode() -> KzgMode {
match env::var("NOMOS_KZG_MODE").ok().as_deref() {
match tf_env::nomos_kzg_mode().as_deref() {
Some("hostPath") => KzgMode::HostPath,
Some("inImage") => KzgMode::InImage,
None => KzgMode::InImage,
@ -125,8 +126,8 @@ pub fn prepare_assets(
let chart_path = helm_chart_path()?;
let values_yaml = render_values_yaml(topology)?;
let values_file = write_temp_file(tempdir.path(), "values.yaml", values_yaml)?;
let image = env::var("NOMOS_TESTNET_IMAGE")
.unwrap_or_else(|_| String::from("public.ecr.aws/r4s5t9y4/logos/logos-blockchain:test"));
let image = tf_env::nomos_testnet_image()
.unwrap_or_else(|| String::from("public.ecr.aws/r4s5t9y4/logos/logos-blockchain:test"));
let kzg_display = kzg_path
.as_ref()
@ -175,8 +176,7 @@ fn render_cfgsync_config(
apply_topology_overrides(&mut cfg, topology, kzg_mode == KzgMode::HostPath);
if kzg_mode == KzgMode::InImage {
cfg.global_params_path = env::var("NOMOS_KZGRS_PARAMS_PATH")
.ok()
cfg.global_params_path = tf_env::nomos_kzgrs_params_path()
.unwrap_or_else(|| DEFAULT_IN_IMAGE_KZG_PARAMS_PATH.to_string());
}
@ -229,8 +229,7 @@ fn validate_scripts(root: &Path) -> Result<ScriptPaths, AssetsError> {
}
fn validate_kzg_params(root: &Path) -> Result<PathBuf, AssetsError> {
let rel = env::var("NOMOS_KZG_DIR_REL")
.ok()
let rel = tf_env::nomos_kzg_dir_rel()
.unwrap_or_else(|| testing_framework_core::constants::DEFAULT_KZG_HOST_DIR.to_string());
let path = root.join(rel);
if path.exists() {
@ -334,7 +333,7 @@ fn build_values(topology: &GeneratedTopology) -> HelmValues {
};
let pol_mode = pol_proof_mode();
let image_pull_policy =
env::var("NOMOS_TESTNET_IMAGE_PULL_POLICY").unwrap_or_else(|_| "IfNotPresent".into());
tf_env::nomos_testnet_image_pull_policy().unwrap_or_else(|| "IfNotPresent".into());
debug!(pol_mode, "rendering Helm values for k8s stack");
let validators = topology
.validators()
@ -425,5 +424,5 @@ fn build_values(topology: &GeneratedTopology) -> HelmValues {
}
fn pol_proof_mode() -> String {
env::var("POL_PROOF_DEV_MODE").unwrap_or_else(|_| "true".to_string())
tf_env::pol_proof_dev_mode().unwrap_or_else(|| "true".to_string())
}

15
testing-framework/env/Cargo.toml vendored Normal file
View File

@ -0,0 +1,15 @@
[package]
categories.workspace = true
description.workspace = true
edition.workspace = true
keywords.workspace = true
license.workspace = true
name = "testing-framework-env"
readme.workspace = true
repository.workspace = true
version.workspace = true
[lints]
workspace = true
[dependencies]

103
testing-framework/env/src/lib.rs vendored Normal file
View File

@ -0,0 +1,103 @@
use std::{env, path::PathBuf};
#[must_use]
pub fn slow_test_env() -> bool {
env::var("SLOW_TEST_ENV").is_ok_and(|s| s == "true")
}
#[must_use]
pub fn debug_tracing() -> bool {
env::var("NOMOS_TESTS_TRACING").is_ok_and(|val| val.eq_ignore_ascii_case("true"))
}
#[must_use]
pub fn nomos_log_dir() -> Option<PathBuf> {
env::var("NOMOS_LOG_DIR").ok().map(PathBuf::from)
}
#[must_use]
pub fn nomos_log_level() -> Option<String> {
env::var("NOMOS_LOG_LEVEL").ok()
}
#[must_use]
pub fn nomos_log_filter() -> Option<String> {
env::var("NOMOS_LOG_FILTER").ok()
}
#[must_use]
pub fn nomos_use_autonat() -> bool {
env::var("NOMOS_USE_AUTONAT").is_ok()
}
#[must_use]
pub fn nomos_cfgsync_port() -> Option<u16> {
env::var("NOMOS_CFGSYNC_PORT")
.ok()
.and_then(|v| v.parse::<u16>().ok())
}
#[must_use]
pub fn nomos_kzg_container_path() -> Option<String> {
env::var("NOMOS_KZG_CONTAINER_PATH").ok()
}
#[must_use]
pub fn nomos_tests_keep_logs() -> bool {
env::var("NOMOS_TESTS_KEEP_LOGS").is_ok()
}
#[must_use]
pub fn nomos_testnet_image() -> Option<String> {
env::var("NOMOS_TESTNET_IMAGE").ok()
}
#[must_use]
pub fn nomos_testnet_image_pull_policy() -> Option<String> {
env::var("NOMOS_TESTNET_IMAGE_PULL_POLICY").ok()
}
#[must_use]
pub fn nomos_kzg_mode() -> Option<String> {
env::var("NOMOS_KZG_MODE").ok()
}
#[must_use]
pub fn nomos_kzg_dir_rel() -> Option<String> {
env::var("NOMOS_KZG_DIR_REL").ok()
}
#[must_use]
pub fn nomos_kzg_file() -> Option<String> {
env::var("NOMOS_KZG_FILE").ok()
}
#[must_use]
pub fn pol_proof_dev_mode() -> Option<String> {
env::var("POL_PROOF_DEV_MODE").ok()
}
#[must_use]
pub fn rust_log() -> Option<String> {
env::var("RUST_LOG").ok()
}
#[must_use]
pub fn nomos_time_backend() -> Option<String> {
env::var("NOMOS_TIME_BACKEND").ok()
}
#[must_use]
pub fn nomos_kzgrs_params_path() -> Option<String> {
env::var("NOMOS_KZGRS_PARAMS_PATH").ok()
}
#[must_use]
pub fn nomos_otlp_endpoint() -> Option<String> {
env::var("NOMOS_OTLP_ENDPOINT").ok()
}
#[must_use]
pub fn nomos_otlp_metrics_endpoint() -> Option<String> {
env::var("NOMOS_OTLP_METRICS_ENDPOINT").ok()
}