strest 0.1.10

Blazing-fast async HTTP load tester in Rust - lock-free design, real-time stats, distributed runs, and optional chart exports for high-load API testing.
Documentation
use ratatui::{
    prelude::text,
    text::Span,
    widgets::{Block, Borders, Paragraph, Wrap},
};

use crate::ui::model::UiRenderData;

use super::formatting::{format_bytes_compact, format_count_compact};
use super::theme::{
    ACCENT_AMBER_RGB, ACCENT_DATA_RGB, ACCENT_GREEN_RGB, ACCENT_LOAD_RGB, ACCENT_RED_RGB,
    ACCENT_REPLAY_RGB, panel_block_style, panel_border_style, panel_title_style, rgb, style_color,
};

pub fn latency_panel(data: &UiRenderData) -> Paragraph<'static> {
    let compare = data.compare.as_ref();
    let latency_lines = compare.map_or_else(
        || {
            vec![
                text::Line::from(vec![
                    Span::from("P50: "),
                    Span::styled(
                        format!("{}ms", data.p50),
                        style_color(data.no_color, rgb(ACCENT_GREEN_RGB)),
                    ),
                    Span::from("   P90: "),
                    Span::styled(
                        format!("{}ms", data.p90),
                        style_color(data.no_color, rgb(ACCENT_AMBER_RGB)),
                    ),
                    Span::from("   P99: "),
                    Span::styled(
                        format!("{}ms", data.p99),
                        style_color(data.no_color, rgb(ACCENT_RED_RGB)),
                    ),
                ]),
                text::Line::from(vec![
                    Span::from("OK P50: "),
                    Span::styled(
                        format!("{}ms", data.p50_ok),
                        style_color(data.no_color, rgb(ACCENT_GREEN_RGB)),
                    ),
                    Span::from("  P90: "),
                    Span::styled(
                        format!("{}ms", data.p90_ok),
                        style_color(data.no_color, rgb(ACCENT_AMBER_RGB)),
                    ),
                    Span::from("  P99: "),
                    Span::styled(
                        format!("{}ms", data.p99_ok),
                        style_color(data.no_color, rgb(ACCENT_RED_RGB)),
                    ),
                ]),
            ]
        },
        |compare| {
            vec![
                text::Line::from(vec![
                    Span::from("P50: "),
                    Span::styled(
                        format!("{}ms", data.p50),
                        style_color(data.no_color, rgb(ACCENT_GREEN_RGB)),
                    ),
                    Span::from(" / "),
                    Span::styled(
                        format!("{}ms", compare.p50),
                        style_color(data.no_color, rgb(ACCENT_REPLAY_RGB)),
                    ),
                    Span::from("   P90: "),
                    Span::styled(
                        format!("{}ms", data.p90),
                        style_color(data.no_color, rgb(ACCENT_AMBER_RGB)),
                    ),
                    Span::from(" / "),
                    Span::styled(
                        format!("{}ms", compare.p90),
                        style_color(data.no_color, rgb(ACCENT_REPLAY_RGB)),
                    ),
                    Span::from("   P99: "),
                    Span::styled(
                        format!("{}ms", data.p99),
                        style_color(data.no_color, rgb(ACCENT_RED_RGB)),
                    ),
                    Span::from(" / "),
                    Span::styled(
                        format!("{}ms", compare.p99),
                        style_color(data.no_color, rgb(ACCENT_REPLAY_RGB)),
                    ),
                ]),
                text::Line::from(vec![
                    Span::from("OK P50: "),
                    Span::styled(
                        format!("{}ms", data.p50_ok),
                        style_color(data.no_color, rgb(ACCENT_GREEN_RGB)),
                    ),
                    Span::from(" / "),
                    Span::styled(
                        format!("{}ms", compare.p50_ok),
                        style_color(data.no_color, rgb(ACCENT_REPLAY_RGB)),
                    ),
                    Span::from("  P90: "),
                    Span::styled(
                        format!("{}ms", data.p90_ok),
                        style_color(data.no_color, rgb(ACCENT_AMBER_RGB)),
                    ),
                    Span::from(" / "),
                    Span::styled(
                        format!("{}ms", compare.p90_ok),
                        style_color(data.no_color, rgb(ACCENT_REPLAY_RGB)),
                    ),
                    Span::from("  P99: "),
                    Span::styled(
                        format!("{}ms", data.p99_ok),
                        style_color(data.no_color, rgb(ACCENT_RED_RGB)),
                    ),
                    Span::from(" / "),
                    Span::styled(
                        format!("{}ms", compare.p99_ok),
                        style_color(data.no_color, rgb(ACCENT_REPLAY_RGB)),
                    ),
                ]),
            ]
        },
    );

    Paragraph::new(latency_lines)
        .block(
            Block::default()
                .title("Latency")
                .borders(Borders::ALL)
                .style(panel_block_style(data.no_color))
                .border_style(panel_border_style(data.no_color))
                .title_style(panel_title_style(data.no_color)),
        )
        .style(panel_block_style(data.no_color))
        .wrap(Wrap { trim: true })
}

pub fn flow_panel(data: &UiRenderData) -> Paragraph<'static> {
    let compare = data.compare.as_ref();
    let flow_lines = compare.map_or_else(
        || {
            vec![
                text::Line::from(vec![
                    Span::from("In-flight: "),
                    Span::styled(
                        format!("{:>5}", format_count_compact(data.in_flight_ops)),
                        style_color(data.no_color, rgb(ACCENT_LOAD_RGB)),
                    ),
                    Span::from("   RX/s: "),
                    Span::styled(
                        data.data_usage.as_ref().map_or_else(
                            || "0B/s".to_owned(),
                            |usage| {
                                format!(
                                    "{}/s",
                                    format_bytes_compact(u128::from(usage.bytes_per_sec))
                                )
                            },
                        ),
                        style_color(data.no_color, rgb(ACCENT_DATA_RGB)),
                    ),
                ]),
                text::Line::from(vec![
                    Span::from("Timeout: "),
                    Span::styled(
                        format!("{:>4}", format_count_compact(data.timeout_requests)),
                        style_color(data.no_color, rgb(ACCENT_RED_RGB)),
                    ),
                    Span::from("  Transport: "),
                    Span::styled(
                        format!("{:>4}", format_count_compact(data.transport_errors)),
                        style_color(data.no_color, rgb(ACCENT_AMBER_RGB)),
                    ),
                    Span::from("  Non-Exp: "),
                    Span::styled(
                        format!("{:>4}", format_count_compact(data.non_expected_status)),
                        style_color(data.no_color, rgb(ACCENT_AMBER_RGB)),
                    ),
                ]),
            ]
        },
        |compare| {
            let compare_rate = compare
                .data_usage
                .as_ref()
                .map(|usage| {
                    format!(
                        "{}/s",
                        format_bytes_compact(u128::from(usage.bytes_per_sec))
                    )
                })
                .unwrap_or_else(|| "0B/s".to_owned());
            vec![
                text::Line::from(vec![
                    Span::from("In-flight: "),
                    Span::styled(
                        format!("{:>5}", format_count_compact(data.in_flight_ops)),
                        style_color(data.no_color, rgb(ACCENT_LOAD_RGB)),
                    ),
                    Span::from(" / "),
                    Span::styled(
                        format!("{:>5}", format_count_compact(compare.in_flight_ops)),
                        style_color(data.no_color, rgb(ACCENT_REPLAY_RGB)),
                    ),
                    Span::from("   RX/s: "),
                    Span::styled(
                        data.data_usage.as_ref().map_or_else(
                            || "0B/s".to_owned(),
                            |usage| {
                                format!(
                                    "{}/s",
                                    format_bytes_compact(u128::from(usage.bytes_per_sec))
                                )
                            },
                        ),
                        style_color(data.no_color, rgb(ACCENT_DATA_RGB)),
                    ),
                    Span::from(" / "),
                    Span::styled(
                        compare_rate,
                        style_color(data.no_color, rgb(ACCENT_REPLAY_RGB)),
                    ),
                ]),
                text::Line::from(vec![
                    Span::from("Timeout: "),
                    Span::styled(
                        format!("{:>4}", format_count_compact(data.timeout_requests)),
                        style_color(data.no_color, rgb(ACCENT_RED_RGB)),
                    ),
                    Span::from(" / "),
                    Span::styled(
                        format!("{:>4}", format_count_compact(compare.timeout_requests)),
                        style_color(data.no_color, rgb(ACCENT_REPLAY_RGB)),
                    ),
                    Span::from("  Transport: "),
                    Span::styled(
                        format!("{:>4}", format_count_compact(data.transport_errors)),
                        style_color(data.no_color, rgb(ACCENT_AMBER_RGB)),
                    ),
                    Span::from(" / "),
                    Span::styled(
                        format!("{:>4}", format_count_compact(compare.transport_errors)),
                        style_color(data.no_color, rgb(ACCENT_REPLAY_RGB)),
                    ),
                    Span::from("  Non-Exp: "),
                    Span::styled(
                        format!("{:>4}", format_count_compact(data.non_expected_status)),
                        style_color(data.no_color, rgb(ACCENT_AMBER_RGB)),
                    ),
                    Span::from(" / "),
                    Span::styled(
                        format!("{:>4}", format_count_compact(compare.non_expected_status)),
                        style_color(data.no_color, rgb(ACCENT_REPLAY_RGB)),
                    ),
                ]),
            ]
        },
    );

    Paragraph::new(flow_lines)
        .block(
            Block::default()
                .title("Flow")
                .borders(Borders::ALL)
                .style(panel_block_style(data.no_color))
                .border_style(panel_border_style(data.no_color))
                .title_style(panel_title_style(data.no_color)),
        )
        .style(panel_block_style(data.no_color))
        .wrap(Wrap { trim: true })
}