Skip to content

Commit cea0c26

Browse files
Add tests for mapped directories
1 parent 0400633 commit cea0c26

File tree

7 files changed

+155
-0
lines changed

7 files changed

+155
-0
lines changed

spec/fixtures/wasi-fs-p2.wasm

129 KB
Binary file not shown.

spec/fixtures/wasi-fs.wasm

64.4 KB
Binary file not shown.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[build]
2+
target = "wasm32-wasip1"

spec/fixtures/wasi-fs/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "wasi-fs"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[workspace]
9+
10+
[dependencies]

spec/fixtures/wasi-fs/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Example WASI program used to test WASI preopened directories
2+
3+
To update:
4+
5+
```shell
6+
cargo build --release && \
7+
wasm-opt -O \
8+
--enable-bulk-memory \
9+
target/wasm32-wasip1/release/wasi-fs.wasm \
10+
-o ../wasi-fs.wasm && \
11+
cargo build --target=wasm32-wasip2 --release && \
12+
cp target/wasm32-wasip2/release/wasi-fs.wasm \
13+
../wasi-fs-p2.wasm
14+
```

spec/fixtures/wasi-fs/src/main.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use std::io::{Write, Read};
2+
use std::fs::File;
3+
4+
fn main() {
5+
let args: Vec<String> = std::env::args().collect();
6+
7+
let counter_file = File::open(&args[1]).expect("failed to open counter file");
8+
9+
let mut counter_str = String::new();
10+
counter_file.take(100).read_to_string(&mut counter_str)
11+
.expect("failed to read counter file");
12+
let mut counter: u32 = counter_str.trim().parse().expect("failed to parse counter");
13+
14+
counter += 1;
15+
16+
let mut counter_file = File::create(&args[1]).expect("failed to create counter file");
17+
write!(counter_file, "{}", counter).expect("failed to write counter file");
18+
}

spec/unit/wasi_spec.rb

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ module Wasmtime
1212
# Compile module only once for speed
1313
@compiled_wasi_module = @engine.precompile_module(IO.binread("spec/fixtures/wasi-debug.wasm"))
1414
@compiled_wasi_deterministic_module = @engine.precompile_module(IO.binread("spec/fixtures/wasi-deterministic.wasm"))
15+
@compiled_wasi_fs_module = @engine.precompile_module(IO.binread("spec/fixtures/wasi-fs.wasm"))
1516

1617
@compiled_wasi_component = @engine.precompile_component(IO.binread("spec/fixtures/wasi-debug-p2.wasm"))
1718
@compiled_wasi_deterministic_component = @engine.precompile_component(IO.binread("spec/fixtures/wasi-deterministic-p2.wasm"))
19+
@compiled_wasi_fs_component = @engine.precompile_component(IO.binread("spec/fixtures/wasi-fs-p2.wasm"))
1820
end
1921

2022
describe "Linker.new" do
@@ -233,13 +235,103 @@ module Wasmtime
233235
end
234236
end
235237
end
238+
239+
it "writes to mapped directory" do
240+
Dir.mkdir(tempfile_path("tmp"))
241+
File.write(tempfile_path(File.join("tmp", "counter")), "0")
242+
243+
wasi_config = WasiConfig.new
244+
.set_argv(["wasi-fs", "/tmp/counter"])
245+
.set_mapped_directory(tempfile_path("tmp"), "/tmp", :all, :all)
246+
247+
expect { run_fs.call(wasi_config) }.not_to raise_error
248+
249+
expect(File.read(tempfile_path(File.join("tmp", "counter")))).to eq("1")
250+
end
251+
252+
it "fails to write to mapped directory if not permitted" do
253+
Dir.mkdir(tempfile_path("tmp"))
254+
File.write(tempfile_path(File.join("tmp", "counter")), "0")
255+
256+
stderr_str = ""
257+
wasi_config = WasiConfig.new
258+
.set_argv(["wasi-fs", "/tmp/counter"])
259+
.set_stderr_buffer(stderr_str, 40000)
260+
.set_mapped_directory(tempfile_path("tmp"), "/tmp", :read, :read)
261+
262+
expect { run_fs.call(wasi_config) }.to raise_error do |error|
263+
expect(error).to be_a(Wasmtime::Error)
264+
end
265+
266+
expect(stderr_str).to match(/failed to create counter file/)
267+
268+
expect(File.read(tempfile_path(File.join("tmp", "counter")))).to eq("0")
269+
end
270+
271+
it "fails to read from mapped directory if not permitted" do
272+
Dir.mkdir(tempfile_path("tmp"))
273+
File.write(tempfile_path(File.join("tmp", "counter")), "0")
274+
275+
stderr_str = ""
276+
wasi_config = WasiConfig.new
277+
.set_argv(["wasi-fs", "/tmp/counter"])
278+
.set_stderr_buffer(stderr_str, 40000)
279+
.set_mapped_directory(tempfile_path("tmp"), "/tmp", :mutate, :write)
280+
281+
expect { run_fs.call(wasi_config) }.to raise_error do |error|
282+
expect(error).to be_a(Wasmtime::Error)
283+
end
284+
285+
expect(stderr_str).to match(/failed to open counter file/)
286+
287+
expect(File.read(tempfile_path(File.join("tmp", "counter")))).to eq("0")
288+
end
289+
290+
it "fails to access non-mapped directories" do
291+
Dir.mkdir(tempfile_path("tmp"))
292+
File.write(tempfile_path(File.join("tmp", "counter")), "0")
293+
294+
stderr_str = ""
295+
wasi_config = WasiConfig.new
296+
.set_argv(["wasi-fs", File.join(tempfile_path("tmp"), "counter")])
297+
.set_stderr_buffer(stderr_str, 40000)
298+
299+
expect { run_fs.call(wasi_config) }.to raise_error do |error|
300+
expect(error).to be_a(Wasmtime::Error)
301+
end
302+
303+
expect(stderr_str).to match(/failed to find a pre-opened file descriptor/)
304+
305+
expect(File.read(tempfile_path(File.join("tmp", "counter")))).to eq("0")
306+
end
307+
308+
it "does not accept an invalid host path" do
309+
wasi_config = WasiConfig.new
310+
.set_mapped_directory(tempfile_path("tmp"), "/tmp", :all, :all)
311+
312+
expect { run_fs.call(wasi_config) }.to raise_error do |error|
313+
expect(error).to be_a(Wasmtime::Error)
314+
# error message is os-specific
315+
end
316+
end
317+
318+
it "does not accept invalid permissions" do
319+
wasi_config = WasiConfig.new
320+
.set_mapped_directory(tempfile_path("tmp"), "/tmp", :mutate, :invalid_permission)
321+
322+
expect { run_fs.call(wasi_config) }.to raise_error do |error|
323+
expect(error).to be_a(Wasmtime::Error)
324+
expect(error.message).to match(/Invalid file_perms: invalid_permission. Use one of :read, :write, or :all/)
325+
end
326+
end
236327
end
237328

238329
describe "WasiConfig preview 1" do
239330
it_behaves_like WasiConfig do
240331
let(:run) { method(:run_wasi_module) }
241332
let(:wasi_env) { method(:wasi_module_env) }
242333
let(:run_deterministic) { method(:run_wasi_module_deterministic) }
334+
let(:run_fs) { method(:run_wasi_module_fs) }
243335
end
244336
end
245337

@@ -248,6 +340,7 @@ module Wasmtime
248340
let(:run) { method(:run_wasi_component) }
249341
let(:wasi_env) { method(:wasi_component_env) }
250342
let(:run_deterministic) { method(:run_wasi_component_deterministic) }
343+
let(:run_fs) { method(:run_wasi_component_fs) }
251344
end
252345
end
253346

@@ -272,6 +365,13 @@ def run_wasi_module_deterministic(wasi_config)
272365
.invoke("_start")
273366
end
274367

368+
def run_wasi_module_fs(wasi_config)
369+
linker = Linker.new(@engine)
370+
WASI::P1.add_to_linker_sync(linker)
371+
store = Store.new(@engine, wasi_p1_config: wasi_config)
372+
linker.instantiate(store, Module.deserialize(@engine, @compiled_wasi_fs_module)).invoke("_start")
373+
end
374+
275375
def wasi_module_env
276376
stdout_file = tempfile_path("stdout")
277377

@@ -318,6 +418,17 @@ def run_wasi_component_deterministic(wasi_config)
318418
).call_run(store)
319419
end
320420

421+
def run_wasi_component_fs(wasi_config)
422+
linker = Component::Linker.new(@engine)
423+
WASI::P2.add_to_linker_sync(linker)
424+
store = Store.new(@engine, wasi_config: wasi_config)
425+
Component::WasiCommand.new(
426+
store,
427+
Component::Component.deserialize(@engine, @compiled_wasi_fs_component),
428+
linker
429+
).call_run(store)
430+
end
431+
321432
def tempfile_path(name)
322433
File.join(tmpdir, name)
323434
end

0 commit comments

Comments
 (0)