From 77a109145884a64b5b66cde68fae853a3c3a93f0 Mon Sep 17 00:00:00 2001 From: Bernhard Kragl Date: Tue, 11 Apr 2023 01:10:51 +0200 Subject: [PATCH] Split schedule output over multiple lines --- src/runtime/failure.rs | 2 +- src/scheduler/serialization.rs | 9 ++++++++- tests/basic/replay.rs | 28 +++++++++++++++++++++++++++- tests/mod.rs | 20 +++++++++++++++++--- 4 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/runtime/failure.rs b/src/runtime/failure.rs index c7066d6..abf0087 100644 --- a/src/runtime/failure.rs +++ b/src/runtime/failure.rs @@ -72,7 +72,7 @@ fn persist_failure_inner(schedule: &Schedule, message: String, config: &Config) } } format!( - "{}\nfailing schedule: \"{}\"\npass that string to `shuttle::replay` to replay the failure", + "{}\nfailing schedule:\n\"\n{}\n\"\npass that string to `shuttle::replay` to replay the failure", message, serialized_schedule ) } diff --git a/src/scheduler/serialization.rs b/src/scheduler/serialization.rs index 745253c..6a21f7e 100644 --- a/src/scheduler/serialization.rs +++ b/src/scheduler/serialization.rs @@ -86,6 +86,8 @@ mod varint { const SCHEDULE_MAGIC_V2: u8 = 0x91; +const LINE_WIDTH: usize = 76; + pub(crate) fn serialize_schedule(schedule: &Schedule) -> String { use self::varint::{space_needed, WriteVarInt}; @@ -128,12 +130,17 @@ pub(crate) fn serialize_schedule(schedule: &Schedule) -> String { buf.write_u64_varint(schedule.len() as u64).unwrap(); buf.write_u64_varint(schedule.seed).unwrap(); buf.extend(encoded.as_raw_slice()); - hex::encode(buf) + + let serialized = hex::encode(buf); + let lines = serialized.as_bytes().chunks(LINE_WIDTH).collect::>(); + let wrapped = lines.join(&['\n' as u8][..]); + String::from_utf8(wrapped).unwrap() } pub(crate) fn deserialize_schedule(str: &str) -> Option { use self::varint::ReadVarInt; + let str: String = str.chars().filter(|c| !c.is_whitespace()).collect(); let bytes = hex::decode(str).ok()?; let version = bytes[0]; diff --git a/tests/basic/replay.rs b/tests/basic/replay.rs index 74c28c7..04c463c 100644 --- a/tests/basic/replay.rs +++ b/tests/basic/replay.rs @@ -1,5 +1,5 @@ use crate::{check_replay_roundtrip, check_replay_roundtrip_file, Config, FailurePersistence}; -use shuttle::scheduler::{PctScheduler, ReplayScheduler, Schedule}; +use shuttle::scheduler::{PctScheduler, RandomScheduler, ReplayScheduler, Schedule}; use shuttle::sync::Mutex; use shuttle::{replay, thread, Runner}; use std::panic; @@ -136,6 +136,32 @@ fn replay_deadlock3_drop_mutex() { runner.run(deadlock_3); } +fn long_schedule() { + let mut threads = vec![]; + for _ in 0..100 { + threads.push(shuttle::thread::spawn(|| { + for _ in 0..100 { + shuttle::thread::yield_now(); + } + })); + } + for t in threads { + t.join().unwrap(); + } + // If this would be a `panic!`, downcasting the `catch_unwind` error to `String` fails. + assert_eq!(1, 2, "so much work, and all for nothing"); +} + +#[test] +fn replay_long_schedule() { + check_replay_roundtrip(long_schedule, RandomScheduler::new(1)); +} + +#[test] +fn replay_long_schedule_file() { + check_replay_roundtrip_file(long_schedule, RandomScheduler::new(1)); +} + // Check that FailurePersistence::None does not print a schedule #[test] fn replay_persist_none() { diff --git a/tests/mod.rs b/tests/mod.rs index 7e00a04..bcfa26f 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -111,8 +111,22 @@ mod parse_schedule { } pub(super) fn from_stdout>(output: S) -> Option { - let string_regex = Regex::new("failing schedule: \"([0-9a-f]+)\"").unwrap(); - let captures = string_regex.captures(output.as_ref().as_str())?; - Some(captures.get(1)?.as_str().to_string()) + let mut schedule = String::new(); + let mut lines = output.as_ref().lines(); + for line in &mut lines { + if line.eq("failing schedule:") { + break; + } + } + assert_eq!(lines.next().unwrap(), "\""); + for line in lines { + if line.eq("\"") { + schedule.pop(); // trailing newline, if any + return Some(schedule); + } + schedule.push_str(line); + schedule.push('\n'); + } + None } }