mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-03-25 22:41:04 +00:00
This commit reverts part of the implementation of [RFC 6]. That RFC specified that the `--browser` flag was going to be repurposed for the new "natively loadable as ES module output", but unfortunately the breakage is far broader than initially expected. It turns out that `wasm-pack` passes `--browser` by default which means that a change to break `--browser` would break all historical versions of `wasm-pack` which is a bit much for now. To solve this the `--browser` flag is going back to what it represents on the current released version of `wasm-bindgen` (optimize away some node.js checks in a few places for bundler-style output) and a new `--web` flag is being introduced as the new deployment strategy. [RFC 6]: https://github.com/rustwasm/rfcs/pull/6 Closes #1318
160 lines
5.5 KiB
Rust
160 lines
5.5 KiB
Rust
//! A "wrapper binary" used to execute wasm files as tests
|
|
//!
|
|
//! This binary is intended to be used as a "test runner" for wasm binaries,
|
|
//! being compatible with `cargo test` for the wasm target. It will
|
|
//! automatically execute `wasm-bindgen` (or the equivalent thereof) and then
|
|
//! execute either Node.js over the tests or start a server which a browser can
|
|
//! be used to run against to execute tests. In a browser mode if `CI` is in the
|
|
//! environment then it'll also attempt headless testing, spawning the server in
|
|
//! the background and then using the WebDriver protocol to execute tests.
|
|
//!
|
|
//! For more documentation about this see the `wasm-bindgen-test` crate README
|
|
//! and source code.
|
|
|
|
use failure::{bail, format_err, Error, ResultExt};
|
|
use std::env;
|
|
use std::fs;
|
|
use std::path::PathBuf;
|
|
use std::process;
|
|
use std::thread;
|
|
use wasm_bindgen_cli_support::Bindgen;
|
|
|
|
// no need for jemalloc bloat in this binary (and we don't need speed)
|
|
#[global_allocator]
|
|
static ALLOC: std::alloc::System = std::alloc::System;
|
|
|
|
mod headless;
|
|
mod node;
|
|
mod server;
|
|
mod shell;
|
|
|
|
fn main() {
|
|
env_logger::init();
|
|
let err = match rmain() {
|
|
Ok(()) => return,
|
|
Err(e) => e,
|
|
};
|
|
eprintln!("error: {}", err);
|
|
for cause in err.iter_causes() {
|
|
eprintln!("\tcaused by: {}", cause);
|
|
}
|
|
process::exit(1);
|
|
}
|
|
|
|
fn rmain() -> Result<(), Error> {
|
|
let mut args = env::args_os().skip(1);
|
|
let shell = shell::Shell::new();
|
|
|
|
// Currently no flags are supported, and assume there's only one argument
|
|
// which is the wasm file to test. This'll want to improve over time!
|
|
let wasm_file_to_test = match args.next() {
|
|
Some(file) => PathBuf::from(file),
|
|
None => bail!("must have a file to test as first argument"),
|
|
};
|
|
|
|
// Assume a cargo-like directory layout and generate output at
|
|
// `target/wasm32-unknown-unknown/wbg-tmp/...`
|
|
let tmpdir = wasm_file_to_test
|
|
.parent() // chop off file name
|
|
.and_then(|p| p.parent()) // chop off `deps`
|
|
.and_then(|p| p.parent()) // chop off `debug`
|
|
.map(|p| p.join("wbg-tmp"))
|
|
.ok_or_else(|| format_err!("file to test doesn't follow the expected Cargo conventions"))?;
|
|
|
|
// Make sure there's no stale state from before
|
|
drop(fs::remove_dir_all(&tmpdir));
|
|
fs::create_dir(&tmpdir).context("creating temporary directory")?;
|
|
|
|
let module = "wasm-bindgen-test";
|
|
|
|
// Collect all tests that the test harness is supposed to run. We assume
|
|
// that any exported function with the prefix `__wbg_test` is a test we need
|
|
// to execute.
|
|
let wasm = fs::read(&wasm_file_to_test).context("failed to read wasm file")?;
|
|
let wasm = walrus::Module::from_buffer(&wasm).context("failed to deserialize wasm module")?;
|
|
let mut tests = Vec::new();
|
|
|
|
for export in wasm.exports.iter() {
|
|
if !export.name.starts_with("__wbg_test") {
|
|
continue;
|
|
}
|
|
tests.push(export.name.to_string());
|
|
}
|
|
|
|
// Right now there's a bug where if no tests are present then the
|
|
// `wasm-bindgen-test` runtime support isn't linked in, so just bail out
|
|
// early saying everything is ok.
|
|
if tests.len() == 0 {
|
|
println!("no tests to run!");
|
|
return Ok(());
|
|
}
|
|
|
|
// Figure out if this tests is supposed to execute in node.js or a browser.
|
|
// That's done on a per-test-binary basis with the
|
|
// `wasm_bindgen_test_configure` macro, which emits a custom section for us
|
|
// to read later on.
|
|
let mut node = true;
|
|
for custom in wasm.custom.iter() {
|
|
if custom.name != "__wasm_bindgen_test_unstable" {
|
|
continue;
|
|
}
|
|
node = !custom.value.contains(&0x01);
|
|
}
|
|
let headless = env::var("NO_HEADLESS").is_err();
|
|
let debug = env::var("WASM_BINDGEN_NO_DEBUG").is_err();
|
|
|
|
// Make the generated bindings available for the tests to execute against.
|
|
shell.status("Executing bindgen...");
|
|
let mut b = Bindgen::new();
|
|
b.debug(debug)
|
|
.nodejs(node)?
|
|
.web(!node)?
|
|
.input_module(module, wasm)
|
|
.keep_debug(false)
|
|
.emit_start(false)
|
|
.generate(&tmpdir)
|
|
.context("executing `wasm-bindgen` over the wasm file")?;
|
|
shell.clear();
|
|
|
|
// If we're executing in node.js, that module will take it from here.
|
|
if node {
|
|
return node::execute(&module, &tmpdir, &args.collect::<Vec<_>>(), &tests);
|
|
}
|
|
|
|
// Otherwise we're executing in a browser. Spawn a server which serves up
|
|
// the local generated files over an HTTP server.
|
|
let srv = server::spawn(
|
|
&if headless {
|
|
"127.0.0.1:0".parse().unwrap()
|
|
} else {
|
|
"127.0.0.1:8000".parse().unwrap()
|
|
},
|
|
headless,
|
|
&module,
|
|
&tmpdir,
|
|
&args.collect::<Vec<_>>(),
|
|
&tests,
|
|
)
|
|
.context("failed to spawn server")?;
|
|
let addr = srv.server_addr();
|
|
|
|
// TODO: eventually we should provide the ability to exit at some point
|
|
// (gracefully) here, but for now this just runs forever.
|
|
if !headless {
|
|
println!(
|
|
"Interactive browsers tests are now available at http://{}",
|
|
addr
|
|
);
|
|
println!("");
|
|
println!("Note that interactive mode is enabled because `NO_HEADLESS`");
|
|
println!("is specified in the environment of this process. Once you're");
|
|
println!("done with testing you'll need to kill this server with");
|
|
println!("Ctrl-C.");
|
|
return Ok(srv.run());
|
|
}
|
|
|
|
thread::spawn(|| srv.run());
|
|
headless::run(&addr, &shell)?;
|
|
Ok(())
|
|
}
|