End-to-End testing
Multi-stage .e2e flow for lind-wasm end-to-end testing and image creation.
- Installs build dependencies
- Builds wasmtime, glibc, and a sysroot for clang cross-compilation
- A. Runs end-to-end tests (default)
- B. Creates a Docker image with the lind-wasm toolchain
- C. Provides a base image for interactive development with the full source tree mounted
NOTE
Theteststage (A) runs end-to-end tests ondocker buildand is optimized for build time and caching. It is not meant fordocker run.Use the
releasestage (B) to create an image that includes the full lind-wasm toolchain (for demos, experiments, etc.).For development, you may want to build just the
basestage (C) and mount the full source tree.The Dev image is automatically rebuilt weekly from
Docker/Dockerfile.devonmainand pushed to Docker Hub assecuresystemslab/lind-wasm-dev:latest.
Usage A — test
From repo root
docker build --platform=linux/amd64 -f Docker/Dockerfile.e2e .
-
Triggers the default test stage.
-
Earlier stages build prerequisites (clang/LLVM, Rust, wasmtime, sysroot).
-
The test stage executes make test during the build and fails the build on any test failure.
-
Check the build log for the e2e report (the harness prints results.json).
Usage B — create and run a toolchain image (release)
Build a runnable toolchain image
docker build --platform=linux/amd64 -f Docker/Dockerfile.e2e -t release --target release .
Run image
docker run --platform=linux/amd64 -it release /bin/bash
-
Contains the lind-wasm toolchain (wasmtime + sysroot + scripts/tests).
-
Intended for demos/experiments.
-
Not designed to run make test directly (the Makefile isn’t copied here).
Usage C — create a base image and mount the source
docker build --platform=linux/amd64 -f Docker/Dockerfile.e2e -t dev --target base .
docker run --platform=linux/amd64 -v $(PWD):/lind -w /lind -it dev /bin/bash
-
Use the
basestage to match CI dependencies while keeping your source outside the image for fast, iterative editing. -
Inside the container, run
make build && make testto mirror CI exactly; the command exits non-zero on any e2e failure.
Build steps
make sysroot
Runs scripts/make_glibc_and_sysroot.sh to:
-
Configure & build glibc (WASM/WASI target) and compile additional NPTL/syscall bits and tiny ASM stubs.
-
Collect selected
.oobjects (excluding objects definingmain) and archive them intosrc/glibc/sysroot/lib/wasm32-wasi/libc.a; createslibpthread.a; installs headers undersrc/glibc/sysroot/include/wasm32-wasi/; and copiescrt1.o.
make wasmtime
- Builds the embedded Wasmtime with Cargo (release) from
src/wasmtime/.
make test
Runs scripts/wasmtestreport.py which:
-
Discovers tests from the repository’s test trees and honors
skip_test_cases.txt. -
Organizes results (e.g., deterministic / non_deterministic groups), writes
results.json(and may render an HTML summary if enabled). -
The Makefile prints
results.jsonand fails when any failures are present.
CI overview (how e2e is wired)
Workflow: .github/workflows/e2e.yml
High level:
-
Set up Docker Buildx for linux/amd64
-
Build Docker/Dockerfile.e2e with GitHub Actions cache
-
Execute the test stage (same behavior as Usage A)
Caching
What we cache
-
Buildx GHA layer cache (
cache-from/to: type=gha) for apt/clang/rust/tooling and per-stage layers. -
Multi-stage outputs:
build-wasmtimeandbuild-glibcare mounted intotest, so tests avoid rebuilding toolchains.
GitHub Actions semantics
-
cache-from: type=ghapulls layers from the hosted GitHub Actions cache. -
cache-to: type=gha,mode=maxpushes all reusable layers (not just the final image). -
The first cold run builds all layers; subsequent runs only rebuild changed layers, dramatically speeding up CI.
Note: GitHub Actions may evict cached layers over time; when that happens a run starts cold but still passes the same way.
Local build with cache
One-time: create/select a builder
docker buildx create --use --name lind-builder || docker buildx use lind-builder
Build with cache import/export
docker buildx build --platform=linux/amd64 -f Docker/Dockerfile.e2e --cache-from type=local,src=~/.cache/docker-buildx --cache-to type=type=local,dest=.~/.cache/docker-buildx,mode=max .
CI typically uses type=gha; locally a local cache is simple and reliable.
Troubleshooting
-
Apple Silicon / wrong arch → add --platform=linux/amd64 to all build/run commands.
-
Slow first build → increase Docker memory (≈ 6–8 GB) to accommodate sysroot/wasmtime builds.
-
Stale artifacts → run make clean/make distclean and rebuild inside the dev (base) container.
-
Cache debugging → add --progress=plain to docker build to see which step invalidated.