use std::fmt::Debug; use hyper::Method; use icinga_client::{ client, types::{AckState, Acknowledgement, CheckedObject, Host, HostState, Service, ServiceState}, }; use icinga_mock::{IcingaOptions, Session}; use serde::de::DeserializeOwned; use serde_json::Value; fn ackowledged(ack: &Acknowledgement) -> bool { ack.state != AckState::None } use pretty_assertions::assert_eq; #[test] fn hosts_in_each_state() { let hosts: Vec = Session::new().get_objects(); fn in_state(state: HostState) -> impl Fn(&&Host) -> bool { move |host: &&Host| host.state == state } fn acknowledged_with_expiry(h: &&Host) -> bool { match &h.acknowledgement.state { icinga_client::types::AckState::None => false, icinga_client::types::AckState::Acknowledged { expiry, .. } => expiry.is_some(), } } fn acknowledged_without_expiry(h: &&Host) -> bool { match &h.acknowledgement.state { icinga_client::types::AckState::None => false, icinga_client::types::AckState::Acknowledged { expiry, .. } => expiry.is_none(), } } let up_count = hosts.iter().filter(in_state(HostState::UP)).count(); let down_count = hosts.iter().filter(in_state(HostState::DOWN)).count(); let ack_count_with_expiry = hosts.iter().filter(acknowledged_without_expiry).count(); let ack_count_without_expiry = hosts.iter().filter(acknowledged_with_expiry).count(); let down_without_ack_count = hosts .iter() .filter(|h| in_state(HostState::DOWN)(h) && !ackowledged(&h.acknowledgement)) .count(); assert!(up_count > 0, "no UP hosts: {:#?}", hosts); assert!(down_count > 0, "no DOWN hosts: {:#?}", hosts); assert!( down_without_ack_count > 0, "no DOWN hosts without ack: {:#?}", hosts ); assert!( ack_count_with_expiry > 0, "no acknowledged hosts with expiry: {:#?}", hosts ); assert!( ack_count_without_expiry > 0, "no acknowledged hosts without expiry: {:#?}", hosts ); } #[test] fn services_in_each_state() { let services: Vec = Session::new().get_objects(); fn in_state(state: ServiceState) -> impl Fn(&&Service) -> bool { move |service: &&Service| service.state == state } fn acknowledged_with_expiry(s: &&Service) -> bool { match &s.acknowledgement.state { icinga_client::types::AckState::None => false, icinga_client::types::AckState::Acknowledged { expiry, .. } => expiry.is_some(), } } fn acknowledged_without_expiry(s: &&Service) -> bool { match &s.acknowledgement.state { icinga_client::types::AckState::None => false, icinga_client::types::AckState::Acknowledged { expiry, .. } => expiry.is_none(), } } let ok_count = services.iter().filter(in_state(ServiceState::OK)).count(); let warn_count = services .iter() .filter(in_state(ServiceState::WARNING)) .count(); let critical_count = services .iter() .filter(in_state(ServiceState::CRITICAL)) .count(); let unknown_count = services .iter() .filter(in_state(ServiceState::UNKNOWN)) .count(); let ack_count_with_expiry = services.iter().filter(acknowledged_without_expiry).count(); let ack_count_without_expiry = services.iter().filter(acknowledged_with_expiry).count(); let not_ok_without_ack_count = services .iter() .filter(|s| !in_state(ServiceState::OK)(s) && !ackowledged(&s.acknowledgement)) .count(); assert!(ok_count > 0, "no OK services: {:#?}", services); assert!(warn_count > 0, "no WARNING services: {:#?}", services); assert!(critical_count > 0, "no CRITICAL services: {:#?}", services); assert!(unknown_count > 0, "no UNKNOWN services: {:#?}", services); assert!( not_ok_without_ack_count > 0, "no not-OK services without ack: {:#?}", services ); assert!( ack_count_with_expiry > 0, "no acknowledged hosts with expiry: {:#?}", services ); assert!( ack_count_without_expiry > 0, "no acknowledged hosts without expiry: {:#?}", services ); } #[test] fn ack_host_without_expiry() { test_ack::(None); } #[test] fn ack_host_with_expiry() { test_ack::(Some(2000.0)); } #[test] fn ack_service_with_expiry() { test_ack::(Some(2000.0)); } #[test] fn ack_service_without_expiry() { test_ack::(None); } fn test_ack(until: Option) where T: CheckedObject + DeserializeOwned + Debug + PartialEq, { let session = Session::new(); let before_services: Vec = session.get_objects(); let obj_to_ack = before_services .iter() .find(|s| !s.is_ok() && !ackowledged(s.acknowledgement())) .ok_or("No DOWN-and-not-ack service found") .unwrap(); let query = [(T::OBJECT_TYPE_FOR_QUERY, obj_to_ack.name())]; let mut req_body: Value = serde_json::json!({ "type": T::OBJECT_TYPE_FOR_QUERY, "author": "icingaadmin", "comment": "for testing", }); if let Some(expiry) = until { req_body .as_object_mut() .unwrap() .insert("expiry".to_owned(), serde_json::json!(expiry)); } session.post::("/v1/actions/acknowledge-problem", &query, req_body); let after_services: Vec = session.get_objects(); let relevant_service = after_services .iter() .find(|h| h.name() == obj_to_ack.name()) .ok_or("Could not find acknowledged service") .unwrap(); if let AckState::Acknowledged { expiry, .. } = relevant_service.acknowledgement().state { assert!( relevant_service.is_handled(), "service should be 'handled': {:#?}", relevant_service ); assert_eq!( expiry.map(|t| t.localtime().timestamp() as f64), until, "Expiry does not match" ); } else { assert!(false, "No acknowledged: {:#?}", relevant_service); } assert_eq!( before_services .iter() .filter(|h| h != &obj_to_ack) .collect::>(), after_services .iter() .filter(|h| h != &relevant_service) .collect::>(), "Other services are not equal" ); } #[test] fn test_basic_auth_good() { Session::from_options(&IcingaOptions::new().with_credentials("test", "mutti123")).with_client( |client| { let req = client .request(Method::GET, "/v1/objects/hosts") .unwrap() .basic_auth("test", Some("mutti123")); let result = client.send_request::(req); assert!( result.is_ok(), "Unexpected error sending basic auth request: {:#?}", result ); }, ) } #[test] fn test_basic_auth_bad() { Session::from_options(&IcingaOptions::new().with_credentials("test", "mutti123")).with_client( |client| { let req = client .request(Method::GET, "/v1/objects/hosts") .unwrap() .basic_auth("test", Some("monkey")); let result = client.send_request::(req); match result { Err(client::Error::Unauthorized) => (), _ => assert!( false, "Unexpected result sending basic auth request: {:#?}", result ), } }, ) }