summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/tests/unit/dispatch_bin_test.ts23
-rw-r--r--core/core.js52
-rw-r--r--core/ops_json.rs48
3 files changed, 73 insertions, 50 deletions
diff --git a/cli/tests/unit/dispatch_bin_test.ts b/cli/tests/unit/dispatch_bin_test.ts
index ca1864621..54a379bc0 100644
--- a/cli/tests/unit/dispatch_bin_test.ts
+++ b/cli/tests/unit/dispatch_bin_test.ts
@@ -1,27 +1,16 @@
-import {
- assert,
- assertEquals,
- assertMatch,
- unitTest,
- unreachable,
-} from "./test_util.ts";
+import { assertStringIncludes, unitTest, unreachable } from "./test_util.ts";
-const readErrorStackPattern = new RegExp(
- `^.*
- at processErr \\(.*core\\.js:.*\\)
- at opAsyncHandler \\(.*core\\.js:.*\\)
- at handleAsyncMsgFromRust \\(.*core\\.js:.*\\).*$`,
- "ms",
-);
-
-unitTest(async function sendAsyncStackTrace(): Promise<void> {
+unitTest(async function sendAsyncStackTrace() {
const buf = new Uint8Array(10);
const rid = 10;
try {
await Deno.read(rid, buf);
unreachable();
} catch (error) {
- assertMatch(error.stack, readErrorStackPattern);
+ const s = error.stack.toString();
+ console.log(s);
+ assertStringIncludes(s, "dispatch_bin_test.ts");
+ assertStringIncludes(s, "read");
}
});
diff --git a/core/core.js b/core/core.js
index 3ec5c3e41..3142aa93a 100644
--- a/core/core.js
+++ b/core/core.js
@@ -65,7 +65,10 @@
function handleAsyncMsgFromRust() {
for (let i = 0; i < arguments.length; i += 2) {
- opAsyncHandler(arguments[i], arguments[i + 1]);
+ const promiseId = arguments[i];
+ const res = arguments[i + 1];
+ const promise = getPromise(promiseId);
+ promise.resolve(res);
}
}
@@ -84,48 +87,31 @@
return errorMap[errorName] ?? [undefined, []];
}
- function processResponse(res) {
- if (!isErr(res)) {
- return res;
- }
- throw processErr(res);
- }
-
- // .$err_class_name is a special key that should only exist on errors
- function isErr(res) {
- return !!(res && res.$err_class_name);
- }
-
- function processErr(err) {
- const className = err.$err_class_name;
- const [ErrorClass, args] = getErrorClassAndArgs(className);
- if (!ErrorClass) {
- return new Error(
- `Unregistered error class: "${className}"\n ${err.message}\n Classes of errors returned from ops should be registered via Deno.core.registerErrorClass().`,
- );
+ function unwrapOpResult(res) {
+ // .$err_class_name is a special key that should only exist on errors
+ if (res?.$err_class_name) {
+ const className = res.$err_class_name;
+ const [ErrorClass, args] = getErrorClassAndArgs(className);
+ if (!ErrorClass) {
+ throw new Error(
+ `Unregistered error class: "${className}"\n ${res.message}\n Classes of errors returned from ops should be registered via Deno.core.registerErrorClass().`,
+ );
+ }
+ throw new ErrorClass(res.message, ...args);
}
- return new ErrorClass(err.message, ...args);
+ return res;
}
function jsonOpAsync(opName, args = null, zeroCopy = null) {
const promiseId = nextPromiseId++;
const maybeError = dispatch(opName, promiseId, args, zeroCopy);
// Handle sync error (e.g: error parsing args)
- if (maybeError) processResponse(maybeError);
- return setPromise(promiseId);
+ if (maybeError) return unwrapOpResult(maybeError);
+ return setPromise(promiseId).then(unwrapOpResult);
}
function jsonOpSync(opName, args = null, zeroCopy = null) {
- return processResponse(dispatch(opName, null, args, zeroCopy));
- }
-
- function opAsyncHandler(promiseId, res) {
- const promise = getPromise(promiseId);
- if (!isErr(res)) {
- promise.resolve(res);
- } else {
- promise.reject(processErr(res));
- }
+ return unwrapOpResult(dispatch(opName, null, args, zeroCopy));
}
function binOpSync(opName, args = null, zeroCopy = null) {
diff --git a/core/ops_json.rs b/core/ops_json.rs
index 21c6b219f..0efd44a90 100644
--- a/core/ops_json.rs
+++ b/core/ops_json.rs
@@ -108,3 +108,51 @@ where
},
)
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[tokio::test]
+ async fn json_op_async_stack_trace() {
+ let mut runtime = crate::JsRuntime::new(Default::default());
+
+ async fn op_throw(
+ _state: Rc<RefCell<OpState>>,
+ msg: Option<String>,
+ zero_copy: Option<ZeroCopyBuf>,
+ ) -> Result<(), AnyError> {
+ assert_eq!(msg.unwrap(), "hello");
+ assert!(zero_copy.is_none());
+ Err(crate::error::generic_error("foo"))
+ }
+
+ runtime.register_op("op_throw", json_op_async(op_throw));
+ runtime
+ .execute(
+ "<init>",
+ r#"
+ // First we initialize the ops cache. This maps op names to their id's.
+ Deno.core.ops();
+ // Register the error class.
+ Deno.core.registerErrorClass('Error', Error);
+
+ async function f1() {
+ await Deno.core.jsonOpAsync('op_throw', 'hello');
+ }
+
+ async function f2() {
+ await f1();
+ }
+
+ f2();
+ "#,
+ )
+ .unwrap();
+ let e = runtime.run_event_loop().await.unwrap_err().to_string();
+ println!("{}", e);
+ assert!(e.contains("Error: foo"));
+ assert!(e.contains("at async f1 (<init>:"));
+ assert!(e.contains("at async f2 (<init>:"));
+ }
+}