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