Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
dda065d
fix: Update API calls for Zig 0.15.2 compatibility
Dec 29, 2025
05d6a62
feat(wasi): add fd_tell and fd_readdir implementations
Dec 29, 2025
ae950e6
Refactor fd_readdir to use std.os.wasi types and add Windows support
Dec 29, 2025
b26a7b9
Add missing error mappings in toWasiError
Dec 29, 2025
4b4ca75
fix(fd_readdir): include . and .. entries for WASI compliance
Dec 29, 2025
eb61726
refactor(wasi): clean up fd_tell/fd_readdir, remove Windows impl
Dec 29, 2025
e9f0c38
fix(fd_readdir): proper error handling for lseek calls
Dec 29, 2025
f2079b3
env vars for cpython
Dec 30, 2025
2263fb6
Add WASI testsuite integration with full CI/CD support
Dec 31, 2025
96d04a2
Add individual WASI test steps for granular CI visibility
Dec 31, 2025
5535e3a
Replace hardcoded test lists with dynamic test discovery
Dec 31, 2025
cf79efa
wasi testsuite initial pass
Dec 31, 2025
243c212
merge
Dec 31, 2025
8778fd0
Fix WASI fd_prestat_get structure writing and path_open directory han…
Dec 31, 2025
4a7c63b
Install wasi_test_runner Python package in CI
Dec 31, 2025
7408da5
CI python depends
Dec 31, 2025
8ddb3eb
Merge pull request #1 from nbaertsch/wasi-cpython-support
nbaertsch Dec 31, 2025
4f90142
Fix path_readlink panic on regular files (NotLink error)
Dec 31, 2025
ebb9f02
feat: Implement poll_oneoff for socket I/O polling
Jan 1, 2026
1fcc368
Merge pull request #2 from nbaertsch/feat/poll-oneoff-implementation
nbaertsch Jan 1, 2026
5c711ee
fix: Handle WouldBlock error in toWasiError
Jan 1, 2026
c57e71d
Merge pull request #3 from nbaertsch/fix/wouldblock-error-handling
nbaertsch Jan 1, 2026
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
38 changes: 38 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,44 @@ jobs:
- uses: mlugg/setup-zig@v2.0.5
- name: Run testsuite
run: zig build testsuite
wasi-testsuite-discover:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.discover.outputs.matrix }}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Fetch WASI testsuite
run: |
git clone --depth 1 --branch prod/testsuite-base https://github.com/WebAssembly/wasi-testsuite.git /tmp/wasi-testsuite
- name: Discover tests
id: discover
run: |
MATRIX=$(python3 test/wasi-testsuite/discover-wasi-tests.py /tmp/wasi-testsuite --format github-matrix)
echo "matrix=$MATRIX" >> $GITHUB_OUTPUT

wasi-testsuite:
needs: wasi-testsuite-discover
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.wasi-testsuite-discover.outputs.matrix) }}
runs-on: ubuntu-latest
name: wasi-${{ matrix.suite }}-${{ matrix.test }}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v4
with:
python-version: '3.x'
- uses: mlugg/setup-zig@v2.0.5
- name: Fetch WASI testsuite
run: |
git clone --depth 1 --branch prod/testsuite-base https://github.com/WebAssembly/wasi-testsuite.git /tmp/wasi-testsuite
pip3 install -r /tmp/wasi-testsuite/test-runner/requirements.txt
- name: Run WASI test ${{ matrix.suite }}/${{ matrix.test }}
run: zig build wasi-${{ matrix.suite }}-${{ matrix.test }}

lint:
runs-on: ubuntu-latest
steps:
Expand Down
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
zig-cache
.zig-cache
zig-out
test/testrunner/bin
test/testrunner/bin

# WASI testsuite generated files
test/wasi-testsuite/discovered_tests.json
__pycache__/
**/__pycache__/
*.pyc
87 changes: 86 additions & 1 deletion build.zig
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const Build = @import("std").Build;
const std = @import("std");
const Build = std.Build;

pub fn build(b: *Build) !void {
const target = b.standardTargetOptions(.{});
Expand Down Expand Up @@ -60,9 +61,93 @@ pub fn build(b: *Build) !void {
testsuite_step.dependOn(&run_test.step);
}

// WASI testsuite integration - individual and aggregated test steps
const wasi_testsuite_dep = b.dependency("wasi-testsuite", .{});

// Aggregated step that runs all WASI tests at once
const wasi_testsuite_step = b.step("wasi-testsuite", "Run WASI testsuite tests (all languages)");
const run_wasi_tests = b.addSystemCommand(&.{
"python3",
"test-runner/wasi_test_runner.py",
"-t",
"tests/c/testsuite/wasm32-wasip1",
"tests/rust/testsuite/wasm32-wasip1",
"tests/assemblyscript/testsuite/wasm32-wasip1",
"-r",
b.pathFromRoot("test/wasi-testsuite/adapter/zware.py"),
});
run_wasi_tests.setCwd(wasi_testsuite_dep.path("."));
run_wasi_tests.setEnvironmentVariable("ZWARE_RUN", b.getInstallPath(.bin, "zware-run"));
run_wasi_tests.step.dependOn(b.getInstallStep());
wasi_testsuite_step.dependOn(&run_wasi_tests.step);

// Individual test steps - dynamically discovered from testsuite
// Create a helper function to discover and register tests for a suite
const TestSuite = struct {
key: []const u8,
path: []const u8,
};

const test_suites = [_]TestSuite{
.{ .key = "c", .path = "tests/c/testsuite/wasm32-wasip1" },
.{ .key = "rust", .path = "tests/rust/testsuite/wasm32-wasip1" },
.{ .key = "as", .path = "tests/assemblyscript/testsuite/wasm32-wasip1" },
};

for (test_suites) |suite| {
// Get the actual path to the testsuite directory
const suite_dir_path = wasi_testsuite_dep.path(suite.path).getPath(b);

// Open and scan the directory for .wasm files
var suite_dir = std.fs.cwd().openDir(suite_dir_path, .{ .iterate = true }) catch continue;
defer suite_dir.close();

var test_list: std.ArrayList([]const u8) = .empty;
defer test_list.deinit(b.allocator);

var iter = suite_dir.iterate();
while (iter.next() catch null) |entry| {
if (entry.kind == .file and std.mem.endsWith(u8, entry.name, ".wasm")) {
const test_name = entry.name[0 .. entry.name.len - 5]; // remove .wasm extension
const test_name_owned = b.allocator.dupe(u8, test_name) catch continue;
test_list.append(b.allocator, test_name_owned) catch continue;
}
}

// Sort test names for deterministic ordering
std.mem.sort([]const u8, test_list.items, {}, struct {
fn lessThan(_: void, lhs: []const u8, rhs: []const u8) bool {
return std.mem.lessThan(u8, lhs, rhs);
}
}.lessThan);

// Create individual build steps for each discovered test
for (test_list.items) |test_name| {
const run_test = b.addSystemCommand(&.{
"python3",
b.pathFromRoot("test/wasi-testsuite/run-single-wasi-test.py"),
suite.path,
test_name,
"-r",
b.pathFromRoot("test/wasi-testsuite/adapter/zware.py"),
"--test-runner",
"test-runner/wasi_test_runner.py",
});
run_test.setCwd(wasi_testsuite_dep.path("."));
run_test.setEnvironmentVariable("ZWARE_RUN", b.getInstallPath(.bin, "zware-run"));
run_test.step.dependOn(b.getInstallStep());
b.step(
b.fmt("wasi-{s}-{s}", .{ suite.key, test_name }),
b.fmt("Run WASI {s} test: {s}", .{ suite.key, test_name }),
).dependOn(&run_test.step);
}
}

const test_step = b.step("test", "Run all the tests");
test_step.dependOn(unittest_step);
test_step.dependOn(testsuite_step);
// Note: WASI testsuite is not included in default test step due to external dependencies
// Run it explicitly with: zig build wasi-testsuite

{
const exe = b.addExecutable(.{
Expand Down
4 changes: 4 additions & 0 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
.url = "https://github.com/WebAssembly/testsuite/archive/e25ae159357c055b3a6fac99043644e208d26d2a.tar.gz",
.hash = "N-V-__8AAKtbtgBFkB_BMIKSUqC-temKvHmuqBSvjBlf4hD6",
},
.@"wasi-testsuite" = .{
.url = "https://github.com/WebAssembly/wasi-testsuite/archive/refs/heads/prod/testsuite-base.tar.gz",
.hash = "N-V-__8AAHAN1wCGU7h8wcRWoFr0TLZ_5M4KqbBYKfkLqIoY",
},
},
.paths = .{
"build.zig",
Expand Down
9 changes: 9 additions & 0 deletions src/instance.zig
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,15 @@ pub const Instance = struct {
});
}

/// Inherit stdin, stdout, and stderr from the host process.
/// Maps WASI fds 0, 1, 2 to host fds 0, 1, 2 respectively.
/// This matches the behavior of wasmtime's inherit_stdio().
pub fn inheritStdio(self: *Instance) !void {
try self.addWasiPreopen(0, "stdin", 0);
try self.addWasiPreopen(1, "stdout", 1);
try self.addWasiPreopen(2, "stderr", 2);
}

// FIXME: hide any allocation / deinit inside Instance
// Caller must call std.process.argsFree on returned args
//
Expand Down
Loading
Loading