postfix-log-parser 0.2.0

高性能模块化Postfix日志解析器,经3.2GB生产数据验证,SMTPD事件100%准确率
Documentation
use postfix_log_parser::components::{ComponentParser, LocalParser};
use postfix_log_parser::events::local::{DeliveryMethod, DeliveryStatus, LocalEvent, WarningType};
use postfix_log_parser::events::ComponentEvent;

#[test]
fn test_parse_nis_domain_warning() {
    let parser = LocalParser::new();
    let message = "dict_nis_init: NIS domain name not set - NIS lookups disabled";

    let result = parser.parse(message).unwrap();

    if let ComponentEvent::Local(LocalEvent::ConfigurationWarning(warning)) = result {
        assert_eq!(warning.warning_type, WarningType::NisDomainNotSet);
        assert!(warning.message.contains("NIS domain name not set"));
    } else {
        panic!("Expected LocalEvent::ConfigurationWarning");
    }
}

#[test]
fn test_parse_alias_not_found_warning() {
    let parser = LocalParser::new();
    let message = "required alias not found: postmaster";

    let result = parser.parse(message).unwrap();

    if let ComponentEvent::Local(LocalEvent::ConfigurationWarning(warning)) = result {
        assert_eq!(warning.warning_type, WarningType::RequiredAliasNotFound);
        assert!(warning.message.contains("postmaster"));
        assert_eq!(
            warning.details.get("alias_name"),
            Some(&"postmaster".to_string())
        );
    } else {
        panic!("Expected LocalEvent::ConfigurationWarning with RequiredAliasNotFound");
    }
}

#[test]
fn test_parse_local_delivery_sent_discarded() {
    let parser = LocalParser::new();
    let message = "B9A1E1D83DA8: to=<postmaster@m01.gov110.cn>, orig_to=<postmaster>, relay=local, delay=0.01, delays=0.01/0.01/0/0, dsn=2.0.0, status=sent (discarded)";

    let result = parser.parse(message).unwrap();

    if let ComponentEvent::Local(LocalEvent::LocalDelivery(delivery)) = result {
        assert_eq!(delivery.queue_id, "B9A1E1D83DA8");
        assert_eq!(delivery.recipient, "postmaster@m01.gov110.cn");
        assert_eq!(delivery.original_recipient, Some("postmaster".to_string()));
        assert_eq!(delivery.relay, "local");
        assert_eq!(delivery.delay, 0.01);
        assert_eq!(delivery.dsn, "2.0.0");
        assert_eq!(delivery.status, DeliveryStatus::Sent);
        assert_eq!(delivery.delivery_method, DeliveryMethod::Discarded);
        assert_eq!(delivery.delays.len(), 4);
    } else {
        panic!("Expected LocalEvent::LocalDelivery");
    }
}

#[test]
fn test_parse_local_delivery_sent_zero_delay() {
    let parser = LocalParser::new();
    let message = "27ED71D83DA8: to=<postmaster@m01.gov110.cn>, orig_to=<postmaster>, relay=local, delay=0, delays=0/0/0/0, dsn=2.0.0, status=sent (discarded)";

    let result = parser.parse(message).unwrap();

    if let ComponentEvent::Local(LocalEvent::LocalDelivery(delivery)) = result {
        assert_eq!(delivery.queue_id, "27ED71D83DA8");
        assert_eq!(delivery.recipient, "postmaster@m01.gov110.cn");
        assert_eq!(delivery.delay, 0.0);
        assert_eq!(delivery.status, DeliveryStatus::Sent);
        assert_eq!(delivery.delivery_method, DeliveryMethod::Discarded);
    } else {
        panic!("Expected LocalEvent::LocalDelivery");
    }
}

#[test]
fn test_parse_local_delivery_mailbox() {
    let parser = LocalParser::new();
    // 模拟一个没有额外信息的本地投递(默认为mailbox)
    let message = "A39391D83576: to=<user@example.com>, relay=local, delay=0.01, delays=0.01/0/0/0, dsn=2.0.0, status=sent";

    let result = parser.parse(message).unwrap();

    if let ComponentEvent::Local(LocalEvent::LocalDelivery(delivery)) = result {
        assert_eq!(delivery.queue_id, "A39391D83576");
        assert_eq!(delivery.recipient, "user@example.com");
        assert_eq!(delivery.original_recipient, None);
        assert_eq!(delivery.status, DeliveryStatus::Sent);
        assert_eq!(delivery.delivery_method, DeliveryMethod::Mailbox);
    } else {
        panic!("Expected LocalEvent::LocalDelivery with Mailbox method");
    }
}

#[test]
fn test_parse_local_delivery_bounced() {
    let parser = LocalParser::new();
    let message = "CC9361D83576: to=<user@example.com>, relay=local, delay=0.01, delays=0.01/0.01/0/0, dsn=5.1.1, status=bounced (user unknown)";

    let result = parser.parse(message).unwrap();

    if let ComponentEvent::Local(LocalEvent::LocalDelivery(delivery)) = result {
        assert_eq!(delivery.queue_id, "CC9361D83576");
        assert_eq!(delivery.status, DeliveryStatus::Bounced);
        assert_eq!(delivery.dsn, "5.1.1");
    } else {
        panic!("Expected LocalEvent::LocalDelivery with Bounced status");
    }
}

#[test]
fn test_parse_local_delivery_deferred() {
    let parser = LocalParser::new();
    let message = "9F8801D83DA8: to=<user@example.com>, relay=local, delay=0.5, delays=0.1/0.1/0.1/0.2, dsn=4.2.2, status=deferred (temporary failure)";

    let result = parser.parse(message).unwrap();

    if let ComponentEvent::Local(LocalEvent::LocalDelivery(delivery)) = result {
        assert_eq!(delivery.queue_id, "9F8801D83DA8");
        assert_eq!(delivery.status, DeliveryStatus::Deferred);
        assert_eq!(delivery.dsn, "4.2.2");
        assert_eq!(delivery.delay, 0.5);
    } else {
        panic!("Expected LocalEvent::LocalDelivery with Deferred status");
    }
}

#[test]
fn test_parse_local_delivery_forwarded() {
    let parser = LocalParser::new();
    let message = "6CA581D83576: to=<user@example.com>, relay=local, delay=0.02, delays=0.01/0.01/0/0, dsn=2.0.0, status=sent (forwarded)";

    let result = parser.parse(message).unwrap();

    if let ComponentEvent::Local(LocalEvent::LocalDelivery(delivery)) = result {
        assert_eq!(delivery.delivery_method, DeliveryMethod::Forwarded);
        assert_eq!(delivery.status, DeliveryStatus::Sent);
    } else {
        panic!("Expected LocalEvent::LocalDelivery with Forwarded method");
    }
}

#[test]
fn test_parse_invalid_message() {
    let parser = LocalParser::new();
    let message = "this is not a valid local log message";

    let result = parser.parse(message);
    assert!(result.is_err());
}

#[test]
fn test_component_name() {
    let parser = LocalParser::new();
    assert_eq!(parser.component_name(), "local");
}

#[test]
fn test_can_parse() {
    let parser = LocalParser::new();

    // 测试NIS警告
    let nis_message = "dict_nis_init: NIS domain name not set - NIS lookups disabled";
    assert!(parser.parse(nis_message).is_ok());

    // 测试别名警告
    let alias_message = "required alias not found: postmaster";
    assert!(parser.parse(alias_message).is_ok());

    // 测试本地投递
    let delivery_message = "B9A1E1D83DA8: to=<postmaster@m01.gov110.cn>, orig_to=<postmaster>, relay=local, delay=0.01, delays=0.01/0.01/0/0, dsn=2.0.0, status=sent (discarded)";
    assert!(parser.parse(delivery_message).is_ok());
}

#[test]
fn test_parse_delivery_with_various_methods() {
    let parser = LocalParser::new();

    // 测试piped投递
    let piped_message = "123456789ABC: to=<user@example.com>, relay=local, delay=0.05, delays=0.01/0.01/0.01/0.02, dsn=2.0.0, status=sent (piped to command)";
    let result = parser.parse(piped_message).unwrap();
    if let ComponentEvent::Local(LocalEvent::LocalDelivery(delivery)) = result {
        assert_eq!(delivery.delivery_method, DeliveryMethod::Piped);
    } else {
        panic!("Expected LocalEvent::LocalDelivery with Piped method");
    }

    // 测试file投递
    let file_message = "123456789DEF: to=<user@example.com>, relay=local, delay=0.03, delays=0.01/0.01/0.01/0, dsn=2.0.0, status=sent (file delivery)";
    let result = parser.parse(file_message).unwrap();
    if let ComponentEvent::Local(LocalEvent::LocalDelivery(delivery)) = result {
        assert_eq!(delivery.delivery_method, DeliveryMethod::File);
    } else {
        panic!("Expected LocalEvent::LocalDelivery with File method");
    }
}