postfix-log-parser 0.2.0

高性能模块化Postfix日志解析器,经3.2GB生产数据验证,SMTPD事件100%准确率
Documentation
//! Tests for master component parser

use postfix_log_parser::components::{ComponentParser, MasterParser};
use postfix_log_parser::events::master::{
    MasterConfigWarning, MasterEvent, MasterLifecycleEvent, MasterProcessWarning,
    MasterServiceLimit,
};
use postfix_log_parser::events::ComponentEvent;

#[test]
fn test_daemon_started() {
    let parser = MasterParser::new();

    let result = parser.parse("daemon started -- version 3.8.0, configuration /etc/postfix");

    assert!(result.is_ok());
    if let Ok(ComponentEvent::Master(MasterEvent::DaemonLifecycle { lifecycle, .. })) = result {
        assert_eq!(
            lifecycle,
            MasterLifecycleEvent::Started {
                version: "3.8.0".to_string(),
                configuration: "/etc/postfix".to_string()
            }
        );
    } else {
        panic!("Expected DaemonLifecycle::Started");
    }
}

#[test]
fn test_daemon_reload() {
    let parser = MasterParser::new();

    let result = parser.parse("reload -- version 3.10.1, configuration /etc/postfix");

    assert!(result.is_ok());
    if let Ok(ComponentEvent::Master(MasterEvent::DaemonLifecycle { lifecycle, .. })) = result {
        assert_eq!(
            lifecycle,
            MasterLifecycleEvent::Reload {
                version: "3.10.1".to_string(),
                configuration: "/etc/postfix".to_string()
            }
        );
    } else {
        panic!("Expected DaemonLifecycle::Reload");
    }
}

#[test]
fn test_process_killed() {
    let parser = MasterParser::new();

    let result =
        parser.parse("warning: process /usr/libexec/postfix/smtpd pid 866 killed by signal 9");

    assert!(result.is_ok());
    if let Ok(ComponentEvent::Master(MasterEvent::ProcessWarning { warning, .. })) = result {
        assert_eq!(
            warning,
            MasterProcessWarning::ProcessKilled {
                service: "smtpd".to_string(),
                process_path: "/usr/libexec/postfix/smtpd".to_string(),
                pid: 866,
                signal: 9,
            }
        );
    } else {
        panic!("Expected ProcessWarning::ProcessKilled");
    }
}

#[test]
fn test_bad_command_startup() {
    let parser = MasterParser::new();

    let result =
        parser.parse("warning: /usr/libexec/postfix/smtpd: bad command startup -- throttling");

    assert!(result.is_ok());
    if let Ok(ComponentEvent::Master(MasterEvent::ProcessWarning { warning, .. })) = result {
        assert_eq!(
            warning,
            MasterProcessWarning::BadCommandStartup {
                service: "smtpd".to_string(),
            }
        );
    } else {
        panic!("Expected ProcessWarning::BadCommandStartup");
    }
}

#[test]
fn test_service_limit_reached() {
    let parser = MasterParser::new();

    let result = parser.parse(r#"warning: service "0.0.0.0:10026" ([0.0.0.0]:10026) has reached its process limit "10": new clients may experience noticeable delays"#);

    assert!(result.is_ok());
    if let Ok(ComponentEvent::Master(MasterEvent::ServiceLimit { limit, .. })) = result {
        assert_eq!(
            limit,
            MasterServiceLimit::ProcessLimitReached {
                service: "0.0.0.0:10026".to_string(),
                service_address: "[0.0.0.0]:10026".to_string(),
                limit: 10,
            }
        );
    } else {
        panic!("Expected ServiceLimit::ProcessLimitReached");
    }
}

#[test]
fn test_process_count_suggestion() {
    let parser = MasterParser::new();

    let result = parser.parse("warning: to avoid this condition, increase the process count in master.cf or reduce the service time per client");

    assert!(result.is_ok());
    if let Ok(ComponentEvent::Master(MasterEvent::ConfigurationWarning { warning, .. })) = result {
        assert_eq!(warning, MasterConfigWarning::ProcessCountSuggestion);
    } else {
        panic!("Expected ConfigurationWarning::ProcessCountSuggestion");
    }
}

#[test]
fn test_stress_config_reference() {
    let parser = MasterParser::new();

    let result = parser.parse("warning: see https://www.postfix.org/STRESS_README.html for examples of stress-adapting configuration settings");

    assert!(result.is_ok());
    if let Ok(ComponentEvent::Master(MasterEvent::ConfigurationWarning { warning, .. })) = result {
        assert_eq!(
            warning,
            MasterConfigWarning::StressConfigReference {
                url: "https://www.postfix.org/STRESS_README.html".to_string(),
            }
        );
    } else {
        panic!("Expected ConfigurationWarning::StressConfigReference");
    }
}

#[test]
fn test_component_parser_interface() {
    let parser = MasterParser::new();

    assert_eq!(parser.component_name(), "master");
    assert!(parser.can_parse("master"));
    assert!(!parser.can_parse("smtpd"));
    assert!(!parser.can_parse("qmgr"));
}

#[test]
fn test_unsupported_message() {
    let parser = MasterParser::new();

    let result = parser.parse("some unsupported message format");

    assert!(result.is_err());
}

#[test]
fn test_event_type_methods() {
    use chrono::{DateTime, Utc};
    use postfix_log_parser::events::base::{BaseEvent, PostfixLogLevel};

    let base = BaseEvent {
        timestamp: DateTime::parse_from_rfc3339("2024-04-27T16:20:48Z")
            .unwrap()
            .with_timezone(&Utc),
        hostname: "m01".to_string(),
        component: "master".to_string(),
        process_id: 1,
        log_level: PostfixLogLevel::Info,
        raw_message: "test message".to_string(),
    };

    let started_event = MasterEvent::DaemonLifecycle {
        base: base.clone(),
        lifecycle: MasterLifecycleEvent::Started {
            version: "3.8.0".to_string(),
            configuration: "/etc/postfix".to_string(),
        },
    };
    assert_eq!(started_event.event_type(), "daemon_started");

    let reload_event = MasterEvent::DaemonLifecycle {
        base: base.clone(),
        lifecycle: MasterLifecycleEvent::Reload {
            version: "3.10.1".to_string(),
            configuration: "/etc/postfix".to_string(),
        },
    };
    assert_eq!(reload_event.event_type(), "daemon_reload");

    let process_killed_event = MasterEvent::ProcessWarning {
        base: base.clone(),
        warning: MasterProcessWarning::ProcessKilled {
            service: "smtpd".to_string(),
            process_path: "/usr/libexec/postfix/smtpd".to_string(),
            pid: 866,
            signal: 9,
        },
    };
    assert_eq!(process_killed_event.event_type(), "process_killed");

    let service_limit_event = MasterEvent::ServiceLimit {
        base: base.clone(),
        limit: MasterServiceLimit::ProcessLimitReached {
            service: "test".to_string(),
            service_address: "test".to_string(),
            limit: 10,
        },
    };
    assert_eq!(service_limit_event.event_type(), "service_limit_reached");
}