1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
use crate::error::LightSpeedError;
use log::info;

#[async_trait::async_trait]
pub trait ModuleBuilder<T: Module> {
    async fn build(&self) -> Result<T, LightSpeedError>;
}

#[async_trait::async_trait]
pub trait Module {
    async fn start(&mut self) -> Result<(), LightSpeedError>;
}

pub async fn start(modules: &mut [&mut dyn Module]) -> Result<(), LightSpeedError> {
    info!("Begin modules 'start' phase");
    for module in modules.iter_mut() {
        module.start().await?;
    }
    Ok(())
}

#[cfg(test)]
mod test {

    use crate::LightSpeedError;
    use std::sync::Arc;
    use tokio::sync::Mutex;

    #[tokio::test]
    async fn should_start_all() {
        let output = Arc::new(Mutex::new(vec![]));

        let mut mod1 = SimpleModOne { output: output.clone(), name: "one".to_string() };
        let mut mod2 = SimpleModTwo { output: output.clone(), name: "two".to_string(), fail: false };

        let mut modules: Vec<&mut dyn super::Module> = vec![&mut mod1, &mut mod2];

        let result = super::start(modules.as_mut()).await;

        assert!(result.is_ok());
        assert_eq!(2, output.lock().await.len());
        assert_eq!(&"one-start".to_string(), output.lock().await.get(0).unwrap());
        assert_eq!(&"two-start".to_string(), output.lock().await.get(1).unwrap());
    }

    #[tokio::test]
    async fn should_fail_on_start() {
        let output = Arc::new(Mutex::new(vec![]));

        let mut mod1 = SimpleModOne { output: output.clone(), name: "one".to_string() };
        let mut mod2 = SimpleModTwo { output: output.clone(), name: "two".to_string(), fail: true };

        let mut modules: Vec<&mut dyn super::Module> = vec![&mut mod1, &mut mod2];

        let result = super::start(&mut modules).await;

        assert!(result.is_err());

        match result {
            Err(err) => match err {
                LightSpeedError::ModuleStartError { message } => {
                    assert_eq!("test_failure", message)
                }
                _ => assert!(false),
            },
            _ => assert!(false),
        }

        assert_eq!(1, output.lock().await.len());
        assert_eq!(&"one-start".to_string(), output.lock().await.get(0).unwrap());
    }

    #[derive(Clone)]
    struct SimpleModOne {
        output: Arc<Mutex<Vec<String>>>,
        name: String,
    }

    #[async_trait::async_trait]
    impl super::Module for SimpleModOne {
        async fn start(&mut self) -> Result<(), LightSpeedError> {
            let mut owned = self.name.to_owned();
            owned.push_str(&"-start");
            self.output.lock().await.push(owned);
            Ok(())
        }
    }

    #[derive(Clone)]
    struct SimpleModTwo {
        output: Arc<Mutex<Vec<String>>>,
        name: String,
        fail: bool,
    }

    #[async_trait::async_trait]
    impl super::Module for SimpleModTwo {
        async fn start(&mut self) -> Result<(), LightSpeedError> {
            if self.fail {
                return Err(LightSpeedError::ModuleStartError { message: "test_failure".to_owned() });
            }

            let mut owned = self.name.to_owned();
            owned.push_str(&"-start");
            self.output.lock().await.push(owned);

            Ok(())
        }
    }
}