Skip to content

Commit 51d8f4d

Browse files
committed
Make the chdir tests thread safe
The both change their process's cwd, which is global. Handle this by running the tests in subprocesses.
1 parent 274b09e commit 51d8f4d

File tree

1 file changed

+59
-40
lines changed

1 file changed

+59
-40
lines changed

test/test_unistd.rs

Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,26 @@ use std::iter;
88
use std::ffi::CString;
99
use std::fs::File;
1010
use std::io::{Write, Read};
11+
use std::ops::Fn;
1112
use std::os::unix::prelude::*;
1213
use std::env::current_dir;
1314
use tempfile::tempfile;
1415
use tempdir::TempDir;
1516
use libc::off_t;
1617

18+
fn test_in_subprocess<F: Fn()>(func: F) {
19+
let pid = fork();
20+
match pid {
21+
Ok(Child) => {
22+
func();
23+
}
24+
Ok(Parent{child}) => {
25+
assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 0)))
26+
}
27+
Err(_) => panic!("Error: fork")
28+
}
29+
}
30+
1731
#[test]
1832
fn test_fork_and_waitpid() {
1933
let pid = fork();
@@ -42,18 +56,22 @@ fn test_fork_and_waitpid() {
4256

4357
#[test]
4458
fn test_wait() {
45-
let pid = fork();
46-
match pid {
47-
Ok(Child) => {} // ignore child here
48-
Ok(Parent { child }) => {
49-
let wait_status = wait();
50-
51-
// just assert that (any) one child returns with WaitStatus::Exited
52-
assert_eq!(wait_status, Ok(WaitStatus::Exited(child, 0)));
53-
},
54-
// panic, fork should never fail unless there is a serious problem with the OS
55-
Err(_) => panic!("Error: Fork Failed")
56-
}
59+
// wait could reap a different test's child process
60+
test_in_subprocess(|| {
61+
let pid = fork();
62+
match pid {
63+
Ok(Child) => {} // ignore child here
64+
Ok(Parent { child }) => {
65+
let wait_status = wait();
66+
67+
// just assert that (any) one child returns with WaitStatus::Exited
68+
assert_eq!(wait_status, Ok(WaitStatus::Exited(child, 0)));
69+
},
70+
// panic, fork should never fail unless there is a serious problem
71+
// with the OS
72+
Err(_) => panic!("Error: Fork Failed")
73+
}
74+
});
5775
}
5876

5977
#[test]
@@ -144,40 +162,41 @@ macro_rules! execve_test_factory(
144162

145163
#[test]
146164
fn test_fchdir() {
147-
let tmpdir = TempDir::new("test_fchdir").unwrap();
148-
let tmpdir_path = tmpdir.path().canonicalize().unwrap();
149-
let tmpdir_fd = File::open(&tmpdir_path).unwrap().into_raw_fd();
150-
let olddir_path = getcwd().unwrap();
151-
let olddir_fd = File::open(&olddir_path).unwrap().into_raw_fd();
152-
153-
assert!(fchdir(tmpdir_fd).is_ok());
154-
assert_eq!(getcwd().unwrap(), tmpdir_path);
165+
// fchdir changes the process's cwd
166+
test_in_subprocess(|| {
167+
let tmpdir = TempDir::new("test_fchdir").unwrap();
168+
let tmpdir_path = tmpdir.path().canonicalize().unwrap();
169+
let tmpdir_fd = File::open(&tmpdir_path).unwrap().into_raw_fd();
155170

156-
assert!(fchdir(olddir_fd).is_ok());
157-
assert_eq!(getcwd().unwrap(), olddir_path);
171+
assert!(fchdir(tmpdir_fd).is_ok());
172+
assert_eq!(getcwd().unwrap(), tmpdir_path);
158173

159-
assert!(close(olddir_fd).is_ok());
160-
assert!(close(tmpdir_fd).is_ok());
174+
assert!(close(tmpdir_fd).is_ok());
175+
});
161176
}
162177

163178
#[test]
164179
fn test_getcwd() {
165-
let tmp_dir = TempDir::new("test_getcwd").unwrap();
166-
assert!(chdir(tmp_dir.path()).is_ok());
167-
assert_eq!(getcwd().unwrap(), current_dir().unwrap());
168-
169-
// make path 500 chars longer so that buffer doubling in getcwd kicks in.
170-
// Note: One path cannot be longer than 255 bytes (NAME_MAX)
171-
// whole path cannot be longer than PATH_MAX (usually 4096 on linux, 1024 on macos)
172-
let mut inner_tmp_dir = tmp_dir.path().to_path_buf();
173-
for _ in 0..5 {
174-
let newdir = iter::repeat("a").take(100).collect::<String>();
175-
//inner_tmp_dir = inner_tmp_dir.join(newdir).path();
176-
inner_tmp_dir.push(newdir);
177-
assert!(mkdir(inner_tmp_dir.as_path(), stat::S_IRWXU).is_ok());
178-
}
179-
assert!(chdir(inner_tmp_dir.as_path()).is_ok());
180-
assert_eq!(getcwd().unwrap(), current_dir().unwrap());
180+
// chdir changes the process's cwd
181+
test_in_subprocess(|| {
182+
let tmp_dir = TempDir::new("test_getcwd").unwrap();
183+
assert!(chdir(tmp_dir.path()).is_ok());
184+
assert_eq!(getcwd().unwrap(), current_dir().unwrap());
185+
186+
// make path 500 chars longer so that buffer doubling in getcwd
187+
// kicks in. Note: One path cannot be longer than 255 bytes
188+
// (NAME_MAX) whole path cannot be longer than PATH_MAX (usually
189+
// 4096 on linux, 1024 on macos)
190+
let mut inner_tmp_dir = tmp_dir.path().to_path_buf();
191+
for _ in 0..5 {
192+
let newdir = iter::repeat("a").take(100).collect::<String>();
193+
//inner_tmp_dir = inner_tmp_dir.join(newdir).path();
194+
inner_tmp_dir.push(newdir);
195+
assert!(mkdir(inner_tmp_dir.as_path(), stat::S_IRWXU).is_ok());
196+
}
197+
assert!(chdir(inner_tmp_dir.as_path()).is_ok());
198+
assert_eq!(getcwd().unwrap(), current_dir().unwrap());
199+
});
181200
}
182201

183202
#[test]

0 commit comments

Comments
 (0)