mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-15 22:53:43 +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",
|
"serde",
|
||||||
"slog",
|
"slog",
|
||||||
"slog-scope",
|
"slog-scope",
|
||||||
|
"test-utils",
|
||||||
"tokio",
|
"tokio",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
@ -2588,6 +2589,13 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "test-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"nix 0.24.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tests_utils"
|
name = "tests_utils"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -4,6 +4,9 @@ version = "0.1.0"
|
|||||||
authors = ["The Kata Containers community <kata-dev@lists.katacontainers.io>"]
|
authors = ["The Kata Containers community <kata-dev@lists.katacontainers.io>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
test-utils = { path = "../../../libs/test-utils" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "^1.0"
|
anyhow = "^1.0"
|
||||||
async-trait = "0.1.48"
|
async-trait = "0.1.48"
|
||||||
|
@ -20,6 +20,7 @@ mod tests {
|
|||||||
NetworkModelType, TC_FILTER_NET_MODEL_STR,
|
NetworkModelType, TC_FILTER_NET_MODEL_STR,
|
||||||
},
|
},
|
||||||
network_pair::{NetworkInterface, NetworkPair, TapInterface},
|
network_pair::{NetworkInterface, NetworkPair, TapInterface},
|
||||||
|
utils::link::net_test_utils::delete_link,
|
||||||
};
|
};
|
||||||
|
|
||||||
// this unit test tests the integrity of MacVlanEndpoint::new()
|
// 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);
|
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
|
.await
|
||||||
.expect("failed to fetch index");
|
.is_ok());
|
||||||
assert!(handle.link().del(link_index).execute().await.is_ok());
|
assert!(delete_link(&handle, tap_iface_name.as_str()).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());
|
|
||||||
assert!(handle.link().del(dummy_index).execute().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);
|
assert_eq!(manual.net_pair.network_qos, result.net_pair.network_qos);
|
||||||
}
|
}
|
||||||
// delete the manually created links
|
// 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
|
.await
|
||||||
.expect("failed to fetch index");
|
.is_ok());
|
||||||
assert!(handle.link().del(link_index).execute().await.is_ok());
|
assert!(delete_link(&handle, tap_iface_name.as_str()).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());
|
|
||||||
assert!(handle.link().del(dummy_index).execute().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);
|
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
|
.await
|
||||||
.expect("failed to fetch index");
|
.is_ok());
|
||||||
assert!(handle.link().del(link_index).execute().await.is_ok());
|
assert!(delete_link(&handle, tap_iface_name.as_str()).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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,3 +177,85 @@ pub async fn get_link_by_name(
|
|||||||
|
|
||||||
Ok(link::get_link_from_message(msg))
|
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()?))
|
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;
|
use netlink_packet_route::link::nlas::State;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub use create::net_test_utils;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum Namespace {
|
pub enum Namespace {
|
||||||
NetNsPid(u32),
|
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