Skip to content

Commit

Permalink
Merge pull request #1463 from fitzgen/fix-c-api-tests
Browse files Browse the repository at this point in the history
Fix wasmtime-c-api tests and run them in CI
  • Loading branch information
fitzgen authored Apr 2, 2020
2 parents e425bfc + 1d337ef commit a325b62
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 171 deletions.
12 changes: 1 addition & 11 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ jobs:
- run: cargo run -p run-examples

# Build and test all features except for lightbeam
- run: cargo test --features test-programs/test_programs --all --exclude lightbeam --exclude wasmtime-c-api -- --nocapture
- run: cargo test --features test-programs/test_programs --all --exclude lightbeam -- --nocapture
env:
RUST_BACKTRACE: 1
RUSTFLAGS: "-D warnings"
Expand All @@ -247,16 +247,6 @@ jobs:
env:
RUST_BACKTRACE: 1

# Build and test c-api examples. Skipping testing on Windows due to
# GNU make dependency when executing the wasm-c-api examples.
- run: cargo build --package wasmtime-c-api
if: matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest'
- run: cargo test --package wasmtime-c-api -- --nocapture --test-threads 1
if: matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest'
continue-on-error: true
env:
RUST_BACKTRACE: 1

# Verify that cranelift's code generation is deterministic
meta_determinist_check:
name: Meta deterministic check
Expand Down
269 changes: 109 additions & 160 deletions crates/c-api/tests/wasm-c-examples.rs
Original file line number Diff line number Diff line change
@@ -1,198 +1,147 @@
use std::env;
use std::path::PathBuf;
use std::fs;
use std::path::Path;
use std::process::Command;
use std::sync::Once;

fn run_c_example(name: &'static str, expected_out: &[u8]) {
let cargo = env::var("MAKE").unwrap_or("make".to_string());
let pkg_dir = env!("CARGO_MANIFEST_DIR");
let examples_dir = PathBuf::from(pkg_dir).join("examples");
let make_arg = format!("run-{}-c", name);
let output = Command::new(cargo)
.current_dir(examples_dir)
.args(&["-s", &make_arg])
fn run_c_example(name: &'static str, expected_out: &str) {
// Windows requires different `cc` flags and I'm not sure what they
// are. Also we need a way to shepherd the current host target to the `cc`
// invocation but `cargo` only defines the `TARGET` environment variable for
// build scripts, not tests. Therefore, we just make these tests specific to
// bog standard x64 linux. This should run in CI, at least!
if cfg!(not(all(
target_arch = "x86_64",
target_os = "linux",
target_env = "gnu"
))) {
eprintln!("This test is only enabled for the `x86_64-unknown-linux-gnu` target");
return;
}

let pkg_dir = Path::new(env!("CARGO_MANIFEST_DIR"));

// Make sure we've built `libwasmtime.a` with the `wat` feature enabled
// so that we have the `wasmtime_wat2wasm` function.
static BUILD_LIBWASMTIME: Once = Once::new();
BUILD_LIBWASMTIME.call_once(|| {
let status = Command::new("cargo")
.args(&["build", "-p", "wasmtime-c-api", "--features", "wat"])
.current_dir(pkg_dir)
.status()
.expect("should run `cargo build` OK");
assert!(status.success());
});

let examples_dir = pkg_dir
// Pop `c-api`.
.join("..")
// Pop `crates`.
.join("..")
.join("examples");
let include_dir = pkg_dir.join("include");
let wasm_c_api_include_dir = pkg_dir.join("wasm-c-api").join("include");
let out_dir = pkg_dir.join("..").join("..").join("target").join("debug");
let c_examples_dir = out_dir.join("c-examples");
fs::create_dir_all(&c_examples_dir).unwrap();
let libwasmtime = out_dir.join("libwasmtime.a");
assert!(libwasmtime.exists());

let status = Command::new(env::var("CC").unwrap_or("gcc".into()))
.arg(examples_dir.join(name).with_extension("c"))
.arg(libwasmtime)
.arg(format!("-I{}", include_dir.display()))
.arg(format!("-I{}", wasm_c_api_include_dir.display()))
.arg("-lpthread")
.arg("-ldl")
.arg("-lm")
.current_dir(&examples_dir)
.arg("-o")
.arg(c_examples_dir.join(name))
.status()
.expect("should spawn CC ok");
assert!(status.success());
assert!(c_examples_dir.join(name).exists());

let output = Command::new(c_examples_dir.join(name))
.current_dir(pkg_dir.join("..").join(".."))
.output()
.expect("success");
.expect("should spawn C example OK");

assert!(
output.status.success(),
"failed to execute the C example '{}': {}",
name,
String::from_utf8_lossy(&output.stderr),
);

let actual_stdout =
String::from_utf8(output.stdout).expect("C example's output should be utf-8");
assert_eq!(
output.stdout.as_slice(),
expected_out,
"unexpected stdout from example: {}",
String::from_utf8_lossy(&output.stdout),
actual_stdout, expected_out,
"unexpected stdout from example",
);
}

#[test]
fn test_run_hello_example() {
run_c_example(
"hello",
br#"==== C hello ====
Initializing...
Loading binary...
Compiling module...
Creating callback...
Instantiating module...
Extracting export...
Calling export...
Calling back...
> Hello World!
Shutting down...
Done.
==== Done ====
"#,
"Initializing...\n\
Compiling module...\n\
Creating callback...\n\
Instantiating module...\n\
Extracting export...\n\
Calling export...\n\
Calling back...\n\
> Hello World!\n\
All finished!\n",
);
}

#[test]
fn test_run_memory_example() {
run_c_example(
"memory",
br#"==== C memory ====
Initializing...
Loading binary...
Compiling module...
Instantiating module...
Extracting exports...
Checking memory...
Mutating memory...
Growing memory...
Creating stand-alone memory...
Shutting down...
Done.
==== Done ====
"#,
"Initializing...\n\
Compiling module...\n\
Instantiating module...\n\
Extracting exports...\n\
Checking memory...\n\
Mutating memory...\n\
Growing memory...\n\
Creating stand-alone memory...\n\
Shutting down...\n\
Done.\n",
);
}

#[test]
fn test_run_global_example() {
run_c_example(
"global",
br#"==== C global ====
Initializing...
Loading binary...
Compiling module...
Creating globals...
Instantiating module...
Extracting exports...
Accessing globals...
Shutting down...
Done.
==== Done ====
"#,
);
fn test_run_linking_example() {
run_c_example("linking", "Hello, world!\n");
}

#[test]
fn test_run_callback_example() {
fn test_run_multi_example() {
run_c_example(
"callback",
br#"==== C callback ====
Initializing...
Loading binary...
Compiling module...
Creating callback...
Instantiating module...
Extracting export...
Calling export...
Calling back...
> 7
Calling back closure...
> 42
Printing result...
> 49
Shutting down...
Done.
==== Done ====
"#,
"multi",
"Initializing...\n\
Compiling module...\n\
Creating callback...\n\
Instantiating module...\n\
Extracting export...\n\
Calling export...\n\
Calling back...\n\
> 1 2\n\
\n\
Printing result...\n\
> 2 1\n\
Shutting down...\n\
Done.\n",
);
}

#[test]
fn test_run_reflect_example() {
run_c_example(
"reflect",
br#"==== C reflect ====
Initializing...
Loading binary...
Compiling module...
Instantiating module...
Extracting export...
> export 0 "func"
>> initial: func i32 f64 f32 -> i32
>> current: func i32 f64 f32 -> i32
>> in-arity: 3, out-arity: 1
> export 1 "global"
>> initial: global const f64
>> current: global const f64
> export 2 "table"
>> initial: table 0d 50d funcref
>> current: table 0d 50d funcref
> export 3 "memory"
>> initial: memory 1d
>> current: memory 1d
Shutting down...
Done.
==== Done ====
"#,
);
}

#[test]
fn test_run_start_example() {
run_c_example(
"start",
br#"==== C start ====
Initializing...
Loading binary...
Compiling module...
Instantiating module...
Printing message...
> wasm trap: unreachable, source location: @002e
Printing origin...
> Empty origin.
Printing trace...
> Empty trace.
Shutting down...
Done.
==== Done ====
"#,
);
}

#[test]
fn test_run_trap_example() {
run_c_example(
"trap",
br#"==== C trap ====
Initializing...
Loading binary...
Compiling module...
Creating callback...
Instantiating module...
Extracting exports...
Calling export 0...
Calling back...
Printing message...
> callback abort
Printing origin...
> Empty origin.
Printing trace...
> Empty trace.
Calling export 1...
Printing message...
> wasm trap: unreachable, source location: @0065
Printing origin...
> Empty origin.
Printing trace...
> Empty trace.
Shutting down...
Done.
==== Done ====
"#,
);
fn test_run_gcd_example() {
run_c_example("gcd", "gcd(6, 27) = 3\n");
}

0 comments on commit a325b62

Please sign in to comment.