Single mutable global for all tests


#1

I am in need of a mutable global BTreeMap. I’ll tell why so that if there is alternative then you can tell. Every operation that happens in my crate depends on finally getting or putting information onto the network. The networking crate is not yet ready. So i just made a mock backend that will mimic networking but actually use this global BTreeMap to give an illusion of data being stored persistently in the network. I need all tests in all modules to use that global Map indirectly through the mock. For instance, every unit test needs to start out by creating an account. This account name cannot be repeated and has to be randomly generated. So if any test uses same name for the account creation i have to flag it as an error, hence need persistence across all tests (which i guess rust runs in parallel). So when actual network is up, the testing will happen in CI (travis, jenkins etc) against that network and no extra code/test will be required and no existing ones will be modified.

So is there a way i can do something like:
static mut DATA_STORE: ::std::sync::Mutex<::std::collections::BTreeMap<SomeType, Vec<u8>>> = ::std::sync::Mutex::new(::std::collections::BTreeMap::new());

ofcourse the usage will require unsafe blocks but i am fine with it as just one mod (the mock backend) will be using it and other mods just use this mock - so other mods will not have access to DATA_STORE (they don’t even know and believe it is gone into the network)


#2

Check out lazy_static. Also note, it doesn’t need to be mutable; Mutex’s have interior mutability.


#3

Ah thanks ! In the meantime i came across this:

lazy_static uses macros and i haven’t read up macros in rust yet :frowning: … I’ll look into that too once i get the hang of macros. Till then mutable singleton seems to help me understand how to go about global variables. I also think it’s better to put it in a function like in that SO link above because otherwise in C++ it lead to Static-initialization-order-fiasco and putting it in a function was a way to avoid it - don’t know much about rust to comment on this though.

Only one more question while on this topic. So if all the tests in cargo test access this singleton is it guaranteed to get the persistence of a singleton or are all tests like separate processes and all will be in vain ?


#4

lazy_static does pretty much what that post suggests but instead of defining a free function, it creates a custom smart pointer with a Once inside and implements Deref for it. When dereferenced, the smart pointer calls call_once(|| /* initialization code */) on the inner Once. TL;DR: rust doesn’t have static initialization (that’s how it avoids the C++ static initialization order fiasco). Of course, if two lazy static constructors reference each other, you’re going to get a panic or deadlock.

IIRC, rust runs tests in parallel in a single process. Note: If you use a static, you will not get test isolation (but it sounds like this is exactly what you want).


#5

yep that’s what i want exactly. Thank you so much !