blob: aba5ff336e68e6874f2187b0a03526849d81b43a [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#![cfg(test)]
use lazy_static::lazy_static;
use std::env;
use std::ffi::OsString;
use std::path::{Path, PathBuf};
use std::sync::{Mutex, MutexGuard};
use tempfile::{tempdir, TempDir};
lazy_static! {
static ref ENV_MUTEX: Mutex<()> = Mutex::new(());
}
const FUCHSIA_DIR_KEY: &'static str = "FUCHSIA_DIR";
/// A test environment that has the current working directory
/// and the FUCHSIA_DIR environment variable set to a temporary
/// directory.
///
/// This test environment only permits serial execution of threads
/// to prevent other tests from overwriting environment variables.
///
/// Once dropped, the current working directory and FUCHSIA_DIR
/// environment variable are restored to their previous values.
pub struct LockedEnv<'a> {
_guard: MutexGuard<'a, ()>,
temp_dir: TempDir,
fuchsia_dir_snapshot: Option<OsString>,
current_dir_snapshot: PathBuf,
}
impl<'a> LockedEnv<'a> {
pub fn path(&self) -> &Path {
self.temp_dir.path()
}
}
impl<'a> Drop for LockedEnv<'a> {
fn drop(&mut self) {
env::set_current_dir(&self.current_dir_snapshot)
.expect("previous current_dir value should always be valid");
if let Some(fuchsia_dir_snapshot) = &self.fuchsia_dir_snapshot {
env::set_var(FUCHSIA_DIR_KEY, fuchsia_dir_snapshot);
} else {
env::remove_var(FUCHSIA_DIR_KEY);
}
}
}
/// Creates and locks a test environment with the current working directory and
/// FUCHSIA_DIR environment variable set to a temporary directory.
///
/// Using this environment prevents multiple tests from modifying environment
/// variables and interfering with each other.
pub fn lock_test_environment<'a>() -> LockedEnv<'a> {
let guard = match ENV_MUTEX.lock() {
Ok(guard) => guard,
// If a test failed, it will have panicked while holding
// this lock. We don't care, we just want to ensure serial
// execution.
Err(poisoned) => poisoned.into_inner(),
};
let current_dir_snapshot = env::current_dir().expect("failed to get current_dir");
let fuchsia_dir_snapshot = env::var_os(FUCHSIA_DIR_KEY);
let temp_dir = tempdir().expect("failed to create temp dir");
env::set_current_dir(temp_dir.path()).expect("failed to set new current_dir");
env::set_var(FUCHSIA_DIR_KEY, temp_dir.path());
LockedEnv { _guard: guard, temp_dir, fuchsia_dir_snapshot, current_dir_snapshot }
}