Skip to content

Commit 2455117

Browse files
committed
test: example uffd
Testing for example uffd ensuring it can accept multiple uffds. Also now CI will run tests from examples as well. Signed-off-by: Egor Lazarchuk <yegorlz@amazon.co.uk>
1 parent 64a2619 commit 2455117

File tree

2 files changed

+92
-2
lines changed

2 files changed

+92
-2
lines changed

src/firecracker/examples/uffd/uffd_utils.rs

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
1010
use std::os::unix::net::UnixStream;
1111
use std::ptr;
1212

13-
use serde::Deserialize;
13+
use serde::{Deserialize, Serialize};
1414
use userfaultfd::{Error, Event, Uffd};
1515
use utils::get_page_size;
1616
use utils::sock_ctrl_msg::ScmSocket;
@@ -22,7 +22,7 @@ use utils::sock_ctrl_msg::ScmSocket;
2222
///
2323
/// E.g. Guest memory contents for a region of `size` bytes can be found in the backend
2424
/// at `offset` bytes from the beginning, and should be copied/populated into `base_host_address`.
25-
#[derive(Clone, Debug, Deserialize)]
25+
#[derive(Clone, Debug, Serialize, Deserialize)]
2626
pub struct GuestRegionUffdMapping {
2727
/// Base host virtual address where the guest memory contents for this region
2828
/// should be copied/populated.
@@ -292,3 +292,92 @@ fn create_mem_regions(mappings: &Vec<GuestRegionUffdMapping>) -> Vec<MemRegion>
292292

293293
mem_regions
294294
}
295+
296+
#[cfg(test)]
297+
mod tests {
298+
use std::mem::MaybeUninit;
299+
use std::os::unix::net::UnixListener;
300+
301+
use utils::tempdir::TempDir;
302+
use utils::tempfile::TempFile;
303+
304+
use super::*;
305+
306+
unsafe impl Send for Runtime {}
307+
308+
#[test]
309+
fn test_runtime() {
310+
let tmp_dir = TempDir::new().unwrap();
311+
let dummy_socket_path = tmp_dir.as_path().join("dummy_socket");
312+
let dummy_socket_path_clone = dummy_socket_path.clone();
313+
314+
let mut uninit_runtime = Box::new(MaybeUninit::<Runtime>::uninit());
315+
// We will use this pointer to bypass a bunch of Rust Safety
316+
// for the sake of convenience.
317+
let runtime_ptr = uninit_runtime.as_ptr() as *const Runtime;
318+
319+
let runtime_thread = std::thread::spawn(move || {
320+
let tmp_file = TempFile::new().unwrap();
321+
tmp_file.as_file().set_len(0x1000).unwrap();
322+
let dummy_mem_path = tmp_file.as_path();
323+
324+
let file = File::open(dummy_mem_path).expect("Cannot open memfile");
325+
let listener =
326+
UnixListener::bind(dummy_socket_path).expect("Cannot bind to socket path");
327+
let (stream, _) = listener.accept().expect("Cannot listen on UDS socket");
328+
// Update runtime with actual runtime
329+
let runtime = uninit_runtime.write(Runtime::new(stream, file));
330+
runtime.run(|_: &mut UffdHandler| {});
331+
});
332+
333+
// wait for runtime thread to initialize itself
334+
std::thread::sleep(std::time::Duration::from_millis(100));
335+
336+
let stream =
337+
UnixStream::connect(dummy_socket_path_clone).expect("Cannot connect to the socket");
338+
339+
let dummy_memory_region = vec![GuestRegionUffdMapping {
340+
base_host_virt_addr: 0,
341+
size: 0x1000,
342+
offset: 0,
343+
}];
344+
let dummy_memory_region_json = serde_json::to_string(&dummy_memory_region).unwrap();
345+
346+
let dummy_file_1 = TempFile::new().unwrap();
347+
let dummy_fd_1 = dummy_file_1.as_file().as_raw_fd();
348+
stream
349+
.send_with_fd(dummy_memory_region_json.as_bytes(), dummy_fd_1)
350+
.unwrap();
351+
// wait for the runtime thread to process message
352+
std::thread::sleep(std::time::Duration::from_millis(100));
353+
unsafe {
354+
assert_eq!((*runtime_ptr).uffds.len(), 1);
355+
}
356+
357+
let dummy_file_2 = TempFile::new().unwrap();
358+
let dummy_fd_2 = dummy_file_2.as_file().as_raw_fd();
359+
stream
360+
.send_with_fd(dummy_memory_region_json.as_bytes(), dummy_fd_2)
361+
.unwrap();
362+
// wait for the runtime thread to process message
363+
std::thread::sleep(std::time::Duration::from_millis(100));
364+
unsafe {
365+
assert_eq!((*runtime_ptr).uffds.len(), 2);
366+
}
367+
368+
// there is no way to properly stop runtime, so
369+
// we send a message with an incorrect memory region
370+
// to cause runtime thread to panic
371+
let error_memory_region = vec![GuestRegionUffdMapping {
372+
base_host_virt_addr: 0,
373+
size: 0,
374+
offset: 0,
375+
}];
376+
let error_memory_region_json = serde_json::to_string(&error_memory_region).unwrap();
377+
stream
378+
.send_with_fd(error_memory_region_json.as_bytes(), dummy_fd_2)
379+
.unwrap();
380+
381+
runtime_thread.join().unwrap_err();
382+
}
383+
}

tests/integration_tests/build/test_unittests.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def test_unittests(test_fc_session_root_path):
2323

2424
extra_args = f"--target {TARGET}"
2525
host.cargo_test(test_fc_session_root_path, extra_args=extra_args)
26+
host.cargo_test(test_fc_session_root_path, extra_args=extra_args + " --examples")
2627

2728

2829
def test_benchmarks_compile():

0 commit comments

Comments
 (0)