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