fips-core 0.3.87

Reusable FIPS mesh, endpoint, transport, and protocol library
Documentation
#[cfg(target_os = "linux")]
use super::udp_send_batch_tail_bucket_flags;
use super::{
    EVENTS, Event, HIST_BUCKETS, N_EVENTS, N_STAGES, Stage, TraceStamp, bucket_upper_ns,
    dataplane_crypto_batch_bucket_flags, event_from_index, fmt_rate_per_sec, percentile_ns,
    record_event_count_sample, record_wait_threshold, stage_from_index,
};
use std::sync::atomic::Ordering::Relaxed;
use std::time::Instant;

#[test]
fn trace_stamp_is_compact_for_hot_queue_records() {
    assert_eq!(std::mem::size_of::<Option<TraceStamp>>(), 8);
    assert!(std::mem::size_of::<Option<TraceStamp>>() < std::mem::size_of::<Option<Instant>>());
}

#[test]
fn reporter_rate_format_preserves_sub_one_hz_samples() {
    assert_eq!(fmt_rate_per_sec(10, 5), "2");
    assert_eq!(fmt_rate_per_sec(1, 5), "0.2");
    assert_eq!(fmt_rate_per_sec(1, 60), "0.017");
    assert_eq!(fmt_rate_per_sec(1_234_567, 10), "123456.7");
}

#[test]
fn percentile_uses_observed_histogram_count_when_stage_count_leads() {
    let mut hist = [0u64; HIST_BUCKETS];
    hist[10] = 1;

    assert_eq!(percentile_ns(&hist, 2, 99), bucket_upper_ns(10));
    assert_eq!(percentile_ns(&[0u64; HIST_BUCKETS], 1, 99), 0);
}

#[test]
fn event_table_is_exhaustive() {
    assert_eq!(N_EVENTS, 269);
    for index in 0..N_EVENTS {
        let event = event_from_index(index);
        assert_eq!(event as usize, index);
        assert!(!event.name().is_empty());
    }
}
#[test]
#[cfg(target_os = "linux")]
fn udp_send_batch_buckets_classify_large_bursts() {
    assert_eq!(udp_send_batch_tail_bucket_flags(0), (false, false, false));
    assert_eq!(udp_send_batch_tail_bucket_flags(31), (false, false, false));
    assert_eq!(udp_send_batch_tail_bucket_flags(32), (true, false, false));
    assert_eq!(udp_send_batch_tail_bucket_flags(47), (true, false, false));
    assert_eq!(udp_send_batch_tail_bucket_flags(48), (true, true, false));
    assert_eq!(udp_send_batch_tail_bucket_flags(63), (true, true, false));
    assert_eq!(udp_send_batch_tail_bucket_flags(64), (true, true, true));
}

#[test]
fn dataplane_crypto_batch_buckets_classify_worker_chunks() {
    assert_eq!(
        dataplane_crypto_batch_bucket_flags(0),
        (false, false, false, false)
    );
    assert_eq!(
        dataplane_crypto_batch_bucket_flags(1),
        (true, false, false, false)
    );
    assert_eq!(
        dataplane_crypto_batch_bucket_flags(7),
        (false, false, false, false)
    );
    assert_eq!(
        dataplane_crypto_batch_bucket_flags(8),
        (false, true, false, false)
    );
    assert_eq!(
        dataplane_crypto_batch_bucket_flags(31),
        (false, true, false, false)
    );
    assert_eq!(
        dataplane_crypto_batch_bucket_flags(32),
        (false, true, true, false)
    );
    assert_eq!(
        dataplane_crypto_batch_bucket_flags(64),
        (false, true, true, true)
    );
}

#[test]
fn stage_table_exposes_current_dataplane_transport_and_output_stages() {
    assert_eq!(N_STAGES, 69);

    for (stage, name) in [
        (Stage::UdpRecv, "udp_recv"),
        (Stage::TunWrite, "tun_write"),
        (Stage::UdpSend, "udp_send"),
        (Stage::EndpointDeliver, "endpoint_deliver"),
        (Stage::EndpointEventWait, "endpoint_event_wait"),
        (Stage::ReservedStage18, "reserved_stage_18"),
        (Stage::ReservedStage19, "reserved_stage_19"),
        (Stage::TransportChannelWait, "transport_channel_wait"),
        (
            Stage::TransportPriorityChannelWait,
            "transport_priority_channel_wait",
        ),
        (
            Stage::TransportBulkChannelWait,
            "transport_bulk_channel_wait",
        ),
        (
            Stage::TransportRxLoopOwnedWait,
            "transport_rx_loop_owned_wait",
        ),
        (Stage::DataplaneAeadOpen, "dataplane_aead_open"),
        (Stage::DataplaneAeadSeal, "dataplane_aead_seal"),
        (Stage::DataplaneRetire, "dataplane_retire"),
        (Stage::DataplaneFspOwnerSync, "dataplane_fsp_owner_sync"),
        (Stage::DataplaneLiveTurn, "dataplane_live_turn"),
        (
            Stage::DataplaneCompletionDrain,
            "dataplane_completion_drain",
        ),
        (Stage::DataplaneLiveAdmit, "dataplane_live_admit"),
        (Stage::DataplaneAeadDispatch, "dataplane_aead_dispatch"),
        (Stage::DataplaneOutputSink, "dataplane_output_sink"),
        (Stage::DataplaneTransportSend, "dataplane_transport_send"),
        (
            Stage::DataplaneTransportSendBatch,
            "dataplane_transport_send_batch",
        ),
        (Stage::DataplaneOwnerDispatch, "dataplane_owner_dispatch"),
        (Stage::DataplaneExecutorSubmit, "dataplane_executor_submit"),
        (
            Stage::DataplaneCompletionQueue,
            "dataplane_completion_queue",
        ),
        (
            Stage::DataplaneAeadWorkerQueueWait,
            "dataplane_aead_worker_queue_wait",
        ),
    ] {
        assert_eq!(stage_from_index(stage as usize).name(), name);
    }

    for (stage, name) in [
        (Stage::ReservedStage1, "reserved_stage_1"),
        (Stage::ReservedStage3, "reserved_stage_3"),
        (Stage::ReservedStage11, "reserved_stage_11"),
        (Stage::ReservedStage13, "reserved_stage_13"),
        (Stage::ReservedStage24, "reserved_stage_24"),
        (Stage::ReservedStage29, "reserved_stage_29"),
        (Stage::ReservedStage34, "reserved_stage_34"),
        (Stage::ReservedStage37, "reserved_stage_37"),
        (Stage::ReservedStage47, "reserved_stage_47"),
        (Stage::ReservedStage52, "reserved_stage_52"),
        (Stage::ReservedStage68, "reserved_stage_68"),
    ] {
        assert_eq!(stage_from_index(stage as usize).name(), name);
    }
}

#[test]
fn live_event_counters_increment() {
    let samples = [
        (Event::RxLoopSlowMaintenanceTimeout, 3),
        (Event::RxLoopSlowMaintenanceSkipped, 5),
        (Event::EndpointEventBacklogHigh, 7),
        (Event::EndpointEventBulkBacklogHigh, 11),
        (Event::EndpointEventBulkDropped, 13),
        (Event::EndpointDataBatchDropped, 17),
        (Event::TransportChannelBacklogHigh, 19),
        (Event::TransportBulkDropped, 23),
        (Event::PendingTunPacketDropped, 29),
        (Event::PendingEndpointPacketDropped, 31),
        (Event::UdpSendSendmmsgBatch, 37),
        (Event::UdpSendSendmmsgPackets, 41),
        (Event::UdpSendSendmmsgBatchGe32, 43),
        (Event::UdpRecvGroBatch, 44),
        (Event::UdpRecvGroPackets, 45),
        (Event::UdpRecvGroBytes, 46),
        (Event::UdpRecvPlainPackets, 47),
        (Event::TunReadPackets, 48),
        (Event::TunReadBytes, 49),
        (Event::TunWritePackets, 50),
        (Event::TunWriteBytes, 51),
        (Event::TunReadFrames, 52),
        (Event::TunReadFrameBytes, 53),
        (Event::TunWriteFrames, 54),
        (Event::TunWriteFrameBytes, 55),
        (Event::TunOutboundAdmissionDropped, 56),
        (Event::PendingTunSessionOldestDropped, 57),
        (Event::PendingTunSessionStaleDropped, 58),
        (Event::DataplaneFspPathOpen, 47),
        (Event::DataplaneFspPathOpenBulk, 53),
        (Event::DataplaneFspOwnerSyncCall, 57),
        (Event::DataplaneCryptoOpenBatch, 59),
        (Event::DataplaneCryptoSealPackets, 61),
        (Event::ReservedEvent199, 63),
        (Event::DataplaneFspOwnerSyncApplied, 65),
        (Event::PacketBatchPoolReuse, 67),
        (Event::PacketBufferPoolFresh, 71),
        (Event::UdpKernelDropped, 73),
        (Event::UdpSocketKernelDropped, 79),
        (Event::UdpNamespaceRcvbufErrors, 83),
        (Event::TunWriteBulkDropped, 89),
        (Event::TunWriteBulkBacklogHigh, 97),
        (Event::ReservedEvent210, 101),
        (Event::ReservedEvent211, 103),
        (Event::DataplaneTransportSendFailed, 107),
    ];

    for (event, count) in samples {
        let before = EVENTS[event as usize].load(Relaxed);
        record_event_count_sample(event, count);
        assert_eq!(EVENTS[event as usize].load(Relaxed) - before, count);
    }
}

#[test]
fn wait_threshold_events_only_count_samples_at_or_above_threshold() {
    let event = Event::EndpointEventBacklogHigh;
    let before = EVENTS[event as usize].load(Relaxed);

    record_wait_threshold(event, 499_999, 3, 500_000);
    record_wait_threshold(event, 500_000, 5, 500_000);
    record_wait_threshold(event, 750_000, 7, 500_000);

    assert_eq!(EVENTS[event as usize].load(Relaxed) - before, 12);
}