use crate::actions::action::Action; use crate::app::Enableable; use color_eyre::eyre::Result; use log::{debug, info, warn}; /// Initialize an action from a configuration pub fn init_action(config_opt: &Option, creator: F) -> Result>> where C: Enableable + Clone, A: Action + 'static, F: FnOnce(&C) -> Result, { if let Some(config) = config_opt { if config.is_enabled() { info!("Initializing {}", A::name()); match creator(config) { Ok(action) => { return Ok(Some(Box::new(action))); } Err(e) => { warn!("Failed to initialize {}: {}", A::name(), e); } } } else { debug!("{} is disabled", A::name()); } } else { debug!("No {} configuration found", A::name()); } Ok(None) } #[cfg(test)] mod tests { use super::*; use crate::actions::action::ProcessedMagnets; use crate::db::Database; use crate::models::Magnet; use crate::services::database::DatabaseService; use async_trait::async_trait; use color_eyre::eyre::{eyre, Result}; use std::sync::atomic::{AtomicBool, Ordering}; #[derive(Clone)] struct FakeConfig { enabled: bool, } impl Enableable for FakeConfig { fn is_enabled(&self) -> bool { self.enabled } } struct FakeAction {} #[async_trait] impl Action for FakeAction { fn name() -> &'static str { "FakeAction" } fn get_name(&self) -> &'static str { "FakeAction" } async fn process_unprocessed_magnets( &mut self, _db_service: &mut DatabaseService, ) -> Result { Ok(ProcessedMagnets { success: Vec::::new(), failed: Vec::::new(), }) } } #[test] fn test_init_action_no_config() { let config: Option = None; let result = init_action::<_, FakeAction, _>(&config, |_| { panic!("Creator should not be called when config is None"); }) .unwrap(); assert!(result.is_none()); } #[test] fn test_init_action_disabled_config() { let config = Some(FakeConfig { enabled: false }); let result = init_action::<_, FakeAction, _>(&config, |_| { panic!("Creator should not be called when config is disabled"); }) .unwrap(); assert!(result.is_none()); } #[test] fn test_init_action_creator_fails() { let config = Some(FakeConfig { enabled: true }); let result = init_action::<_, FakeAction, _>(&config, |_| Err(eyre!("Creator failed"))).unwrap(); assert!(result.is_none()); } #[test] fn test_init_action_success() { let config = Some(FakeConfig { enabled: true }); let creator_called = AtomicBool::new(false); let result = init_action::<_, FakeAction, _>(&config, |_| { creator_called.store(true, Ordering::SeqCst); Ok(FakeAction {}) }) .unwrap(); assert!(creator_called.load(Ordering::SeqCst)); assert!(result.is_some()); } }