forked from ROMEO/nexosim
Add support for simulation timeouts
This commit is contained in:
8
asynchronix/tests/integration/main.rs
Normal file
8
asynchronix/tests/integration/main.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// Integration tests follow the organization suggested by Matklad:
|
||||
// https://matklad.github.io/2021/02/27/delete-cargo-integration-tests.html
|
||||
|
||||
mod model_scheduling;
|
||||
mod simulation_deadlock;
|
||||
mod simulation_scheduling;
|
||||
#[cfg(not(miri))]
|
||||
mod simulation_timeout;
|
@ -2,8 +2,6 @@
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
const MT_NUM_THREADS: usize = 4;
|
||||
|
||||
#[cfg(not(miri))]
|
||||
use asynchronix::model::Context;
|
||||
use asynchronix::model::Model;
|
||||
@ -11,6 +9,8 @@ use asynchronix::ports::{EventBuffer, Output};
|
||||
use asynchronix::simulation::{Address, Mailbox, SimInit, Simulation};
|
||||
use asynchronix::time::MonotonicTime;
|
||||
|
||||
const MT_NUM_THREADS: usize = 4;
|
||||
|
||||
// Input-to-output pass-through model.
|
||||
struct PassThroughModel<T: Clone + Send + 'static> {
|
||||
pub output: Output<T>,
|
||||
@ -49,7 +49,7 @@ fn passthrough_bench<T: Clone + Send + 'static>(
|
||||
(simu, addr, out_stream)
|
||||
}
|
||||
|
||||
fn simulation_schedule_events(num_threads: usize) {
|
||||
fn schedule_events(num_threads: usize) {
|
||||
let t0 = MonotonicTime::EPOCH;
|
||||
let (mut simu, addr, mut output) = passthrough_bench(num_threads, t0);
|
||||
|
||||
@ -90,7 +90,7 @@ fn simulation_schedule_events(num_threads: usize) {
|
||||
assert!(output.next().is_none());
|
||||
}
|
||||
|
||||
fn simulation_schedule_keyed_events(num_threads: usize) {
|
||||
fn schedule_keyed_events(num_threads: usize) {
|
||||
let t0 = MonotonicTime::EPOCH;
|
||||
let (mut simu, addr, mut output) = passthrough_bench(num_threads, t0);
|
||||
|
||||
@ -131,7 +131,7 @@ fn simulation_schedule_keyed_events(num_threads: usize) {
|
||||
assert!(output.next().is_none());
|
||||
}
|
||||
|
||||
fn simulation_schedule_periodic_events(num_threads: usize) {
|
||||
fn schedule_periodic_events(num_threads: usize) {
|
||||
let t0 = MonotonicTime::EPOCH;
|
||||
let (mut simu, addr, mut output) = passthrough_bench(num_threads, t0);
|
||||
|
||||
@ -170,7 +170,7 @@ fn simulation_schedule_periodic_events(num_threads: usize) {
|
||||
}
|
||||
}
|
||||
|
||||
fn simulation_schedule_periodic_keyed_events(num_threads: usize) {
|
||||
fn schedule_periodic_keyed_events(num_threads: usize) {
|
||||
let t0 = MonotonicTime::EPOCH;
|
||||
let (mut simu, addr, mut output) = passthrough_bench(num_threads, t0);
|
||||
|
||||
@ -219,43 +219,43 @@ fn simulation_schedule_periodic_keyed_events(num_threads: usize) {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simulation_schedule_events_st() {
|
||||
simulation_schedule_events(1);
|
||||
fn schedule_events_st() {
|
||||
schedule_events(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simulation_schedule_events_mt() {
|
||||
simulation_schedule_events(MT_NUM_THREADS);
|
||||
fn schedule_events_mt() {
|
||||
schedule_events(MT_NUM_THREADS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simulation_schedule_keyed_events_st() {
|
||||
simulation_schedule_keyed_events(1);
|
||||
fn schedule_keyed_events_st() {
|
||||
schedule_keyed_events(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simulation_schedule_keyed_events_mt() {
|
||||
simulation_schedule_keyed_events(MT_NUM_THREADS);
|
||||
fn schedule_keyed_events_mt() {
|
||||
schedule_keyed_events(MT_NUM_THREADS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simulation_schedule_periodic_events_st() {
|
||||
simulation_schedule_periodic_events(1);
|
||||
fn schedule_periodic_events_st() {
|
||||
schedule_periodic_events(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simulation_schedule_periodic_events_mt() {
|
||||
simulation_schedule_periodic_events(MT_NUM_THREADS);
|
||||
fn schedule_periodic_events_mt() {
|
||||
schedule_periodic_events(MT_NUM_THREADS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simulation_schedule_periodic_keyed_events_st() {
|
||||
simulation_schedule_periodic_keyed_events(1);
|
||||
fn schedule_periodic_keyed_events_st() {
|
||||
schedule_periodic_keyed_events(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simulation_schedule_periodic_keyed_events_mt() {
|
||||
simulation_schedule_periodic_keyed_events(MT_NUM_THREADS);
|
||||
fn schedule_periodic_keyed_events_mt() {
|
||||
schedule_periodic_keyed_events(MT_NUM_THREADS);
|
||||
}
|
||||
|
||||
#[cfg(not(miri))]
|
||||
@ -313,7 +313,7 @@ fn timestamp_bench(
|
||||
}
|
||||
|
||||
#[cfg(not(miri))]
|
||||
fn simulation_system_clock_from_instant(num_threads: usize) {
|
||||
fn system_clock_from_instant(num_threads: usize) {
|
||||
let t0 = MonotonicTime::EPOCH;
|
||||
const TOLERANCE: f64 = 0.005; // [s]
|
||||
|
||||
@ -369,7 +369,7 @@ fn simulation_system_clock_from_instant(num_threads: usize) {
|
||||
}
|
||||
|
||||
#[cfg(not(miri))]
|
||||
fn simulation_system_clock_from_system_time(num_threads: usize) {
|
||||
fn system_clock_from_system_time(num_threads: usize) {
|
||||
let t0 = MonotonicTime::EPOCH;
|
||||
const TOLERANCE: f64 = 0.005; // [s]
|
||||
|
||||
@ -431,7 +431,7 @@ fn simulation_system_clock_from_system_time(num_threads: usize) {
|
||||
}
|
||||
|
||||
#[cfg(not(miri))]
|
||||
fn simulation_auto_system_clock(num_threads: usize) {
|
||||
fn auto_system_clock(num_threads: usize) {
|
||||
let t0 = MonotonicTime::EPOCH;
|
||||
const TOLERANCE: f64 = 0.005; // [s]
|
||||
|
||||
@ -478,36 +478,36 @@ fn simulation_auto_system_clock(num_threads: usize) {
|
||||
|
||||
#[cfg(not(miri))]
|
||||
#[test]
|
||||
fn simulation_system_clock_from_instant_st() {
|
||||
simulation_system_clock_from_instant(1);
|
||||
fn system_clock_from_instant_st() {
|
||||
system_clock_from_instant(1);
|
||||
}
|
||||
|
||||
#[cfg(not(miri))]
|
||||
#[test]
|
||||
fn simulation_system_clock_from_instant_mt() {
|
||||
simulation_system_clock_from_instant(MT_NUM_THREADS);
|
||||
fn system_clock_from_instant_mt() {
|
||||
system_clock_from_instant(MT_NUM_THREADS);
|
||||
}
|
||||
|
||||
#[cfg(not(miri))]
|
||||
#[test]
|
||||
fn simulation_system_clock_from_system_time_st() {
|
||||
simulation_system_clock_from_system_time(1);
|
||||
fn system_clock_from_system_time_st() {
|
||||
system_clock_from_system_time(1);
|
||||
}
|
||||
|
||||
#[cfg(not(miri))]
|
||||
#[test]
|
||||
fn simulation_system_clock_from_system_time_mt() {
|
||||
simulation_system_clock_from_system_time(MT_NUM_THREADS);
|
||||
fn system_clock_from_system_time_mt() {
|
||||
system_clock_from_system_time(MT_NUM_THREADS);
|
||||
}
|
||||
|
||||
#[cfg(not(miri))]
|
||||
#[test]
|
||||
fn simulation_auto_system_clock_st() {
|
||||
simulation_auto_system_clock(1);
|
||||
fn auto_system_clock_st() {
|
||||
auto_system_clock(1);
|
||||
}
|
||||
|
||||
#[cfg(not(miri))]
|
||||
#[test]
|
||||
fn simulation_auto_system_clock_mt() {
|
||||
simulation_auto_system_clock(MT_NUM_THREADS);
|
||||
fn auto_system_clock_mt() {
|
||||
auto_system_clock(MT_NUM_THREADS);
|
||||
}
|
103
asynchronix/tests/integration/simulation_timeout.rs
Normal file
103
asynchronix/tests/integration/simulation_timeout.rs
Normal file
@ -0,0 +1,103 @@
|
||||
//! Timeout during step execution.
|
||||
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use asynchronix::model::Model;
|
||||
use asynchronix::ports::Output;
|
||||
use asynchronix::simulation::{ExecutionError, Mailbox, SimInit};
|
||||
use asynchronix::time::MonotonicTime;
|
||||
|
||||
const MT_NUM_THREADS: usize = 4;
|
||||
|
||||
#[derive(Default)]
|
||||
struct TestModel {
|
||||
output: Output<()>,
|
||||
// A liveliness flag that is cleared when the model is dropped.
|
||||
is_alive: Arc<AtomicBool>,
|
||||
}
|
||||
impl TestModel {
|
||||
fn new() -> (Self, Arc<AtomicBool>) {
|
||||
let is_alive = Arc::new(AtomicBool::new(true));
|
||||
|
||||
(
|
||||
Self {
|
||||
output: Output::default(),
|
||||
is_alive: is_alive.clone(),
|
||||
},
|
||||
is_alive,
|
||||
)
|
||||
}
|
||||
|
||||
async fn input(&mut self) {
|
||||
self.output.send(()).await;
|
||||
}
|
||||
}
|
||||
impl Drop for TestModel {
|
||||
fn drop(&mut self) {
|
||||
self.is_alive.store(false, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
impl Model for TestModel {}
|
||||
|
||||
fn timeout_untriggered(num_threads: usize) {
|
||||
let (model, _model_is_alive) = TestModel::new();
|
||||
let mbox = Mailbox::new();
|
||||
let addr = mbox.address();
|
||||
|
||||
let t0 = MonotonicTime::EPOCH;
|
||||
let mut simu = SimInit::with_num_threads(num_threads)
|
||||
.add_model(model, mbox, "test")
|
||||
.set_timeout(Duration::from_secs(1))
|
||||
.init(t0)
|
||||
.unwrap();
|
||||
|
||||
assert!(simu.process_event(TestModel::input, (), addr).is_ok());
|
||||
}
|
||||
|
||||
fn timeout_triggered(num_threads: usize) {
|
||||
let (mut model, model_is_alive) = TestModel::new();
|
||||
let mbox = Mailbox::new();
|
||||
let addr = mbox.address();
|
||||
|
||||
// Make a loopback connection.
|
||||
model.output.connect(TestModel::input, addr.clone());
|
||||
|
||||
let t0 = MonotonicTime::EPOCH;
|
||||
let mut simu = SimInit::with_num_threads(num_threads)
|
||||
.add_model(model, mbox, "test")
|
||||
.set_timeout(Duration::from_secs(1))
|
||||
.init(t0)
|
||||
.unwrap();
|
||||
|
||||
assert!(matches!(
|
||||
simu.process_event(TestModel::input, (), addr),
|
||||
Err(ExecutionError::Timeout)
|
||||
));
|
||||
|
||||
// Make sure the request to stop the simulation has succeeded.
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
assert!(!model_is_alive.load(Ordering::Relaxed));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timeout_untriggered_st() {
|
||||
timeout_untriggered(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timeout_untriggered_mt() {
|
||||
timeout_untriggered(MT_NUM_THREADS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timeout_triggered_st() {
|
||||
timeout_triggered(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timeout_triggered_mt() {
|
||||
timeout_triggered(MT_NUM_THREADS);
|
||||
}
|
Reference in New Issue
Block a user