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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
pub mod service;
pub mod status;
pub mod manager;
pub mod utils;

pub use service::Service;
pub use status::*;
pub use manager::ServiceManager;

#[allow(unused_must_use)]
#[cfg(test)]
mod tests {
  use super::*;
  use std::{time::{Duration, Instant}, thread};
  use crossbeam_channel::{Sender, bounded};

  struct ExampleService {
    id: String,
    pub delay: Duration,
    sender: Sender<String>,
    flag: ServiceStatusFlag
  }

  impl ExampleService {
    fn new(id: String, delay: Duration, sender: Sender<String>) -> ExampleService {
      ExampleService {
        id,
        delay,
        sender,
        flag: ServiceStatusFlag::default()
      }
    }
  }

  impl Service for ExampleService {

    fn start(&mut self) {
      self.flag.starting();

      let id = self.id.clone();
      let delay = self.delay.clone();
      let sender = self.sender.clone();
      let flag = self.flag.clone();
      thread::spawn(move || {
        thread::sleep(delay);
        sender.send(format!("Service {} STARTED", id).to_string());

        flag.started();
      });
    }

    fn await_started(&mut self) {
      while !self.flag.is_started() {}
    }


    fn stop(&mut self) {
      self.flag.stopping();

      let id = self.id.clone();
      let delay = self.delay.clone();
      let sender = self.sender.clone();
      let flag = self.flag.clone();
      thread::spawn(move || {
        thread::sleep(delay);
        sender.send(format!("Service {} STOPPED", id).to_string());

        flag.stopped();
      });
    }

    fn await_stopped(&mut self) {
      while !self.flag.is_stopped() {}
    }

  }

  #[test]
  fn should_start_then_stop() {
    let (sender, receiver) = bounded(2);
    let mut sm = ServiceManager::new();
    let sa_delay = 1000;
    let sb_delay = 2000;

    sm.register(Box::new(ExampleService::new("SA".to_string(), Duration::from_millis(sa_delay), sender.clone())));
    sm.register(Box::new(ExampleService::new("SB".to_string(), Duration::from_millis(sb_delay), sender.clone())));

    let now = Instant::now();
    sm.start();
    sm.await_started();
    let start_time = now.elapsed().as_millis();
    assert!(start_time >= sb_delay as u128);
    assert!(start_time < (sb_delay + sa_delay) as u128);
    assert_eq!("Service SA STARTED", receiver.recv().unwrap());
    assert_eq!("Service SB STARTED", receiver.recv().unwrap());

    let now = Instant::now();
    sm.stop();
    sm.await_stopped();
    let stop_time = now.elapsed().as_millis();
    assert!(stop_time >= sb_delay as u128);
    assert!(start_time < (sb_delay + sa_delay) as u128);
    assert_eq!("Service SA STOPPED", receiver.recv().unwrap());
    assert_eq!("Service SB STOPPED", receiver.recv().unwrap());
  }

  #[test]
  fn should_start_and_await_then_stop_and_await() {
    let (sender, receiver) = bounded(2);
    let mut sm = ServiceManager::new();
    let sa_delay = 1000;
    let sb_delay = 2000;

    sm.register(Box::new(ExampleService::new("SA".to_string(), Duration::from_millis(sa_delay), sender.clone())));
    sm.register(Box::new(ExampleService::new("SB".to_string(), Duration::from_millis(sb_delay), sender.clone())));

    let now = Instant::now();
    sm.start_and_await();
    assert!(now.elapsed().as_millis() >= (sa_delay + sb_delay) as u128);
    assert_eq!("Service SA STARTED", receiver.recv().unwrap());
    assert_eq!("Service SB STARTED", receiver.recv().unwrap());

    let now = Instant::now();
    sm.stop_and_await();
    assert!(now.elapsed().as_millis() >= (sa_delay + sb_delay) as u128);
    assert_eq!("Service SB STOPPED", receiver.recv().unwrap());
    assert_eq!("Service SA STOPPED", receiver.recv().unwrap());
  }
}