Start to check device relay information
This commit is contained in:
		@@ -36,6 +36,10 @@ impl SizeConstraint {
 | 
			
		||||
        let len = val.trim().len();
 | 
			
		||||
        len >= self.min && len <= self.max
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn validate_usize(&self, val: usize) -> bool {
 | 
			
		||||
        val >= self.min && val <= self.max
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Backend static constraints
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
//! # Devices entities definition
 | 
			
		||||
 | 
			
		||||
use crate::constants::StaticConstraints;
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
 | 
			
		||||
/// Device information provided directly by the device during syncrhonisation.
 | 
			
		||||
///
 | 
			
		||||
@@ -75,13 +76,20 @@ pub struct DailyMinRuntime {
 | 
			
		||||
    pub catch_up_hours: Vec<usize>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
 | 
			
		||||
#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
 | 
			
		||||
pub struct DeviceRelayID(uuid::Uuid);
 | 
			
		||||
 | 
			
		||||
impl Default for DeviceRelayID {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self(uuid::Uuid::new_v4())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Single device relay information
 | 
			
		||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Default)]
 | 
			
		||||
pub struct DeviceRelay {
 | 
			
		||||
    /// Device relay id. Should be unique across the whole application
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    id: DeviceRelayID,
 | 
			
		||||
    /// Human-readable name for the relay
 | 
			
		||||
    name: String,
 | 
			
		||||
@@ -103,6 +111,80 @@ pub struct DeviceRelay {
 | 
			
		||||
    conflicts_with: Vec<DeviceRelayID>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl DeviceRelay {
 | 
			
		||||
    /// Check device relay for errors
 | 
			
		||||
    pub fn error(&self, list: &[DeviceRelay]) -> Option<&'static str> {
 | 
			
		||||
        let constraints = StaticConstraints::default();
 | 
			
		||||
        if !constraints.relay_name_len.validate(&self.name) {
 | 
			
		||||
            return Some("Invalid relay name length!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if !constraints.relay_priority.validate_usize(self.priority) {
 | 
			
		||||
            return Some("Invalid relay priority!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if !constraints
 | 
			
		||||
            .relay_consumption
 | 
			
		||||
            .validate_usize(self.consumption)
 | 
			
		||||
        {
 | 
			
		||||
            return Some("Invalid consumption!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if !constraints
 | 
			
		||||
            .relay_minimal_uptime
 | 
			
		||||
            .validate_usize(self.minimal_uptime)
 | 
			
		||||
        {
 | 
			
		||||
            return Some("Invalid minimal uptime!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if !constraints
 | 
			
		||||
            .relay_minimal_downtime
 | 
			
		||||
            .validate_usize(self.minimal_downtime)
 | 
			
		||||
        {
 | 
			
		||||
            return Some("Invalid minimal uptime!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if let Some(daily) = &self.daily_runtime {
 | 
			
		||||
            if !constraints
 | 
			
		||||
                .relay_daily_minimal_runtime
 | 
			
		||||
                .validate_usize(daily.min_runtime)
 | 
			
		||||
            {
 | 
			
		||||
                return Some("Invalid minimal daily runtime!");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if daily.reset_time > 3600 * 24 {
 | 
			
		||||
                return Some("Invalid daily reset time!");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if daily.catch_up_hours.is_empty() {
 | 
			
		||||
                return Some("No catchup hours defined!");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if daily.catch_up_hours.iter().any(|h| h > &23) {
 | 
			
		||||
                return Some("At least one catch up hour is invalid!");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let relays_map = list.iter().map(|r| (r.id, r)).collect::<HashMap<_, _>>();
 | 
			
		||||
 | 
			
		||||
        if self.depends_on.iter().any(|d| !relays_map.contains_key(d)) {
 | 
			
		||||
            return Some("A specified dependent relay does not exists!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if self
 | 
			
		||||
            .conflicts_with
 | 
			
		||||
            .iter()
 | 
			
		||||
            .any(|d| !relays_map.contains_key(d))
 | 
			
		||||
        {
 | 
			
		||||
            return Some("A specified conflicting relay does not exists!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // TODO : check for loops
 | 
			
		||||
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Device general information
 | 
			
		||||
///
 | 
			
		||||
/// This structure is used to update device information
 | 
			
		||||
@@ -128,3 +210,33 @@ impl DeviceGeneralInfo {
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use crate::devices::device::DeviceRelay;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn check_device_relay_error() {
 | 
			
		||||
        let unitary = DeviceRelay {
 | 
			
		||||
            name: "unitary".to_string(),
 | 
			
		||||
            ..Default::default()
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let bad_name = DeviceRelay {
 | 
			
		||||
            name: "".to_string(),
 | 
			
		||||
            ..Default::default()
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let dep_on_unitary = DeviceRelay {
 | 
			
		||||
            name: "dep_on_unitary".to_string(),
 | 
			
		||||
            depends_on: vec![unitary.id],
 | 
			
		||||
            ..Default::default()
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        assert_eq!(unitary.error(&[]), None);
 | 
			
		||||
        assert_eq!(unitary.error(&[unitary.clone(), bad_name.clone()]), None);
 | 
			
		||||
        assert!(bad_name.error(&[]).is_some());
 | 
			
		||||
        assert_eq!(dep_on_unitary.error(&[unitary.clone()]), None);
 | 
			
		||||
        assert!(dep_on_unitary.error(&[]).is_some());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user