vhost_user: add more unit test cases

Add more unit test cases for vhost-user protocol.

Signed-off-by: Liu Jiang <gerry@linux.alibaba.com>
This commit is contained in:
Liu Jiang 2021-02-21 22:56:35 +08:00 committed by Sergio Lopez
parent 56b823482b
commit ec6eae722e
9 changed files with 417 additions and 81 deletions

View file

@ -1 +1 @@
{"coverage_score": 73.3, "exclude_path": "src/vhost_kern/", "crate_features": ""}
{"coverage_score": 78.9, "exclude_path": "src/vhost_kern/", "crate_features": "vhost-user-master,vhost-user-slave"}

View file

@ -74,7 +74,7 @@ pub enum Error {
IoctlError(std::io::Error),
/// Error from IO subsystem.
IOError(std::io::Error),
#[cfg(feature = "vhost-user-master")]
#[cfg(feature = "vhost-user")]
/// Error from the vhost-user subsystem.
VhostUserProtocol(vhost_user::Error),
}
@ -95,7 +95,7 @@ impl std::fmt::Display for Error {
Error::VhostOpen(e) => write!(f, "failure in opening vhost file: {}", e),
#[cfg(feature = "vhost-kern")]
Error::IoctlError(e) => write!(f, "failure in vhost ioctl: {}", e),
#[cfg(feature = "vhost-user-master")]
#[cfg(feature = "vhost-user")]
Error::VhostUserProtocol(e) => write!(f, "vhost-user: {}", e),
}
}
@ -151,4 +151,12 @@ mod tests {
assert_eq!(format!("{:?}", Error::AvailAddress), "AvailAddress");
}
#[cfg(feature = "vhost-user")]
#[test]
fn test_convert_from_vhost_user_error() {
let e: Error = vhost_user::Error::OversizedMsg.into();
assert_eq!(format!("{}", e), "vhost-user: oversized message");
}
}

View file

@ -606,29 +606,32 @@ fn get_sub_iovs_offset(iov_lens: &[usize], skip_size: usize) -> (usize, usize) {
#[cfg(test)]
mod tests {
use super::*;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom, Write};
use std::os::unix::io::FromRawFd;
use vmm_sys_util::rand::rand_alphanumerics;
use vmm_sys_util::tempfile::TempFile;
const UNIX_SOCKET_LISTENER: &'static str = "/tmp/vhost_user_test_rust_listener";
const UNIX_SOCKET_CONNECTION: &'static str = "/tmp/vhost_user_test_rust_connection";
const UNIX_SOCKET_DATA: &'static str = "/tmp/vhost_user_test_rust_data";
const UNIX_SOCKET_FD: &'static str = "/tmp/vhost_user_test_rust_fd";
const UNIX_SOCKET_SEND: &'static str = "/tmp/vhost_user_test_rust_send";
fn temp_path() -> String {
format!(
"/tmp/vhost_test_{}",
rand_alphanumerics(8).to_str().unwrap()
)
}
#[test]
fn create_listener() {
let listener = Listener::new(UNIX_SOCKET_LISTENER, true).unwrap();
let path = temp_path();
let listener = Listener::new(&path, true).unwrap();
assert!(listener.as_raw_fd() > 0);
}
#[test]
fn accept_connection() {
let listener = Listener::new(UNIX_SOCKET_CONNECTION, true).unwrap();
let path = temp_path();
let listener = Listener::new(&path, true).unwrap();
listener.set_nonblocking(true).unwrap();
// accept on a fd without incoming connection
@ -638,9 +641,10 @@ mod tests {
#[test]
fn send_data() {
let listener = Listener::new(UNIX_SOCKET_DATA, true).unwrap();
let path = temp_path();
let listener = Listener::new(&path, true).unwrap();
listener.set_nonblocking(true).unwrap();
let mut master = Endpoint::<MasterReq>::connect(UNIX_SOCKET_DATA).unwrap();
let mut master = Endpoint::<MasterReq>::connect(&path).unwrap();
let sock = listener.accept().unwrap().unwrap();
let mut slave = Endpoint::<MasterReq>::from_stream(sock);
@ -663,9 +667,10 @@ mod tests {
#[test]
fn send_fd() {
let listener = Listener::new(UNIX_SOCKET_FD, true).unwrap();
let path = temp_path();
let listener = Listener::new(&path, true).unwrap();
listener.set_nonblocking(true).unwrap();
let mut master = Endpoint::<MasterReq>::connect(UNIX_SOCKET_FD).unwrap();
let mut master = Endpoint::<MasterReq>::connect(&path).unwrap();
let sock = listener.accept().unwrap().unwrap();
let mut slave = Endpoint::<MasterReq>::from_stream(sock);
@ -816,9 +821,10 @@ mod tests {
#[test]
fn send_recv() {
let listener = Listener::new(UNIX_SOCKET_SEND, true).unwrap();
let path = temp_path();
let listener = Listener::new(&path, true).unwrap();
listener.set_nonblocking(true).unwrap();
let mut master = Endpoint::<MasterReq>::connect(UNIX_SOCKET_SEND).unwrap();
let mut master = Endpoint::<MasterReq>::connect(&path).unwrap();
let sock = listener.accept().unwrap().unwrap();
let mut slave = Endpoint::<MasterReq>::from_stream(sock);

View file

@ -1,9 +1,10 @@
// Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
use std::os::unix::io::RawFd;
use super::message::*;
use super::*;
use std::os::unix::io::RawFd;
pub const MAX_QUEUE_NUM: usize = 2;
pub const MAX_VRING_NUM: usize = 256;
@ -34,7 +35,7 @@ impl DummySlaveReqHandler {
}
}
impl VhostUserSlaveReqHandler for DummySlaveReqHandler {
impl VhostUserSlaveReqHandlerMut for DummySlaveReqHandler {
fn set_owner(&mut self) -> Result<()> {
if self.owned {
return Err(Error::InvalidOperation);
@ -83,30 +84,10 @@ impl VhostUserSlaveReqHandler for DummySlaveReqHandler {
Ok(())
}
fn get_protocol_features(&mut self) -> Result<VhostUserProtocolFeatures> {
Ok(VhostUserProtocolFeatures::all())
}
fn set_protocol_features(&mut self, features: u64) -> Result<()> {
// Note: slave that reported VHOST_USER_F_PROTOCOL_FEATURES must
// support this message even before VHOST_USER_SET_FEATURES was
// called.
// What happens if the master calls set_features() with
// VHOST_USER_F_PROTOCOL_FEATURES cleared after calling this
// interface?
self.acked_protocol_features = features;
Ok(())
}
fn set_mem_table(&mut self, _ctx: &[VhostUserMemoryRegion], _fds: &[RawFd]) -> Result<()> {
// TODO
Ok(())
}
fn get_queue_num(&mut self) -> Result<u64> {
Ok(MAX_QUEUE_NUM as u64)
}
fn set_vring_num(&mut self, index: u32, num: u32) -> Result<()> {
if index as usize >= self.queue_num || num == 0 || num as usize > MAX_VRING_NUM {
return Err(Error::InvalidParam);
@ -199,6 +180,25 @@ impl VhostUserSlaveReqHandler for DummySlaveReqHandler {
Ok(())
}
fn get_protocol_features(&mut self) -> Result<VhostUserProtocolFeatures> {
Ok(VhostUserProtocolFeatures::all())
}
fn set_protocol_features(&mut self, features: u64) -> Result<()> {
// Note: slave that reported VHOST_USER_F_PROTOCOL_FEATURES must
// support this message even before VHOST_USER_SET_FEATURES was
// called.
// What happens if the master calls set_features() with
// VHOST_USER_F_PROTOCOL_FEATURES cleared after calling this
// interface?
self.acked_protocol_features = features;
Ok(())
}
fn get_queue_num(&mut self) -> Result<u64> {
Ok(MAX_QUEUE_NUM as u64)
}
fn set_vring_enable(&mut self, index: u32, enable: bool) -> Result<()> {
// This request should be handled only when VHOST_USER_F_PROTOCOL_FEATURES
// has been negotiated.
@ -222,7 +222,7 @@ impl VhostUserSlaveReqHandler for DummySlaveReqHandler {
size: u32,
_flags: VhostUserConfigFlags,
) -> Result<Vec<u8>> {
if self.acked_features & VhostUserProtocolFeatures::CONFIG.bits() == 0 {
if self.acked_protocol_features & VhostUserProtocolFeatures::CONFIG.bits() == 0 {
return Err(Error::InvalidOperation);
} else if offset < VHOST_USER_CONFIG_OFFSET
|| offset >= VHOST_USER_CONFIG_SIZE
@ -236,7 +236,7 @@ impl VhostUserSlaveReqHandler for DummySlaveReqHandler {
fn set_config(&mut self, offset: u32, buf: &[u8], _flags: VhostUserConfigFlags) -> Result<()> {
let size = buf.len() as u32;
if self.acked_features & VhostUserProtocolFeatures::CONFIG.bits() == 0 {
if self.acked_protocol_features & VhostUserProtocolFeatures::CONFIG.bits() == 0 {
return Err(Error::InvalidOperation);
} else if offset < VHOST_USER_CONFIG_OFFSET
|| offset >= VHOST_USER_CONFIG_SIZE

View file

@ -393,7 +393,10 @@ impl VhostUserMaster for Master {
return error_code(VhostUserError::SlaveInternalError);
} else if body_reply.size != body.size || body_reply.size as usize != buf.len() {
return error_code(VhostUserError::InvalidMessage);
} else if body_reply.offset != body.offset {
return error_code(VhostUserError::InvalidMessage);
}
Ok((body_reply, buf_reply))
}
@ -571,6 +574,7 @@ impl MasterInternal {
) -> VhostUserResult<(T, Vec<u8>, Option<Vec<RawFd>>)> {
if mem::size_of::<T>() > MAX_MSG_SIZE
|| hdr.get_size() as usize <= mem::size_of::<T>()
|| hdr.get_size() as usize > MAX_MSG_SIZE
|| hdr.is_reply()
{
return Err(VhostUserError::InvalidParam);
@ -586,11 +590,8 @@ impl MasterInternal {
{
Endpoint::<MasterReq>::close_rfds(rfds);
return Err(VhostUserError::InvalidMessage);
} else if bytes > MAX_MSG_SIZE - mem::size_of::<T>() {
} else if bytes != buf.len() {
return Err(VhostUserError::InvalidMessage);
} else if bytes < buf.len() {
// It's safe because we have checked the buffer size
unsafe { buf.set_len(bytes) };
}
Ok((body, buf, rfds))
}
@ -638,11 +639,14 @@ impl MasterInternal {
mod tests {
use super::super::connection::Listener;
use super::*;
use vmm_sys_util::rand::rand_alphanumerics;
const UNIX_SOCKET_MASTER: &'static str = "/tmp/vhost_user_test_rust_master";
const UNIX_SOCKET_MASTER2: &'static str = "/tmp/vhost_user_test_rust_master2";
const UNIX_SOCKET_MASTER3: &'static str = "/tmp/vhost_user_test_rust_master3";
const UNIX_SOCKET_MASTER4: &'static str = "/tmp/vhost_user_test_rust_master4";
fn temp_path() -> String {
format!(
"/tmp/vhost_test_{}",
rand_alphanumerics(8).to_str().unwrap()
)
}
fn create_pair(path: &str) -> (Master, Endpoint<MasterReq>) {
let listener = Listener::new(path, true).unwrap();
@ -653,14 +657,15 @@ mod tests {
}
#[test]
#[ignore]
fn create_master() {
let listener = Listener::new(UNIX_SOCKET_MASTER, true).unwrap();
let path = temp_path();
let listener = Listener::new(&path, true).unwrap();
listener.set_nonblocking(true).unwrap();
let master = Master::connect(UNIX_SOCKET_MASTER, 1).unwrap();
let master = Master::connect(&path, 1).unwrap();
let mut slave = Endpoint::<MasterReq>::from_stream(listener.accept().unwrap().unwrap());
assert!(master.as_raw_fd() > 0);
// Send two messages continuously
master.set_owner().unwrap();
master.reset_owner().unwrap();
@ -679,24 +684,24 @@ mod tests {
}
#[test]
#[ignore]
fn test_create_failure() {
let _ = Listener::new(UNIX_SOCKET_MASTER2, true).unwrap();
let _ = Listener::new(UNIX_SOCKET_MASTER2, false).is_err();
assert!(Master::connect(UNIX_SOCKET_MASTER2, 1).is_err());
let path = temp_path();
let _ = Listener::new(&path, true).unwrap();
let _ = Listener::new(&path, false).is_err();
assert!(Master::connect(&path, 1).is_err());
let listener = Listener::new(UNIX_SOCKET_MASTER2, true).unwrap();
assert!(Listener::new(UNIX_SOCKET_MASTER2, false).is_err());
let listener = Listener::new(&path, true).unwrap();
assert!(Listener::new(&path, false).is_err());
listener.set_nonblocking(true).unwrap();
let _master = Master::connect(UNIX_SOCKET_MASTER2, 1).unwrap();
let _master = Master::connect(&path, 1).unwrap();
let _slave = listener.accept().unwrap().unwrap();
}
#[test]
#[ignore]
fn test_features() {
let (master, mut peer) = create_pair(UNIX_SOCKET_MASTER3);
let path = temp_path();
let (master, mut peer) = create_pair(&path);
master.set_owner().unwrap();
let (hdr, rfds) = peer.recv_header().unwrap();
@ -713,6 +718,9 @@ mod tests {
let (_hdr, rfds) = peer.recv_header().unwrap();
assert!(rfds.is_none());
let hdr = VhostUserMsgHeader::new(MasterReq::SET_FEATURES, 0x4, 8);
let msg = VhostUserU64::new(0x15);
peer.send_message(&hdr, &msg, None).unwrap();
master.set_features(0x15).unwrap();
let (_hdr, msg, rfds) = peer.recv_body::<VhostUserU64>().unwrap();
assert!(rfds.is_none());
@ -726,9 +734,9 @@ mod tests {
}
#[test]
#[ignore]
fn test_protocol_features() {
let (mut master, mut peer) = create_pair(UNIX_SOCKET_MASTER4);
let path = temp_path();
let (mut master, mut peer) = create_pair(&path);
master.set_owner().unwrap();
let (hdr, rfds) = peer.recv_header().unwrap();
@ -775,14 +783,4 @@ mod tests {
peer.send_message(&hdr, &msg, None).unwrap();
assert!(master.get_protocol_features().is_err());
}
#[test]
fn test_set_mem_table() {
// TODO
}
#[test]
fn test_get_ring_num() {
// TODO
}
}

View file

@ -377,3 +377,102 @@ impl<S: VhostUserMasterReqHandler> AsRawFd for MasterReqHandler<S> {
self.sub_sock.as_raw_fd()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "vhost-user-slave")]
use crate::vhost_user::SlaveFsCacheReq;
#[cfg(feature = "vhost-user-slave")]
use std::os::unix::io::FromRawFd;
struct MockMasterReqHandler {}
impl VhostUserMasterReqHandlerMut for MockMasterReqHandler {
/// Handle virtio-fs map file requests from the slave.
fn fs_slave_map(&mut self, _fs: &VhostUserFSSlaveMsg, fd: RawFd) -> HandlerResult<u64> {
// Safe because we have just received the rawfd from kernel.
unsafe { libc::close(fd) };
Ok(0)
}
/// Handle virtio-fs unmap file requests from the slave.
fn fs_slave_unmap(&mut self, _fs: &VhostUserFSSlaveMsg) -> HandlerResult<u64> {
Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
}
}
#[test]
fn test_new_master_req_handler() {
let backend = Arc::new(Mutex::new(MockMasterReqHandler {}));
let mut handler = MasterReqHandler::new(backend).unwrap();
assert!(handler.get_tx_raw_fd() >= 0);
assert!(handler.as_raw_fd() >= 0);
handler.check_state().unwrap();
assert_eq!(handler.error, None);
handler.set_failed(libc::EAGAIN);
assert_eq!(handler.error, Some(libc::EAGAIN));
handler.check_state().unwrap_err();
}
#[cfg(feature = "vhost-user-slave")]
#[test]
fn test_master_slave_req_handler() {
let backend = Arc::new(Mutex::new(MockMasterReqHandler {}));
let mut handler = MasterReqHandler::new(backend).unwrap();
let fd = unsafe { libc::dup(handler.get_tx_raw_fd()) };
if fd < 0 {
panic!("failed to duplicated tx fd!");
}
let stream = unsafe { UnixStream::from_raw_fd(fd) };
let fs_cache = SlaveFsCacheReq::from_stream(stream);
std::thread::spawn(move || {
let res = handler.handle_request().unwrap();
assert_eq!(res, 0);
handler.handle_request().unwrap_err();
});
fs_cache
.fs_slave_map(&VhostUserFSSlaveMsg::default(), fd)
.unwrap();
// When REPLY_ACK has not been negotiated, the master has no way to detect failure from
// slave side.
fs_cache
.fs_slave_unmap(&VhostUserFSSlaveMsg::default())
.unwrap();
}
#[cfg(feature = "vhost-user-slave")]
#[test]
fn test_master_slave_req_handler_with_ack() {
let backend = Arc::new(Mutex::new(MockMasterReqHandler {}));
let mut handler = MasterReqHandler::new(backend).unwrap();
handler.set_reply_ack_flag(true);
let fd = unsafe { libc::dup(handler.get_tx_raw_fd()) };
if fd < 0 {
panic!("failed to duplicated tx fd!");
}
let stream = unsafe { UnixStream::from_raw_fd(fd) };
let fs_cache = SlaveFsCacheReq::from_stream(stream);
std::thread::spawn(move || {
let res = handler.handle_request().unwrap();
assert_eq!(res, 0);
handler.handle_request().unwrap_err();
});
fs_cache.set_reply_ack_flag(true);
fs_cache
.fs_slave_map(&VhostUserFSSlaveMsg::default(), fd)
.unwrap();
fs_cache
.fs_slave_unmap(&VhostUserFSSlaveMsg::default())
.unwrap_err();
}
}

View file

@ -175,21 +175,32 @@ pub type Result<T> = std::result::Result<T, Error>;
/// Result of request handler.
pub type HandlerResult<T> = std::result::Result<T, IOError>;
#[cfg(all(test, feature = "vhost-user-master", feature = "vhost-user-slave"))]
#[cfg(all(test, feature = "vhost-user-slave"))]
mod dummy_slave;
#[cfg(all(test, feature = "vhost-user-master", feature = "vhost-user-slave"))]
mod tests {
use std::os::unix::io::AsRawFd;
use std::sync::{Arc, Barrier, Mutex};
use std::thread;
use vmm_sys_util::rand::rand_alphanumerics;
use super::dummy_slave::{DummySlaveReqHandler, VIRTIO_FEATURES};
use super::message::*;
use super::*;
use crate::backend::VhostBackend;
use std::sync::{Arc, Barrier, Mutex};
use std::thread;
use crate::{VhostUserMemoryRegionInfo, VringConfigData};
fn temp_path() -> String {
format!(
"/tmp/vhost_test_{}",
rand_alphanumerics(8).to_str().unwrap()
)
}
fn create_slave<S: VhostUserSlaveReqHandler>(
path: &str,
backend: Arc<Mutex<S>>,
backend: Arc<S>,
) -> (Master, SlaveReqHandler<S>) {
let listener = Listener::new(path, true).unwrap();
let mut slave_listener = SlaveListener::new(listener, backend).unwrap();
@ -208,8 +219,8 @@ mod tests {
#[test]
fn test_set_owner() {
let slave_be = Arc::new(Mutex::new(DummySlaveReqHandler::new()));
let (master, mut slave) =
create_slave("/tmp/vhost_user_lib_unit_test_owner", slave_be.clone());
let path = temp_path();
let (master, mut slave) = create_slave(&path, slave_be.clone());
assert_eq!(slave_be.lock().unwrap().owned, false);
master.set_owner().unwrap();
@ -224,9 +235,9 @@ mod tests {
fn test_set_features() {
let mbar = Arc::new(Barrier::new(2));
let sbar = mbar.clone();
let path = temp_path();
let slave_be = Arc::new(Mutex::new(DummySlaveReqHandler::new()));
let (mut master, mut slave) =
create_slave("/tmp/vhost_user_lib_unit_test_feature", slave_be.clone());
let (mut master, mut slave) = create_slave(&path, slave_be.clone());
thread::spawn(move || {
slave.handle_request().unwrap();
@ -263,4 +274,157 @@ mod tests {
mbar.wait();
}
#[test]
fn test_master_slave_process() {
let mbar = Arc::new(Barrier::new(2));
let sbar = mbar.clone();
let path = temp_path();
let slave_be = Arc::new(Mutex::new(DummySlaveReqHandler::new()));
let (mut master, mut slave) = create_slave(&path, slave_be.clone());
thread::spawn(move || {
// set_own()
slave.handle_request().unwrap();
assert_eq!(slave_be.lock().unwrap().owned, true);
// get/set_features()
slave.handle_request().unwrap();
slave.handle_request().unwrap();
assert_eq!(
slave_be.lock().unwrap().acked_features,
VIRTIO_FEATURES & !0x1
);
slave.handle_request().unwrap();
slave.handle_request().unwrap();
assert_eq!(
slave_be.lock().unwrap().acked_protocol_features,
VhostUserProtocolFeatures::all().bits()
);
// get_queue_num()
slave.handle_request().unwrap();
// set_mem_table()
slave.handle_request().unwrap();
// get/set_config()
slave.handle_request().unwrap();
slave.handle_request().unwrap();
// set_slave_request_fd
slave.handle_request().unwrap();
// set_vring_enable
slave.handle_request().unwrap();
/*
// set_log_base,set_log_fd()
slave.handle_request().unwrap();
slave.handle_request().unwrap();
*/
// set_vring_xxx
slave.handle_request().unwrap();
slave.handle_request().unwrap();
slave.handle_request().unwrap();
slave.handle_request().unwrap();
slave.handle_request().unwrap();
slave.handle_request().unwrap();
sbar.wait();
});
master.set_owner().unwrap();
// set virtio features
let features = master.get_features().unwrap();
assert_eq!(features, VIRTIO_FEATURES);
master.set_features(VIRTIO_FEATURES & !0x1).unwrap();
// set vhost protocol features
let features = master.get_protocol_features().unwrap();
assert_eq!(features.bits(), VhostUserProtocolFeatures::all().bits());
master.set_protocol_features(features).unwrap();
let num = master.get_queue_num().unwrap();
assert_eq!(num, 2);
let eventfd = vmm_sys_util::eventfd::EventFd::new(0).unwrap();
let mem = [VhostUserMemoryRegionInfo {
guest_phys_addr: 0,
memory_size: 0x10_0000,
userspace_addr: 0,
mmap_offset: 0,
mmap_handle: eventfd.as_raw_fd(),
}];
master.set_mem_table(&mem).unwrap();
master
.set_config(0x100, VhostUserConfigFlags::WRITABLE, &[0xa5u8])
.unwrap();
let buf = [0x0u8; 4];
let (reply_body, reply_payload) = master
.get_config(0x100, 4, VhostUserConfigFlags::empty(), &buf)
.unwrap();
let offset = reply_body.offset;
assert_eq!(offset, 0x100);
assert_eq!(reply_payload[0], 0xa5);
master.set_slave_request_fd(eventfd.as_raw_fd()).unwrap();
master.set_vring_enable(0, true).unwrap();
/*
master.set_log_base(0, Some(eventfd.as_raw_fd())).unwrap();
master.set_log_fd(eventfd.as_raw_fd()).unwrap();
*/
master.set_vring_num(0, 256).unwrap();
master.set_vring_base(0, 0).unwrap();
let config = VringConfigData {
queue_max_size: 256,
queue_size: 128,
flags: VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits(),
desc_table_addr: 0x1000,
used_ring_addr: 0x2000,
avail_ring_addr: 0x3000,
log_addr: Some(0x4000),
};
master.set_vring_addr(0, &config).unwrap();
master.set_vring_call(0, &eventfd).unwrap();
master.set_vring_kick(0, &eventfd).unwrap();
master.set_vring_err(0, &eventfd).unwrap();
mbar.wait();
}
#[test]
fn test_error_display() {
assert_eq!(format!("{}", Error::InvalidParam), "invalid parameters");
assert_eq!(format!("{}", Error::InvalidOperation), "invalid operation");
}
#[test]
fn test_should_reconnect() {
assert_eq!(Error::PartialMessage.should_reconnect(), true);
assert_eq!(Error::SlaveInternalError.should_reconnect(), true);
assert_eq!(Error::MasterInternalError.should_reconnect(), true);
assert_eq!(Error::InvalidParam.should_reconnect(), false);
assert_eq!(Error::InvalidOperation.should_reconnect(), false);
assert_eq!(Error::InvalidMessage.should_reconnect(), false);
assert_eq!(Error::IncorrectFds.should_reconnect(), false);
assert_eq!(Error::OversizedMsg.should_reconnect(), false);
assert_eq!(Error::FeatureMismatch.should_reconnect(), false);
}
#[test]
fn test_error_from_sys_util_error() {
let e: Error = vmm_sys_util::errno::Error::new(libc::EAGAIN.into()).into();
if let Error::SocketRetry(e1) = e {
assert_eq!(e1.raw_os_error().unwrap(), libc::EAGAIN);
} else {
panic!("invalid error code conversion!");
}
}
}

View file

@ -44,3 +44,43 @@ impl<S: VhostUserSlaveReqHandler> SlaveListener<S> {
self.listener.set_nonblocking(block)
}
}
#[cfg(test)]
mod tests {
use std::sync::Mutex;
use super::*;
use crate::vhost_user::dummy_slave::DummySlaveReqHandler;
#[test]
fn test_slave_listener_set_nonblocking() {
let backend = Arc::new(Mutex::new(DummySlaveReqHandler::new()));
let listener =
Listener::new("/tmp/vhost_user_lib_unit_test_slave_nonblocking", true).unwrap();
let slave_listener = SlaveListener::new(listener, backend).unwrap();
slave_listener.set_nonblocking(true).unwrap();
slave_listener.set_nonblocking(false).unwrap();
slave_listener.set_nonblocking(false).unwrap();
slave_listener.set_nonblocking(true).unwrap();
slave_listener.set_nonblocking(true).unwrap();
}
#[cfg(feature = "vhost-user-master")]
#[test]
fn test_slave_listener_accept() {
use super::super::Master;
let path = "/tmp/vhost_user_lib_unit_test_slave_accept";
let backend = Arc::new(Mutex::new(DummySlaveReqHandler::new()));
let listener = Listener::new(path, true).unwrap();
let mut slave_listener = SlaveListener::new(listener, backend).unwrap();
slave_listener.set_nonblocking(true).unwrap();
assert!(slave_listener.accept().unwrap().is_none());
assert!(slave_listener.accept().unwrap().is_none());
let _master = Master::connect(path, 1).unwrap();
let _slave = slave_listener.accept().unwrap().unwrap();
}
}

View file

@ -743,3 +743,24 @@ impl<S: VhostUserSlaveReqHandler> AsRawFd for SlaveReqHandler<S> {
self.main_sock.as_raw_fd()
}
}
#[cfg(test)]
mod tests {
use std::os::unix::io::AsRawFd;
use super::*;
use crate::vhost_user::dummy_slave::DummySlaveReqHandler;
#[test]
fn test_slave_req_handler_new() {
let (p1, _p2) = UnixStream::pair().unwrap();
let endpoint = Endpoint::<MasterReq>::from_stream(p1);
let backend = Arc::new(Mutex::new(DummySlaveReqHandler::new()));
let mut handler = SlaveReqHandler::new(endpoint, backend);
handler.check_state().unwrap();
handler.set_failed(libc::EAGAIN);
handler.check_state().unwrap_err();
assert!(handler.as_raw_fd() >= 0);
}
}