diff options
author | Nayeem Rahman <nayeemrmn99@gmail.com> | 2023-04-13 18:43:23 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-13 19:43:23 +0200 |
commit | 6e8618ae0f55bcaa4cfaaa579b4e21f9f74b117d (patch) | |
tree | dc0facd89b255b2bffe51b33920e46cb2a5d55d1 /cli/ops | |
parent | 4e53bc5a94a66858e9c141c7d807a8c9caa93403 (diff) |
refactor(cli): move runTests() and runBenchmarks() to rust (#18563)
Stores the test/bench functions in rust op state during registration.
The functions are wrapped in JS first so that they return a directly
convertible `TestResult`/`BenchResult`. Test steps are still mostly
handled in JS since they are pretty much invoked by the user. Allows
removing a bunch of infrastructure for communicating between JS and
rust. Allows using rust utilities for things like shuffling tests
(`Vec::shuffle`). We can progressively move op and resource sanitization
to rust as well.
Fixes #17122.
Fixes #17312.
Diffstat (limited to 'cli/ops')
-rw-r--r-- | cli/ops/bench.rs | 54 | ||||
-rw-r--r-- | cli/ops/testing.rs | 79 |
2 files changed, 71 insertions, 62 deletions
diff --git a/cli/ops/bench.rs b/cli/ops/bench.rs index 86498cd7c..da0f3d959 100644 --- a/cli/ops/bench.rs +++ b/cli/ops/bench.rs @@ -7,6 +7,8 @@ use std::time; use deno_core::error::generic_error; use deno_core::error::AnyError; use deno_core::op; +use deno_core::serde_v8; +use deno_core::v8; use deno_core::ModuleSpecifier; use deno_core::OpState; use deno_runtime::permissions::create_child_permissions; @@ -19,24 +21,26 @@ use uuid::Uuid; use crate::tools::bench::BenchDescription; use crate::tools::bench::BenchEvent; -use crate::tools::test::TestFilter; + +#[derive(Default)] +pub(crate) struct BenchContainer( + pub Vec<(BenchDescription, v8::Global<v8::Function>)>, +); deno_core::extension!(deno_bench, ops = [ op_pledge_test_permissions, op_restore_test_permissions, - op_get_bench_origin, op_register_bench, op_dispatch_bench_event, op_bench_now, ], options = { sender: UnboundedSender<BenchEvent>, - filter: TestFilter, }, state = |state, options| { state.put(options.sender); - state.put(options.filter); + state.put(BenchContainer::default()); }, customizer = |ext: &mut deno_core::ExtensionBuilder| { ext.force_op_registration(); @@ -90,51 +94,61 @@ pub fn op_restore_test_permissions( } } -#[op] -fn op_get_bench_origin(state: &mut OpState) -> String { - state.borrow::<ModuleSpecifier>().to_string() -} - -#[derive(Debug, Deserialize)] +#[derive(Deserialize)] #[serde(rename_all = "camelCase")] -struct BenchInfo { +struct BenchInfo<'s> { + #[serde(rename = "fn")] + function: serde_v8::Value<'s>, name: String, - origin: String, baseline: bool, group: Option<String>, + ignore: bool, + only: bool, } #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] struct BenchRegisterResult { id: usize, - filtered_out: bool, + origin: String, } static NEXT_ID: AtomicUsize = AtomicUsize::new(0); -#[op] -fn op_register_bench( +#[op(v8)] +fn op_register_bench<'a>( + scope: &mut v8::HandleScope<'a>, state: &mut OpState, - info: BenchInfo, + info: BenchInfo<'a>, ) -> Result<BenchRegisterResult, AnyError> { let id = NEXT_ID.fetch_add(1, Ordering::SeqCst); - let filter = state.borrow::<TestFilter>().clone(); - let filtered_out = !filter.includes(&info.name); + let origin = state.borrow::<ModuleSpecifier>().to_string(); let description = BenchDescription { id, name: info.name, - origin: info.origin, + origin: origin.clone(), baseline: info.baseline, group: info.group, + ignore: info.ignore, + only: info.only, }; + let function: v8::Local<v8::Function> = info.function.v8_value.try_into()?; + let function = v8::Global::new(scope, function); + state + .borrow_mut::<BenchContainer>() + .0 + .push((description.clone(), function)); let sender = state.borrow::<UnboundedSender<BenchEvent>>().clone(); sender.send(BenchEvent::Register(description)).ok(); - Ok(BenchRegisterResult { id, filtered_out }) + Ok(BenchRegisterResult { id, origin }) } #[op] fn op_dispatch_bench_event(state: &mut OpState, event: BenchEvent) { + assert!( + matches!(event, BenchEvent::Output(_)), + "Only output events are expected from JS." + ); let sender = state.borrow::<UnboundedSender<BenchEvent>>().clone(); sender.send(event).ok(); } diff --git a/cli/ops/testing.rs b/cli/ops/testing.rs index 8b5c95fea..e36d7e611 100644 --- a/cli/ops/testing.rs +++ b/cli/ops/testing.rs @@ -1,17 +1,16 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -use crate::tools::test::FailFastTracker; use crate::tools::test::TestDescription; use crate::tools::test::TestEvent; use crate::tools::test::TestEventSender; -use crate::tools::test::TestFilter; use crate::tools::test::TestLocation; -use crate::tools::test::TestResult; use crate::tools::test::TestStepDescription; use deno_core::error::generic_error; use deno_core::error::AnyError; use deno_core::op; +use deno_core::serde_v8; +use deno_core::v8; use deno_core::ModuleSpecifier; use deno_core::OpState; use deno_runtime::permissions::create_child_permissions; @@ -24,25 +23,25 @@ use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; use uuid::Uuid; +#[derive(Default)] +pub(crate) struct TestContainer( + pub Vec<(TestDescription, v8::Global<v8::Function>)>, +); + deno_core::extension!(deno_test, ops = [ op_pledge_test_permissions, op_restore_test_permissions, - op_get_test_origin, op_register_test, op_register_test_step, op_dispatch_test_event, - op_tests_should_stop, ], options = { sender: TestEventSender, - fail_fast_tracker: FailFastTracker, - filter: TestFilter, }, state = |state, options| { state.put(options.sender); - state.put(options.fail_fast_tracker); - state.put(options.filter); + state.put(TestContainer::default()); }, customizer = |ext: &mut deno_core::ExtensionBuilder| { ext.force_op_registration(); @@ -95,16 +94,14 @@ pub fn op_restore_test_permissions( } } -#[op] -fn op_get_test_origin(state: &mut OpState) -> Result<String, AnyError> { - Ok(state.borrow::<ModuleSpecifier>().to_string()) -} - -#[derive(Debug, Deserialize)] +#[derive(Deserialize)] #[serde(rename_all = "camelCase")] -struct TestInfo { +struct TestInfo<'s> { + #[serde(rename = "fn")] + function: serde_v8::Value<'s>, name: String, - origin: String, + ignore: bool, + only: bool, location: TestLocation, } @@ -112,28 +109,36 @@ struct TestInfo { #[serde(rename_all = "camelCase")] struct TestRegisterResult { id: usize, - filtered_out: bool, + origin: String, } static NEXT_ID: AtomicUsize = AtomicUsize::new(0); -#[op] -fn op_register_test( +#[op(v8)] +fn op_register_test<'a>( + scope: &mut v8::HandleScope<'a>, state: &mut OpState, - info: TestInfo, + info: TestInfo<'a>, ) -> Result<TestRegisterResult, AnyError> { let id = NEXT_ID.fetch_add(1, Ordering::SeqCst); - let filter = state.borrow::<TestFilter>().clone(); - let filtered_out = !filter.includes(&info.name); + let origin = state.borrow::<ModuleSpecifier>().to_string(); let description = TestDescription { id, name: info.name, - origin: info.origin, + ignore: info.ignore, + only: info.only, + origin: origin.clone(), location: info.location, }; + let function: v8::Local<v8::Function> = info.function.v8_value.try_into()?; + let function = v8::Global::new(scope, function); + state + .borrow_mut::<TestContainer>() + .0 + .push((description.clone(), function)); let mut sender = state.borrow::<TestEventSender>().clone(); sender.send(TestEvent::Register(description)).ok(); - Ok(TestRegisterResult { id, filtered_out }) + Ok(TestRegisterResult { id, origin }) } fn deserialize_parent<'de, D>(deserializer: D) -> Result<usize, D::Error> @@ -151,7 +156,6 @@ where #[serde(rename_all = "camelCase")] struct TestStepInfo { name: String, - origin: String, location: TestLocation, level: usize, #[serde(rename = "parent")] @@ -167,10 +171,11 @@ fn op_register_test_step( info: TestStepInfo, ) -> Result<TestRegisterResult, AnyError> { let id = NEXT_ID.fetch_add(1, Ordering::SeqCst); + let origin = state.borrow::<ModuleSpecifier>().to_string(); let description = TestStepDescription { id, name: info.name, - origin: info.origin, + origin: origin.clone(), location: info.location, level: info.level, parent_id: info.parent_id, @@ -179,10 +184,7 @@ fn op_register_test_step( }; let mut sender = state.borrow::<TestEventSender>().clone(); sender.send(TestEvent::StepRegister(description)).ok(); - Ok(TestRegisterResult { - id, - filtered_out: false, - }) + Ok(TestRegisterResult { id, origin }) } #[op] @@ -190,18 +192,11 @@ fn op_dispatch_test_event( state: &mut OpState, event: TestEvent, ) -> Result<(), AnyError> { - if matches!( - event, - TestEvent::Result(_, TestResult::Cancelled | TestResult::Failed(_), _) - ) { - state.borrow::<FailFastTracker>().add_failure(); - } + assert!( + matches!(event, TestEvent::StepWait(_) | TestEvent::StepResult(..)), + "Only step wait/result events are expected from JS." + ); let mut sender = state.borrow::<TestEventSender>().clone(); sender.send(event).ok(); Ok(()) } - -#[op] -fn op_tests_should_stop(state: &mut OpState) -> bool { - state.borrow::<FailFastTracker>().should_stop() -} |