netls 1.1.0

Network connections viewer for daily use and automation - container visibility, JSON/CSV output, process tree, live watch mode
Documentation
use anyhow::Result;

use netls::Connection;

/// Render `conns` as JSON to stdout - one object per line, or a single
/// pretty-printed object per connection when `pretty` is `true`.
///
/// # Errors
///
/// Propagates JSON serialisation errors and stdout write errors.
pub fn print_conns(conns: &[Connection], pretty: bool) -> Result<()> {
    for c in conns {
        let s = if pretty {
            serde_json::to_string_pretty(c)?
        } else {
            serde_json::to_string(c)?
        };
        println!("{s}");
    }
    Ok(())
}

#[cfg(test)]
mod tests {
    use netls::{Connection, Proto, State};

    fn make_conn() -> Connection {
        let mut c = Connection::new(Proto::Tcp, "0.0.0.0:80", "0.0.0.0:*");
        c.state = Some(State::Listen);
        c.pid = Some(42);
        c.process = Some("nginx".to_string());
        c
    }

    #[test]
    fn json_serializes_all_fields() {
        let c = make_conn();
        let s = serde_json::to_string(&c).unwrap();
        assert!(s.contains("\"proto\":\"tcp\""));
        assert!(s.contains("\"local\":\"0.0.0.0:80\""));
        assert!(s.contains("\"state\":\"LISTEN\""));
        assert!(s.contains("\"pid\":42"));
        assert!(s.contains("\"process\":\"nginx\""));
    }

    #[test]
    fn json_roundtrip_preserves_state() {
        let c = make_conn();
        let s = serde_json::to_string(&c).unwrap();
        let back: Connection = serde_json::from_str(&s).unwrap();
        assert_eq!(back.state, Some(State::Listen));
        assert_eq!(back.pid, Some(42));
        assert_eq!(back.process.as_deref(), Some("nginx"));
    }

    #[test]
    fn json_omits_recv_send_q_when_none() {
        let c = make_conn();
        let s = serde_json::to_string(&c).unwrap();
        assert!(!s.contains("recv_q"));
        assert!(!s.contains("send_q"));
    }

    #[test]
    fn json_includes_recv_send_q_when_present() {
        let mut c = make_conn();
        c.recv_q = Some(128);
        c.send_q = Some(0);
        let s = serde_json::to_string(&c).unwrap();
        assert!(s.contains("\"recv_q\":128"));
        assert!(s.contains("\"send_q\":0"));
    }
}