A lame race condition in Rust code
Rust is damn1 nice. It allows you to write code without fearing for race conditions, while it maintains C++-like performance, and has other nice features.
That being said, it doesn’t control outside factors, for instance std::env
.
Rust protects you from all kinds of things, except when it doesn’t.
Imagine you want to test whether your application actually writes a file when it has to. You may mock you XDG directories as follows:
extern crate tempdir;
fn mock_xdg_env() -> Vec<tempdir::TempDir> {
let mocks = [
"XDG_DATA_HOME",
"XDG_CONFIG_HOME",
"XDG_CACHE_HOME",
];
mocks.iter().map(|varname| {
let tmp = temp_dir();
std::env::set_var(varname, tmp.path());
tmp
}).collect()
}
and then, you write two tests. One test tests whether the mocked directories were actually created:
#[test]
fn test_xdg_mock() {
let paths = mock_xdg_env();
for path in paths.iter() {
assert!(path.path().is_dir());
}
}
and the other one actually runs your useful code.
#[test]
fn test_my_fancy_stuff() {
// `_paths` acts like a guard here.
let _paths = mock_xdg_env();
my_app::create_fancy_files();
assert!(my_fancy_file_path.is_file());
}
Turn out that Rust runs these concurrently, and combined with both the environment and the filesystem being globally mutable, things may go haywire: tests randomly succeeding, and randomly throwing random errors.
In any case, this was my first time having a race condition in Rust. Neat.
-
vim
told me to substitute “very” for “damn”. ↩