Skip to content

Wasm unit tests on CI #1275

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/minimal-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,36 @@ jobs:
run: cargo test $TEST_FEATURES


unit-test-web:
name: unit-test-web
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4

- name: "Patch Cargo.toml to use nightly extension API"
run: .github/other/patch-prebuilt.sh nightly

- name: "Install Rust"
uses: ./.github/composite/rust
with:
rust: nightly
components: rust-src

- name: "Install emscripten"
env:
EMSCRIPTEN_SRC_REF: 4.0.13
EMSCRIPTEN_VERSION: 3.1.74
run: |
git clone https://github.com/emscripten-core/emsdk.git --depth 1 --branch $EMSCRIPTEN_SRC_REF --single-branch
./emsdk/emsdk install $EMSCRIPTEN_VERSION
./emsdk/emsdk activate $EMSCRIPTEN_VERSION
source ./emsdk/emsdk_env.sh
echo PATH=$PATH >> $GITHUB_ENV

- name: "Test (Wasm)"
run: ./check.sh testweb


# For complex matrix workflow, see https://stackoverflow.com/a/65434401
godot-itest:
name: godot-itest (${{ matrix.name }})
Expand Down
35 changes: 34 additions & 1 deletion check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Commands:
fmt format code, fail if bad
test run unit tests (no Godot needed)
itest run integration tests (from within Godot)
testweb run unit tests on web environment (requires node.js and emcc)
clippy validate clippy lints
klippy validate + fix clippy
doc generate docs for 'godot' crate
Expand Down Expand Up @@ -179,6 +180,38 @@ function cmd_itest() {
run "$godotBin" $GODOT_ARGS --path itest/godot --headless -- "[${extraArgs[@]}]"
}

function cmd_testweb() {
# Add more debug symbols to build
common_flags="-C link-args=-g"

# Avoid problems with emcc potentially writing to read-only dir
cache_dir="$(realpath ./target)/emscripten_cache"
mkdir -p "${cache_dir}"

echo "==============================="
echo "Initiating threaded Wasm tests."
echo "==============================="

# For the runner env var: https://github.com/rust-lang/cargo/issues/7471
# More memory (256 MiB) is needed for the parallel godot-cell tests which
# spawn 70 threads each.
CARGO_TARGET_WASM32_UNKNOWN_EMSCRIPTEN_RUNNER=node RUSTFLAGS="-C link-args=-pthread \
-C target-feature=+atomics \
-C link-args=-sINITIAL_MEMORY=268435456 \
${common_flags}" EM_CACHE="${cache_dir}" run cargo +nightly test \
--features godot/experimental-wasm,godot/lazy-function-tables \
-Zbuild-std --target wasm32-unknown-emscripten

echo "==================================="
echo "Initiating non-threaded Wasm tests."
echo "==================================="

CARGO_TARGET_WASM32_UNKNOWN_EMSCRIPTEN_RUNNER=node RUSTFLAGS="${common_flags}" \
EM_CACHE="${cache_dir}" run cargo +nightly test \
--features godot/experimental-wasm-nothreads,godot/experimental-wasm,godot/lazy-function-tables \
-Zbuild-std --target wasm32-unknown-emscripten
}

function cmd_doc() {
run cargo doc --lib -p godot --no-deps "${extraCargoArgs[@]}"
}
Expand Down Expand Up @@ -211,7 +244,7 @@ while [[ $# -gt 0 ]]; do
--double)
extraCargoArgs+=("--features" "godot/double-precision")
;;
fmt | test | itest | clippy | klippy | doc | dok)
fmt | test | itest | testweb | clippy | klippy | doc | dok)
cmds+=("$arg")
;;
-f | --filter)
Expand Down
20 changes: 20 additions & 0 deletions godot-cell/tests/mock/blocking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ impl MyClass {
///
/// This should not cause borrow failures and should not lead to deadlocks.
#[test]
#[cfg_attr(
all(target_family = "wasm", not(target_feature = "atomics")),
ignore = "Threading not available"
)]
fn calls_parallel() {
use std::thread;

Expand Down Expand Up @@ -72,6 +76,10 @@ fn calls_parallel() {
/// Runs each method several times in a row. This should reduce the non-determinism that comes from
/// scheduling of threads.
#[test]
#[cfg_attr(
all(target_family = "wasm", not(target_feature = "atomics")),
ignore = "Threading not available"
)]
fn calls_parallel_many_serial() {
use std::thread;

Expand Down Expand Up @@ -106,6 +114,10 @@ fn calls_parallel_many_serial() {
/// Runs all the tests several times. This is different from [`calls_parallel_many_serial`] as that calls the
/// methods like AAA...BBB...CCC..., whereas this interleaves the methods like ABC...ABC...ABC...
#[test]
#[cfg_attr(
all(target_family = "wasm", not(target_feature = "atomics")),
ignore = "Threading not available"
)]
fn calls_parallel_many_parallel() {
use std::thread;

Expand Down Expand Up @@ -142,6 +154,10 @@ fn calls_parallel_many_parallel() {
/// a) Thread A holds mutable reference AND thread B holds no references.
/// b) One or more threads hold shared references AND thread A holds no references
#[test]
#[cfg_attr(
all(target_family = "wasm", not(target_feature = "atomics")),
ignore = "Threading not available"
)]
fn non_blocking_reborrow() {
use std::thread;
let instance_id = MyClass::init();
Expand Down Expand Up @@ -172,6 +188,10 @@ fn non_blocking_reborrow() {
/// This verifies that the thread which initialized the `GdCell` does not panic when it attempts to mutably borrow while there is already a
/// shared borrow on an other thread.
#[test]
#[cfg_attr(
all(target_family = "wasm", not(target_feature = "atomics")),
ignore = "Threading not available"
)]
fn no_mut_panic_on_main() {
use std::thread;
let instance_id = MyClass::init();
Expand Down
16 changes: 16 additions & 0 deletions godot-cell/tests/mock/panicking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ fn all_calls_work() {

/// Run each method both from the main thread and a newly created thread.
#[test]
#[cfg_attr(
all(target_family = "wasm", not(target_feature = "atomics")),
ignore = "Threading not available"
)]
fn calls_different_thread() {
use std::thread;

Expand Down Expand Up @@ -87,6 +91,10 @@ fn calls_different_thread() {
/// if the first call failed, so then we know the integer was incremented by 0. Otherwise, we at least know
/// the range of values that it can be incremented by.
#[test]
#[cfg_attr(
all(target_family = "wasm", not(target_feature = "atomics")),
ignore = "Threading not available"
)]
fn calls_parallel() {
use std::thread;

Expand Down Expand Up @@ -121,6 +129,10 @@ fn calls_parallel() {
/// Runs each method several times in a row. This should reduce the non-determinism that comes from
/// scheduling of threads.
#[test]
#[cfg_attr(
all(target_family = "wasm", not(target_feature = "atomics")),
ignore = "Threading not available"
)]
fn calls_parallel_many_serial() {
use std::thread;

Expand Down Expand Up @@ -157,6 +169,10 @@ fn calls_parallel_many_serial() {
/// Runs all the tests several times. This is different from [`calls_parallel_many_serial`] as that calls the
/// methods like AAA...BBB...CCC..., whereas this interleaves the methods like ABC...ABC...ABC...
#[test]
#[cfg_attr(
all(target_family = "wasm", not(target_feature = "atomics")),
ignore = "Threading not available"
)]
fn calls_parallel_many_parallel() {
use std::thread;

Expand Down
Loading