Avoid example tests overwriting each other's platforms

Closes https://github.com/roc-lang/roc/issues/4038
This commit is contained in:
Ayaz Hafiz 2022-09-19 12:11:51 -05:00
parent 39d82d6cbb
commit d65f0bbedc
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
3 changed files with 40 additions and 4 deletions

6
Cargo.lock generated
View file

@ -2615,9 +2615,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.13.0"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0"
[[package]]
name = "oorandom"
@ -3458,6 +3458,8 @@ dependencies = [
"libloading",
"memexec",
"mimalloc",
"once_cell",
"parking_lot 0.12.1",
"pretty_assertions",
"roc_build",
"roc_builtins",

View file

@ -101,6 +101,8 @@ criterion = { git = "https://github.com/Anton-4/criterion.rs"}
cli_utils = { path = "../cli_utils" }
strum = "0.24.0"
strum_macros = "0.24"
once_cell = "1.14.0"
parking_lot = "0.12"
# Wasmer singlepass compiler only works on x86_64.
[target.'cfg(target_arch = "x86_64")'.dev-dependencies]

View file

@ -16,11 +16,14 @@ mod cli_run {
};
use const_format::concatcp;
use indoc::indoc;
use once_cell::sync::Lazy;
use parking_lot::{Mutex, RwLock};
use roc_cli::{CMD_BUILD, CMD_CHECK, CMD_FORMAT, CMD_RUN};
use roc_test_utils::assert_multiline_str_eq;
use serial_test::serial;
use std::iter;
use std::path::Path;
use std::path::{Path, PathBuf};
use std::sync::Once;
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
@ -31,8 +34,19 @@ mod cli_run {
#[allow(dead_code)]
const TARGET_FLAG: &str = concatcp!("--", roc_cli::FLAG_TARGET);
use std::sync::Once;
static BENCHMARKS_BUILD_PLATFORM: Once = Once::new();
static POPULATED_EXAMPLE_LOCKS: Once = Once::new();
use std::collections::HashMap;
static EXAMPLE_PLATFORM_LOCKS: Lazy<RwLock<HashMap<PathBuf, Mutex<()>>>> =
once_cell::sync::Lazy::new(|| RwLock::new(HashMap::default()));
fn populate_example_locks(examples: impl Iterator<Item = PathBuf>) {
let mut locks = EXAMPLE_PLATFORM_LOCKS.write();
for example in examples {
locks.insert(example, Default::default());
}
}
#[derive(Debug, EnumIter)]
enum CliMode {
@ -270,12 +284,19 @@ mod cli_run {
/// add a test for it here!
macro_rules! examples {
($($test_name:ident:$name:expr => $example:expr,)+) => {
static EXAMPLE_NAMES: &[&str] = &[$($name,)+];
$(
#[test]
#[allow(non_snake_case)]
fn $test_name() {
POPULATED_EXAMPLE_LOCKS.call_once( || {
populate_example_locks(EXAMPLE_NAMES.iter().map(|name| examples_dir(name)))
});
let dir_name = $name;
let example = $example;
let example_dir = examples_dir(dir_name);
let file_name = example_file(dir_name, example.filename);
let mut app_args: Vec<String> = vec![];
@ -318,6 +339,17 @@ mod cli_run {
_ => {}
}
// To avoid concurrent examples tests overwriting produced host binaries, lock
// on the example's directory, so that only one example per directory runs at a
// time.
// NOTE: we are assuming that each example corresponds to one platform, under
// the subdirectory. This is not necessarily true, and moreover is too
// restrictive. To increase throughput we only need to lock the produced host
// file, however, it is not trivial to recover what that file is today (without
// enumerating all examples and their platforms).
let locks = EXAMPLE_PLATFORM_LOCKS.read();
let _example_guard = locks.get(&example_dir).unwrap().lock();
// Check with and without optimizations
check_output_with_stdin(
&file_name,