mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-29 12:17:14 -06:00
Merge pull request #4520 from mockydevs/fix/gpu-start-tests-spawn-race
test(app): keep a child's start from holding the GPU start file's lock
This commit is contained in:
@@ -548,11 +548,14 @@ fn a_normal_exit_or_another_failure_does_not_restart() {
|
||||
assert_eq!(finish(Err("a bug".into()), &startup), Err("a bug".into()));
|
||||
}
|
||||
|
||||
/// A log folder of its own for each test.
|
||||
fn start_dir(tag: &str) -> std::path::PathBuf {
|
||||
/// A log folder of its own for each test, and the guard that keeps other tests from starting a
|
||||
/// program while it runs: the test releases the start file's lock and takes it again, and a child
|
||||
/// starting meanwhile would keep it held (`crate::no_spawns`).
|
||||
fn start_dir(tag: &str) -> (std::path::PathBuf, std::sync::RwLockReadGuard<'static, ()>) {
|
||||
let spawns = crate::no_spawns();
|
||||
let d = std::env::temp_dir().join(format!("vectorcraft-gpu-start-{tag}-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&d);
|
||||
d
|
||||
(d, spawns)
|
||||
}
|
||||
|
||||
/// What a start in `dir` leaves out; it then ends without crashing.
|
||||
@@ -578,7 +581,7 @@ fn issue_2243() -> Vec<Candidate> {
|
||||
/// it, without a status-bar note.
|
||||
#[test]
|
||||
fn a_start_that_never_showed_a_frame_leaves_its_adapter_out_of_the_next() {
|
||||
let dir = start_dir("crash");
|
||||
let (dir, _spawns) = start_dir("crash");
|
||||
let c = issue_2243();
|
||||
let first = Startup::default();
|
||||
assert_eq!(first.track(&dir, None, false), LeftOut::default());
|
||||
@@ -609,7 +612,7 @@ fn a_start_that_never_showed_a_frame_leaves_its_adapter_out_of_the_next() {
|
||||
/// an error, a restart on another adapter), leaves nothing out of the next.
|
||||
#[test]
|
||||
fn a_start_that_showed_its_first_frame_or_ended_is_cleared() {
|
||||
let dir = start_dir("shown");
|
||||
let (dir, _spawns) = start_dir("shown");
|
||||
let c = issue_2243();
|
||||
for end in [Startup::presented as fn(&Startup), Startup::ended] {
|
||||
let first = Startup::default();
|
||||
@@ -633,7 +636,7 @@ fn a_start_that_showed_its_first_frame_or_ended_is_cleared() {
|
||||
/// macOS, where wgpu has none.
|
||||
#[test]
|
||||
fn a_crash_while_listing_lists_opengl_alone() {
|
||||
let dir = start_dir("listing");
|
||||
let (dir, _spawns) = start_dir("listing");
|
||||
let first = Startup::default();
|
||||
first.track(&dir, None, false);
|
||||
drop(first);
|
||||
@@ -660,7 +663,7 @@ fn a_crash_while_listing_lists_opengl_alone() {
|
||||
/// start shows its first frame on the adapter that crashed, the adapter counts again.
|
||||
#[test]
|
||||
fn wgpu_backend_or_adapter_name_ignores_the_crashes() {
|
||||
let dir = start_dir("explicit");
|
||||
let (dir, _spawns) = start_dir("explicit");
|
||||
let c = issue_2243();
|
||||
let first = Startup::default();
|
||||
first.track(&dir, None, false);
|
||||
@@ -681,7 +684,7 @@ fn wgpu_backend_or_adapter_name_ignores_the_crashes() {
|
||||
/// are ignored: the start goes on with nothing left out.
|
||||
#[test]
|
||||
fn a_damaged_or_unreadable_start_file_is_ignored() {
|
||||
let dir = start_dir("damaged");
|
||||
let (dir, _spawns) = start_dir("damaged");
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let damaged: [&[u8]; 9] = [
|
||||
b"",
|
||||
|
||||
@@ -483,5 +483,28 @@ fn main() -> std::process::ExitCode {
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests only: while a test starts another program, the child briefly holds a copy of every file
|
||||
/// this process has open, until it runs that program. A file lock held through such a copy outlives
|
||||
/// its own handle, so a GPU start test that released the start file and opened it again found it
|
||||
/// still locked, as if another copy of the app were running, and failed. A test that starts a
|
||||
/// program holds [`spawning`]; a test that depends on the start file's lock holds [`no_spawns`].
|
||||
#[cfg(all(
|
||||
test,
|
||||
any(feature = "wgpu", any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd", target_os = "openbsd"))
|
||||
))]
|
||||
static CHILD_SPAWN: std::sync::RwLock<()> = std::sync::RwLock::new(());
|
||||
|
||||
/// Held while a test starts another program (see [`CHILD_SPAWN`]).
|
||||
#[cfg(all(test, any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd", target_os = "openbsd")))]
|
||||
fn spawning() -> std::sync::RwLockWriteGuard<'static, ()> {
|
||||
CHILD_SPAWN.write().unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
}
|
||||
|
||||
/// Held by a test that releases a locked file and opens it again (see [`CHILD_SPAWN`]).
|
||||
#[cfg(all(test, feature = "wgpu"))]
|
||||
fn no_spawns() -> std::sync::RwLockReadGuard<'static, ()> {
|
||||
CHILD_SPAWN.read().unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "wgpu"))]
|
||||
mod tests;
|
||||
|
||||
@@ -450,11 +450,13 @@ mod tests {
|
||||
use std::io::BufRead as _;
|
||||
|
||||
use zbus::zvariant::OwnedObjectPath;
|
||||
let mut daemon = std::process::Command::new("dbus-daemon")
|
||||
let spawning = crate::spawning();
|
||||
let daemon = std::process::Command::new("dbus-daemon")
|
||||
.args(["--session", "--nofork", "--print-address=1"])
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.spawn()
|
||||
.ok()?;
|
||||
.spawn();
|
||||
drop(spawning);
|
||||
let mut daemon = daemon.ok()?;
|
||||
let mut address = String::new();
|
||||
std::io::BufReader::new(daemon.stdout.take()?).read_line(&mut address).ok()?;
|
||||
let address = address.trim().to_string();
|
||||
|
||||
Reference in New Issue
Block a user