Unique ID per test

I've run into the problem with my library when it needs to generate some temporary file. That's what I'm doing now:

lazy_static! {
    static ref TARGET: PathBuf = {
        let mut tmp: PathBuf = [".", "target", "batch"].iter().collect();
        std::fs::create_dir_all(&tmp).unwrap();
        tmp.push(&format!("{:x}", rand::random::<u64>()));
        tmp.with_extension(EXE_EXTENSION)
    };
}

Playground

It works fine when there is only one instance, but blows up when running tests in multiple threads: it seems that they get the same value from this lazy_static, and at least one of the tests is trying to use this file while it is locked by another test, therefore crashing. I feel like there should be another way to create them, but I'm not sure how to approach it.

Are you looking for the tempfile crate?

1 Like

If you don't want to create a temporary file for each test, using thread-local storage is a solution. thead_local macro from std can be used to create a TLS variable but because it has to be accessed in a closure as in doc, you may have to change your code a bit.

1 Like

You can use a global atomic variable which will return a unique number each time it is called (until you run out of numbers)

fn id() -> usize {
    use std::sync::atomic::{AtomicUsize, Ordering};
    static ID: AtomicUsize = AtomicUsize::new(0);
    ID.fetch_add(1, Ordering::SeqCst)
}

#[test]
fn one() {
    panic!("{}", id());
}

#[test]
fn two() {
    panic!("{}", id());
}

#[test]
fn three() {
    panic!("{}", id());
}

This could be combined with a thread-local variable if you wanted each thread to reuse a single ID.

See also:

2 Likes

I thought about it too, but I don't create the file myself, in fact. I need to pass the path to the dependency (which will operate on it).

Looks like the thing I need, thanks. Global atomic is nice too, but for my case the thread-local seems to be enough.