blob: 8ab2413b99a1c1a56da6fd726012e078280ad4e0 [file] [log] [blame]
Jooyung Hanf48ceb42021-06-01 18:00:04 +09001// Copyright 2021, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! IO utilities
16
Jooyung Hana6d11eb2021-09-10 11:48:05 +090017use anyhow::{anyhow, Result};
Jooyung Han311b1202021-09-14 22:00:16 +090018use log::debug;
19use std::fmt::Debug;
Jooyung Hanf48ceb42021-06-01 18:00:04 +090020use std::fs::File;
21use std::io;
22use std::path::Path;
23use std::thread;
24use std::time::{Duration, Instant};
25
26const SLEEP_DURATION: Duration = Duration::from_millis(5);
27
28/// waits for a file with a timeout and returns it
Jooyung Han311b1202021-09-14 22:00:16 +090029pub fn wait_for_file<P: AsRef<Path> + Debug>(path: P, timeout: Duration) -> Result<File> {
30 debug!("waiting for {:?}...", path);
Jooyung Hanf48ceb42021-06-01 18:00:04 +090031 let begin = Instant::now();
32 loop {
33 match File::open(&path) {
34 Ok(file) => return Ok(file),
35 Err(error) => {
36 if error.kind() != io::ErrorKind::NotFound {
Jooyung Hana6d11eb2021-09-10 11:48:05 +090037 return Err(anyhow!(error));
Jooyung Hanf48ceb42021-06-01 18:00:04 +090038 }
39 if begin.elapsed() > timeout {
Jooyung Hana6d11eb2021-09-10 11:48:05 +090040 return Err(anyhow!(io::Error::from(io::ErrorKind::NotFound)));
Jooyung Hanf48ceb42021-06-01 18:00:04 +090041 }
42 thread::sleep(SLEEP_DURATION);
43 }
44 }
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use std::io::{Read, Write};
52
53 #[test]
Jooyung Hana6d11eb2021-09-10 11:48:05 +090054 fn test_wait_for_file() -> Result<()> {
Jooyung Hanf48ceb42021-06-01 18:00:04 +090055 let test_dir = tempfile::TempDir::new().unwrap();
56 let test_file = test_dir.path().join("test.txt");
57 thread::spawn(move || -> io::Result<()> {
58 thread::sleep(Duration::from_secs(1));
59 File::create(test_file)?.write_all(b"test")
60 });
61
62 let test_file = test_dir.path().join("test.txt");
63 let mut file = wait_for_file(&test_file, Duration::from_secs(5))?;
64 let mut buffer = String::new();
65 file.read_to_string(&mut buffer)?;
66 assert_eq!("test", buffer);
67 Ok(())
68 }
69
70 #[test]
71 fn test_wait_for_file_fails() {
72 let test_dir = tempfile::TempDir::new().unwrap();
73 let test_file = test_dir.path().join("test.txt");
74 let file = wait_for_file(&test_file, Duration::from_secs(1));
75 assert!(file.is_err());
Jooyung Hana6d11eb2021-09-10 11:48:05 +090076 assert_eq!(
77 io::ErrorKind::NotFound,
78 file.unwrap_err().root_cause().downcast_ref::<io::Error>().unwrap().kind()
79 );
Jooyung Hanf48ceb42021-06-01 18:00:04 +090080 }
81}