fix: migrate vendor rustfmt.toml to stable-only features
- Update vendor/pezkuwi-zombienet-sdk/rustfmt.toml to stable-only - Reformat 74 vendor files with stable rustfmt - Remove nightly-only features causing CI failures
This commit is contained in:
+263
-307
@@ -1,383 +1,339 @@
|
||||
use std::{
|
||||
error::Error,
|
||||
fmt::Display,
|
||||
net::IpAddr,
|
||||
path::{Path, PathBuf},
|
||||
str::FromStr,
|
||||
error::Error,
|
||||
fmt::Display,
|
||||
net::IpAddr,
|
||||
path::{Path, PathBuf},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use multiaddr::Multiaddr;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
shared::{
|
||||
errors::{ConfigError, FieldError},
|
||||
helpers::{merge_errors, merge_errors_vecs},
|
||||
types::Duration,
|
||||
},
|
||||
utils::{default_as_true, default_node_spawn_timeout, default_timeout},
|
||||
shared::{
|
||||
errors::{ConfigError, FieldError},
|
||||
helpers::{merge_errors, merge_errors_vecs},
|
||||
types::Duration,
|
||||
},
|
||||
utils::{default_as_true, default_node_spawn_timeout, default_timeout},
|
||||
};
|
||||
|
||||
/// Global settings applied to an entire network.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct GlobalSettings {
|
||||
/// Global bootnodes to use (we will then add more)
|
||||
#[serde(skip_serializing_if = "std::vec::Vec::is_empty", default)]
|
||||
bootnodes_addresses: Vec<Multiaddr>,
|
||||
// TODO: parse both case in zombienet node version to avoid renamed ?
|
||||
/// Global spawn timeout
|
||||
#[serde(rename = "timeout", default = "default_timeout")]
|
||||
network_spawn_timeout: Duration,
|
||||
// TODO: not used yet
|
||||
/// Node spawn timeout
|
||||
#[serde(default = "default_node_spawn_timeout")]
|
||||
node_spawn_timeout: Duration,
|
||||
// TODO: not used yet
|
||||
/// Local ip to use for construct the direct links
|
||||
local_ip: Option<IpAddr>,
|
||||
/// Directory to use as base dir
|
||||
/// Used to reuse the same files (database) from a previous run,
|
||||
/// also note that we will override the content of some of those files.
|
||||
base_dir: Option<PathBuf>,
|
||||
/// Number of concurrent spawning process to launch, None means try to spawn all at the same time.
|
||||
spawn_concurrency: Option<usize>,
|
||||
/// If enabled, will launch a task to monitor nodes' liveness and tear down the network if there are any.
|
||||
#[serde(default = "default_as_true")]
|
||||
tear_down_on_failure: bool,
|
||||
/// Global bootnodes to use (we will then add more)
|
||||
#[serde(skip_serializing_if = "std::vec::Vec::is_empty", default)]
|
||||
bootnodes_addresses: Vec<Multiaddr>,
|
||||
// TODO: parse both case in zombienet node version to avoid renamed ?
|
||||
/// Global spawn timeout
|
||||
#[serde(rename = "timeout", default = "default_timeout")]
|
||||
network_spawn_timeout: Duration,
|
||||
// TODO: not used yet
|
||||
/// Node spawn timeout
|
||||
#[serde(default = "default_node_spawn_timeout")]
|
||||
node_spawn_timeout: Duration,
|
||||
// TODO: not used yet
|
||||
/// Local ip to use for construct the direct links
|
||||
local_ip: Option<IpAddr>,
|
||||
/// Directory to use as base dir
|
||||
/// Used to reuse the same files (database) from a previous run,
|
||||
/// also note that we will override the content of some of those files.
|
||||
base_dir: Option<PathBuf>,
|
||||
/// Number of concurrent spawning process to launch, None means try to spawn all at the same time.
|
||||
spawn_concurrency: Option<usize>,
|
||||
/// If enabled, will launch a task to monitor nodes' liveness and tear down the network if there are any.
|
||||
#[serde(default = "default_as_true")]
|
||||
tear_down_on_failure: bool,
|
||||
}
|
||||
|
||||
impl GlobalSettings {
|
||||
/// External bootnode address.
|
||||
pub fn bootnodes_addresses(&self) -> Vec<&Multiaddr> {
|
||||
self.bootnodes_addresses.iter().collect()
|
||||
}
|
||||
/// External bootnode address.
|
||||
pub fn bootnodes_addresses(&self) -> Vec<&Multiaddr> {
|
||||
self.bootnodes_addresses.iter().collect()
|
||||
}
|
||||
|
||||
/// Global spawn timeout in seconds.
|
||||
pub fn network_spawn_timeout(&self) -> Duration {
|
||||
self.network_spawn_timeout
|
||||
}
|
||||
/// Global spawn timeout in seconds.
|
||||
pub fn network_spawn_timeout(&self) -> Duration {
|
||||
self.network_spawn_timeout
|
||||
}
|
||||
|
||||
/// Individual node spawn timeout in seconds.
|
||||
pub fn node_spawn_timeout(&self) -> Duration {
|
||||
self.node_spawn_timeout
|
||||
}
|
||||
/// Individual node spawn timeout in seconds.
|
||||
pub fn node_spawn_timeout(&self) -> Duration {
|
||||
self.node_spawn_timeout
|
||||
}
|
||||
|
||||
/// Local IP used to expose local services (including RPC, metrics and monitoring).
|
||||
pub fn local_ip(&self) -> Option<&IpAddr> {
|
||||
self.local_ip.as_ref()
|
||||
}
|
||||
/// Local IP used to expose local services (including RPC, metrics and monitoring).
|
||||
pub fn local_ip(&self) -> Option<&IpAddr> {
|
||||
self.local_ip.as_ref()
|
||||
}
|
||||
|
||||
/// Base directory to use (instead a random tmp one)
|
||||
/// All the artifacts will be created in this directory.
|
||||
pub fn base_dir(&self) -> Option<&Path> {
|
||||
self.base_dir.as_deref()
|
||||
}
|
||||
/// Base directory to use (instead a random tmp one)
|
||||
/// All the artifacts will be created in this directory.
|
||||
pub fn base_dir(&self) -> Option<&Path> {
|
||||
self.base_dir.as_deref()
|
||||
}
|
||||
|
||||
/// Number of concurrent spawning process to launch
|
||||
pub fn spawn_concurrency(&self) -> Option<usize> {
|
||||
self.spawn_concurrency
|
||||
}
|
||||
/// Number of concurrent spawning process to launch
|
||||
pub fn spawn_concurrency(&self) -> Option<usize> {
|
||||
self.spawn_concurrency
|
||||
}
|
||||
|
||||
/// A flag to tear down the network if there are any unresponsive nodes detected.
|
||||
pub fn tear_down_on_failure(&self) -> bool {
|
||||
self.tear_down_on_failure
|
||||
}
|
||||
/// A flag to tear down the network if there are any unresponsive nodes detected.
|
||||
pub fn tear_down_on_failure(&self) -> bool {
|
||||
self.tear_down_on_failure
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GlobalSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bootnodes_addresses: Default::default(),
|
||||
network_spawn_timeout: default_timeout(),
|
||||
node_spawn_timeout: default_node_spawn_timeout(),
|
||||
local_ip: Default::default(),
|
||||
base_dir: Default::default(),
|
||||
spawn_concurrency: Default::default(),
|
||||
tear_down_on_failure: true,
|
||||
}
|
||||
}
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bootnodes_addresses: Default::default(),
|
||||
network_spawn_timeout: default_timeout(),
|
||||
node_spawn_timeout: default_node_spawn_timeout(),
|
||||
local_ip: Default::default(),
|
||||
base_dir: Default::default(),
|
||||
spawn_concurrency: Default::default(),
|
||||
tear_down_on_failure: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A global settings builder, used to build [`GlobalSettings`] declaratively with fields validation.
|
||||
#[derive(Default)]
|
||||
pub struct GlobalSettingsBuilder {
|
||||
config: GlobalSettings,
|
||||
errors: Vec<anyhow::Error>,
|
||||
config: GlobalSettings,
|
||||
errors: Vec<anyhow::Error>,
|
||||
}
|
||||
|
||||
impl GlobalSettingsBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
// Transition to the next state of the builder.
|
||||
fn transition(config: GlobalSettings, errors: Vec<anyhow::Error>) -> Self {
|
||||
Self { config, errors }
|
||||
}
|
||||
// Transition to the next state of the builder.
|
||||
fn transition(config: GlobalSettings, errors: Vec<anyhow::Error>) -> Self {
|
||||
Self { config, errors }
|
||||
}
|
||||
|
||||
/// Set the external bootnode address.
|
||||
///
|
||||
/// Note: Bootnode address replacements are NOT supported here.
|
||||
/// Only arguments (`args`) support dynamic replacements. Bootnode addresses must be a valid address.
|
||||
pub fn with_raw_bootnodes_addresses<T>(self, bootnodes_addresses: Vec<T>) -> Self
|
||||
where
|
||||
T: TryInto<Multiaddr> + Display + Copy,
|
||||
T::Error: Error + Send + Sync + 'static,
|
||||
{
|
||||
let mut addrs = vec![];
|
||||
let mut errors = vec![];
|
||||
/// Set the external bootnode address.
|
||||
///
|
||||
/// Note: Bootnode address replacements are NOT supported here.
|
||||
/// Only arguments (`args`) support dynamic replacements. Bootnode addresses must be a valid address.
|
||||
pub fn with_raw_bootnodes_addresses<T>(self, bootnodes_addresses: Vec<T>) -> Self
|
||||
where
|
||||
T: TryInto<Multiaddr> + Display + Copy,
|
||||
T::Error: Error + Send + Sync + 'static,
|
||||
{
|
||||
let mut addrs = vec![];
|
||||
let mut errors = vec![];
|
||||
|
||||
for (index, addr) in bootnodes_addresses.into_iter().enumerate() {
|
||||
match addr.try_into() {
|
||||
Ok(addr) => addrs.push(addr),
|
||||
Err(error) => errors.push(
|
||||
FieldError::BootnodesAddress(index, addr.to_string(), error.into()).into(),
|
||||
),
|
||||
}
|
||||
}
|
||||
for (index, addr) in bootnodes_addresses.into_iter().enumerate() {
|
||||
match addr.try_into() {
|
||||
Ok(addr) => addrs.push(addr),
|
||||
Err(error) => errors.push(
|
||||
FieldError::BootnodesAddress(index, addr.to_string(), error.into()).into(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
Self::transition(
|
||||
GlobalSettings {
|
||||
bootnodes_addresses: addrs,
|
||||
..self.config
|
||||
},
|
||||
merge_errors_vecs(self.errors, errors),
|
||||
)
|
||||
}
|
||||
Self::transition(
|
||||
GlobalSettings { bootnodes_addresses: addrs, ..self.config },
|
||||
merge_errors_vecs(self.errors, errors),
|
||||
)
|
||||
}
|
||||
|
||||
/// Set global spawn timeout in seconds.
|
||||
pub fn with_network_spawn_timeout(self, timeout: Duration) -> Self {
|
||||
Self::transition(
|
||||
GlobalSettings {
|
||||
network_spawn_timeout: timeout,
|
||||
..self.config
|
||||
},
|
||||
self.errors,
|
||||
)
|
||||
}
|
||||
/// Set global spawn timeout in seconds.
|
||||
pub fn with_network_spawn_timeout(self, timeout: Duration) -> Self {
|
||||
Self::transition(
|
||||
GlobalSettings { network_spawn_timeout: timeout, ..self.config },
|
||||
self.errors,
|
||||
)
|
||||
}
|
||||
|
||||
/// Set individual node spawn timeout in seconds.
|
||||
pub fn with_node_spawn_timeout(self, timeout: Duration) -> Self {
|
||||
Self::transition(
|
||||
GlobalSettings {
|
||||
node_spawn_timeout: timeout,
|
||||
..self.config
|
||||
},
|
||||
self.errors,
|
||||
)
|
||||
}
|
||||
/// Set individual node spawn timeout in seconds.
|
||||
pub fn with_node_spawn_timeout(self, timeout: Duration) -> Self {
|
||||
Self::transition(GlobalSettings { node_spawn_timeout: timeout, ..self.config }, self.errors)
|
||||
}
|
||||
|
||||
/// Set local IP used to expose local services (including RPC, metrics and monitoring).
|
||||
pub fn with_local_ip(self, local_ip: &str) -> Self {
|
||||
match IpAddr::from_str(local_ip) {
|
||||
Ok(local_ip) => Self::transition(
|
||||
GlobalSettings {
|
||||
local_ip: Some(local_ip),
|
||||
..self.config
|
||||
},
|
||||
self.errors,
|
||||
),
|
||||
Err(error) => Self::transition(
|
||||
self.config,
|
||||
merge_errors(self.errors, FieldError::LocalIp(error.into()).into()),
|
||||
),
|
||||
}
|
||||
}
|
||||
/// Set local IP used to expose local services (including RPC, metrics and monitoring).
|
||||
pub fn with_local_ip(self, local_ip: &str) -> Self {
|
||||
match IpAddr::from_str(local_ip) {
|
||||
Ok(local_ip) => Self::transition(
|
||||
GlobalSettings { local_ip: Some(local_ip), ..self.config },
|
||||
self.errors,
|
||||
),
|
||||
Err(error) => Self::transition(
|
||||
self.config,
|
||||
merge_errors(self.errors, FieldError::LocalIp(error.into()).into()),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the directory to use as base (instead of a random tmp one).
|
||||
pub fn with_base_dir(self, base_dir: impl Into<PathBuf>) -> Self {
|
||||
Self::transition(
|
||||
GlobalSettings {
|
||||
base_dir: Some(base_dir.into()),
|
||||
..self.config
|
||||
},
|
||||
self.errors,
|
||||
)
|
||||
}
|
||||
/// Set the directory to use as base (instead of a random tmp one).
|
||||
pub fn with_base_dir(self, base_dir: impl Into<PathBuf>) -> Self {
|
||||
Self::transition(
|
||||
GlobalSettings { base_dir: Some(base_dir.into()), ..self.config },
|
||||
self.errors,
|
||||
)
|
||||
}
|
||||
|
||||
/// Set the spawn concurrency
|
||||
pub fn with_spawn_concurrency(self, spawn_concurrency: usize) -> Self {
|
||||
Self::transition(
|
||||
GlobalSettings {
|
||||
spawn_concurrency: Some(spawn_concurrency),
|
||||
..self.config
|
||||
},
|
||||
self.errors,
|
||||
)
|
||||
}
|
||||
/// Set the spawn concurrency
|
||||
pub fn with_spawn_concurrency(self, spawn_concurrency: usize) -> Self {
|
||||
Self::transition(
|
||||
GlobalSettings { spawn_concurrency: Some(spawn_concurrency), ..self.config },
|
||||
self.errors,
|
||||
)
|
||||
}
|
||||
|
||||
/// Set the `tear_down_on_failure` flag
|
||||
pub fn with_tear_down_on_failure(self, tear_down_on_failure: bool) -> Self {
|
||||
Self::transition(
|
||||
GlobalSettings {
|
||||
tear_down_on_failure,
|
||||
..self.config
|
||||
},
|
||||
self.errors,
|
||||
)
|
||||
}
|
||||
/// Set the `tear_down_on_failure` flag
|
||||
pub fn with_tear_down_on_failure(self, tear_down_on_failure: bool) -> Self {
|
||||
Self::transition(GlobalSettings { tear_down_on_failure, ..self.config }, self.errors)
|
||||
}
|
||||
|
||||
/// Seals the builder and returns a [`GlobalSettings`] if there are no validation errors, else returns errors.
|
||||
pub fn build(self) -> Result<GlobalSettings, Vec<anyhow::Error>> {
|
||||
if !self.errors.is_empty() {
|
||||
return Err(self
|
||||
.errors
|
||||
.into_iter()
|
||||
.map(|error| ConfigError::GlobalSettings(error).into())
|
||||
.collect::<Vec<_>>());
|
||||
}
|
||||
/// Seals the builder and returns a [`GlobalSettings`] if there are no validation errors, else returns errors.
|
||||
pub fn build(self) -> Result<GlobalSettings, Vec<anyhow::Error>> {
|
||||
if !self.errors.is_empty() {
|
||||
return Err(self
|
||||
.errors
|
||||
.into_iter()
|
||||
.map(|error| ConfigError::GlobalSettings(error).into())
|
||||
.collect::<Vec<_>>());
|
||||
}
|
||||
|
||||
Ok(self.config)
|
||||
}
|
||||
Ok(self.config)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn global_settings_config_builder_should_succeeds_and_returns_a_global_settings_config() {
|
||||
let global_settings_config = GlobalSettingsBuilder::new()
|
||||
.with_raw_bootnodes_addresses(vec![
|
||||
"/ip4/10.41.122.55/tcp/45421",
|
||||
"/ip4/51.144.222.10/tcp/2333",
|
||||
])
|
||||
.with_network_spawn_timeout(600)
|
||||
.with_node_spawn_timeout(120)
|
||||
.with_local_ip("10.0.0.1")
|
||||
.with_base_dir("/home/nonroot/mynetwork")
|
||||
.with_spawn_concurrency(5)
|
||||
.with_tear_down_on_failure(true)
|
||||
.build()
|
||||
.unwrap();
|
||||
#[test]
|
||||
fn global_settings_config_builder_should_succeeds_and_returns_a_global_settings_config() {
|
||||
let global_settings_config = GlobalSettingsBuilder::new()
|
||||
.with_raw_bootnodes_addresses(vec![
|
||||
"/ip4/10.41.122.55/tcp/45421",
|
||||
"/ip4/51.144.222.10/tcp/2333",
|
||||
])
|
||||
.with_network_spawn_timeout(600)
|
||||
.with_node_spawn_timeout(120)
|
||||
.with_local_ip("10.0.0.1")
|
||||
.with_base_dir("/home/nonroot/mynetwork")
|
||||
.with_spawn_concurrency(5)
|
||||
.with_tear_down_on_failure(true)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let bootnodes_addresses: Vec<Multiaddr> = vec![
|
||||
"/ip4/10.41.122.55/tcp/45421".try_into().unwrap(),
|
||||
"/ip4/51.144.222.10/tcp/2333".try_into().unwrap(),
|
||||
];
|
||||
assert_eq!(
|
||||
global_settings_config.bootnodes_addresses(),
|
||||
bootnodes_addresses.iter().collect::<Vec<_>>()
|
||||
);
|
||||
assert_eq!(global_settings_config.network_spawn_timeout(), 600);
|
||||
assert_eq!(global_settings_config.node_spawn_timeout(), 120);
|
||||
assert_eq!(
|
||||
global_settings_config
|
||||
.local_ip()
|
||||
.unwrap()
|
||||
.to_string()
|
||||
.as_str(),
|
||||
"10.0.0.1"
|
||||
);
|
||||
assert_eq!(
|
||||
global_settings_config.base_dir().unwrap(),
|
||||
Path::new("/home/nonroot/mynetwork")
|
||||
);
|
||||
assert_eq!(global_settings_config.spawn_concurrency().unwrap(), 5);
|
||||
assert!(global_settings_config.tear_down_on_failure());
|
||||
}
|
||||
let bootnodes_addresses: Vec<Multiaddr> = vec![
|
||||
"/ip4/10.41.122.55/tcp/45421".try_into().unwrap(),
|
||||
"/ip4/51.144.222.10/tcp/2333".try_into().unwrap(),
|
||||
];
|
||||
assert_eq!(
|
||||
global_settings_config.bootnodes_addresses(),
|
||||
bootnodes_addresses.iter().collect::<Vec<_>>()
|
||||
);
|
||||
assert_eq!(global_settings_config.network_spawn_timeout(), 600);
|
||||
assert_eq!(global_settings_config.node_spawn_timeout(), 120);
|
||||
assert_eq!(global_settings_config.local_ip().unwrap().to_string().as_str(), "10.0.0.1");
|
||||
assert_eq!(
|
||||
global_settings_config.base_dir().unwrap(),
|
||||
Path::new("/home/nonroot/mynetwork")
|
||||
);
|
||||
assert_eq!(global_settings_config.spawn_concurrency().unwrap(), 5);
|
||||
assert!(global_settings_config.tear_down_on_failure());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn global_settings_config_builder_should_succeeds_when_node_spawn_timeout_is_missing() {
|
||||
let global_settings_config = GlobalSettingsBuilder::new()
|
||||
.with_raw_bootnodes_addresses(vec![
|
||||
"/ip4/10.41.122.55/tcp/45421",
|
||||
"/ip4/51.144.222.10/tcp/2333",
|
||||
])
|
||||
.with_network_spawn_timeout(600)
|
||||
.with_local_ip("10.0.0.1")
|
||||
.build()
|
||||
.unwrap();
|
||||
#[test]
|
||||
fn global_settings_config_builder_should_succeeds_when_node_spawn_timeout_is_missing() {
|
||||
let global_settings_config = GlobalSettingsBuilder::new()
|
||||
.with_raw_bootnodes_addresses(vec![
|
||||
"/ip4/10.41.122.55/tcp/45421",
|
||||
"/ip4/51.144.222.10/tcp/2333",
|
||||
])
|
||||
.with_network_spawn_timeout(600)
|
||||
.with_local_ip("10.0.0.1")
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let bootnodes_addresses: Vec<Multiaddr> = vec![
|
||||
"/ip4/10.41.122.55/tcp/45421".try_into().unwrap(),
|
||||
"/ip4/51.144.222.10/tcp/2333".try_into().unwrap(),
|
||||
];
|
||||
assert_eq!(
|
||||
global_settings_config.bootnodes_addresses(),
|
||||
bootnodes_addresses.iter().collect::<Vec<_>>()
|
||||
);
|
||||
assert_eq!(global_settings_config.network_spawn_timeout(), 600);
|
||||
assert_eq!(global_settings_config.node_spawn_timeout(), 600);
|
||||
assert_eq!(
|
||||
global_settings_config
|
||||
.local_ip()
|
||||
.unwrap()
|
||||
.to_string()
|
||||
.as_str(),
|
||||
"10.0.0.1"
|
||||
);
|
||||
}
|
||||
let bootnodes_addresses: Vec<Multiaddr> = vec![
|
||||
"/ip4/10.41.122.55/tcp/45421".try_into().unwrap(),
|
||||
"/ip4/51.144.222.10/tcp/2333".try_into().unwrap(),
|
||||
];
|
||||
assert_eq!(
|
||||
global_settings_config.bootnodes_addresses(),
|
||||
bootnodes_addresses.iter().collect::<Vec<_>>()
|
||||
);
|
||||
assert_eq!(global_settings_config.network_spawn_timeout(), 600);
|
||||
assert_eq!(global_settings_config.node_spawn_timeout(), 600);
|
||||
assert_eq!(global_settings_config.local_ip().unwrap().to_string().as_str(), "10.0.0.1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn global_settings_builder_should_fails_and_returns_an_error_if_one_bootnode_address_is_invalid(
|
||||
) {
|
||||
let errors = GlobalSettingsBuilder::new()
|
||||
.with_raw_bootnodes_addresses(vec!["/ip4//tcp/45421"])
|
||||
.build()
|
||||
.unwrap_err();
|
||||
#[test]
|
||||
fn global_settings_builder_should_fails_and_returns_an_error_if_one_bootnode_address_is_invalid(
|
||||
) {
|
||||
let errors = GlobalSettingsBuilder::new()
|
||||
.with_raw_bootnodes_addresses(vec!["/ip4//tcp/45421"])
|
||||
.build()
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(errors.len(), 1);
|
||||
assert_eq!(
|
||||
assert_eq!(errors.len(), 1);
|
||||
assert_eq!(
|
||||
errors.first().unwrap().to_string(),
|
||||
"global_settings.bootnodes_addresses[0]: '/ip4//tcp/45421' failed to parse: invalid IPv4 address syntax"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn global_settings_builder_should_fails_and_returns_multiple_errors_if_multiple_bootnodes_addresses_are_invalid(
|
||||
) {
|
||||
let errors = GlobalSettingsBuilder::new()
|
||||
.with_raw_bootnodes_addresses(vec!["/ip4//tcp/45421", "//10.42.153.10/tcp/43111"])
|
||||
.build()
|
||||
.unwrap_err();
|
||||
#[test]
|
||||
fn global_settings_builder_should_fails_and_returns_multiple_errors_if_multiple_bootnodes_addresses_are_invalid(
|
||||
) {
|
||||
let errors = GlobalSettingsBuilder::new()
|
||||
.with_raw_bootnodes_addresses(vec!["/ip4//tcp/45421", "//10.42.153.10/tcp/43111"])
|
||||
.build()
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(errors.len(), 2);
|
||||
assert_eq!(
|
||||
assert_eq!(errors.len(), 2);
|
||||
assert_eq!(
|
||||
errors.first().unwrap().to_string(),
|
||||
"global_settings.bootnodes_addresses[0]: '/ip4//tcp/45421' failed to parse: invalid IPv4 address syntax"
|
||||
);
|
||||
assert_eq!(
|
||||
assert_eq!(
|
||||
errors.get(1).unwrap().to_string(),
|
||||
"global_settings.bootnodes_addresses[1]: '//10.42.153.10/tcp/43111' unknown protocol string: "
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn global_settings_builder_should_fails_and_returns_an_error_if_local_ip_is_invalid() {
|
||||
let errors = GlobalSettingsBuilder::new()
|
||||
.with_local_ip("invalid")
|
||||
.build()
|
||||
.unwrap_err();
|
||||
#[test]
|
||||
fn global_settings_builder_should_fails_and_returns_an_error_if_local_ip_is_invalid() {
|
||||
let errors = GlobalSettingsBuilder::new().with_local_ip("invalid").build().unwrap_err();
|
||||
|
||||
assert_eq!(errors.len(), 1);
|
||||
assert_eq!(
|
||||
errors.first().unwrap().to_string(),
|
||||
"global_settings.local_ip: invalid IP address syntax"
|
||||
);
|
||||
}
|
||||
assert_eq!(errors.len(), 1);
|
||||
assert_eq!(
|
||||
errors.first().unwrap().to_string(),
|
||||
"global_settings.local_ip: invalid IP address syntax"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn global_settings_builder_should_fails_and_returns_multiple_errors_if_multiple_fields_are_invalid(
|
||||
) {
|
||||
let errors = GlobalSettingsBuilder::new()
|
||||
.with_raw_bootnodes_addresses(vec!["/ip4//tcp/45421", "//10.42.153.10/tcp/43111"])
|
||||
.with_local_ip("invalid")
|
||||
.build()
|
||||
.unwrap_err();
|
||||
#[test]
|
||||
fn global_settings_builder_should_fails_and_returns_multiple_errors_if_multiple_fields_are_invalid(
|
||||
) {
|
||||
let errors = GlobalSettingsBuilder::new()
|
||||
.with_raw_bootnodes_addresses(vec!["/ip4//tcp/45421", "//10.42.153.10/tcp/43111"])
|
||||
.with_local_ip("invalid")
|
||||
.build()
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(errors.len(), 3);
|
||||
assert_eq!(
|
||||
assert_eq!(errors.len(), 3);
|
||||
assert_eq!(
|
||||
errors.first().unwrap().to_string(),
|
||||
"global_settings.bootnodes_addresses[0]: '/ip4//tcp/45421' failed to parse: invalid IPv4 address syntax"
|
||||
);
|
||||
assert_eq!(
|
||||
assert_eq!(
|
||||
errors.get(1).unwrap().to_string(),
|
||||
"global_settings.bootnodes_addresses[1]: '//10.42.153.10/tcp/43111' unknown protocol string: "
|
||||
);
|
||||
assert_eq!(
|
||||
errors.get(2).unwrap().to_string(),
|
||||
"global_settings.local_ip: invalid IP address syntax"
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
errors.get(2).unwrap().to_string(),
|
||||
"global_settings.local_ip: invalid IP address syntax"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,131 +7,116 @@ use crate::shared::{macros::states, types::ParaId};
|
||||
/// HRMP channel configuration, with fine-grained configuration options.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct HrmpChannelConfig {
|
||||
sender: ParaId,
|
||||
recipient: ParaId,
|
||||
max_capacity: u32,
|
||||
max_message_size: u32,
|
||||
sender: ParaId,
|
||||
recipient: ParaId,
|
||||
max_capacity: u32,
|
||||
max_message_size: u32,
|
||||
}
|
||||
|
||||
impl HrmpChannelConfig {
|
||||
/// The sending parachain ID.
|
||||
pub fn sender(&self) -> ParaId {
|
||||
self.sender
|
||||
}
|
||||
/// The sending parachain ID.
|
||||
pub fn sender(&self) -> ParaId {
|
||||
self.sender
|
||||
}
|
||||
|
||||
/// The receiving parachain ID.
|
||||
pub fn recipient(&self) -> ParaId {
|
||||
self.recipient
|
||||
}
|
||||
/// The receiving parachain ID.
|
||||
pub fn recipient(&self) -> ParaId {
|
||||
self.recipient
|
||||
}
|
||||
|
||||
/// The maximum capacity of messages in the channel.
|
||||
pub fn max_capacity(&self) -> u32 {
|
||||
self.max_capacity
|
||||
}
|
||||
/// The maximum capacity of messages in the channel.
|
||||
pub fn max_capacity(&self) -> u32 {
|
||||
self.max_capacity
|
||||
}
|
||||
|
||||
/// The maximum size of a message in the channel.
|
||||
pub fn max_message_size(&self) -> u32 {
|
||||
self.max_message_size
|
||||
}
|
||||
/// The maximum size of a message in the channel.
|
||||
pub fn max_message_size(&self) -> u32 {
|
||||
self.max_message_size
|
||||
}
|
||||
}
|
||||
|
||||
states! {
|
||||
Initial,
|
||||
WithSender,
|
||||
WithRecipient
|
||||
Initial,
|
||||
WithSender,
|
||||
WithRecipient
|
||||
}
|
||||
|
||||
/// HRMP channel configuration builder, used to build an [`HrmpChannelConfig`] declaratively with fields validation.
|
||||
pub struct HrmpChannelConfigBuilder<State> {
|
||||
config: HrmpChannelConfig,
|
||||
_state: PhantomData<State>,
|
||||
config: HrmpChannelConfig,
|
||||
_state: PhantomData<State>,
|
||||
}
|
||||
|
||||
impl Default for HrmpChannelConfigBuilder<Initial> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
config: HrmpChannelConfig {
|
||||
sender: 0,
|
||||
recipient: 0,
|
||||
max_capacity: 8,
|
||||
max_message_size: 512,
|
||||
},
|
||||
_state: PhantomData,
|
||||
}
|
||||
}
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
config: HrmpChannelConfig {
|
||||
sender: 0,
|
||||
recipient: 0,
|
||||
max_capacity: 8,
|
||||
max_message_size: 512,
|
||||
},
|
||||
_state: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> HrmpChannelConfigBuilder<A> {
|
||||
fn transition<B>(&self, config: HrmpChannelConfig) -> HrmpChannelConfigBuilder<B> {
|
||||
HrmpChannelConfigBuilder {
|
||||
config,
|
||||
_state: PhantomData,
|
||||
}
|
||||
}
|
||||
fn transition<B>(&self, config: HrmpChannelConfig) -> HrmpChannelConfigBuilder<B> {
|
||||
HrmpChannelConfigBuilder { config, _state: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl HrmpChannelConfigBuilder<Initial> {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Set the sending parachain ID.
|
||||
pub fn with_sender(self, sender: ParaId) -> HrmpChannelConfigBuilder<WithSender> {
|
||||
self.transition(HrmpChannelConfig {
|
||||
sender,
|
||||
..self.config
|
||||
})
|
||||
}
|
||||
/// Set the sending parachain ID.
|
||||
pub fn with_sender(self, sender: ParaId) -> HrmpChannelConfigBuilder<WithSender> {
|
||||
self.transition(HrmpChannelConfig { sender, ..self.config })
|
||||
}
|
||||
}
|
||||
|
||||
impl HrmpChannelConfigBuilder<WithSender> {
|
||||
/// Set the receiving parachain ID.
|
||||
pub fn with_recipient(self, recipient: ParaId) -> HrmpChannelConfigBuilder<WithRecipient> {
|
||||
self.transition(HrmpChannelConfig {
|
||||
recipient,
|
||||
..self.config
|
||||
})
|
||||
}
|
||||
/// Set the receiving parachain ID.
|
||||
pub fn with_recipient(self, recipient: ParaId) -> HrmpChannelConfigBuilder<WithRecipient> {
|
||||
self.transition(HrmpChannelConfig { recipient, ..self.config })
|
||||
}
|
||||
}
|
||||
|
||||
impl HrmpChannelConfigBuilder<WithRecipient> {
|
||||
/// Set the max capacity of messages in the channel.
|
||||
pub fn with_max_capacity(self, max_capacity: u32) -> Self {
|
||||
self.transition(HrmpChannelConfig {
|
||||
max_capacity,
|
||||
..self.config
|
||||
})
|
||||
}
|
||||
/// Set the max capacity of messages in the channel.
|
||||
pub fn with_max_capacity(self, max_capacity: u32) -> Self {
|
||||
self.transition(HrmpChannelConfig { max_capacity, ..self.config })
|
||||
}
|
||||
|
||||
/// Set the maximum size of a message in the channel.
|
||||
pub fn with_max_message_size(self, max_message_size: u32) -> Self {
|
||||
self.transition(HrmpChannelConfig {
|
||||
max_message_size,
|
||||
..self.config
|
||||
})
|
||||
}
|
||||
/// Set the maximum size of a message in the channel.
|
||||
pub fn with_max_message_size(self, max_message_size: u32) -> Self {
|
||||
self.transition(HrmpChannelConfig { max_message_size, ..self.config })
|
||||
}
|
||||
|
||||
pub fn build(self) -> HrmpChannelConfig {
|
||||
self.config
|
||||
}
|
||||
pub fn build(self) -> HrmpChannelConfig {
|
||||
self.config
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn hrmp_channel_config_builder_should_build_a_new_hrmp_channel_config_correctly() {
|
||||
let hrmp_channel_config = HrmpChannelConfigBuilder::new()
|
||||
.with_sender(1000)
|
||||
.with_recipient(2000)
|
||||
.with_max_capacity(50)
|
||||
.with_max_message_size(100)
|
||||
.build();
|
||||
#[test]
|
||||
fn hrmp_channel_config_builder_should_build_a_new_hrmp_channel_config_correctly() {
|
||||
let hrmp_channel_config = HrmpChannelConfigBuilder::new()
|
||||
.with_sender(1000)
|
||||
.with_recipient(2000)
|
||||
.with_max_capacity(50)
|
||||
.with_max_message_size(100)
|
||||
.build();
|
||||
|
||||
assert_eq!(hrmp_channel_config.sender(), 1000);
|
||||
assert_eq!(hrmp_channel_config.recipient(), 2000);
|
||||
assert_eq!(hrmp_channel_config.max_capacity(), 50);
|
||||
assert_eq!(hrmp_channel_config.max_message_size(), 100);
|
||||
}
|
||||
assert_eq!(hrmp_channel_config.sender(), 1000);
|
||||
assert_eq!(hrmp_channel_config.recipient(), 2000);
|
||||
assert_eq!(hrmp_channel_config.max_capacity(), 50);
|
||||
assert_eq!(hrmp_channel_config.max_message_size(), 100);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ pub use relaychain::{RelaychainConfig, RelaychainConfigBuilder};
|
||||
// re-export shared
|
||||
pub use shared::{node::NodeConfig, types};
|
||||
pub use teyrchain::{
|
||||
states as para_states, RegistrationStrategy, TeyrchainConfig, TeyrchainConfigBuilder,
|
||||
states as para_states, RegistrationStrategy, TeyrchainConfig, TeyrchainConfigBuilder,
|
||||
};
|
||||
|
||||
// Backward compatibility aliases for external crates that use Polkadot SDK terminology
|
||||
|
||||
+1525
-1643
File diff suppressed because it is too large
Load Diff
+873
-977
File diff suppressed because it is too large
Load Diff
@@ -3,114 +3,114 @@ use super::types::{ParaId, Port};
|
||||
/// An error at the configuration level.
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum ConfigError {
|
||||
#[error("relaychain.{0}")]
|
||||
Relaychain(anyhow::Error),
|
||||
#[error("relaychain.{0}")]
|
||||
Relaychain(anyhow::Error),
|
||||
|
||||
#[error("teyrchain[{0}].{1}")]
|
||||
Teyrchain(ParaId, anyhow::Error),
|
||||
#[error("teyrchain[{0}].{1}")]
|
||||
Teyrchain(ParaId, anyhow::Error),
|
||||
|
||||
#[error("global_settings.{0}")]
|
||||
GlobalSettings(anyhow::Error),
|
||||
#[error("global_settings.{0}")]
|
||||
GlobalSettings(anyhow::Error),
|
||||
|
||||
#[error("nodes['{0}'].{1}")]
|
||||
Node(String, anyhow::Error),
|
||||
#[error("nodes['{0}'].{1}")]
|
||||
Node(String, anyhow::Error),
|
||||
|
||||
#[error("collators['{0}'].{1}")]
|
||||
Collator(String, anyhow::Error),
|
||||
#[error("collators['{0}'].{1}")]
|
||||
Collator(String, anyhow::Error),
|
||||
}
|
||||
|
||||
/// An error at the field level.
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum FieldError {
|
||||
#[error("name: {0}")]
|
||||
Name(anyhow::Error),
|
||||
#[error("name: {0}")]
|
||||
Name(anyhow::Error),
|
||||
|
||||
#[error("chain: {0}")]
|
||||
Chain(anyhow::Error),
|
||||
#[error("chain: {0}")]
|
||||
Chain(anyhow::Error),
|
||||
|
||||
#[error("image: {0}")]
|
||||
Image(anyhow::Error),
|
||||
#[error("image: {0}")]
|
||||
Image(anyhow::Error),
|
||||
|
||||
#[error("default_image: {0}")]
|
||||
DefaultImage(anyhow::Error),
|
||||
#[error("default_image: {0}")]
|
||||
DefaultImage(anyhow::Error),
|
||||
|
||||
#[error("command: {0}")]
|
||||
Command(anyhow::Error),
|
||||
#[error("command: {0}")]
|
||||
Command(anyhow::Error),
|
||||
|
||||
#[error("default_command: {0}")]
|
||||
DefaultCommand(anyhow::Error),
|
||||
#[error("default_command: {0}")]
|
||||
DefaultCommand(anyhow::Error),
|
||||
|
||||
#[error("bootnodes_addresses[{0}]: '{1}' {2}")]
|
||||
BootnodesAddress(usize, String, anyhow::Error),
|
||||
#[error("bootnodes_addresses[{0}]: '{1}' {2}")]
|
||||
BootnodesAddress(usize, String, anyhow::Error),
|
||||
|
||||
#[error("genesis_wasm_generator: {0}")]
|
||||
GenesisWasmGenerator(anyhow::Error),
|
||||
#[error("genesis_wasm_generator: {0}")]
|
||||
GenesisWasmGenerator(anyhow::Error),
|
||||
|
||||
#[error("genesis_state_generator: {0}")]
|
||||
GenesisStateGenerator(anyhow::Error),
|
||||
#[error("genesis_state_generator: {0}")]
|
||||
GenesisStateGenerator(anyhow::Error),
|
||||
|
||||
#[error("local_ip: {0}")]
|
||||
LocalIp(anyhow::Error),
|
||||
#[error("local_ip: {0}")]
|
||||
LocalIp(anyhow::Error),
|
||||
|
||||
#[error("default_resources.{0}")]
|
||||
DefaultResources(anyhow::Error),
|
||||
#[error("default_resources.{0}")]
|
||||
DefaultResources(anyhow::Error),
|
||||
|
||||
#[error("resources.{0}")]
|
||||
Resources(anyhow::Error),
|
||||
#[error("resources.{0}")]
|
||||
Resources(anyhow::Error),
|
||||
|
||||
#[error("request_memory: {0}")]
|
||||
RequestMemory(anyhow::Error),
|
||||
#[error("request_memory: {0}")]
|
||||
RequestMemory(anyhow::Error),
|
||||
|
||||
#[error("request_cpu: {0}")]
|
||||
RequestCpu(anyhow::Error),
|
||||
#[error("request_cpu: {0}")]
|
||||
RequestCpu(anyhow::Error),
|
||||
|
||||
#[error("limit_memory: {0}")]
|
||||
LimitMemory(anyhow::Error),
|
||||
#[error("limit_memory: {0}")]
|
||||
LimitMemory(anyhow::Error),
|
||||
|
||||
#[error("limit_cpu: {0}")]
|
||||
LimitCpu(anyhow::Error),
|
||||
#[error("limit_cpu: {0}")]
|
||||
LimitCpu(anyhow::Error),
|
||||
|
||||
#[error("ws_port: {0}")]
|
||||
WsPort(anyhow::Error),
|
||||
#[error("ws_port: {0}")]
|
||||
WsPort(anyhow::Error),
|
||||
|
||||
#[error("rpc_port: {0}")]
|
||||
RpcPort(anyhow::Error),
|
||||
#[error("rpc_port: {0}")]
|
||||
RpcPort(anyhow::Error),
|
||||
|
||||
#[error("prometheus_port: {0}")]
|
||||
PrometheusPort(anyhow::Error),
|
||||
#[error("prometheus_port: {0}")]
|
||||
PrometheusPort(anyhow::Error),
|
||||
|
||||
#[error("p2p_port: {0}")]
|
||||
P2pPort(anyhow::Error),
|
||||
#[error("p2p_port: {0}")]
|
||||
P2pPort(anyhow::Error),
|
||||
|
||||
#[error("session_key: {0}")]
|
||||
SessionKey(anyhow::Error),
|
||||
#[error("session_key: {0}")]
|
||||
SessionKey(anyhow::Error),
|
||||
|
||||
#[error("registration_strategy: {0}")]
|
||||
RegistrationStrategy(anyhow::Error),
|
||||
#[error("registration_strategy: {0}")]
|
||||
RegistrationStrategy(anyhow::Error),
|
||||
}
|
||||
|
||||
/// A conversion error for shared types across fields.
|
||||
#[derive(thiserror::Error, Debug, Clone)]
|
||||
pub enum ConversionError {
|
||||
#[error("'{0}' shouldn't contains whitespace")]
|
||||
ContainsWhitespaces(String),
|
||||
#[error("'{0}' shouldn't contains whitespace")]
|
||||
ContainsWhitespaces(String),
|
||||
|
||||
#[error("'{}' doesn't match regex '{}'", .value, .regex)]
|
||||
DoesntMatchRegex { value: String, regex: String },
|
||||
#[error("'{}' doesn't match regex '{}'", .value, .regex)]
|
||||
DoesntMatchRegex { value: String, regex: String },
|
||||
|
||||
#[error("can't be empty")]
|
||||
CantBeEmpty,
|
||||
#[error("can't be empty")]
|
||||
CantBeEmpty,
|
||||
|
||||
#[error("deserialize error")]
|
||||
DeserializeError(String),
|
||||
#[error("deserialize error")]
|
||||
DeserializeError(String),
|
||||
}
|
||||
|
||||
/// A validation error for shared types across fields.
|
||||
#[derive(thiserror::Error, Debug, Clone)]
|
||||
pub enum ValidationError {
|
||||
#[error("'{0}' is already used across config")]
|
||||
PortAlreadyUsed(Port),
|
||||
#[error("'{0}' is already used across config")]
|
||||
PortAlreadyUsed(Port),
|
||||
|
||||
#[error("can't be empty")]
|
||||
CantBeEmpty(),
|
||||
#[error("can't be empty")]
|
||||
CantBeEmpty(),
|
||||
}
|
||||
|
||||
@@ -4,28 +4,28 @@ use support::constants::{BORROWABLE, THIS_IS_A_BUG};
|
||||
use tracing::warn;
|
||||
|
||||
use super::{
|
||||
errors::ValidationError,
|
||||
types::{ParaId, Port, ValidationContext},
|
||||
errors::ValidationError,
|
||||
types::{ParaId, Port, ValidationContext},
|
||||
};
|
||||
|
||||
pub fn merge_errors(errors: Vec<anyhow::Error>, new_error: anyhow::Error) -> Vec<anyhow::Error> {
|
||||
let mut errors = errors;
|
||||
errors.push(new_error);
|
||||
let mut errors = errors;
|
||||
errors.push(new_error);
|
||||
|
||||
errors
|
||||
errors
|
||||
}
|
||||
|
||||
pub fn merge_errors_vecs(
|
||||
errors: Vec<anyhow::Error>,
|
||||
new_errors: Vec<anyhow::Error>,
|
||||
errors: Vec<anyhow::Error>,
|
||||
new_errors: Vec<anyhow::Error>,
|
||||
) -> Vec<anyhow::Error> {
|
||||
let mut errors = errors;
|
||||
let mut errors = errors;
|
||||
|
||||
for new_error in new_errors.into_iter() {
|
||||
errors.push(new_error);
|
||||
}
|
||||
for new_error in new_errors.into_iter() {
|
||||
errors.push(new_error);
|
||||
}
|
||||
|
||||
errors
|
||||
errors
|
||||
}
|
||||
|
||||
/// Generates a unique name from a base name and the names already present in a
|
||||
@@ -34,14 +34,13 @@ pub fn merge_errors_vecs(
|
||||
/// Uses [`generate_unique_node_name_from_names()`] internally to ensure uniqueness.
|
||||
/// Logs a warning if the generated name differs from the original due to duplicates.
|
||||
pub fn generate_unique_node_name(
|
||||
node_name: impl Into<String>,
|
||||
validation_context: Rc<RefCell<ValidationContext>>,
|
||||
node_name: impl Into<String>,
|
||||
validation_context: Rc<RefCell<ValidationContext>>,
|
||||
) -> String {
|
||||
let mut context = validation_context
|
||||
.try_borrow_mut()
|
||||
.expect(&format!("{BORROWABLE}, {THIS_IS_A_BUG}"));
|
||||
let mut context =
|
||||
validation_context.try_borrow_mut().expect(&format!("{BORROWABLE}, {THIS_IS_A_BUG}"));
|
||||
|
||||
generate_unique_node_name_from_names(node_name, &mut context.used_nodes_names)
|
||||
generate_unique_node_name_from_names(node_name, &mut context.used_nodes_names)
|
||||
}
|
||||
|
||||
/// Returns `node_name` if it is not already in `names`.
|
||||
@@ -49,70 +48,68 @@ pub fn generate_unique_node_name(
|
||||
/// Otherwise, appends an incrementing `-{counter}` suffix until a unique name is found,
|
||||
/// then returns it. Logs a warning when a duplicate is detected.
|
||||
pub fn generate_unique_node_name_from_names(
|
||||
node_name: impl Into<String>,
|
||||
names: &mut HashSet<String>,
|
||||
node_name: impl Into<String>,
|
||||
names: &mut HashSet<String>,
|
||||
) -> String {
|
||||
let node_name = node_name.into();
|
||||
let node_name = node_name.into();
|
||||
|
||||
if names.insert(node_name.clone()) {
|
||||
return node_name;
|
||||
}
|
||||
if names.insert(node_name.clone()) {
|
||||
return node_name;
|
||||
}
|
||||
|
||||
let mut counter = 1;
|
||||
let mut candidate = node_name.clone();
|
||||
while names.contains(&candidate) {
|
||||
candidate = format!("{node_name}-{counter}");
|
||||
counter += 1;
|
||||
}
|
||||
let mut counter = 1;
|
||||
let mut candidate = node_name.clone();
|
||||
while names.contains(&candidate) {
|
||||
candidate = format!("{node_name}-{counter}");
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
warn!(
|
||||
original = %node_name,
|
||||
adjusted = %candidate,
|
||||
"Duplicate node name detected."
|
||||
);
|
||||
warn!(
|
||||
original = %node_name,
|
||||
adjusted = %candidate,
|
||||
"Duplicate node name detected."
|
||||
);
|
||||
|
||||
names.insert(candidate.clone());
|
||||
candidate
|
||||
names.insert(candidate.clone());
|
||||
candidate
|
||||
}
|
||||
|
||||
pub fn ensure_value_is_not_empty(value: &str) -> Result<(), anyhow::Error> {
|
||||
if value.is_empty() {
|
||||
Err(ValidationError::CantBeEmpty().into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
if value.is_empty() {
|
||||
Err(ValidationError::CantBeEmpty().into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ensure_port_unique(
|
||||
port: Port,
|
||||
validation_context: Rc<RefCell<ValidationContext>>,
|
||||
port: Port,
|
||||
validation_context: Rc<RefCell<ValidationContext>>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
let mut context = validation_context
|
||||
.try_borrow_mut()
|
||||
.expect(&format!("{BORROWABLE}, {THIS_IS_A_BUG}"));
|
||||
let mut context =
|
||||
validation_context.try_borrow_mut().expect(&format!("{BORROWABLE}, {THIS_IS_A_BUG}"));
|
||||
|
||||
if !context.used_ports.contains(&port) {
|
||||
context.used_ports.push(port);
|
||||
return Ok(());
|
||||
}
|
||||
if !context.used_ports.contains(&port) {
|
||||
context.used_ports.push(port);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err(ValidationError::PortAlreadyUsed(port).into())
|
||||
Err(ValidationError::PortAlreadyUsed(port).into())
|
||||
}
|
||||
|
||||
pub fn generate_unique_para_id(
|
||||
para_id: ParaId,
|
||||
validation_context: Rc<RefCell<ValidationContext>>,
|
||||
para_id: ParaId,
|
||||
validation_context: Rc<RefCell<ValidationContext>>,
|
||||
) -> String {
|
||||
let mut context = validation_context
|
||||
.try_borrow_mut()
|
||||
.expect(&format!("{BORROWABLE}, {THIS_IS_A_BUG}"));
|
||||
let mut context =
|
||||
validation_context.try_borrow_mut().expect(&format!("{BORROWABLE}, {THIS_IS_A_BUG}"));
|
||||
|
||||
if let Some(suffix) = context.used_para_ids.get_mut(¶_id) {
|
||||
*suffix += 1;
|
||||
format!("{para_id}-{suffix}")
|
||||
} else {
|
||||
// insert 0, since will be used next time.
|
||||
context.used_para_ids.insert(para_id, 0);
|
||||
para_id.to_string()
|
||||
}
|
||||
if let Some(suffix) = context.used_para_ids.get_mut(¶_id) {
|
||||
*suffix += 1;
|
||||
format!("{para_id}-{suffix}")
|
||||
} else {
|
||||
// insert 0, since will be used next time.
|
||||
context.used_para_ids.insert(para_id, 0);
|
||||
para_id.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
+1040
-1139
File diff suppressed because it is too large
Load Diff
+339
-358
@@ -3,15 +3,15 @@ use std::error::Error;
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
use serde::{
|
||||
de::{self},
|
||||
ser::SerializeStruct,
|
||||
Deserialize, Serialize,
|
||||
de::{self},
|
||||
ser::SerializeStruct,
|
||||
Deserialize, Serialize,
|
||||
};
|
||||
use support::constants::{SHOULD_COMPILE, THIS_IS_A_BUG};
|
||||
|
||||
use super::{
|
||||
errors::{ConversionError, FieldError},
|
||||
helpers::merge_errors,
|
||||
errors::{ConversionError, FieldError},
|
||||
helpers::merge_errors,
|
||||
};
|
||||
|
||||
/// A resource quantity used to define limits (k8s/podman only).
|
||||
@@ -37,453 +37,434 @@ use super::{
|
||||
pub struct ResourceQuantity(String);
|
||||
|
||||
impl ResourceQuantity {
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for ResourceQuantity {
|
||||
type Error = ConversionError;
|
||||
type Error = ConversionError;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
lazy_static! {
|
||||
static ref RE: Regex = Regex::new(r"^\d+(.\d+)?(m|K|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$")
|
||||
.expect(&format!("{SHOULD_COMPILE}, {THIS_IS_A_BUG}"));
|
||||
}
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
lazy_static! {
|
||||
static ref RE: Regex = Regex::new(r"^\d+(.\d+)?(m|K|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$")
|
||||
.expect(&format!("{SHOULD_COMPILE}, {THIS_IS_A_BUG}"));
|
||||
}
|
||||
|
||||
if !RE.is_match(value) {
|
||||
return Err(ConversionError::DoesntMatchRegex {
|
||||
value: value.to_string(),
|
||||
regex: r"^\d+(.\d+)?(m|K|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$".to_string(),
|
||||
});
|
||||
}
|
||||
if !RE.is_match(value) {
|
||||
return Err(ConversionError::DoesntMatchRegex {
|
||||
value: value.to_string(),
|
||||
regex: r"^\d+(.\d+)?(m|K|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$".to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(Self(value.to_string()))
|
||||
}
|
||||
Ok(Self(value.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for ResourceQuantity {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value.to_string())
|
||||
}
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// Resources limits used in the context of podman/k8s.
|
||||
#[derive(Debug, Default, Clone, PartialEq)]
|
||||
pub struct Resources {
|
||||
request_memory: Option<ResourceQuantity>,
|
||||
request_cpu: Option<ResourceQuantity>,
|
||||
limit_memory: Option<ResourceQuantity>,
|
||||
limit_cpu: Option<ResourceQuantity>,
|
||||
request_memory: Option<ResourceQuantity>,
|
||||
request_cpu: Option<ResourceQuantity>,
|
||||
limit_memory: Option<ResourceQuantity>,
|
||||
limit_cpu: Option<ResourceQuantity>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct ResourcesField {
|
||||
memory: Option<ResourceQuantity>,
|
||||
cpu: Option<ResourceQuantity>,
|
||||
memory: Option<ResourceQuantity>,
|
||||
cpu: Option<ResourceQuantity>,
|
||||
}
|
||||
|
||||
impl Serialize for Resources {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut state = serializer.serialize_struct("Resources", 2)?;
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut state = serializer.serialize_struct("Resources", 2)?;
|
||||
|
||||
if self.request_memory.is_some() || self.request_memory.is_some() {
|
||||
state.serialize_field(
|
||||
"requests",
|
||||
&ResourcesField {
|
||||
memory: self.request_memory.clone(),
|
||||
cpu: self.request_cpu.clone(),
|
||||
},
|
||||
)?;
|
||||
} else {
|
||||
state.skip_field("requests")?;
|
||||
}
|
||||
if self.request_memory.is_some() || self.request_memory.is_some() {
|
||||
state.serialize_field(
|
||||
"requests",
|
||||
&ResourcesField {
|
||||
memory: self.request_memory.clone(),
|
||||
cpu: self.request_cpu.clone(),
|
||||
},
|
||||
)?;
|
||||
} else {
|
||||
state.skip_field("requests")?;
|
||||
}
|
||||
|
||||
if self.limit_memory.is_some() || self.limit_memory.is_some() {
|
||||
state.serialize_field(
|
||||
"limits",
|
||||
&ResourcesField {
|
||||
memory: self.limit_memory.clone(),
|
||||
cpu: self.limit_cpu.clone(),
|
||||
},
|
||||
)?;
|
||||
} else {
|
||||
state.skip_field("limits")?;
|
||||
}
|
||||
if self.limit_memory.is_some() || self.limit_memory.is_some() {
|
||||
state.serialize_field(
|
||||
"limits",
|
||||
&ResourcesField { memory: self.limit_memory.clone(), cpu: self.limit_cpu.clone() },
|
||||
)?;
|
||||
} else {
|
||||
state.skip_field("limits")?;
|
||||
}
|
||||
|
||||
state.end()
|
||||
}
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
|
||||
struct ResourcesVisitor;
|
||||
|
||||
impl<'de> de::Visitor<'de> for ResourcesVisitor {
|
||||
type Value = Resources;
|
||||
type Value = Resources;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("a resources object")
|
||||
}
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("a resources object")
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: de::MapAccess<'de>,
|
||||
{
|
||||
let mut resources: Resources = Resources::default();
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: de::MapAccess<'de>,
|
||||
{
|
||||
let mut resources: Resources = Resources::default();
|
||||
|
||||
while let Some((key, value)) = map.next_entry::<String, ResourcesField>()? {
|
||||
match key.as_str() {
|
||||
"requests" => {
|
||||
resources.request_memory = value.memory;
|
||||
resources.request_cpu = value.cpu;
|
||||
},
|
||||
"limits" => {
|
||||
resources.limit_memory = value.memory;
|
||||
resources.limit_cpu = value.cpu;
|
||||
},
|
||||
_ => {
|
||||
return Err(de::Error::unknown_field(
|
||||
&key,
|
||||
&["requests", "limits", "cpu", "memory"],
|
||||
))
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(resources)
|
||||
}
|
||||
while let Some((key, value)) = map.next_entry::<String, ResourcesField>()? {
|
||||
match key.as_str() {
|
||||
"requests" => {
|
||||
resources.request_memory = value.memory;
|
||||
resources.request_cpu = value.cpu;
|
||||
},
|
||||
"limits" => {
|
||||
resources.limit_memory = value.memory;
|
||||
resources.limit_cpu = value.cpu;
|
||||
},
|
||||
_ => {
|
||||
return Err(de::Error::unknown_field(
|
||||
&key,
|
||||
&["requests", "limits", "cpu", "memory"],
|
||||
))
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(resources)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Resources {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_any(ResourcesVisitor)
|
||||
}
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_any(ResourcesVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl Resources {
|
||||
/// Memory limit applied to requests.
|
||||
pub fn request_memory(&self) -> Option<&ResourceQuantity> {
|
||||
self.request_memory.as_ref()
|
||||
}
|
||||
/// Memory limit applied to requests.
|
||||
pub fn request_memory(&self) -> Option<&ResourceQuantity> {
|
||||
self.request_memory.as_ref()
|
||||
}
|
||||
|
||||
/// CPU limit applied to requests.
|
||||
pub fn request_cpu(&self) -> Option<&ResourceQuantity> {
|
||||
self.request_cpu.as_ref()
|
||||
}
|
||||
/// CPU limit applied to requests.
|
||||
pub fn request_cpu(&self) -> Option<&ResourceQuantity> {
|
||||
self.request_cpu.as_ref()
|
||||
}
|
||||
|
||||
/// Overall memory limit applied.
|
||||
pub fn limit_memory(&self) -> Option<&ResourceQuantity> {
|
||||
self.limit_memory.as_ref()
|
||||
}
|
||||
/// Overall memory limit applied.
|
||||
pub fn limit_memory(&self) -> Option<&ResourceQuantity> {
|
||||
self.limit_memory.as_ref()
|
||||
}
|
||||
|
||||
/// Overall CPU limit applied.
|
||||
pub fn limit_cpu(&self) -> Option<&ResourceQuantity> {
|
||||
self.limit_cpu.as_ref()
|
||||
}
|
||||
/// Overall CPU limit applied.
|
||||
pub fn limit_cpu(&self) -> Option<&ResourceQuantity> {
|
||||
self.limit_cpu.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// A resources builder, used to build a [`Resources`] declaratively with fields validation.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ResourcesBuilder {
|
||||
config: Resources,
|
||||
errors: Vec<anyhow::Error>,
|
||||
config: Resources,
|
||||
errors: Vec<anyhow::Error>,
|
||||
}
|
||||
|
||||
impl ResourcesBuilder {
|
||||
pub fn new() -> ResourcesBuilder {
|
||||
Self::default()
|
||||
}
|
||||
pub fn new() -> ResourcesBuilder {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
fn transition(config: Resources, errors: Vec<anyhow::Error>) -> Self {
|
||||
Self { config, errors }
|
||||
}
|
||||
fn transition(config: Resources, errors: Vec<anyhow::Error>) -> Self {
|
||||
Self { config, errors }
|
||||
}
|
||||
|
||||
/// Set the requested memory for a pod. This is the minimum memory allocated for a pod.
|
||||
pub fn with_request_memory<T>(self, quantity: T) -> Self
|
||||
where
|
||||
T: TryInto<ResourceQuantity>,
|
||||
T::Error: Error + Send + Sync + 'static,
|
||||
{
|
||||
match quantity.try_into() {
|
||||
Ok(quantity) => Self::transition(
|
||||
Resources {
|
||||
request_memory: Some(quantity),
|
||||
..self.config
|
||||
},
|
||||
self.errors,
|
||||
),
|
||||
Err(error) => Self::transition(
|
||||
self.config,
|
||||
merge_errors(self.errors, FieldError::RequestMemory(error.into()).into()),
|
||||
),
|
||||
}
|
||||
}
|
||||
/// Set the requested memory for a pod. This is the minimum memory allocated for a pod.
|
||||
pub fn with_request_memory<T>(self, quantity: T) -> Self
|
||||
where
|
||||
T: TryInto<ResourceQuantity>,
|
||||
T::Error: Error + Send + Sync + 'static,
|
||||
{
|
||||
match quantity.try_into() {
|
||||
Ok(quantity) => Self::transition(
|
||||
Resources { request_memory: Some(quantity), ..self.config },
|
||||
self.errors,
|
||||
),
|
||||
Err(error) => Self::transition(
|
||||
self.config,
|
||||
merge_errors(self.errors, FieldError::RequestMemory(error.into()).into()),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the requested CPU limit for a pod. This is the minimum CPU allocated for a pod.
|
||||
pub fn with_request_cpu<T>(self, quantity: T) -> Self
|
||||
where
|
||||
T: TryInto<ResourceQuantity>,
|
||||
T::Error: Error + Send + Sync + 'static,
|
||||
{
|
||||
match quantity.try_into() {
|
||||
Ok(quantity) => Self::transition(
|
||||
Resources {
|
||||
request_cpu: Some(quantity),
|
||||
..self.config
|
||||
},
|
||||
self.errors,
|
||||
),
|
||||
Err(error) => Self::transition(
|
||||
self.config,
|
||||
merge_errors(self.errors, FieldError::RequestCpu(error.into()).into()),
|
||||
),
|
||||
}
|
||||
}
|
||||
/// Set the requested CPU limit for a pod. This is the minimum CPU allocated for a pod.
|
||||
pub fn with_request_cpu<T>(self, quantity: T) -> Self
|
||||
where
|
||||
T: TryInto<ResourceQuantity>,
|
||||
T::Error: Error + Send + Sync + 'static,
|
||||
{
|
||||
match quantity.try_into() {
|
||||
Ok(quantity) => Self::transition(
|
||||
Resources { request_cpu: Some(quantity), ..self.config },
|
||||
self.errors,
|
||||
),
|
||||
Err(error) => Self::transition(
|
||||
self.config,
|
||||
merge_errors(self.errors, FieldError::RequestCpu(error.into()).into()),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the overall memory limit for a pod. This is the maximum memory threshold for a pod.
|
||||
pub fn with_limit_memory<T>(self, quantity: T) -> Self
|
||||
where
|
||||
T: TryInto<ResourceQuantity>,
|
||||
T::Error: Error + Send + Sync + 'static,
|
||||
{
|
||||
match quantity.try_into() {
|
||||
Ok(quantity) => Self::transition(
|
||||
Resources {
|
||||
limit_memory: Some(quantity),
|
||||
..self.config
|
||||
},
|
||||
self.errors,
|
||||
),
|
||||
Err(error) => Self::transition(
|
||||
self.config,
|
||||
merge_errors(self.errors, FieldError::LimitMemory(error.into()).into()),
|
||||
),
|
||||
}
|
||||
}
|
||||
/// Set the overall memory limit for a pod. This is the maximum memory threshold for a pod.
|
||||
pub fn with_limit_memory<T>(self, quantity: T) -> Self
|
||||
where
|
||||
T: TryInto<ResourceQuantity>,
|
||||
T::Error: Error + Send + Sync + 'static,
|
||||
{
|
||||
match quantity.try_into() {
|
||||
Ok(quantity) => Self::transition(
|
||||
Resources { limit_memory: Some(quantity), ..self.config },
|
||||
self.errors,
|
||||
),
|
||||
Err(error) => Self::transition(
|
||||
self.config,
|
||||
merge_errors(self.errors, FieldError::LimitMemory(error.into()).into()),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the overall CPU limit for a pod. This is the maximum CPU threshold for a pod.
|
||||
pub fn with_limit_cpu<T>(self, quantity: T) -> Self
|
||||
where
|
||||
T: TryInto<ResourceQuantity>,
|
||||
T::Error: Error + Send + Sync + 'static,
|
||||
{
|
||||
match quantity.try_into() {
|
||||
Ok(quantity) => Self::transition(
|
||||
Resources {
|
||||
limit_cpu: Some(quantity),
|
||||
..self.config
|
||||
},
|
||||
self.errors,
|
||||
),
|
||||
Err(error) => Self::transition(
|
||||
self.config,
|
||||
merge_errors(self.errors, FieldError::LimitCpu(error.into()).into()),
|
||||
),
|
||||
}
|
||||
}
|
||||
/// Set the overall CPU limit for a pod. This is the maximum CPU threshold for a pod.
|
||||
pub fn with_limit_cpu<T>(self, quantity: T) -> Self
|
||||
where
|
||||
T: TryInto<ResourceQuantity>,
|
||||
T::Error: Error + Send + Sync + 'static,
|
||||
{
|
||||
match quantity.try_into() {
|
||||
Ok(quantity) => Self::transition(
|
||||
Resources { limit_cpu: Some(quantity), ..self.config },
|
||||
self.errors,
|
||||
),
|
||||
Err(error) => Self::transition(
|
||||
self.config,
|
||||
merge_errors(self.errors, FieldError::LimitCpu(error.into()).into()),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Seals the builder and returns a [`Resources`] if there are no validation errors, else returns errors.
|
||||
pub fn build(self) -> Result<Resources, Vec<anyhow::Error>> {
|
||||
if !self.errors.is_empty() {
|
||||
return Err(self.errors);
|
||||
}
|
||||
/// Seals the builder and returns a [`Resources`] if there are no validation errors, else returns errors.
|
||||
pub fn build(self) -> Result<Resources, Vec<anyhow::Error>> {
|
||||
if !self.errors.is_empty() {
|
||||
return Err(self.errors);
|
||||
}
|
||||
|
||||
Ok(self.config)
|
||||
}
|
||||
Ok(self.config)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(non_snake_case)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::NetworkConfig;
|
||||
use super::*;
|
||||
use crate::NetworkConfig;
|
||||
|
||||
macro_rules! impl_resources_quantity_unit_test {
|
||||
($val:literal) => {{
|
||||
let resources = ResourcesBuilder::new()
|
||||
.with_request_memory($val)
|
||||
.build()
|
||||
.unwrap();
|
||||
macro_rules! impl_resources_quantity_unit_test {
|
||||
($val:literal) => {{
|
||||
let resources = ResourcesBuilder::new().with_request_memory($val).build().unwrap();
|
||||
|
||||
assert_eq!(resources.request_memory().unwrap().as_str(), $val);
|
||||
assert_eq!(resources.request_cpu(), None);
|
||||
assert_eq!(resources.limit_cpu(), None);
|
||||
assert_eq!(resources.limit_memory(), None);
|
||||
}};
|
||||
}
|
||||
assert_eq!(resources.request_memory().unwrap().as_str(), $val);
|
||||
assert_eq!(resources.request_cpu(), None);
|
||||
assert_eq!(resources.limit_cpu(), None);
|
||||
assert_eq!(resources.limit_memory(), None);
|
||||
}};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converting_a_string_a_resource_quantity_without_unit_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("1000");
|
||||
}
|
||||
#[test]
|
||||
fn converting_a_string_a_resource_quantity_without_unit_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("1000");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converting_a_str_with_m_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("100m");
|
||||
}
|
||||
#[test]
|
||||
fn converting_a_str_with_m_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("100m");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converting_a_str_with_K_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("50K");
|
||||
}
|
||||
#[test]
|
||||
fn converting_a_str_with_K_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("50K");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converting_a_str_with_M_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("100M");
|
||||
}
|
||||
#[test]
|
||||
fn converting_a_str_with_M_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("100M");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converting_a_str_with_G_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("1G");
|
||||
}
|
||||
#[test]
|
||||
fn converting_a_str_with_G_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("1G");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converting_a_str_with_T_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("0.01T");
|
||||
}
|
||||
#[test]
|
||||
fn converting_a_str_with_T_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("0.01T");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converting_a_str_with_P_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("0.00001P");
|
||||
}
|
||||
#[test]
|
||||
fn converting_a_str_with_P_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("0.00001P");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converting_a_str_with_E_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("0.000000001E");
|
||||
}
|
||||
#[test]
|
||||
fn converting_a_str_with_E_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("0.000000001E");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converting_a_str_with_Ki_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("50Ki");
|
||||
}
|
||||
#[test]
|
||||
fn converting_a_str_with_Ki_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("50Ki");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converting_a_str_with_Mi_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("100Mi");
|
||||
}
|
||||
#[test]
|
||||
fn converting_a_str_with_Mi_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("100Mi");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converting_a_str_with_Gi_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("1Gi");
|
||||
}
|
||||
#[test]
|
||||
fn converting_a_str_with_Gi_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("1Gi");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converting_a_str_with_Ti_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("0.01Ti");
|
||||
}
|
||||
#[test]
|
||||
fn converting_a_str_with_Ti_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("0.01Ti");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converting_a_str_with_Pi_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("0.00001Pi");
|
||||
}
|
||||
#[test]
|
||||
fn converting_a_str_with_Pi_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("0.00001Pi");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converting_a_str_with_Ei_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("0.000000001Ei");
|
||||
}
|
||||
#[test]
|
||||
fn converting_a_str_with_Ei_unit_into_a_resource_quantity_should_succeeds() {
|
||||
impl_resources_quantity_unit_test!("0.000000001Ei");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resources_config_builder_should_succeeds_and_returns_a_resources_config() {
|
||||
let resources = ResourcesBuilder::new()
|
||||
.with_request_memory("200M")
|
||||
.with_request_cpu("1G")
|
||||
.with_limit_cpu("500M")
|
||||
.with_limit_memory("2G")
|
||||
.build()
|
||||
.unwrap();
|
||||
#[test]
|
||||
fn resources_config_builder_should_succeeds_and_returns_a_resources_config() {
|
||||
let resources = ResourcesBuilder::new()
|
||||
.with_request_memory("200M")
|
||||
.with_request_cpu("1G")
|
||||
.with_limit_cpu("500M")
|
||||
.with_limit_memory("2G")
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(resources.request_memory().unwrap().as_str(), "200M");
|
||||
assert_eq!(resources.request_cpu().unwrap().as_str(), "1G");
|
||||
assert_eq!(resources.limit_cpu().unwrap().as_str(), "500M");
|
||||
assert_eq!(resources.limit_memory().unwrap().as_str(), "2G");
|
||||
}
|
||||
assert_eq!(resources.request_memory().unwrap().as_str(), "200M");
|
||||
assert_eq!(resources.request_cpu().unwrap().as_str(), "1G");
|
||||
assert_eq!(resources.limit_cpu().unwrap().as_str(), "500M");
|
||||
assert_eq!(resources.limit_memory().unwrap().as_str(), "2G");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resources_config_toml_import_should_succeeds_and_returns_a_resources_config() {
|
||||
let load_from_toml =
|
||||
NetworkConfig::load_from_toml("./testing/snapshots/0001-big-network.toml").unwrap();
|
||||
#[test]
|
||||
fn resources_config_toml_import_should_succeeds_and_returns_a_resources_config() {
|
||||
let load_from_toml =
|
||||
NetworkConfig::load_from_toml("./testing/snapshots/0001-big-network.toml").unwrap();
|
||||
|
||||
let resources = load_from_toml.relaychain().default_resources().unwrap();
|
||||
assert_eq!(resources.request_memory().unwrap().as_str(), "500M");
|
||||
assert_eq!(resources.request_cpu().unwrap().as_str(), "100000");
|
||||
assert_eq!(resources.limit_cpu().unwrap().as_str(), "10Gi");
|
||||
assert_eq!(resources.limit_memory().unwrap().as_str(), "4000M");
|
||||
}
|
||||
let resources = load_from_toml.relaychain().default_resources().unwrap();
|
||||
assert_eq!(resources.request_memory().unwrap().as_str(), "500M");
|
||||
assert_eq!(resources.request_cpu().unwrap().as_str(), "100000");
|
||||
assert_eq!(resources.limit_cpu().unwrap().as_str(), "10Gi");
|
||||
assert_eq!(resources.limit_memory().unwrap().as_str(), "4000M");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resources_config_builder_should_fails_and_returns_an_error_if_couldnt_parse_request_memory()
|
||||
{
|
||||
let resources_builder = ResourcesBuilder::new().with_request_memory("invalid");
|
||||
#[test]
|
||||
fn resources_config_builder_should_fails_and_returns_an_error_if_couldnt_parse_request_memory()
|
||||
{
|
||||
let resources_builder = ResourcesBuilder::new().with_request_memory("invalid");
|
||||
|
||||
let errors = resources_builder.build().err().unwrap();
|
||||
let errors = resources_builder.build().err().unwrap();
|
||||
|
||||
assert_eq!(errors.len(), 1);
|
||||
assert_eq!(
|
||||
errors.first().unwrap().to_string(),
|
||||
r"request_memory: 'invalid' doesn't match regex '^\d+(.\d+)?(m|K|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$'"
|
||||
);
|
||||
}
|
||||
assert_eq!(errors.len(), 1);
|
||||
assert_eq!(
|
||||
errors.first().unwrap().to_string(),
|
||||
r"request_memory: 'invalid' doesn't match regex '^\d+(.\d+)?(m|K|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$'"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resources_config_builder_should_fails_and_returns_an_error_if_couldnt_parse_request_cpu() {
|
||||
let resources_builder = ResourcesBuilder::new().with_request_cpu("invalid");
|
||||
#[test]
|
||||
fn resources_config_builder_should_fails_and_returns_an_error_if_couldnt_parse_request_cpu() {
|
||||
let resources_builder = ResourcesBuilder::new().with_request_cpu("invalid");
|
||||
|
||||
let errors = resources_builder.build().err().unwrap();
|
||||
let errors = resources_builder.build().err().unwrap();
|
||||
|
||||
assert_eq!(errors.len(), 1);
|
||||
assert_eq!(
|
||||
errors.first().unwrap().to_string(),
|
||||
r"request_cpu: 'invalid' doesn't match regex '^\d+(.\d+)?(m|K|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$'"
|
||||
);
|
||||
}
|
||||
assert_eq!(errors.len(), 1);
|
||||
assert_eq!(
|
||||
errors.first().unwrap().to_string(),
|
||||
r"request_cpu: 'invalid' doesn't match regex '^\d+(.\d+)?(m|K|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$'"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resources_config_builder_should_fails_and_returns_an_error_if_couldnt_parse_limit_memory() {
|
||||
let resources_builder = ResourcesBuilder::new().with_limit_memory("invalid");
|
||||
#[test]
|
||||
fn resources_config_builder_should_fails_and_returns_an_error_if_couldnt_parse_limit_memory() {
|
||||
let resources_builder = ResourcesBuilder::new().with_limit_memory("invalid");
|
||||
|
||||
let errors = resources_builder.build().err().unwrap();
|
||||
let errors = resources_builder.build().err().unwrap();
|
||||
|
||||
assert_eq!(errors.len(), 1);
|
||||
assert_eq!(
|
||||
errors.first().unwrap().to_string(),
|
||||
r"limit_memory: 'invalid' doesn't match regex '^\d+(.\d+)?(m|K|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$'"
|
||||
);
|
||||
}
|
||||
assert_eq!(errors.len(), 1);
|
||||
assert_eq!(
|
||||
errors.first().unwrap().to_string(),
|
||||
r"limit_memory: 'invalid' doesn't match regex '^\d+(.\d+)?(m|K|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$'"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resources_config_builder_should_fails_and_returns_an_error_if_couldnt_parse_limit_cpu() {
|
||||
let resources_builder = ResourcesBuilder::new().with_limit_cpu("invalid");
|
||||
#[test]
|
||||
fn resources_config_builder_should_fails_and_returns_an_error_if_couldnt_parse_limit_cpu() {
|
||||
let resources_builder = ResourcesBuilder::new().with_limit_cpu("invalid");
|
||||
|
||||
let errors = resources_builder.build().err().unwrap();
|
||||
let errors = resources_builder.build().err().unwrap();
|
||||
|
||||
assert_eq!(errors.len(), 1);
|
||||
assert_eq!(
|
||||
errors.first().unwrap().to_string(),
|
||||
r"limit_cpu: 'invalid' doesn't match regex '^\d+(.\d+)?(m|K|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$'"
|
||||
);
|
||||
}
|
||||
assert_eq!(errors.len(), 1);
|
||||
assert_eq!(
|
||||
errors.first().unwrap().to_string(),
|
||||
r"limit_cpu: 'invalid' doesn't match regex '^\d+(.\d+)?(m|K|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$'"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resources_config_builder_should_fails_and_returns_multiple_error_if_couldnt_parse_multiple_fields(
|
||||
) {
|
||||
let resources_builder = ResourcesBuilder::new()
|
||||
.with_limit_cpu("invalid")
|
||||
.with_request_memory("invalid");
|
||||
#[test]
|
||||
fn resources_config_builder_should_fails_and_returns_multiple_error_if_couldnt_parse_multiple_fields(
|
||||
) {
|
||||
let resources_builder =
|
||||
ResourcesBuilder::new().with_limit_cpu("invalid").with_request_memory("invalid");
|
||||
|
||||
let errors = resources_builder.build().err().unwrap();
|
||||
let errors = resources_builder.build().err().unwrap();
|
||||
|
||||
assert_eq!(errors.len(), 2);
|
||||
assert_eq!(
|
||||
errors.first().unwrap().to_string(),
|
||||
r"limit_cpu: 'invalid' doesn't match regex '^\d+(.\d+)?(m|K|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$'"
|
||||
);
|
||||
assert_eq!(
|
||||
errors.get(1).unwrap().to_string(),
|
||||
r"request_memory: 'invalid' doesn't match regex '^\d+(.\d+)?(m|K|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$'"
|
||||
);
|
||||
}
|
||||
assert_eq!(errors.len(), 2);
|
||||
assert_eq!(
|
||||
errors.first().unwrap().to_string(),
|
||||
r"limit_cpu: 'invalid' doesn't match regex '^\d+(.\d+)?(m|K|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$'"
|
||||
);
|
||||
assert_eq!(
|
||||
errors.get(1).unwrap().to_string(),
|
||||
r"request_memory: 'invalid' doesn't match regex '^\d+(.\d+)?(m|K|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$'"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+525
-561
File diff suppressed because it is too large
Load Diff
+1448
-1644
File diff suppressed because it is too large
Load Diff
+24
-24
@@ -5,61 +5,61 @@ use support::constants::ZOMBIE_NODE_SPAWN_TIMEOUT_SECONDS;
|
||||
use crate::types::{Chain, Command, Duration};
|
||||
|
||||
pub(crate) fn is_true(value: &bool) -> bool {
|
||||
*value
|
||||
*value
|
||||
}
|
||||
|
||||
pub(crate) fn is_false(value: &bool) -> bool {
|
||||
!(*value)
|
||||
!(*value)
|
||||
}
|
||||
|
||||
pub(crate) fn default_as_true() -> bool {
|
||||
true
|
||||
true
|
||||
}
|
||||
|
||||
pub(crate) fn default_as_false() -> bool {
|
||||
false
|
||||
false
|
||||
}
|
||||
|
||||
pub(crate) fn default_initial_balance() -> crate::types::U128 {
|
||||
2_000_000_000_000.into()
|
||||
2_000_000_000_000.into()
|
||||
}
|
||||
|
||||
/// Default timeout for spawning a node (10mins)
|
||||
pub(crate) fn default_node_spawn_timeout() -> Duration {
|
||||
env::var(ZOMBIE_NODE_SPAWN_TIMEOUT_SECONDS)
|
||||
.ok()
|
||||
.and_then(|s| s.parse::<u32>().ok())
|
||||
.unwrap_or(600)
|
||||
env::var(ZOMBIE_NODE_SPAWN_TIMEOUT_SECONDS)
|
||||
.ok()
|
||||
.and_then(|s| s.parse::<u32>().ok())
|
||||
.unwrap_or(600)
|
||||
}
|
||||
|
||||
/// Default timeout for spawning the whole network (1hr)
|
||||
pub(crate) fn default_timeout() -> Duration {
|
||||
3600
|
||||
3600
|
||||
}
|
||||
|
||||
pub(crate) fn default_command_polkadot() -> Option<Command> {
|
||||
TryInto::<Command>::try_into("polkadot").ok()
|
||||
TryInto::<Command>::try_into("polkadot").ok()
|
||||
}
|
||||
|
||||
pub(crate) fn default_relaychain_chain() -> Chain {
|
||||
TryInto::<Chain>::try_into("rococo-local").expect("'rococo-local' should be a valid chain")
|
||||
TryInto::<Chain>::try_into("rococo-local").expect("'rococo-local' should be a valid chain")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn default_node_spawn_timeout_works_before_and_after_env_is_set() {
|
||||
// The default should be 600 seconds if the env var is not set
|
||||
assert_eq!(default_node_spawn_timeout(), 600);
|
||||
#[test]
|
||||
fn default_node_spawn_timeout_works_before_and_after_env_is_set() {
|
||||
// The default should be 600 seconds if the env var is not set
|
||||
assert_eq!(default_node_spawn_timeout(), 600);
|
||||
|
||||
// If env var is set to a valid number, it should return that number
|
||||
env::set_var(ZOMBIE_NODE_SPAWN_TIMEOUT_SECONDS, "123");
|
||||
assert_eq!(default_node_spawn_timeout(), 123);
|
||||
// If env var is set to a valid number, it should return that number
|
||||
env::set_var(ZOMBIE_NODE_SPAWN_TIMEOUT_SECONDS, "123");
|
||||
assert_eq!(default_node_spawn_timeout(), 123);
|
||||
|
||||
// If env var is set to a NOT valid number, it should return 600
|
||||
env::set_var(ZOMBIE_NODE_SPAWN_TIMEOUT_SECONDS, "NOT_A_NUMBER");
|
||||
assert_eq!(default_node_spawn_timeout(), 600);
|
||||
}
|
||||
// If env var is set to a NOT valid number, it should return 600
|
||||
env::set_var(ZOMBIE_NODE_SPAWN_TIMEOUT_SECONDS, "NOT_A_NUMBER");
|
||||
assert_eq!(default_node_spawn_timeout(), 600);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user