Skip to content

Commit a80ab84

Browse files
committed
Actually test for empty execution context
1 parent a3d077e commit a80ab84

2 files changed

Lines changed: 27 additions & 11 deletions

File tree

crates/ark/src/r_task.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,3 +519,20 @@ unsafe extern "C-unwind" fn ps_test_spawn_sleeping_idle_tasks(
519519

520520
Ok(libr::R_NilValue)
521521
}
522+
523+
/// Spawn an idle task that evaluates an R expression. Used in integration tests.
524+
#[cfg(debug_assertions)]
525+
#[harp::register]
526+
unsafe extern "C-unwind" fn ps_test_spawn_eval_idle_task(code: SEXP) -> anyhow::Result<SEXP> {
527+
stdext::assert_testing();
528+
529+
let code: String = harp::RObject::view(code).try_into()?;
530+
531+
spawn(RTask::idle(async move |_capture| {
532+
if let Err(err) = harp::parse_eval_global(&code) {
533+
log::error!("Idle task eval failed: {err:?}");
534+
}
535+
}));
536+
537+
Ok(libr::R_NilValue)
538+
}

crates/ark/tests/plots.rs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -720,24 +720,23 @@ fn test_plot_during_frontend_ready() {
720720
fn test_plot_without_execution_context_has_empty_metadata() {
721721
let frontend = DummyArkFrontend::lock();
722722

723-
// Register a task callback that creates a plot. Task callbacks fire
724-
// after each top-level R evaluation completes, at which point the
725-
// execution context has already been cleared by `on_did_execute_request`.
726-
// The callback removes itself after one invocation (returns FALSE).
727-
//
728-
// The task callback fires immediately after this evaluation completes
729-
// (but still within the busy/idle window), so the display_data for the
730-
// plot arrives before idle.
723+
// Spawn an idle task that creates a plot. Idle tasks run during the
724+
// event loop between execute requests, so no execution context is
725+
// active when the plot is produced.
731726
frontend.send_execute_request(
732-
r#"invisible(addTaskCallback(function(...) { plot(1:10); FALSE }))"#,
727+
r#"invisible(.Call("ps_test_spawn_eval_idle_task", "plot(1:10)"))"#,
733728
ExecuteRequestOptions::default(),
734729
);
735730
frontend.recv_iopub_busy();
736731
frontend.recv_iopub_execute_input();
737-
let display_id = frontend.recv_iopub_display_data_id();
738732
frontend.recv_iopub_idle();
739733
frontend.recv_shell_execute_reply();
740734

735+
// After the request completes, R re-enters the idle loop. The test
736+
// thread is blocked here (not sending new requests), so `select`
737+
// picks up the idle task and the display_data arrives promptly.
738+
let display_id = frontend.recv_iopub_display_data_id();
739+
741740
// Query metadata using the display_id from the plot
742741
let query_code = format!(".ps.graphics.get_metadata('{display_id}')");
743742
frontend.send_execute_request(&query_code, ExecuteRequestOptions::default());
@@ -748,7 +747,7 @@ fn test_plot_without_execution_context_has_empty_metadata() {
748747
frontend.recv_shell_execute_reply();
749748

750749
// execution_id and code should be empty since the plot was created
751-
// outside of an execute request's execution context
750+
// outside of any execute request
752751
assert!(result.contains("$execution_id\n[1] \"\""));
753752
assert!(result.contains("$code\n[1] \"\""));
754753
}

0 commit comments

Comments
 (0)