summaryrefslogtreecommitdiff
path: root/cli/ops/testing.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/ops/testing.rs')
-rw-r--r--cli/ops/testing.rs100
1 files changed, 99 insertions, 1 deletions
diff --git a/cli/ops/testing.rs b/cli/ops/testing.rs
index eb2deb90c..16544dd98 100644
--- a/cli/ops/testing.rs
+++ b/cli/ops/testing.rs
@@ -1,17 +1,31 @@
+use std::cell::RefCell;
+use std::io::Read;
+use std::rc::Rc;
+
use crate::tools::test::TestEvent;
+use crate::tools::test::TestOutput;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::Extension;
use deno_core::ModuleSpecifier;
use deno_core::OpState;
+use deno_runtime::ops::io::StdFileResource;
use deno_runtime::permissions::create_child_permissions;
use deno_runtime::permissions::ChildPermissionsArg;
use deno_runtime::permissions::Permissions;
use tokio::sync::mpsc::UnboundedSender;
use uuid::Uuid;
-pub fn init(sender: UnboundedSender<TestEvent>) -> Extension {
+pub fn init(
+ sender: UnboundedSender<TestEvent>,
+ stdout_writer: os_pipe::PipeWriter,
+ stderr_writer: os_pipe::PipeWriter,
+) -> Extension {
+ // todo(dsheret): don't do this? Taking out the writers was necessary to prevent invalid handle panics
+ let stdout_writer = Rc::new(RefCell::new(Some(stdout_writer)));
+ let stderr_writer = Rc::new(RefCell::new(Some(stderr_writer)));
+
Extension::builder()
.ops(vec![
op_pledge_test_permissions::decl(),
@@ -19,13 +33,82 @@ pub fn init(sender: UnboundedSender<TestEvent>) -> Extension {
op_get_test_origin::decl(),
op_dispatch_test_event::decl(),
])
+ .middleware(|op| match op.name {
+ "op_print" => op_print::decl(),
+ _ => op,
+ })
.state(move |state| {
+ state.resource_table.replace(
+ 1,
+ StdFileResource::stdio(
+ &pipe_writer_to_file(&stdout_writer.borrow_mut().take().unwrap()),
+ "stdout",
+ ),
+ );
+ state.resource_table.replace(
+ 2,
+ StdFileResource::stdio(
+ &pipe_writer_to_file(&stderr_writer.borrow_mut().take().unwrap()),
+ "stderr",
+ ),
+ );
state.put(sender.clone());
Ok(())
})
.build()
}
+#[cfg(windows)]
+fn pipe_writer_to_file(writer: &os_pipe::PipeWriter) -> std::fs::File {
+ use std::os::windows::prelude::AsRawHandle;
+ use std::os::windows::prelude::FromRawHandle;
+ unsafe { std::fs::File::from_raw_handle(writer.as_raw_handle()) }
+}
+
+#[cfg(unix)]
+fn pipe_writer_to_file(writer: &os_pipe::PipeWriter) -> std::fs::File {
+ use std::os::unix::io::AsRawFd;
+ use std::os::unix::io::FromRawFd;
+ unsafe { std::fs::File::from_raw_fd(writer.as_raw_fd()) }
+}
+
+/// Creates the stdout and stderr pipes and returns the writers for stdout and stderr.
+pub fn create_stdout_stderr_pipes(
+ sender: UnboundedSender<TestEvent>,
+) -> (os_pipe::PipeWriter, os_pipe::PipeWriter) {
+ let (stdout_reader, stdout_writer) = os_pipe::pipe().unwrap();
+ let (stderr_reader, stderr_writer) = os_pipe::pipe().unwrap();
+
+ start_output_redirect_thread(stdout_reader, sender.clone(), |bytes| {
+ TestOutput::Stdout(bytes)
+ });
+ start_output_redirect_thread(stderr_reader, sender, |bytes| {
+ TestOutput::Stderr(bytes)
+ });
+
+ (stdout_writer, stderr_writer)
+}
+
+fn start_output_redirect_thread(
+ mut pipe_reader: os_pipe::PipeReader,
+ sender: UnboundedSender<TestEvent>,
+ map_test_output: impl Fn(Vec<u8>) -> TestOutput + Send + 'static,
+) {
+ tokio::task::spawn_blocking(move || loop {
+ let mut buffer = [0; 512];
+ let size = match pipe_reader.read(&mut buffer) {
+ Ok(0) | Err(_) => break,
+ Ok(size) => size,
+ };
+ if sender
+ .send(TestEvent::Output(map_test_output(buffer[0..size].to_vec())))
+ .is_err()
+ {
+ break;
+ }
+ });
+}
+
#[derive(Clone)]
struct PermissionsHolder(Uuid, Permissions);
@@ -77,6 +160,21 @@ fn op_dispatch_test_event(
) -> Result<(), AnyError> {
let sender = state.borrow::<UnboundedSender<TestEvent>>().clone();
sender.send(event).ok();
+ Ok(())
+}
+#[op]
+pub fn op_print(
+ state: &mut OpState,
+ msg: String,
+ is_err: bool,
+) -> Result<(), AnyError> {
+ let sender = state.borrow::<UnboundedSender<TestEvent>>().clone();
+ let msg = if is_err {
+ TestOutput::PrintStderr(msg)
+ } else {
+ TestOutput::PrintStdout(msg)
+ };
+ sender.send(TestEvent::Output(msg)).ok();
Ok(())
}