blob: ab82e05fc1714251cfc9b30d84dc10cd5f3bd7b1 [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 Hanf48ceb42021-06-01 18:00:04 +090018use std::fs::File;
19use std::io;
20use std::path::Path;
21use std::thread;
22use std::time::{Duration, Instant};
23
24const SLEEP_DURATION: Duration = Duration::from_millis(5);
25
26/// waits for a file with a timeout and returns it
Jooyung Hana6d11eb2021-09-10 11:48:05 +090027pub fn wait_for_file<P: AsRef<Path>>(path: P, timeout: Duration) -> Result<File> {
Jooyung Hanf48ceb42021-06-01 18:00:04 +090028 let begin = Instant::now();
29 loop {
30 match File::open(&path) {
31 Ok(file) => return Ok(file),
32 Err(error) => {
33 if error.kind() != io::ErrorKind::NotFound {
Jooyung Hana6d11eb2021-09-10 11:48:05 +090034 return Err(anyhow!(error));
Jooyung Hanf48ceb42021-06-01 18:00:04 +090035 }
36 if begin.elapsed() > timeout {
Jooyung Hana6d11eb2021-09-10 11:48:05 +090037 return Err(anyhow!(io::Error::from(io::ErrorKind::NotFound)));
Jooyung Hanf48ceb42021-06-01 18:00:04 +090038 }
39 thread::sleep(SLEEP_DURATION);
40 }
41 }
42 }
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48 use std::io::{Read, Write};
49
50 #[test]
Jooyung Hana6d11eb2021-09-10 11:48:05 +090051 fn test_wait_for_file() -> Result<()> {
Jooyung Hanf48ceb42021-06-01 18:00:04 +090052 let test_dir = tempfile::TempDir::new().unwrap();
53 let test_file = test_dir.path().join("test.txt");
54 thread::spawn(move || -> io::Result<()> {
55 thread::sleep(Duration::from_secs(1));
56 File::create(test_file)?.write_all(b"test")
57 });
58
59 let test_file = test_dir.path().join("test.txt");
60 let mut file = wait_for_file(&test_file, Duration::from_secs(5))?;
61 let mut buffer = String::new();
62 file.read_to_string(&mut buffer)?;
63 assert_eq!("test", buffer);
64 Ok(())
65 }
66
67 #[test]
68 fn test_wait_for_file_fails() {
69 let test_dir = tempfile::TempDir::new().unwrap();
70 let test_file = test_dir.path().join("test.txt");
71 let file = wait_for_file(&test_file, Duration::from_secs(1));
72 assert!(file.is_err());
Jooyung Hana6d11eb2021-09-10 11:48:05 +090073 assert_eq!(
74 io::ErrorKind::NotFound,
75 file.unwrap_err().root_cause().downcast_ref::<io::Error>().unwrap().kind()
76 );
Jooyung Hanf48ceb42021-06-01 18:00:04 +090077 }
78}