Skip to content

Commit baf8acc

Browse files
committed
[cts_runner] Print uncaptured errors to stderr
This is useful when running test snippets. Update READMEs including to mention how to do that.
1 parent 5e6c151 commit baf8acc

File tree

8 files changed

+123
-36
lines changed

8 files changed

+123
-36
lines changed

Cargo.lock

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ spirv = "0.3"
187187
static_assertions = "1.1"
188188
strum = { version = "0.27.1", default-features = false, features = ["derive"] }
189189
syn = "2.0.98"
190+
tempfile = "3"
190191
toml = "0.9.0"
191192
trybuild = "1"
192193
tracy-client = "0.18"

cts_runner/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@ deno_webidl.workspace = true
2222
deno_webgpu.workspace = true
2323
tokio = { workspace = true, features = ["full"] }
2424
termcolor.workspace = true
25+
26+
[dev-dependencies]
27+
tempfile.workspace = true

cts_runner/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# cts_runner
2+
3+
This crate contains infrastructure for running the WebGPU conformance tests on
4+
Deno's `wgpu`-based implementation of WebGPU.
5+
6+
Instructions for running the tests via the CTS `xtask` are in the
7+
[top-level README](https://github.com/gfx-rs/wgpu/blob/trunk/README.md#webgpu-conformance-test-suite).
8+
The file [revision.txt](./revision.txt) specifies the version of the CTS that
9+
will be used by default.
10+
11+
`cts_runner` is somewhat misnamed at this point, in that it is useful for
12+
things other than just running the CTS:
13+
14+
- The [tests](./tests) directory contains a few directed tests for
15+
Deno's bindings to `wgpu`.
16+
- Standalone JavaScript snippets that use WebGPU can be run
17+
with a command like: `cargo run -p cts_runner -- test.js`.

cts_runner/src/bootstrap.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,25 @@ const windowOrWorkerGlobalScope = {
224224

225225
windowOrWorkerGlobalScope.console.enumerable = false;
226226

227+
// Print uncaptured WebGPU errors to stderr. This is useful when running
228+
// standalone JavaScript test snippets. It isn't needed for the CTS, because the
229+
// CTS uses error scopes. (The CTS also installs its own error handler with
230+
// `addEventListener`, so having this here may result in printing duplicate
231+
// errors from the CTS in some cases.) Printing uncaptured errors to stderr
232+
// isn't desired as built-in behavior in Deno, because the console is reserved
233+
// for the application.
234+
//
235+
// Note that catching an error here _does not_ result in a non-zero exit status.
236+
const requestDevice = webgpu.GPUAdapter.prototype.requestDevice;
237+
webgpu.GPUAdapter.prototype.requestDevice = function(desc) {
238+
return requestDevice.call(this, desc).then((device) => {
239+
device.onuncapturederror = (event) => {
240+
core.print("cts_runner caught WebGPU error:" + event.error.message, true);
241+
};
242+
return device;
243+
})
244+
};
245+
227246
const mainRuntimeGlobalProperties = {
228247
Window: globalInterfaces.windowConstructorDescriptor,
229248
window: util.readOnly(globalThis),

cts_runner/tests/features.js

Lines changed: 0 additions & 5 deletions
This file was deleted.

cts_runner/tests/integration.rs

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
// As of June 2025, these tests are not run in CI.
44

55
use std::{
6-
fmt::{self, Debug, Display},
6+
ffi::OsStr,
7+
io::Write,
78
path::PathBuf,
8-
process::Command,
9+
process::{Command, Output},
910
str,
1011
};
1112

13+
use tempfile::NamedTempFile;
14+
1215
pub fn target_dir() -> PathBuf {
1316
let current_exe = std::env::current_exe().unwrap();
1417
let target_dir = current_exe.parent().unwrap().parent().unwrap();
@@ -24,38 +27,71 @@ pub fn cts_runner_exe_path() -> PathBuf {
2427
p
2528
}
2629

27-
pub struct JsError;
30+
fn exec_cts_runner(script_file: impl AsRef<OsStr>) -> Output {
31+
Command::new(cts_runner_exe_path())
32+
.arg(script_file)
33+
.output()
34+
.unwrap()
35+
}
2836

29-
impl Display for JsError {
30-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31-
write!(f, "JavaScript test returned an error")
32-
}
37+
fn exec_js_file(script_file: impl AsRef<OsStr>) {
38+
let output = exec_cts_runner(script_file);
39+
println!("{}", str::from_utf8(&output.stdout).unwrap());
40+
eprintln!("{}", str::from_utf8(&output.stderr).unwrap());
41+
assert!(output.status.success());
3342
}
3443

35-
impl Debug for JsError {
36-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37-
write!(f, "{self}")
38-
}
44+
fn check_js_stderr(script: &str, expected: &str) {
45+
let mut tempfile = NamedTempFile::new().unwrap();
46+
tempfile.write_all(script.as_bytes()).unwrap();
47+
tempfile.flush().unwrap();
48+
let output = exec_cts_runner(tempfile.path());
49+
assert!(
50+
output.stdout.is_empty(),
51+
"unexpected output on stdout: {}",
52+
str::from_utf8(&output.stdout).unwrap(),
53+
);
54+
assert_eq!(str::from_utf8(&output.stderr).unwrap(), expected);
55+
assert!(output.status.success());
3956
}
4057

41-
type JsResult = Result<(), JsError>;
58+
fn exec_js(script: &str) {
59+
check_js_stderr(script, "");
60+
}
4261

43-
fn exec_js_test(script: &str) -> JsResult {
44-
let output = Command::new(cts_runner_exe_path())
45-
.arg(script)
46-
.output()
47-
.unwrap();
48-
println!("{}", str::from_utf8(&output.stdout).unwrap());
49-
eprintln!("{}", str::from_utf8(&output.stderr).unwrap());
50-
output.status.success().then_some(()).ok_or(JsError)
62+
#[test]
63+
fn hello_compute_example() {
64+
exec_js_file("examples/hello-compute.js");
5165
}
5266

5367
#[test]
54-
fn hello_compute_example() -> JsResult {
55-
exec_js_test("examples/hello-compute.js")
68+
fn features() {
69+
exec_js(
70+
r#"
71+
const adapter = await navigator.gpu.requestAdapter();
72+
73+
if (adapter.features.has("mappable-primary-buffers")) {
74+
throw new TypeError("Adapter should not report support for wgpu native-only features");
75+
}
76+
"#,
77+
);
5678
}
5779

5880
#[test]
59-
fn features() -> JsResult {
60-
exec_js_test("tests/features.js")
81+
fn uncaptured_error() {
82+
check_js_stderr(
83+
r#"
84+
const code = `const val: u32 = 1.1;`;
85+
86+
const adapter = await navigator.gpu.requestAdapter();
87+
const device = await adapter.requestDevice();
88+
device.createShaderModule({ code })
89+
"#,
90+
"cts_runner caught WebGPU error:
91+
Shader '' parsing error: the type of `val` is expected to be `u32`, but got `{AbstractFloat}`
92+
┌─ wgsl:1:7
93+
94+
1 │ const val: u32 = 1.1;
95+
│ ^^^ definition of `val`\n\n",
96+
);
6197
}

deno_webgpu/README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ a
1414
[wgpu trace](https://github.com/gfx-rs/wgpu/wiki/Debugging-wgpu-Applications#tracing-infrastructure)
1515
to the specified directory.
1616

17-
For testing this op crate will make use of the WebGPU conformance tests suite,
18-
running through our WPT runner. This will be used to validate implementation
19-
conformance.
20-
21-
GitHub CI doesn't run with GPUs, so testing relies on software like DX WARP &
22-
Vulkan lavapipe. Currently, only using DX WARP works, so tests are only run on
23-
Windows.
17+
This op crate is tested primarily by running the
18+
[WebGPU conformance test suite](https://github.com/gpuweb/cts) using `wgpu`'s
19+
[`cts_runner`](https://github.com/gfx-rs/wgpu/blob/trunk/README.md#webgpu-conformance-test-suite).
20+
`cts_runner` also has a few
21+
[directed tests](https://github.com/gfx-rs/wgpu/tree/trunk/cts_runner/tests)
22+
to fill in missing coverage.
23+
24+
GPU availability in GitHub CI is limited, so some configurations rely on
25+
software like DX WARP & Vulkan lavapipe.
2426

2527
## Links
2628

0 commit comments

Comments
 (0)