use std::{
net::{IpAddr, Ipv4Addr},
time::Duration,
};
use nlink::{
Result,
netlink::{NetworkEvent, RtnetlinkGroup, addr::Ipv4Address, link::DummyLink, tc::NetemConfig},
};
use tokio_stream::StreamExt;
use crate::common::TestNamespace;
#[tokio::test]
async fn test_link_events() -> Result<()> {
require_root!();
let ns = TestNamespace::new("linkev")?;
let mut conn = ns.connection()?;
conn.subscribe(&[RtnetlinkGroup::Link])?;
let mut events = conn.events();
{
let conn2 = ns.connection()?;
conn2.add_link(DummyLink::new("dummy0")).await?;
}
let event = tokio::time::timeout(Duration::from_secs(2), events.next()).await;
if let Ok(Some(Ok(NetworkEvent::NewLink(link)))) = event {
assert_eq!(link.name(), Some("dummy0"));
} else {
}
Ok(())
}
#[tokio::test]
async fn test_address_events() -> Result<()> {
require_root!();
let ns = TestNamespace::new("addrev")?;
let mut conn = ns.connection()?;
conn.add_link(DummyLink::new("dummy0")).await?;
conn.set_link_up("dummy0").await?;
conn.subscribe(&[RtnetlinkGroup::Ipv4Addr])?;
let mut events = conn.events();
{
let conn2 = ns.connection()?;
conn2
.add_address(Ipv4Address::new(
"dummy0",
Ipv4Addr::new(192, 168, 1, 1),
24,
))
.await?;
}
let event = tokio::time::timeout(Duration::from_secs(2), events.next()).await;
if let Ok(Some(Ok(NetworkEvent::NewAddress(addr)))) = event {
let expected: IpAddr = Ipv4Addr::new(192, 168, 1, 1).into();
assert_eq!(addr.address(), Some(&expected));
}
Ok(())
}
#[tokio::test]
async fn test_tc_events() -> Result<()> {
require_root!();
let ns = TestNamespace::new("tcev")?;
let mut conn = ns.connection()?;
conn.add_link(DummyLink::new("dummy0")).await?;
conn.set_link_up("dummy0").await?;
conn.subscribe(&[RtnetlinkGroup::Tc])?;
let mut events = conn.events();
{
let conn2 = ns.connection()?;
let netem = NetemConfig::new().delay(Duration::from_millis(10)).build();
conn2.add_qdisc("dummy0", netem).await?;
}
let event = tokio::time::timeout(Duration::from_secs(2), events.next()).await;
if let Ok(Some(Ok(NetworkEvent::NewQdisc(tc)))) = event {
assert_eq!(tc.kind(), Some("netem"));
}
Ok(())
}
#[tokio::test]
async fn test_subscribe_all() -> Result<()> {
require_root!();
let ns = TestNamespace::new("suball")?;
let mut conn = ns.connection()?;
conn.subscribe_all()?;
let mut events = conn.events();
{
let conn2 = ns.connection()?;
conn2.add_link(DummyLink::new("dummy0")).await?;
}
let event = tokio::time::timeout(Duration::from_secs(2), events.next()).await;
assert!(event.is_ok(), "should receive some event");
Ok(())
}
#[tokio::test]
async fn test_multiple_subscriptions() -> Result<()> {
require_root!();
let ns = TestNamespace::new("multisub")?;
let mut conn = ns.connection()?;
conn.subscribe(&[
RtnetlinkGroup::Link,
RtnetlinkGroup::Ipv4Addr,
RtnetlinkGroup::Ipv4Route,
])?;
conn.add_link(DummyLink::new("dummy0")).await?;
conn.set_link_up("dummy0").await?;
Ok(())
}
#[tokio::test]
async fn test_link_down_event() -> Result<()> {
require_root!();
let ns = TestNamespace::new("linkdown")?;
let mut conn = ns.connection()?;
conn.add_link(DummyLink::new("dummy0")).await?;
conn.set_link_up("dummy0").await?;
conn.subscribe(&[RtnetlinkGroup::Link])?;
let mut events = conn.events();
{
let conn2 = ns.connection()?;
conn2.set_link_down("dummy0").await?;
}
let event = tokio::time::timeout(Duration::from_secs(2), events.next()).await;
if let Ok(Some(Ok(NetworkEvent::NewLink(link)))) = event {
assert_eq!(link.name(), Some("dummy0"));
}
Ok(())
}
#[tokio::test]
async fn test_del_link_event() -> Result<()> {
require_root!();
let ns = TestNamespace::new("dellinkev")?;
let mut conn = ns.connection()?;
conn.add_link(DummyLink::new("dummy0")).await?;
conn.subscribe(&[RtnetlinkGroup::Link])?;
let mut events = conn.events();
{
let conn2 = ns.connection()?;
conn2.del_link("dummy0").await?;
}
let event = tokio::time::timeout(Duration::from_secs(2), events.next()).await;
if let Ok(Some(Ok(NetworkEvent::DelLink(link)))) = event {
assert_eq!(link.name(), Some("dummy0"));
}
Ok(())
}
#[tokio::test]
async fn test_del_address_event() -> Result<()> {
require_root!();
let ns = TestNamespace::new("deladdrev")?;
let mut conn = ns.connection()?;
conn.add_link(DummyLink::new("dummy0")).await?;
conn.set_link_up("dummy0").await?;
let ip = Ipv4Addr::new(10, 0, 0, 1);
conn.add_address(Ipv4Address::new("dummy0", ip, 24)).await?;
conn.subscribe(&[RtnetlinkGroup::Ipv4Addr])?;
let mut events = conn.events();
{
let conn2 = ns.connection()?;
conn2.del_address("dummy0", ip.into(), 24).await?;
}
let event = tokio::time::timeout(Duration::from_secs(2), events.next()).await;
if let Ok(Some(Ok(NetworkEvent::DelAddress(addr)))) = event {
let expected: IpAddr = ip.into();
assert_eq!(addr.address(), Some(&expected));
}
Ok(())
}
#[tokio::test]
async fn test_owned_event_stream() -> Result<()> {
require_root!();
let ns = TestNamespace::new("ownedstream")?;
let mut conn = ns.connection()?;
conn.subscribe(&[RtnetlinkGroup::Link])?;
let mut stream = conn.into_events();
{
let conn2 = ns.connection()?;
conn2.add_link(DummyLink::new("dummy0")).await?;
}
let event = tokio::time::timeout(Duration::from_secs(2), stream.next()).await;
if let Ok(Some(Ok(NetworkEvent::NewLink(link)))) = event {
assert_eq!(link.name(), Some("dummy0"));
}
let _conn = stream.into_connection();
Ok(())
}
#[tokio::test]
async fn test_event_stream_continues() -> Result<()> {
require_root!();
let ns = TestNamespace::new("streamcont")?;
let mut conn = ns.connection()?;
conn.subscribe(&[RtnetlinkGroup::Link])?;
let mut events = conn.events();
let conn2 = ns.connection()?;
conn2.add_link(DummyLink::new("dummy0")).await?;
conn2.add_link(DummyLink::new("dummy1")).await?;
conn2.add_link(DummyLink::new("dummy2")).await?;
let mut received = 0;
while let Ok(Some(Ok(_))) =
tokio::time::timeout(Duration::from_millis(500), events.next()).await
{
received += 1;
}
assert!(received >= 1, "should receive at least one event");
Ok(())
}
#[tokio::test]
async fn test_ipv6_address_events() -> Result<()> {
require_root!();
let ns = TestNamespace::new("addr6ev")?;
let mut conn = ns.connection()?;
conn.add_link(DummyLink::new("dummy0")).await?;
conn.set_link_up("dummy0").await?;
conn.subscribe(&[RtnetlinkGroup::Ipv6Addr])?;
let mut events = conn.events();
{
use std::net::Ipv6Addr;
use nlink::netlink::addr::Ipv6Address;
let conn2 = ns.connection()?;
let ip: Ipv6Addr = "fd00::1".parse().unwrap();
conn2
.add_address(Ipv6Address::new("dummy0", ip, 64))
.await?;
}
let event = tokio::time::timeout(Duration::from_secs(2), events.next()).await;
if let Ok(Some(Ok(NetworkEvent::NewAddress(_)))) = event {
}
Ok(())
}