Start to check device relay information
This commit is contained in:
		@@ -36,6 +36,10 @@ impl SizeConstraint {
 | 
				
			|||||||
        let len = val.trim().len();
 | 
					        let len = val.trim().len();
 | 
				
			||||||
        len >= self.min && len <= self.max
 | 
					        len >= self.min && len <= self.max
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn validate_usize(&self, val: usize) -> bool {
 | 
				
			||||||
 | 
					        val >= self.min && val <= self.max
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Backend static constraints
 | 
					/// Backend static constraints
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
//! # Devices entities definition
 | 
					//! # Devices entities definition
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::constants::StaticConstraints;
 | 
					use crate::constants::StaticConstraints;
 | 
				
			||||||
 | 
					use std::collections::HashMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Device information provided directly by the device during syncrhonisation.
 | 
					/// Device information provided directly by the device during syncrhonisation.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
@@ -75,13 +76,20 @@ pub struct DailyMinRuntime {
 | 
				
			|||||||
    pub catch_up_hours: Vec<usize>,
 | 
					    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);
 | 
					pub struct DeviceRelayID(uuid::Uuid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Default for DeviceRelayID {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        Self(uuid::Uuid::new_v4())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Single device relay information
 | 
					/// Single device relay information
 | 
				
			||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Default)]
 | 
				
			||||||
pub struct DeviceRelay {
 | 
					pub struct DeviceRelay {
 | 
				
			||||||
    /// Device relay id. Should be unique across the whole application
 | 
					    /// Device relay id. Should be unique across the whole application
 | 
				
			||||||
 | 
					    #[serde(default)]
 | 
				
			||||||
    id: DeviceRelayID,
 | 
					    id: DeviceRelayID,
 | 
				
			||||||
    /// Human-readable name for the relay
 | 
					    /// Human-readable name for the relay
 | 
				
			||||||
    name: String,
 | 
					    name: String,
 | 
				
			||||||
@@ -103,6 +111,80 @@ pub struct DeviceRelay {
 | 
				
			|||||||
    conflicts_with: Vec<DeviceRelayID>,
 | 
					    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
 | 
					/// Device general information
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// This structure is used to update device information
 | 
					/// This structure is used to update device information
 | 
				
			||||||
@@ -128,3 +210,33 @@ impl DeviceGeneralInfo {
 | 
				
			|||||||
        None
 | 
					        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