runtime-rs: add unit tests for network resource

Add UTs for network resource

Fixes: #4923
Signed-off-by: Ji-Xinyou <jerryji0414@outlook.com>
This commit is contained in:
Ji-Xinyou 2022-08-16 15:56:18 +08:00
parent a7e64b1ca9
commit a828292b47
9 changed files with 243 additions and 21 deletions

View File

@ -2153,6 +2153,7 @@ dependencies = [
"serde",
"slog",
"slog-scope",
"test-utils",
"tokio",
"uuid",
]
@ -2588,6 +2589,13 @@ dependencies = [
"winapi",
]
[[package]]
name = "test-utils"
version = "0.1.0"
dependencies = [
"nix 0.24.2",
]
[[package]]
name = "tests_utils"
version = "0.1.0"

View File

@ -4,6 +4,9 @@ version = "0.1.0"
authors = ["The Kata Containers community <kata-dev@lists.katacontainers.io>"]
edition = "2018"
[dev-dependencies]
test-utils = { path = "../../../libs/test-utils" }
[dependencies]
anyhow = "^1.0"
async-trait = "0.1.48"

View File

@ -20,6 +20,7 @@ mod tests {
NetworkModelType, TC_FILTER_NET_MODEL_STR,
},
network_pair::{NetworkInterface, NetworkPair, TapInterface},
utils::link::net_test_utils::delete_link,
};
// this unit test tests the integrity of MacVlanEndpoint::new()
@ -124,14 +125,10 @@ mod tests {
}
assert_eq!(manual.net_pair.network_qos, result.net_pair.network_qos);
}
let link_index = fetch_index(&handle, manual_vlan_iface_name.as_str())
assert!(delete_link(&handle, manual_vlan_iface_name.as_str())
.await
.expect("failed to fetch index");
assert!(handle.link().del(link_index).execute().await.is_ok());
let link_index = fetch_index(&handle, tap_iface_name.as_str())
.await
.expect("failed to fetch index");
assert!(handle.link().del(link_index).execute().await.is_ok());
.is_ok());
assert!(delete_link(&handle, tap_iface_name.as_str()).await.is_ok());
assert!(handle.link().del(dummy_index).execute().await.is_ok());
}
}
@ -253,14 +250,10 @@ mod tests {
assert_eq!(manual.net_pair.network_qos, result.net_pair.network_qos);
}
// delete the manually created links
let link_index = fetch_index(&handle, manual_macvlan_iface_name.as_str())
assert!(delete_link(&handle, manual_macvlan_iface_name.as_str())
.await
.expect("failed to fetch index");
assert!(handle.link().del(link_index).execute().await.is_ok());
let link_index = fetch_index(&handle, tap_iface_name.as_str())
.await
.expect("failed to fetch index");
assert!(handle.link().del(link_index).execute().await.is_ok());
.is_ok());
assert!(delete_link(&handle, tap_iface_name.as_str()).await.is_ok());
assert!(handle.link().del(dummy_index).execute().await.is_ok());
}
}
@ -355,14 +348,10 @@ mod tests {
}
assert_eq!(manual.net_pair.network_qos, result.net_pair.network_qos);
}
let link_index = fetch_index(&handle, manual_virt_iface_name.as_str())
assert!(delete_link(&handle, manual_virt_iface_name.as_str())
.await
.expect("failed to fetch index");
assert!(handle.link().del(link_index).execute().await.is_ok());
let link_index = fetch_index(&handle, tap_iface_name.as_str())
.await
.expect("failed to fetch index");
assert!(handle.link().del(link_index).execute().await.is_ok());
.is_ok());
assert!(delete_link(&handle, tap_iface_name.as_str()).await.is_ok());
}
}
}

View File

@ -177,3 +177,85 @@ pub async fn get_link_by_name(
Ok(link::get_link_from_message(msg))
}
#[cfg(test)]
mod tests {
use scopeguard::defer;
use super::*;
use crate::network::network_model::TC_FILTER_NET_MODEL_STR;
use test_utils::skip_if_not_root;
use utils::link::net_test_utils::delete_link;
// this ut tests create_link() and get_link_by_name()
#[actix_rt::test]
async fn test_utils() {
skip_if_not_root!();
if let Ok((conn, handle, _)) =
rtnetlink::new_connection().context("failed to create netlink connection")
{
let thread_handler = tokio::spawn(conn);
defer!({
thread_handler.abort();
});
assert!(create_link(&handle, "kata_test_1", 2).await.is_ok());
assert!(create_link(&handle, "kata_test_2", 3).await.is_ok());
assert!(create_link(&handle, "kata_test_3", 4).await.is_ok());
assert!(get_link_by_name(&handle, "kata_test_1").await.is_ok());
assert!(get_link_by_name(&handle, "kata_test_2").await.is_ok());
assert!(get_link_by_name(&handle, "kata_test_3").await.is_ok());
assert!(delete_link(&handle, "kata_test_1").await.is_ok());
assert!(delete_link(&handle, "kata_test_2").await.is_ok());
assert!(delete_link(&handle, "kata_test_3").await.is_ok());
assert!(get_link_by_name(&handle, "kata_test_1").await.is_err());
assert!(get_link_by_name(&handle, "kata_test_2").await.is_err());
assert!(get_link_by_name(&handle, "kata_test_3").await.is_err());
}
}
#[actix_rt::test]
async fn test_network_pair() {
let idx = 123456;
let virt_iface_name = format!("eth{}", idx);
let tap_name = format!("tap{}{}", idx, TAP_SUFFIX);
let queues = 2;
let model = TC_FILTER_NET_MODEL_STR;
skip_if_not_root!();
if let Ok((conn, handle, _)) =
rtnetlink::new_connection().context("failed to create netlink connection")
{
let thread_handler = tokio::spawn(conn);
defer!({
thread_handler.abort();
});
// the network pair has not been created
assert!(get_link_by_name(&handle, virt_iface_name.as_str())
.await
.is_err());
// mock containerd to create one end of the network pair
assert!(create_link(&handle, virt_iface_name.as_str(), queues)
.await
.is_ok());
if let Ok(_pair) = NetworkPair::new(&handle, idx, "", model, queues).await {
// the pair is created, we can find the two ends of network pair
assert!(get_link_by_name(&handle, virt_iface_name.as_str())
.await
.is_ok());
assert!(get_link_by_name(&handle, tap_name.as_str()).await.is_ok());
//delete the link created in test
assert!(delete_link(&handle, virt_iface_name.as_str()).await.is_ok());
assert!(delete_link(&handle, tap_name.as_str()).await.is_ok());
}
}
}
}

View File

@ -85,3 +85,30 @@ pub(crate) fn parse_ip(ip: &[u8], family: u8) -> Result<IpAddr> {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_ip() {
let test_ipv4 = [10, 25, 64, 128];
let ipv4 = parse_ip(test_ipv4.as_slice(), AF_INET as u8).unwrap();
let expected_ipv4 = IpAddr::V4(Ipv4Addr::new(10, 25, 64, 128));
assert_eq!(ipv4, expected_ipv4);
let test_ipv6 = [0, 2, 4, 0, 0, 2, 4, 0, 0, 2, 4, 0, 0, 2, 4, 0];
let ipv6 = parse_ip(test_ipv6.as_slice(), AF_INET6 as u8).unwrap();
// two u8 => one u16, (0u8, 2u8 => 0x0002), (4u8, 0u8 => 0x0400)
let expected_ipv6 = IpAddr::V6(Ipv6Addr::new(
0x0002, 0x0400, 0x0002, 0x0400, 0x0002, 0x0400, 0x0002, 0x0400,
));
assert_eq!(ipv6, expected_ipv6);
let fail_ipv4 = [10, 22, 33, 44, 55];
assert!(parse_ip(fail_ipv4.as_slice(), AF_INET as u8).is_err());
let fail_ipv6 = [1, 2, 3, 4, 5, 6, 7, 8, 2, 3];
assert!(parse_ip(fail_ipv6.as_slice(), AF_INET6 as u8).is_err());
}
}

View File

@ -127,3 +127,63 @@ fn create_queue(name: &str, flags: libc::c_int) -> Result<(File, String)> {
};
Ok((file, req.get_name()?))
}
#[cfg(test)]
pub mod net_test_utils {
use crate::network::network_model::tc_filter_model::fetch_index;
// remove a link by its name
#[allow(dead_code)]
pub async fn delete_link(
handle: &rtnetlink::Handle,
name: &str,
) -> Result<(), rtnetlink::Error> {
let link_index = fetch_index(handle, name)
.await
.expect("failed to fetch index");
// the ifindex of a link will not change during its lifetime, so the index
// remains the same between the query above and the deletion below
handle.link().del(link_index).execute().await
}
}
#[cfg(test)]
mod tests {
use scopeguard::defer;
use test_utils::skip_if_not_root;
use crate::network::{
network_pair::get_link_by_name, utils::link::create::net_test_utils::delete_link,
};
use super::*;
#[actix_rt::test]
async fn test_create_link() {
let name_tun = "___test_tun";
let name_tap = "___test_tap";
// tests should be taken under root
skip_if_not_root!();
if let Ok((conn, handle, _)) =
rtnetlink::new_connection().context("failed to create netlink connection")
{
let thread_handler = tokio::spawn(conn);
defer!({
thread_handler.abort();
});
assert!(create_link(name_tun, LinkType::Tun, 2).is_ok());
assert!(create_link(name_tap, LinkType::Tap, 2).is_ok());
assert!(get_link_by_name(&handle, name_tap).await.is_ok());
assert!(get_link_by_name(&handle, name_tun).await.is_ok());
assert!(delete_link(&handle, name_tun).await.is_ok());
assert!(delete_link(&handle, name_tap).await.is_ok());
// link does not present
assert!(get_link_by_name(&handle, name_tun).await.is_err());
assert!(get_link_by_name(&handle, name_tap).await.is_err());
}
}
}

View File

@ -16,6 +16,9 @@ use std::os::unix::io::RawFd;
use netlink_packet_route::link::nlas::State;
#[cfg(test)]
pub use create::net_test_utils;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Namespace {
NetNsPid(u32),

View File

@ -33,3 +33,34 @@ pub(crate) fn get_mac_addr(b: &[u8]) -> Result<String> {
))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_mac_addr() {
// length is not 6
let fail_slice = vec![1, 2, 3];
assert!(get_mac_addr(&fail_slice).is_err());
let expected_slice = vec![10, 11, 128, 3, 4, 5];
let expected_mac = String::from("0a:0b:80:03:04:05");
let res = get_mac_addr(&expected_slice);
assert!(res.is_ok());
assert_eq!(expected_mac, res.unwrap());
}
#[test]
fn test_parse_mac() {
// length is not 6
let fail = "1:2:3";
assert!(parse_mac(fail).is_none());
let v = [10, 11, 128, 3, 4, 5];
let expected_addr = hypervisor::Address(v);
let addr = parse_mac("0a:0b:80:03:04:05");
assert!(addr.is_some());
assert_eq!(expected_addr.0, addr.unwrap().0);
}
}

View File

@ -49,3 +49,22 @@ impl Drop for NetnsGuard {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use test_utils::skip_if_not_root;
#[test]
fn test_new_netns_guard() {
// test run under root
skip_if_not_root!();
let new_netns_path = "/proc/1/task/1/ns/net"; // systemd, always exists
let netns_guard = NetnsGuard::new(new_netns_path).unwrap();
drop(netns_guard);
let empty_path = "";
assert!(NetnsGuard::new(empty_path).unwrap().old_netns.is_none());
}
}