mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-14 22:24:14 +00:00
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:
parent
a7e64b1ca9
commit
a828292b47
8
src/runtime-rs/Cargo.lock
generated
8
src/runtime-rs/Cargo.lock
generated
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user