Skip to content

Commit c9a5cbc

Browse files
Add tests for mapped directories
1 parent 165cf11 commit c9a5cbc

File tree

8 files changed

+148
-4
lines changed

8 files changed

+148
-4
lines changed

ext/src/ruby_api/wasi_config.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::error;
33
use crate::helpers::OutputLimitedBuffer;
44
use magnus::{
55
class, function, gc::Marker, method, typed_data::Obj, value::Opaque, DataTypeFunctions, Error,
6-
Module, Object, RArray, RHash, RString, Symbol, Ruby, TryConvert, TypedData,
6+
Module, Object, RArray, RHash, RString, Ruby, Symbol, TryConvert, TypedData,
77
};
88
use rb_sys::ruby_rarray_flags::RARRAY_EMBED_FLAG;
99
use std::cell::RefCell;
@@ -363,8 +363,12 @@ impl WasiConfig {
363363
RString::try_convert(mapped_directory.entry(0)?)?.to_string()?;
364364
let guest_path =
365365
RString::try_convert(mapped_directory.entry(1)?)?.to_string()?;
366-
let dir_perms = Symbol::from_value(mapped_directory.entry(2)?).unwrap().name()?;
367-
let file_perms = Symbol::from_value(mapped_directory.entry(3)?).unwrap().name()?;
366+
let dir_perms = Symbol::from_value(mapped_directory.entry(2)?)
367+
.unwrap()
368+
.name()?;
369+
let file_perms = Symbol::from_value(mapped_directory.entry(3)?)
370+
.unwrap()
371+
.name()?;
368372

369373
let host_path_dir = Path::new(&host_path);
370374
let guest_path_path = guest_path.as_str();
@@ -397,7 +401,12 @@ impl WasiConfig {
397401
}
398402

399403
builder
400-
.preopened_dir(host_path_dir, guest_path_path, dir_perms_flags, file_perms_flags)
404+
.preopened_dir(
405+
host_path_dir,
406+
guest_path_path,
407+
dir_perms_flags,
408+
file_perms_flags,
409+
)
401410
.map_err(|e| error!("{}", e))?;
402411
}
403412
}

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: 91 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,83 @@ 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
236307
end
237308

238309
describe "WasiConfig preview 1" do
239310
it_behaves_like WasiConfig do
240311
let(:run) { method(:run_wasi_module) }
241312
let(:wasi_env) { method(:wasi_module_env) }
242313
let(:run_deterministic) { method(:run_wasi_module_deterministic) }
314+
let(:run_fs) { method(:run_wasi_module_fs) }
243315
end
244316
end
245317

@@ -248,6 +320,7 @@ module Wasmtime
248320
let(:run) { method(:run_wasi_component) }
249321
let(:wasi_env) { method(:wasi_component_env) }
250322
let(:run_deterministic) { method(:run_wasi_component_deterministic) }
323+
let(:run_fs) { method(:run_wasi_component_fs) }
251324
end
252325
end
253326

@@ -272,6 +345,13 @@ def run_wasi_module_deterministic(wasi_config)
272345
.invoke("_start")
273346
end
274347

348+
def run_wasi_module_fs(wasi_config)
349+
linker = Linker.new(@engine)
350+
WASI::P1.add_to_linker_sync(linker)
351+
store = Store.new(@engine, wasi_p1_config: wasi_config)
352+
linker.instantiate(store, Module.deserialize(@engine, @compiled_wasi_fs_module)).invoke("_start")
353+
end
354+
275355
def wasi_module_env
276356
stdout_file = tempfile_path("stdout")
277357

@@ -318,6 +398,17 @@ def run_wasi_component_deterministic(wasi_config)
318398
).call_run(store)
319399
end
320400

401+
def run_wasi_component_fs(wasi_config)
402+
linker = Component::Linker.new(@engine)
403+
WASI::P2.add_to_linker_sync(linker)
404+
store = Store.new(@engine, wasi_config: wasi_config)
405+
Component::WasiCommand.new(
406+
store,
407+
Component::Component.deserialize(@engine, @compiled_wasi_fs_component),
408+
linker
409+
).call_run(store)
410+
end
411+
321412
def tempfile_path(name)
322413
File.join(tmpdir, name)
323414
end

0 commit comments

Comments
 (0)