summaryrefslogtreecommitdiff
path: root/cli/worker.rs
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2022-11-21 14:36:26 +0100
committerGitHub <noreply@github.com>2022-11-21 14:36:26 +0100
commitd2327469284327c5ec9bbf72d5d16b9b9f8135d6 (patch)
tree598c7dde3ba436b27abf2f6be0c7a9770637e352 /cli/worker.rs
parentfedeea6dde91874774f5a9eb518635427a88e86c (diff)
feat(core): Ability to create snapshots from existing snapshots (#16597)
Co-authored-by: crowlkats <crowlkats@toaxl.com>
Diffstat (limited to 'cli/worker.rs')
-rw-r--r--cli/worker.rs267
1 files changed, 256 insertions, 11 deletions
diff --git a/cli/worker.rs b/cli/worker.rs
index 7fe1f3c0b..d06864634 100644
--- a/cli/worker.rs
+++ b/cli/worker.rs
@@ -7,6 +7,9 @@ use deno_core::error::AnyError;
use deno_core::futures::task::LocalFutureObj;
use deno_core::futures::FutureExt;
use deno_core::located_script_name;
+use deno_core::serde_json::json;
+use deno_core::serde_v8;
+use deno_core::v8;
use deno_core::Extension;
use deno_core::ModuleId;
use deno_runtime::colors;
@@ -38,6 +41,11 @@ pub struct CliMainWorker {
is_main_cjs: bool,
worker: MainWorker,
ps: ProcState,
+
+ js_run_tests_callback: Option<v8::Global<v8::Function>>,
+ js_run_benchmarks_callback: Option<v8::Global<v8::Function>>,
+ js_enable_test_callback: Option<v8::Global<v8::Function>>,
+ js_enable_bench_callback: Option<v8::Global<v8::Function>>,
}
impl CliMainWorker {
@@ -168,7 +176,7 @@ impl CliMainWorker {
&mut self,
mode: TestMode,
) -> Result<(), AnyError> {
- self.worker.enable_test();
+ self.enable_test();
// Enable op call tracing in core to enable better debugging of op sanitizer
// failures.
@@ -194,10 +202,7 @@ impl CliMainWorker {
}
self.worker.dispatch_load_event(&located_script_name!())?;
- self
- .worker
- .run_tests(&self.ps.options.shuffle_tests())
- .await?;
+ self.run_tests(&self.ps.options.shuffle_tests()).await?;
loop {
if !self
.worker
@@ -223,7 +228,7 @@ impl CliMainWorker {
&mut self,
mode: TestMode,
) -> Result<(), AnyError> {
- self.worker.enable_test();
+ self.enable_test();
self
.worker
@@ -239,7 +244,7 @@ impl CliMainWorker {
}
self.worker.dispatch_load_event(&located_script_name!())?;
- self.worker.run_tests(&None).await?;
+ self.run_tests(&None).await?;
loop {
if !self
.worker
@@ -254,13 +259,13 @@ impl CliMainWorker {
}
pub async fn run_bench_specifier(&mut self) -> Result<(), AnyError> {
- self.worker.enable_bench();
+ self.enable_bench();
// We execute the module module as a side module so that import.meta.main is not set.
self.execute_side_module_possibly_with_npm().await?;
self.worker.dispatch_load_event(&located_script_name!())?;
- self.worker.run_benchmarks().await?;
+ self.run_benchmarks().await?;
loop {
if !self
.worker
@@ -340,14 +345,104 @@ impl CliMainWorker {
Ok(None)
}
}
+
+ /// Run tests declared with `Deno.test()`. Test events will be dispatched
+ /// by calling ops which are currently only implemented in the CLI crate.
+ pub async fn run_tests(
+ &mut self,
+ shuffle: &Option<u64>,
+ ) -> Result<(), AnyError> {
+ let promise = {
+ let scope = &mut self.worker.js_runtime.handle_scope();
+ let cb = self.js_run_tests_callback.as_ref().unwrap().open(scope);
+ let this = v8::undefined(scope).into();
+ let options =
+ serde_v8::to_v8(scope, json!({ "shuffle": shuffle })).unwrap();
+ let promise = cb.call(scope, this, &[options]).unwrap();
+ v8::Global::new(scope, promise)
+ };
+ self.worker.js_runtime.resolve_value(promise).await?;
+ Ok(())
+ }
+
+ /// Run benches declared with `Deno.bench()`. Bench events will be dispatched
+ /// by calling ops which are currently only implemented in the CLI crate.
+ pub async fn run_benchmarks(&mut self) -> Result<(), AnyError> {
+ let promise = {
+ let scope = &mut self.worker.js_runtime.handle_scope();
+ let cb = self
+ .js_run_benchmarks_callback
+ .as_ref()
+ .unwrap()
+ .open(scope);
+ let this = v8::undefined(scope).into();
+ let promise = cb.call(scope, this, &[]).unwrap();
+ v8::Global::new(scope, promise)
+ };
+ self.worker.js_runtime.resolve_value(promise).await?;
+ Ok(())
+ }
+
+ /// Enable `Deno.test()`. If this isn't called before executing user code,
+ /// `Deno.test()` calls will noop.
+ pub fn enable_test(&mut self) {
+ let scope = &mut self.worker.js_runtime.handle_scope();
+ let cb = self.js_enable_test_callback.as_ref().unwrap().open(scope);
+ let this = v8::undefined(scope).into();
+ cb.call(scope, this, &[]).unwrap();
+ }
+
+ /// Enable `Deno.bench()`. If this isn't called before executing user code,
+ /// `Deno.bench()` calls will noop.
+ pub fn enable_bench(&mut self) {
+ let scope = &mut self.worker.js_runtime.handle_scope();
+ let cb = self.js_enable_bench_callback.as_ref().unwrap().open(scope);
+ let this = v8::undefined(scope).into();
+ cb.call(scope, this, &[]).unwrap();
+ }
}
pub async fn create_main_worker(
ps: &ProcState,
main_module: ModuleSpecifier,
permissions: Permissions,
+) -> Result<CliMainWorker, AnyError> {
+ create_main_worker_internal(
+ ps,
+ main_module,
+ permissions,
+ vec![],
+ Default::default(),
+ false,
+ )
+ .await
+}
+
+pub async fn create_main_worker_for_test_or_bench(
+ ps: &ProcState,
+ main_module: ModuleSpecifier,
+ permissions: Permissions,
+ custom_extensions: Vec<Extension>,
+ stdio: deno_runtime::ops::io::Stdio,
+) -> Result<CliMainWorker, AnyError> {
+ create_main_worker_internal(
+ ps,
+ main_module,
+ permissions,
+ custom_extensions,
+ stdio,
+ true,
+ )
+ .await
+}
+
+async fn create_main_worker_internal(
+ ps: &ProcState,
+ main_module: ModuleSpecifier,
+ permissions: Permissions,
mut custom_extensions: Vec<Extension>,
stdio: deno_runtime::ops::io::Stdio,
+ bench_or_test: bool,
) -> Result<CliMainWorker, AnyError> {
let (main_module, is_main_cjs) = if let Ok(package_ref) =
NpmPackageReference::from_specifier(&main_module)
@@ -426,7 +521,7 @@ pub async fn create_main_worker(
inspect: ps.options.is_inspecting(),
},
extensions,
- startup_snapshot: None,
+ startup_snapshot: Some(crate::js::deno_isolate_init()),
unsafely_ignore_certificate_errors: ps
.options
.unsafely_ignore_certificate_errors()
@@ -452,16 +547,59 @@ pub async fn create_main_worker(
stdio,
};
- let worker = MainWorker::bootstrap_from_options(
+ let mut worker = MainWorker::bootstrap_from_options(
main_module.clone(),
permissions,
options,
);
+
+ let (
+ js_run_tests_callback,
+ js_run_benchmarks_callback,
+ js_enable_test_callback,
+ js_enable_bench_callback,
+ ) = if bench_or_test {
+ let scope = &mut worker.js_runtime.handle_scope();
+ let js_run_tests_callback = deno_core::JsRuntime::eval::<v8::Function>(
+ scope,
+ "Deno[Deno.internal].testing.runTests",
+ )
+ .unwrap();
+ let js_run_benchmarks_callback =
+ deno_core::JsRuntime::eval::<v8::Function>(
+ scope,
+ "Deno[Deno.internal].testing.runBenchmarks",
+ )
+ .unwrap();
+ let js_enable_tests_callback = deno_core::JsRuntime::eval::<v8::Function>(
+ scope,
+ "Deno[Deno.internal].testing.enableTest",
+ )
+ .unwrap();
+ let js_enable_bench_callback = deno_core::JsRuntime::eval::<v8::Function>(
+ scope,
+ "Deno[Deno.internal].testing.enableBench",
+ )
+ .unwrap();
+ (
+ Some(v8::Global::new(scope, js_run_tests_callback)),
+ Some(v8::Global::new(scope, js_run_benchmarks_callback)),
+ Some(v8::Global::new(scope, js_enable_tests_callback)),
+ Some(v8::Global::new(scope, js_enable_bench_callback)),
+ )
+ } else {
+ (None, None, None, None)
+ };
+
Ok(CliMainWorker {
main_module,
is_main_cjs,
worker,
ps: ps.clone(),
+ js_run_tests_callback,
+ js_run_benchmarks_callback,
+ js_enable_test_callback,
+ js_enable_bench_callback,
})
}
@@ -544,6 +682,7 @@ fn create_web_worker_callback(
inspect: ps.options.is_inspecting(),
},
extensions,
+ startup_snapshot: Some(crate::js::deno_isolate_init()),
unsafely_ignore_certificate_errors: ps
.options
.unsafely_ignore_certificate_errors()
@@ -577,3 +716,109 @@ fn create_web_worker_callback(
)
})
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use deno_core::{resolve_url_or_path, FsModuleLoader};
+ use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel;
+ use deno_runtime::deno_web::BlobStore;
+
+ fn create_test_worker() -> MainWorker {
+ let main_module = resolve_url_or_path("./hello.js").unwrap();
+ let permissions = Permissions::default();
+
+ let options = WorkerOptions {
+ bootstrap: BootstrapOptions {
+ args: vec![],
+ cpu_count: 1,
+ debug_flag: false,
+ enable_testing_features: false,
+ locale: deno_core::v8::icu::get_language_tag(),
+ location: None,
+ no_color: true,
+ is_tty: false,
+ runtime_version: "x".to_string(),
+ ts_version: "x".to_string(),
+ unstable: false,
+ user_agent: "x".to_string(),
+ inspect: false,
+ },
+ extensions: vec![],
+ startup_snapshot: Some(crate::js::deno_isolate_init()),
+ unsafely_ignore_certificate_errors: None,
+ root_cert_store: None,
+ seed: None,
+ format_js_error_fn: None,
+ source_map_getter: None,
+ web_worker_preload_module_cb: Arc::new(|_| unreachable!()),
+ web_worker_pre_execute_module_cb: Arc::new(|_| unreachable!()),
+ create_web_worker_cb: Arc::new(|_| unreachable!()),
+ maybe_inspector_server: None,
+ should_break_on_first_statement: false,
+ module_loader: Rc::new(FsModuleLoader),
+ npm_resolver: None,
+ get_error_class_fn: None,
+ cache_storage_dir: None,
+ origin_storage_dir: None,
+ blob_store: BlobStore::default(),
+ broadcast_channel: InMemoryBroadcastChannel::default(),
+ shared_array_buffer_store: None,
+ compiled_wasm_module_store: None,
+ stdio: Default::default(),
+ };
+
+ MainWorker::bootstrap_from_options(main_module, permissions, options)
+ }
+
+ #[tokio::test]
+ async fn execute_mod_esm_imports_a() {
+ let p = test_util::testdata_path().join("runtime/esm_imports_a.js");
+ let module_specifier = resolve_url_or_path(&p.to_string_lossy()).unwrap();
+ let mut worker = create_test_worker();
+ let result = worker.execute_main_module(&module_specifier).await;
+ if let Err(err) = result {
+ eprintln!("execute_mod err {:?}", err);
+ }
+ if let Err(e) = worker.run_event_loop(false).await {
+ panic!("Future got unexpected error: {:?}", e);
+ }
+ }
+
+ #[tokio::test]
+ async fn execute_mod_circular() {
+ let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
+ .parent()
+ .unwrap()
+ .join("tests/circular1.js");
+ let module_specifier = resolve_url_or_path(&p.to_string_lossy()).unwrap();
+ let mut worker = create_test_worker();
+ let result = worker.execute_main_module(&module_specifier).await;
+ if let Err(err) = result {
+ eprintln!("execute_mod err {:?}", err);
+ }
+ if let Err(e) = worker.run_event_loop(false).await {
+ panic!("Future got unexpected error: {:?}", e);
+ }
+ }
+
+ #[tokio::test]
+ async fn execute_mod_resolve_error() {
+ // "foo" is not a valid module specifier so this should return an error.
+ let mut worker = create_test_worker();
+ let module_specifier = resolve_url_or_path("does-not-exist").unwrap();
+ let result = worker.execute_main_module(&module_specifier).await;
+ assert!(result.is_err());
+ }
+
+ #[tokio::test]
+ async fn execute_mod_002_hello() {
+ // This assumes cwd is project root (an assumption made throughout the
+ // tests).
+ let mut worker = create_test_worker();
+ let p = test_util::testdata_path().join("run/001_hello.js");
+ let module_specifier = resolve_url_or_path(&p.to_string_lossy()).unwrap();
+ let result = worker.execute_main_module(&module_specifier).await;
+ assert!(result.is_ok());
+ }
+}