use flo_scene::*;
use flo_scene::programs::*;
use futures::prelude::*;
use futures::future;
use serde::*;
#[test]
fn notify_on_idle() {
let scene = Scene::default();
let test_program = SubProgramId::new();
TestBuilder::new()
.send_message(IdleRequest::WhenIdle(test_program))
.expect_message(|IdleNotification| { Ok(()) })
.run_in_scene_with_threads(&scene, test_program, 5);
}
#[test]
fn notifies_if_subprogram_drops_input_stream() {
let scene = Scene::default();
let test_program = SubProgramId::new();
scene.add_subprogram(SubProgramId::new(), |_: InputStream<()>, _| async move {
future::pending::<()>().await;
}, 0);
TestBuilder::new()
.send_message(IdleRequest::WhenIdle(test_program))
.expect_message(|IdleNotification| { Ok(()) })
.run_in_scene_with_threads(&scene, test_program, 5);
}
#[test]
fn wait_for_idle_then_send_message_empty_scene() {
let scene = Scene::empty();
let test_program = SubProgramId::new();
scene.add_subprogram(SubProgramId::new(), move |_input: InputStream<()>, context| async move {
context.wait_for_idle(1000).await;
context.send(test_program).unwrap()
.send(IdleNotification).await.unwrap();
}, 1);
TestBuilder::new()
.expect_message(|IdleNotification| { Ok(()) })
.run_in_scene_with_threads(&scene, test_program, 5);
}
#[test]
fn wait_for_idle_then_send_message_default_scene() {
let scene = Scene::default();
let test_program = SubProgramId::new();
scene.add_subprogram(SubProgramId::new(), move |_input: InputStream<()>, context| async move {
context.wait_for_idle(1000).await;
context.send(test_program).unwrap()
.send(IdleNotification).await.unwrap();
}, 1);
TestBuilder::new()
.expect_message(|IdleNotification| { Ok(()) })
.run_in_scene_with_threads(&scene, test_program, 5);
}
#[test]
fn wait_for_idle_program_errors_when_full() {
let scene = Scene::empty();
let test_program = SubProgramId::new();
let waiting_program = SubProgramId::new();
#[derive(PartialEq, Debug, Serialize, Deserialize)]
struct TrySend;
impl SceneMessage for TrySend { }
#[derive(Debug, Serialize, Deserialize)]
struct SendResult(Result<(), SceneSendError<TrySend>>);
impl SceneMessage for SendResult { }
scene.add_subprogram(SubProgramId::new(), move |_: InputStream<()>, context| async move {
let mut idle_program = context.send(waiting_program).unwrap();
let wakes_the_queue = idle_program.send(TrySend).await;
assert!(wakes_the_queue.is_ok(), "Should have woken the stream: {:?}", wakes_the_queue);
let should_be_error = idle_program.send(TrySend).await;
context.send(test_program).unwrap().send(SendResult(should_be_error)).await.unwrap();
}, 0);
scene.add_subprogram(waiting_program, move |input: InputStream<TrySend>, context| async move {
use std::mem;
context.wait_for_idle(0).await;
context.send(test_program).unwrap()
.send(IdleNotification).await.unwrap();
mem::drop(input);
}, 0);
TestBuilder::new()
.expect_message(|SendResult(msg)| { if msg != Err(SceneSendError::CannotAcceptMoreInputUntilSceneIsIdle(TrySend)) { Err(format!("Expected error, got {:?}", msg)) } else { Ok(()) } })
.expect_message(|IdleNotification| { Ok(()) })
.run_in_scene_with_threads(&scene, test_program, 5);
}
#[test]
fn wait_for_idle_program_closed_input_stream() {
let scene = Scene::empty();
let test_program = SubProgramId::new();
let waiting_program = SubProgramId::new();
#[derive(PartialEq, Debug, Serialize, Deserialize)]
struct TrySend;
impl SceneMessage for TrySend { }
#[derive(Debug, Serialize, Deserialize)]
struct SendResult(Result<(), SceneSendError<TrySend>>);
impl SceneMessage for SendResult { }
scene.add_subprogram(SubProgramId::new(), move |_: InputStream<()>, context| async move {
let mut idle_program = context.send(waiting_program).unwrap();
let maybe_wakes_the_queue = idle_program.send(TrySend).await;
let should_be_error = if maybe_wakes_the_queue.is_err() {
maybe_wakes_the_queue
} else {
idle_program.send(TrySend).await
};
context.send(test_program).unwrap().send(SendResult(should_be_error)).await.unwrap();
}, 0);
scene.add_subprogram(waiting_program, move |input: InputStream<TrySend>, context| async move {
use std::mem;
mem::drop(input);
context.wait_for_idle(0).await;
context.send(test_program).unwrap()
.send(IdleNotification).await.unwrap();
}, 0);
TestBuilder::new()
.expect_message(|SendResult(msg)| { if msg != Err(SceneSendError::StreamClosed(TrySend)) { Err(format!("Expected error, got {:?}", msg)) } else { Ok(()) } })
.expect_message(|IdleNotification| { Ok(()) })
.run_in_scene_with_threads(&scene, test_program, 5);
}
#[test]
fn wait_for_idle_program_errors_after_filling_available_space() {
let scene = Scene::empty();
let test_program = SubProgramId::new();
let waiting_program = SubProgramId::new();
#[derive(PartialEq, Debug, Serialize, Deserialize)]
struct TrySend;
impl SceneMessage for TrySend { }
#[derive(Debug, Serialize, Deserialize)]
struct SendResult(Result<(), SceneSendError<TrySend>>);
impl SceneMessage for SendResult { }
scene.add_subprogram(SubProgramId::new(), move |_: InputStream<()>, context| async move {
let mut idle_program = context.send(waiting_program).unwrap();
for i in 0..5 {
println!("Sending {}", i);
idle_program.send(TrySend).await.unwrap();
println!(" Sent {}", i);
}
let should_be_error = idle_program.send(TrySend).await;
context.send(test_program).unwrap().send(SendResult(should_be_error)).await.unwrap();
}, 0);
scene.add_subprogram(waiting_program, move |input: InputStream<TrySend>, context| async move {
use std::mem;
context.wait_for_idle(4).await;
context.send(test_program).unwrap()
.send(IdleNotification).await.unwrap();
mem::drop(input);
}, 2);
TestBuilder::new()
.expect_message(|SendResult(msg)| { if msg != Err(SceneSendError::CannotAcceptMoreInputUntilSceneIsIdle(TrySend)) { Err(format!("Expected error, got {:?}", msg)) } else { Ok(()) } })
.expect_message(|IdleNotification| { Ok(()) })
.run_in_scene_with_threads(&scene, test_program, 5);
}
#[test]
fn wait_for_idle_program_queues_extra_requests() {
let scene = Scene::empty();
let test_program = SubProgramId::new();
let waiting_program = SubProgramId::new();
#[derive(PartialEq, Debug, Serialize, Deserialize)]
struct TrySend;
impl SceneMessage for TrySend { }
scene.add_subprogram(SubProgramId::new(), move |_: InputStream<()>, context| async move {
let mut idle_program = context.send(waiting_program).unwrap();
for _ in 0..5 {
idle_program.send(TrySend).await.unwrap();
}
}, 0);
scene.add_subprogram(waiting_program, move |input: InputStream<TrySend>, context| async move {
context.wait_for_idle(1_000).await;
context.send(test_program).unwrap()
.send(IdleNotification).await.unwrap();
context.wait_for_idle(100).await;
let mut input = input;
for _ in 0..5 {
context.send(test_program).unwrap()
.send(input.next().await.unwrap()).await.unwrap();
}
}, 0);
TestBuilder::new()
.expect_message(|IdleNotification| { Ok(()) })
.expect_message(|TrySend| { Ok(()) })
.expect_message(|TrySend| { Ok(()) })
.expect_message(|TrySend| { Ok(()) })
.expect_message(|TrySend| { Ok(()) })
.expect_message(|TrySend| { Ok(()) })
.run_in_scene_with_threads(&scene, test_program, 5);
}
#[test]
fn wait_for_idle_program_queues_extra_requests_100_times() {
for _ in 0..100 {
let scene = Scene::empty();
let test_program = SubProgramId::new();
let waiting_program = SubProgramId::new();
#[derive(PartialEq, Debug, Serialize, Deserialize)]
struct TrySend;
impl SceneMessage for TrySend { }
scene.add_subprogram(SubProgramId::new(), move |_: InputStream<()>, context| async move {
let mut idle_program = context.send(waiting_program).unwrap();
for _ in 0..5 {
idle_program.send(TrySend).await.unwrap();
}
}, 0);
scene.add_subprogram(waiting_program, move |input: InputStream<TrySend>, context| async move {
context.wait_for_idle(1_000).await;
context.send(test_program).unwrap()
.send(IdleNotification).await.unwrap();
context.wait_for_idle(100).await;
let mut input = input;
for _ in 0..5 {
context.send(test_program).unwrap()
.send(input.next().await.unwrap()).await.unwrap();
}
}, 0);
TestBuilder::new()
.expect_message(|IdleNotification| { Ok(()) })
.expect_message(|TrySend| { Ok(()) })
.expect_message(|TrySend| { Ok(()) })
.expect_message(|TrySend| { Ok(()) })
.expect_message(|TrySend| { Ok(()) })
.expect_message(|TrySend| { Ok(()) })
.run_in_scene_with_threads(&scene, test_program, 5);
}
}