/tests/helpers/daemon.rs

https://github.com/kstep/rust-mpd · Rust · 140 lines · 120 code · 17 blank · 3 comment · 4 complexity · 135340bad913c1197aa9f369fcfeab6a MD5 · raw file

  1. extern crate tempdir;
  2. use self::tempdir::TempDir;
  3. use super::mpd;
  4. use std::fs::{File, create_dir};
  5. use std::io::{Write, Read};
  6. use std::os::unix::net::UnixStream;
  7. use std::path::{Path, PathBuf};
  8. use std::process::{Command, Child, Stdio};
  9. struct MpdConfig {
  10. db_file: PathBuf,
  11. music_directory: PathBuf,
  12. playlist_directory: PathBuf,
  13. sticker_file: PathBuf,
  14. config_path: PathBuf,
  15. sock_path: PathBuf,
  16. }
  17. impl MpdConfig {
  18. pub fn new<P>(base: P) -> MpdConfig
  19. where P: AsRef<Path>
  20. {
  21. let base = base.as_ref();
  22. MpdConfig {
  23. db_file: base.join("db"),
  24. music_directory: base.join("music"),
  25. playlist_directory: base.join("playlists"),
  26. sticker_file: base.join("sticker_file"),
  27. config_path: base.join("config"),
  28. sock_path: base.join("sock"),
  29. }
  30. }
  31. fn config_text(&self) -> String {
  32. format!(r#"
  33. db_file "{db_file}"
  34. log_file "/dev/null"
  35. music_directory "{music_directory}"
  36. playlist_directory "{playlist_directory}"
  37. sticker_file "{sticker_file}"
  38. bind_to_address "{sock_path}"
  39. audio_output {{
  40. type "null"
  41. name "null"
  42. }}
  43. "#,
  44. db_file=self.db_file.display(),
  45. music_directory=self.music_directory.display(),
  46. playlist_directory=self.playlist_directory.display(),
  47. sticker_file=self.sticker_file.display(),
  48. sock_path=self.sock_path.display(),
  49. )
  50. }
  51. fn generate(&self) {
  52. create_dir(&self.music_directory).expect("Could not create music directory.");
  53. create_dir(&self.playlist_directory).expect("Could not create playlist directory.");
  54. let mut file = File::create(&self.config_path).expect("Could not create config file.");
  55. file.write_all(self.config_text().as_bytes()).expect("Could not write config file.");
  56. }
  57. }
  58. pub struct Daemon {
  59. // Saved here so it gets dropped when this does.
  60. _temp_dir: TempDir,
  61. config: MpdConfig,
  62. process: Child,
  63. }
  64. impl Drop for Daemon {
  65. fn drop(&mut self) {
  66. self.process.kill().expect("Could not kill mpd daemon.");
  67. self.process.wait().expect("Could not wait for mpd daemon to shutdown.");
  68. if let Some(ref mut stderr) = self.process.stderr {
  69. let mut output = String::new();
  70. stderr.read_to_string(&mut output).expect("Could not collect output from mpd.");
  71. println!{"Output from mpd:"}
  72. println!{"{}", output};
  73. }
  74. }
  75. }
  76. fn sleep() {
  77. use std::{thread, time};
  78. let ten_millis = time::Duration::from_millis(10);
  79. thread::sleep(ten_millis);
  80. }
  81. static EMPTY_FLAC_BYTES: &'static [u8] = include_bytes!("../data/empty.flac");
  82. impl Daemon {
  83. pub fn start() -> Daemon {
  84. let temp_dir = TempDir::new("mpd-test").unwrap();
  85. let config = MpdConfig::new(&temp_dir);
  86. config.generate();
  87. // TODO: Factor out putting files in the music directory.
  88. File::create(config.music_directory.join("empty.flac")).unwrap().write_all(EMPTY_FLAC_BYTES).unwrap();
  89. let process = Command::new("mpd")
  90. .arg("--no-daemon")
  91. .arg(&config.config_path)
  92. .stdin(Stdio::null())
  93. .stdout(Stdio::null())
  94. .stderr(Stdio::piped())
  95. .spawn()
  96. .expect("Could not create mpd daemon.");
  97. let daemon = Daemon {
  98. _temp_dir: temp_dir,
  99. config: config,
  100. process: process,
  101. };
  102. // Wait until we can connect to the daemon
  103. let mut client;
  104. loop {
  105. if let Ok(c) = daemon.maybe_connect() {
  106. client = c;
  107. break;
  108. }
  109. sleep()
  110. }
  111. while let Some(_) = client.status().expect("Couldn't get status.").updating_db {
  112. sleep()
  113. }
  114. daemon
  115. }
  116. fn maybe_connect(&self) -> Result<mpd::Client<UnixStream>, mpd::error::Error> {
  117. let stream = UnixStream::connect(&self.config.sock_path)?;
  118. mpd::Client::new(stream)
  119. }
  120. pub fn connect(&self) -> mpd::Client<UnixStream> {
  121. self.maybe_connect().expect("Could not connect to daemon.")
  122. }
  123. }