Skip to content
This repository was archived by the owner on Oct 24, 2022. It is now read-only.

Commit 48070cc

Browse files
committed
Add test case to cover VhostUserHandler
Previous patch causes dramatic code coverage decrease, it actually disclose some issue in the code coverage test. Then we add test case to cover VhostUserHandler, it actually increases the code coverage. Signed-off-by: Liu Jiang <gerry@linux.alibaba.com>
1 parent 4e16112 commit 48070cc

File tree

3 files changed

+300
-1
lines changed

3 files changed

+300
-1
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,7 @@ vm-memory = {version = "0.7", features = ["backend-mmap", "backend-atomic"]}
1717
vmm-sys-util = "0.9"
1818

1919
[dev-dependencies]
20+
nix = "0.22"
21+
vhost = { version = "0.3", features = ["vhost-user-master", "vhost-user-slave"] }
2022
vm-memory = {version = "0.7", features = ["backend-mmap", "backend-atomic", "backend-bitmap"]}
2123
tempfile = "3.2.0"

coverage_config_x86_64.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"coverage_score": 49.6,
2+
"coverage_score": 87.7,
33
"exclude_path": "",
44
"crate_features": ""
55
}

tests/vhost-user-server.rs

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
use std::ffi::CString;
2+
use std::fs::File;
3+
use std::io::Result;
4+
use std::os::unix::io::{AsRawFd, FromRawFd};
5+
use std::os::unix::net::UnixStream;
6+
use std::path::Path;
7+
use std::sync::{Arc, Barrier, Mutex};
8+
use std::thread;
9+
10+
use vhost::vhost_user::message::{
11+
VhostUserConfigFlags, VhostUserHeaderFlag, VhostUserInflight, VhostUserProtocolFeatures,
12+
};
13+
use vhost::vhost_user::{Listener, Master, SlaveFsCacheReq, VhostUserMaster};
14+
use vhost::{VhostBackend, VhostUserMemoryRegionInfo, VringConfigData};
15+
use vhost_user_backend::{VhostUserBackendMut, VhostUserDaemon, VringRwLock};
16+
use vm_memory::{
17+
FileOffset, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic, GuestMemoryMmap,
18+
};
19+
use vmm_sys_util::epoll::EventSet;
20+
use vmm_sys_util::eventfd::EventFd;
21+
22+
struct MockVhostBackend {
23+
events: u64,
24+
event_idx: bool,
25+
acked_features: u64,
26+
}
27+
28+
impl MockVhostBackend {
29+
fn new() -> Self {
30+
MockVhostBackend {
31+
events: 0,
32+
event_idx: false,
33+
acked_features: 0,
34+
}
35+
}
36+
}
37+
38+
impl VhostUserBackendMut<VringRwLock, ()> for MockVhostBackend {
39+
fn num_queues(&self) -> usize {
40+
2
41+
}
42+
43+
fn max_queue_size(&self) -> usize {
44+
256
45+
}
46+
47+
fn features(&self) -> u64 {
48+
0xffff_ffff_ffff_ffff
49+
}
50+
51+
fn acked_features(&mut self, features: u64) {
52+
self.acked_features = features;
53+
}
54+
55+
fn protocol_features(&self) -> VhostUserProtocolFeatures {
56+
VhostUserProtocolFeatures::all()
57+
}
58+
59+
fn set_event_idx(&mut self, enabled: bool) {
60+
self.event_idx = enabled;
61+
}
62+
63+
fn get_config(&self, offset: u32, size: u32) -> Vec<u8> {
64+
assert_eq!(offset, 0x200);
65+
assert_eq!(size, 8);
66+
67+
vec![0xa5u8; 8]
68+
}
69+
70+
fn set_config(&mut self, offset: u32, buf: &[u8]) -> Result<()> {
71+
assert_eq!(offset, 0x200);
72+
assert_eq!(buf, &[0xa5u8; 8]);
73+
74+
Ok(())
75+
}
76+
77+
fn update_memory(&mut self, atomic_mem: GuestMemoryAtomic<GuestMemoryMmap>) -> Result<()> {
78+
let mem = atomic_mem.memory();
79+
let region = mem.find_region(GuestAddress(0x100000)).unwrap();
80+
assert_eq!(region.size(), 0x100000);
81+
Ok(())
82+
}
83+
84+
fn set_slave_req_fd(&mut self, _vu_req: SlaveFsCacheReq) {}
85+
86+
fn queues_per_thread(&self) -> Vec<u64> {
87+
vec![1, 1]
88+
}
89+
90+
fn exit_event(&self, _thread_index: usize) -> Option<EventFd> {
91+
let event_fd = EventFd::new(0).unwrap();
92+
93+
Some(event_fd)
94+
}
95+
96+
fn handle_event(
97+
&mut self,
98+
_device_event: u16,
99+
_evset: EventSet,
100+
_vrings: &[VringRwLock],
101+
_thread_id: usize,
102+
) -> Result<bool> {
103+
self.events += 1;
104+
105+
Ok(false)
106+
}
107+
}
108+
109+
fn setup_master(path: &Path, barrier: Arc<Barrier>) -> Master {
110+
barrier.wait();
111+
let mut master = Master::connect(path, 1).unwrap();
112+
master.set_hdr_flags(VhostUserHeaderFlag::NEED_REPLY);
113+
// Wait before issue service requests.
114+
barrier.wait();
115+
116+
let features = master.get_features().unwrap();
117+
let proto = master.get_protocol_features().unwrap();
118+
master.set_features(features).unwrap();
119+
master.set_protocol_features(proto).unwrap();
120+
assert!(proto.contains(VhostUserProtocolFeatures::REPLY_ACK));
121+
122+
master
123+
}
124+
125+
fn vhost_user_client(path: &Path, barrier: Arc<Barrier>) {
126+
barrier.wait();
127+
let mut master = Master::connect(path, 1).unwrap();
128+
master.set_hdr_flags(VhostUserHeaderFlag::NEED_REPLY);
129+
// Wait before issue service requests.
130+
barrier.wait();
131+
132+
let features = master.get_features().unwrap();
133+
let proto = master.get_protocol_features().unwrap();
134+
master.set_features(features).unwrap();
135+
master.set_protocol_features(proto).unwrap();
136+
assert!(proto.contains(VhostUserProtocolFeatures::REPLY_ACK));
137+
138+
let queue_num = master.get_queue_num().unwrap();
139+
assert_eq!(queue_num, 2);
140+
141+
master.set_owner().unwrap();
142+
//master.set_owner().unwrap_err();
143+
master.reset_owner().unwrap();
144+
master.reset_owner().unwrap();
145+
master.set_owner().unwrap();
146+
147+
master.set_features(features).unwrap();
148+
master.set_protocol_features(proto).unwrap();
149+
assert!(proto.contains(VhostUserProtocolFeatures::REPLY_ACK));
150+
151+
let memfd = nix::sys::memfd::memfd_create(
152+
&CString::new("test").unwrap(),
153+
nix::sys::memfd::MemFdCreateFlag::empty(),
154+
)
155+
.unwrap();
156+
let file = unsafe { File::from_raw_fd(memfd) };
157+
file.set_len(0x100000).unwrap();
158+
let file_offset = FileOffset::new(file, 0);
159+
let mem = GuestMemoryMmap::<()>::from_ranges_with_files(&[(
160+
GuestAddress(0x100000),
161+
0x100000,
162+
Some(file_offset),
163+
)])
164+
.unwrap();
165+
let addr = mem.get_host_address(GuestAddress(0x100000)).unwrap() as u64;
166+
let reg = mem.find_region(GuestAddress(0x100000)).unwrap();
167+
let fd = reg.file_offset().unwrap();
168+
let regions = [VhostUserMemoryRegionInfo {
169+
guest_phys_addr: 0x100000,
170+
memory_size: 0x100000,
171+
userspace_addr: addr,
172+
mmap_offset: 0,
173+
mmap_handle: fd.file().as_raw_fd(),
174+
}];
175+
master.set_mem_table(&regions).unwrap();
176+
177+
master.set_vring_num(0, 256).unwrap();
178+
179+
let config = VringConfigData {
180+
queue_max_size: 256,
181+
queue_size: 256,
182+
flags: 0,
183+
desc_table_addr: addr,
184+
used_ring_addr: addr + 0x10000,
185+
avail_ring_addr: addr + 0x20000,
186+
log_addr: None,
187+
};
188+
master.set_vring_addr(0, &config).unwrap();
189+
190+
let eventfd = EventFd::new(0).unwrap();
191+
master.set_vring_kick(0, &eventfd).unwrap();
192+
master.set_vring_call(0, &eventfd).unwrap();
193+
master.set_vring_err(0, &eventfd).unwrap();
194+
master.set_vring_enable(0, true).unwrap();
195+
196+
let buf = [0u8; 8];
197+
let (_cfg, data) = master
198+
.get_config(0x200, 8, VhostUserConfigFlags::empty(), &buf)
199+
.unwrap();
200+
assert_eq!(&data, &[0xa5u8; 8]);
201+
master
202+
.set_config(0x200, VhostUserConfigFlags::empty(), &data)
203+
.unwrap();
204+
205+
let (tx, _rx) = UnixStream::pair().unwrap();
206+
master.set_slave_request_fd(&tx).unwrap();
207+
208+
let state = master.get_vring_base(0).unwrap();
209+
master.set_vring_base(0, state as u16).unwrap();
210+
211+
assert_eq!(master.get_max_mem_slots().unwrap(), 32);
212+
let region = VhostUserMemoryRegionInfo {
213+
guest_phys_addr: 0x800000,
214+
memory_size: 0x100000,
215+
userspace_addr: addr,
216+
mmap_offset: 0,
217+
mmap_handle: fd.file().as_raw_fd(),
218+
};
219+
master.add_mem_region(&region).unwrap();
220+
master.remove_mem_region(&region).unwrap();
221+
}
222+
223+
fn vhost_user_server(cb: fn(&Path, Arc<Barrier>)) {
224+
let mem = GuestMemoryAtomic::new(GuestMemoryMmap::<()>::new());
225+
let backend = Arc::new(Mutex::new(MockVhostBackend::new()));
226+
let mut daemon = VhostUserDaemon::new("test".to_owned(), backend, mem).unwrap();
227+
228+
let barrier = Arc::new(Barrier::new(2));
229+
let tmpdir = tempfile::tempdir().unwrap();
230+
let mut path = tmpdir.path().to_path_buf();
231+
path.push("socket");
232+
233+
let barrier2 = barrier.clone();
234+
let path1 = path.clone();
235+
let thread = thread::spawn(move || cb(&path1, barrier2));
236+
237+
let listener = Listener::new(&path, false).unwrap();
238+
barrier.wait();
239+
daemon.start(listener).unwrap();
240+
barrier.wait();
241+
242+
// handle service requests from clients.
243+
thread.join().unwrap();
244+
}
245+
246+
#[test]
247+
fn test_vhost_user_server() {
248+
vhost_user_server(vhost_user_client);
249+
}
250+
251+
fn vhost_user_enable(path: &Path, barrier: Arc<Barrier>) {
252+
let master = setup_master(path, barrier);
253+
master.set_owner().unwrap();
254+
master.set_owner().unwrap_err();
255+
}
256+
257+
#[test]
258+
fn test_vhost_user_enable() {
259+
vhost_user_server(vhost_user_enable);
260+
}
261+
262+
fn vhost_user_set_inflight(path: &Path, barrier: Arc<Barrier>) {
263+
let mut master = setup_master(path, barrier);
264+
let eventfd = EventFd::new(0).unwrap();
265+
// No implementation for inflight_fd yet.
266+
let inflight = VhostUserInflight {
267+
mmap_size: 0x100000,
268+
mmap_offset: 0,
269+
num_queues: 1,
270+
queue_size: 256,
271+
};
272+
master
273+
.set_inflight_fd(&inflight, eventfd.as_raw_fd())
274+
.unwrap_err();
275+
}
276+
277+
#[test]
278+
fn test_vhost_user_set_inflight() {
279+
vhost_user_server(vhost_user_set_inflight);
280+
}
281+
282+
fn vhost_user_get_inflight(path: &Path, barrier: Arc<Barrier>) {
283+
let mut master = setup_master(path, barrier);
284+
// No implementation for inflight_fd yet.
285+
let inflight = VhostUserInflight {
286+
mmap_size: 0x100000,
287+
mmap_offset: 0,
288+
num_queues: 1,
289+
queue_size: 256,
290+
};
291+
assert!(master.get_inflight_fd(&inflight).is_err());
292+
}
293+
294+
#[test]
295+
fn test_vhost_user_get_inflight() {
296+
vhost_user_server(vhost_user_get_inflight);
297+
}

0 commit comments

Comments
 (0)