1 mod test_helpers;
2
3 use crate::test_helpers::{
4 lucet_wasi_tests_internal_ensure_linked, run, run_with_null_stdin, run_with_stdout,
5 LUCET_WASI_ROOT,
6 };
7 use lucet_wasi::{WasiCtx, WasiCtxBuilder};
8 use std::fs::File;
9 use std::path::Path;
10 use tempfile::TempDir;
11
12 #[test]
double_import()13 fn double_import() {
14 lucet_wasi_tests_internal_ensure_linked();
15
16 let mut ctx = WasiCtxBuilder::new();
17
18 let (exitcode, stdout) = run_with_stdout("duplicate_import.wat", &mut ctx).unwrap();
19
20 assert_eq!(stdout, "duplicate import works!\n");
21 assert_eq!(exitcode, 0);
22 }
23
24 #[test]
hello()25 fn hello() {
26 let mut ctx = WasiCtxBuilder::new();
27 ctx.args(["hello"].iter());
28
29 let (exitcode, stdout) = run_with_stdout(
30 Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"),
31 &mut ctx,
32 )
33 .unwrap();
34
35 assert_eq!(exitcode, 0);
36 assert_eq!(&stdout, "hello, wasi!\n");
37 }
38
39 #[test]
hello_args()40 fn hello_args() {
41 let mut ctx = WasiCtxBuilder::new();
42 ctx.args(["hello", "test suite"].iter());
43
44 let (exitcode, stdout) = run_with_stdout(
45 Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"),
46 &mut ctx,
47 )
48 .unwrap();
49
50 assert_eq!(exitcode, 0);
51 assert_eq!(&stdout, "hello, test suite!\n");
52 }
53
54 #[test]
hello_env()55 fn hello_env() {
56 let mut ctx = WasiCtxBuilder::new();
57 ctx.args(["hello", "test suite"].iter());
58 ctx.env("GREETING", "goodbye");
59
60 let (exitcode, stdout) = run_with_stdout(
61 Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"),
62 &mut ctx,
63 )
64 .unwrap();
65
66 assert_eq!(exitcode, 0);
67 assert_eq!(&stdout, "goodbye, test suite!\n");
68 }
69
70 #[test]
exitcode()71 fn exitcode() {
72 let ctx = WasiCtx::new(["exitcode"].iter()).unwrap();
73
74 let exitcode = run("exitcode.c", ctx).unwrap();
75
76 assert_eq!(exitcode, 120);
77 }
78
79 #[test]
clock_getres()80 fn clock_getres() {
81 let ctx = WasiCtx::new(["clock_getres"].iter()).unwrap();
82
83 let exitcode = run("clock_getres.c", ctx).unwrap();
84
85 assert_eq!(exitcode, 0);
86 }
87
88 #[test]
getrusage()89 fn getrusage() {
90 let ctx = WasiCtx::new(["getrusage"].iter()).unwrap();
91
92 let exitcode = run("getrusage.c", ctx).unwrap();
93
94 assert_eq!(exitcode, 0);
95 }
96
97 #[test]
gettimeofday()98 fn gettimeofday() {
99 let ctx = WasiCtx::new(["gettimeofday"].iter()).unwrap();
100
101 let exitcode = run("gettimeofday.c", ctx).unwrap();
102
103 assert_eq!(exitcode, 0);
104 }
105
106 #[test]
getentropy()107 fn getentropy() {
108 let ctx = WasiCtx::new(["getentropy"].iter()).unwrap();
109
110 let exitcode = run("getentropy.c", ctx).unwrap();
111
112 assert_eq!(exitcode, 0);
113 }
114
115 #[test]
stdin()116 fn stdin() {
117 use std::io::Write;
118 use std::os::unix::io::FromRawFd;
119
120 let (pipe_out, pipe_in) = nix::unistd::pipe().expect("can create pipe");
121
122 let mut stdin_file = unsafe { File::from_raw_fd(pipe_in) };
123 write!(stdin_file, "hello from stdin!").expect("pipe write succeeds");
124 drop(stdin_file);
125
126 let mut ctx = WasiCtxBuilder::new();
127 ctx.args(["stdin"].iter());
128 ctx.stdin(unsafe { File::from_raw_fd(pipe_out) });
129
130 let (exitcode, stdout) = run_with_stdout("stdin.c", &mut ctx).unwrap();
131
132 assert_eq!(exitcode, 0);
133 assert_eq!(&stdout, "hello from stdin!");
134 }
135
136 #[test]
preopen_populates()137 fn preopen_populates() {
138 let tmpdir = TempDir::new().unwrap();
139 let preopen_host_path = tmpdir.path().join("preopen");
140 std::fs::create_dir(&preopen_host_path).unwrap();
141 let preopen_dir = File::open(preopen_host_path).unwrap();
142
143 let mut ctx = WasiCtxBuilder::new();
144 ctx.args(["preopen_populates"].iter());
145 ctx.preopened_dir(preopen_dir, "/preopen");
146 let ctx = ctx.build().expect("can build WasiCtx");
147
148 let exitcode = run("preopen_populates.c", ctx).unwrap();
149
150 drop(tmpdir);
151
152 assert_eq!(exitcode, 0);
153 }
154
155 #[test]
write_file()156 fn write_file() {
157 let tmpdir = TempDir::new().unwrap();
158 let preopen_host_path = tmpdir.path().join("preopen");
159 std::fs::create_dir(&preopen_host_path).unwrap();
160 let preopen_dir = File::open(&preopen_host_path).unwrap();
161
162 let mut ctx = WasiCtxBuilder::new();
163 ctx.args(["write_file"].iter());
164 ctx.preopened_dir(preopen_dir, "/sandbox");
165 let ctx = ctx.build().expect("can build WasiCtx");
166
167 let exitcode = run("write_file.c", ctx).unwrap();
168 assert_eq!(exitcode, 0);
169
170 let output = std::fs::read(preopen_host_path.join("output.txt")).unwrap();
171
172 assert_eq!(output.as_slice(), b"hello, file!");
173
174 drop(tmpdir);
175 }
176
177 #[test]
read_file()178 fn read_file() {
179 const MESSAGE: &str = "hello from file!";
180 let tmpdir = TempDir::new().unwrap();
181 let preopen_host_path = tmpdir.path().join("preopen");
182 std::fs::create_dir(&preopen_host_path).unwrap();
183
184 std::fs::write(preopen_host_path.join("input.txt"), MESSAGE).unwrap();
185
186 let preopen_dir = File::open(&preopen_host_path).unwrap();
187
188 let mut ctx = WasiCtxBuilder::new();
189 ctx.args(["read_file"].iter());
190 ctx.preopened_dir(preopen_dir, "/sandbox");
191
192 let (exitcode, stdout) = run_with_stdout("read_file.c", &mut ctx).unwrap();
193 assert_eq!(exitcode, 0);
194
195 assert_eq!(&stdout, MESSAGE);
196
197 drop(tmpdir);
198 }
199
200 #[test]
read_file_twice()201 fn read_file_twice() {
202 const MESSAGE: &str = "hello from file!";
203 let tmpdir = TempDir::new().unwrap();
204 let preopen_host_path = tmpdir.path().join("preopen");
205 std::fs::create_dir(&preopen_host_path).unwrap();
206
207 std::fs::write(preopen_host_path.join("input.txt"), MESSAGE).unwrap();
208
209 let preopen_dir = File::open(&preopen_host_path).unwrap();
210
211 let mut ctx = WasiCtxBuilder::new();
212 ctx.args(["read_file_twice"].iter());
213 ctx.preopened_dir(preopen_dir, "/sandbox");
214
215 let (exitcode, stdout) = run_with_stdout("read_file_twice.c", &mut ctx).unwrap();
216 assert_eq!(exitcode, 0);
217
218 let double_message = format!("{}{}", MESSAGE, MESSAGE);
219 assert_eq!(stdout, double_message);
220
221 drop(tmpdir);
222 }
223
224 #[test]
cant_dotdot()225 fn cant_dotdot() {
226 const MESSAGE: &str = "hello from file!";
227 let tmpdir = TempDir::new().unwrap();
228 let preopen_host_path = tmpdir.path().join("preopen");
229 std::fs::create_dir(&preopen_host_path).unwrap();
230
231 std::fs::write(
232 preopen_host_path.parent().unwrap().join("outside.txt"),
233 MESSAGE,
234 )
235 .unwrap();
236
237 let preopen_dir = File::open(&preopen_host_path).unwrap();
238
239 let mut ctx = WasiCtxBuilder::new();
240 ctx.args(["cant_dotdot"].iter());
241 ctx.preopened_dir(preopen_dir, "/sandbox");
242 let ctx = ctx.build().unwrap();
243
244 let exitcode = run("cant_dotdot.c", ctx).unwrap();
245 assert_eq!(exitcode, 0);
246
247 drop(tmpdir);
248 }
249
250 #[ignore] // needs fd_readdir
251 #[test]
notdir()252 fn notdir() {
253 const MESSAGE: &str = "hello from file!";
254 let tmpdir = TempDir::new().unwrap();
255 let preopen_host_path = tmpdir.path().join("preopen");
256 std::fs::create_dir(&preopen_host_path).unwrap();
257
258 std::fs::write(preopen_host_path.join("notadir"), MESSAGE).unwrap();
259
260 let preopen_dir = File::open(&preopen_host_path).unwrap();
261
262 let mut ctx = WasiCtxBuilder::new();
263 ctx.args(["notdir"].iter());
264 ctx.preopened_dir(preopen_dir, "/sandbox");
265 let ctx = ctx.build().unwrap();
266
267 let exitcode = run("notdir.c", ctx).unwrap();
268 assert_eq!(exitcode, 0);
269
270 drop(tmpdir);
271 }
272
273 #[test]
follow_symlink()274 fn follow_symlink() {
275 const MESSAGE: &str = "hello from file!";
276
277 let tmpdir = TempDir::new().unwrap();
278 let preopen_host_path = tmpdir.path().join("preopen");
279 let subdir1 = preopen_host_path.join("subdir1");
280 let subdir2 = preopen_host_path.join("subdir2");
281 std::fs::create_dir_all(&subdir1).unwrap();
282 std::fs::create_dir_all(&subdir2).unwrap();
283
284 std::fs::write(subdir1.join("input.txt"), MESSAGE).unwrap();
285
286 std::os::unix::fs::symlink("../subdir1/input.txt", subdir2.join("input_link.txt")).unwrap();
287
288 let preopen_dir = File::open(&preopen_host_path).unwrap();
289
290 let mut ctx = WasiCtxBuilder::new();
291 ctx.args(["follow_symlink"].iter());
292 ctx.preopened_dir(preopen_dir, "/sandbox");
293
294 let (exitcode, stdout) = run_with_stdout("follow_symlink.c", &mut ctx).unwrap();
295 assert_eq!(exitcode, 0);
296 assert_eq!(&stdout, MESSAGE);
297
298 drop(tmpdir);
299 }
300
301 #[test]
symlink_loop()302 fn symlink_loop() {
303 let tmpdir = TempDir::new().unwrap();
304 let preopen_host_path = tmpdir.path().join("preopen");
305 let subdir1 = preopen_host_path.join("subdir1");
306 let subdir2 = preopen_host_path.join("subdir2");
307 std::fs::create_dir_all(&subdir1).unwrap();
308 std::fs::create_dir_all(&subdir2).unwrap();
309
310 std::os::unix::fs::symlink("../subdir1/loop1", subdir2.join("loop2")).unwrap();
311 std::os::unix::fs::symlink("../subdir2/loop2", subdir1.join("loop1")).unwrap();
312
313 let preopen_dir = File::open(&preopen_host_path).unwrap();
314
315 let mut ctx = WasiCtxBuilder::new();
316 ctx.args(["symlink_loop"].iter());
317 ctx.preopened_dir(preopen_dir, "/sandbox");
318 let ctx = ctx.build().unwrap();
319
320 let exitcode = run("symlink_loop.c", ctx).unwrap();
321 assert_eq!(exitcode, 0);
322
323 drop(tmpdir);
324 }
325
326 #[test]
symlink_escape()327 fn symlink_escape() {
328 const MESSAGE: &str = "hello from file!";
329
330 let tmpdir = TempDir::new().unwrap();
331 let preopen_host_path = tmpdir.path().join("preopen");
332 let subdir = preopen_host_path.join("subdir");
333 std::fs::create_dir_all(&subdir).unwrap();
334
335 std::fs::write(
336 preopen_host_path.parent().unwrap().join("outside.txt"),
337 MESSAGE,
338 )
339 .unwrap();
340 std::os::unix::fs::symlink("../../outside.txt", subdir.join("outside.txt")).unwrap();
341
342 let preopen_dir = File::open(&preopen_host_path).unwrap();
343
344 let mut ctx = WasiCtxBuilder::new();
345 ctx.args(["symlink_escape"].iter());
346 ctx.preopened_dir(preopen_dir, "/sandbox");
347 let ctx = ctx.build().unwrap();
348
349 let exitcode = run("symlink_escape.c", ctx).unwrap();
350 assert_eq!(exitcode, 0);
351
352 drop(tmpdir);
353 }
354
355 #[test]
pseudoquine()356 fn pseudoquine() {
357 let examples_dir = Path::new(LUCET_WASI_ROOT).join("examples");
358 let pseudoquine_c = examples_dir.join("pseudoquine.c");
359
360 let mut ctx = WasiCtxBuilder::new();
361 ctx.args(["pseudoquine"].iter());
362 ctx.preopened_dir(File::open(examples_dir).unwrap(), "/examples");
363
364 let (exitcode, stdout) = run_with_stdout(&pseudoquine_c, &mut ctx).unwrap();
365
366 assert_eq!(exitcode, 0);
367
368 let expected = std::fs::read_to_string(&pseudoquine_c).unwrap();
369
370 assert_eq!(stdout, expected);
371 }
372
373 // ACF 2019-10-03: temporarily disabled until we figure out why it's behaving differently only in
374 // one CI environment
375 #[ignore]
376 #[test]
poll()377 fn poll() {
378 let mut ctx = WasiCtxBuilder::new();
379 ctx.args(["poll"].iter());
380 let exitcode = run_with_null_stdin("poll.c", &mut ctx).unwrap();
381 assert_eq!(exitcode, 0);
382 }
383
384 #[test]
stat()385 fn stat() {
386 let tmpdir = TempDir::new().unwrap();
387 let preopen_host_path = tmpdir.path().join("preopen");
388 std::fs::create_dir(&preopen_host_path).unwrap();
389 let preopen_dir = File::open(&preopen_host_path).unwrap();
390 let mut ctx = WasiCtxBuilder::new();
391 ctx.args(["stat"].iter());
392 ctx.preopened_dir(preopen_dir, "/sandbox");
393 let ctx = ctx.build().expect("can build WasiCtx");
394 let exitcode = run("stat.c", ctx).unwrap();
395 assert_eq!(exitcode, 0);
396 }
397
398 #[test]
fs()399 fn fs() {
400 let tmpdir = TempDir::new().unwrap();
401 let preopen_host_path = tmpdir.path().join("preopen");
402 std::fs::create_dir(&preopen_host_path).unwrap();
403 let preopen_dir = File::open(&preopen_host_path).unwrap();
404 let mut ctx = WasiCtxBuilder::new();
405 ctx.args(["stat"].iter());
406 ctx.preopened_dir(preopen_dir, "/sandbox");
407 let ctx = ctx.build().expect("can build WasiCtx");
408 let exitcode = run("fs.c", ctx).unwrap();
409 assert_eq!(exitcode, 0);
410 }
411