use clap::Parser;
use std::time::Duration;
use crate::metrics::MetricsRange;
use crate::sinks::config::SinksConfig;
use super::super::defaults::{default_charts_path, default_tmp_path};
use super::super::parsers::{
parse_bool_env, parse_connect_to, parse_duration_arg, parse_header, parse_positive_u64,
parse_positive_usize, parse_tls_version,
};
use super::super::types::{
ConnectToMapping, ControllerMode, HttpMethod, HttpVersion, LoadMode, LoadProfile, OutputFormat,
PositiveU64, PositiveUsize, Protocol, Scenario, TimeUnit, TlsVersion,
};
use super::presets::Command;
#[derive(Debug, Parser, Clone)]
#[clap(
version,
about = "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.",
next_help_heading = "Advanced Options"
)]
pub struct TesterArgs {
#[command(subcommand)]
pub command: Option<Command>,
#[arg(
long,
short = 'X',
default_value = "get",
ignore_case = true,
help_heading = "Common Options"
)]
pub method: HttpMethod,
#[arg(
long = "protocol",
default_value = "http",
value_enum,
help_heading = "Common Options"
)]
pub protocol: Protocol,
#[arg(
long = "load-mode",
default_value = "arrival",
value_enum,
help_heading = "Common Options"
)]
pub load_mode: LoadMode,
#[arg(long, short, help_heading = "Common Options")]
pub url: Option<String>,
#[arg(
long = "urls-from-file",
conflicts_with = "rand_regex_url",
requires = "url"
)]
pub urls_from_file: bool,
#[arg(
long = "rand-regex-url",
conflicts_with = "urls_from_file",
requires = "url"
)]
pub rand_regex_url: bool,
#[arg(long = "max-repeat", default_value = "4", value_parser = parse_positive_usize)]
pub max_repeat: PositiveUsize,
#[arg(long = "dump-urls", value_parser = parse_positive_usize, requires = "rand_regex_url")]
pub dump_urls: Option<PositiveUsize>,
#[arg(long, short = 'H', value_parser = parse_header, help_heading = "Common Options")]
pub headers: Vec<(String, String)>,
#[arg(long = "accept", short = 'A')]
pub accept_header: Option<String>,
#[arg(long = "content-type", short = 'T')]
pub content_type: Option<String>,
#[arg(long = "no-ua", alias = "no-default-ua")]
pub no_ua: bool,
#[arg(long = "authorized")]
pub authorized: bool,
#[arg(long, short, default_value = "", help_heading = "Common Options")]
pub data: String,
#[arg(long = "form", short = 'F', conflicts_with_all = ["data", "data_file", "data_lines"])]
pub form: Vec<String>,
#[arg(long = "basic-auth", short = 'a')]
pub basic_auth: Option<String>,
#[arg(long = "aws-session")]
pub aws_session: Option<String>,
#[arg(long = "aws-sigv4")]
pub aws_sigv4: Option<String>,
#[arg(long = "data-file", short = 'D', conflicts_with_all = ["data", "data_lines"])]
pub data_file: Option<String>,
#[arg(long = "data-lines", short = 'Z', conflicts_with_all = ["data", "data_file"])]
pub data_lines: Option<String>,
#[arg(
long = "duration",
short = 't',
default_value = "30",
value_parser = parse_positive_u64,
help_heading = "Common Options"
)]
pub target_duration: PositiveU64,
#[arg(long = "wait-ongoing-requests-after-deadline")]
pub wait_ongoing_requests_after_deadline: bool,
#[arg(long = "requests", short = 'n', value_parser = parse_positive_u64, help_heading = "Common Options")]
pub requests: Option<PositiveU64>,
#[arg(
long = "status",
short = 's',
default_value = "200",
help_heading = "Common Options"
)]
pub expected_status_code: u16,
#[arg(
long = "timeout",
default_value = "10s",
value_parser = parse_duration_arg,
help_heading = "Common Options"
)]
pub request_timeout: Duration,
#[arg(long = "redirect", default_value = "10")]
pub redirect_limit: u32,
#[arg(long = "disable-keepalive")]
pub disable_keepalive: bool,
#[arg(long = "disable-compression")]
pub disable_compression: bool,
#[arg(long = "pool-max-idle-per-host", value_parser = parse_positive_usize)]
pub pool_max_idle_per_host: Option<PositiveUsize>,
#[arg(long = "pool-idle-timeout-ms", value_parser = parse_positive_u64)]
pub pool_idle_timeout_ms: Option<PositiveU64>,
#[arg(long = "http-version", value_enum)]
pub http_version: Option<HttpVersion>,
#[arg(
long = "connect-timeout",
default_value = "5s",
value_parser = parse_duration_arg
)]
pub connect_timeout: Duration,
#[arg(long, short = 'c', default_value_t = default_charts_path())]
pub charts_path: String,
#[arg(long, help_heading = "Common Options")]
pub no_charts: bool,
#[arg(long = "charts-latency-bucket-ms", default_value = "100", value_parser = parse_positive_u64)]
pub charts_latency_bucket_ms: PositiveU64,
#[arg(long, short = 'v', alias = "debug", help_heading = "Common Options")]
pub verbose: bool,
#[arg(long, help_heading = "Common Options")]
pub config: Option<String>,
#[arg(long = "tmp-path", default_value_t = default_tmp_path())]
pub tmp_path: String,
#[arg(long = "keep-tmp")]
pub keep_tmp: bool,
#[arg(long = "warmup", value_parser = parse_duration_arg)]
pub warmup: Option<Duration>,
#[arg(long = "output", short = 'o', help_heading = "Common Options")]
pub output: Option<String>,
#[arg(long = "output-format", value_enum, help_heading = "Common Options")]
pub output_format: Option<OutputFormat>,
#[arg(long = "time-unit", value_enum, help_heading = "Common Options")]
pub time_unit: Option<TimeUnit>,
#[arg(long = "export-csv")]
pub export_csv: Option<String>,
#[arg(long = "export-json")]
pub export_json: Option<String>,
#[arg(long = "export-jsonl")]
pub export_jsonl: Option<String>,
#[arg(long = "db-url")]
pub db_url: Option<String>,
#[arg(long = "log-shards", default_value = "1", value_parser = parse_positive_usize)]
pub log_shards: PositiveUsize,
#[arg(long = "no-tui", alias = "no-ui", help_heading = "Common Options")]
pub no_ui: bool,
#[arg(long = "no-splash")]
pub no_splash: bool,
#[arg(
long = "ui-window-ms",
default_value = "10000",
value_parser = parse_positive_u64,
help_heading = "Common Options"
)]
pub ui_window_ms: PositiveU64,
#[arg(long = "summary", help_heading = "Common Options")]
pub summary: bool,
#[arg(long = "show-selections")]
pub show_selections: bool,
#[arg(long = "replay", help_heading = "Advanced Options")]
pub replay: bool,
#[arg(long = "replay-start", help_heading = "Advanced Options")]
pub replay_start: Option<String>,
#[arg(long = "replay-end", help_heading = "Advanced Options")]
pub replay_end: Option<String>,
#[arg(long = "replay-step", value_parser = parse_duration_arg, help_heading = "Advanced Options")]
pub replay_step: Option<Duration>,
#[arg(long = "replay-snapshot-interval", value_parser = parse_duration_arg, help_heading = "Advanced Options")]
pub replay_snapshot_interval: Option<Duration>,
#[arg(long = "replay-snapshot-start", help_heading = "Advanced Options")]
pub replay_snapshot_start: Option<String>,
#[arg(long = "replay-snapshot-end", help_heading = "Advanced Options")]
pub replay_snapshot_end: Option<String>,
#[arg(long = "replay-snapshot-out", help_heading = "Advanced Options")]
pub replay_snapshot_out: Option<String>,
#[arg(
long = "replay-snapshot-format",
default_value = "json",
help_heading = "Advanced Options"
)]
pub replay_snapshot_format: String,
#[arg(long = "tls-min", value_parser = parse_tls_version)]
pub tls_min: Option<TlsVersion>,
#[arg(long = "tls-max", value_parser = parse_tls_version)]
pub tls_max: Option<TlsVersion>,
#[arg(long = "cacert")]
pub cacert: Option<String>,
#[arg(long = "cert")]
pub cert: Option<String>,
#[arg(long = "key")]
pub key: Option<String>,
#[arg(long = "insecure")]
pub insecure: bool,
#[arg(long = "http2")]
pub http2: bool,
#[arg(long = "http2-parallel", default_value = "1", value_parser = parse_positive_usize)]
pub http2_parallel: PositiveUsize,
#[arg(long = "alpn")]
pub alpn: Vec<String>,
#[arg(long = "proxy", short = 'p', alias = "proxy-url")]
pub proxy_url: Option<String>,
#[arg(long = "proxy-header", value_parser = parse_header)]
pub proxy_headers: Vec<(String, String)>,
#[arg(long = "proxy-http-version", value_enum)]
pub proxy_http_version: Option<HttpVersion>,
#[arg(long = "proxy-http2")]
pub proxy_http2: bool,
#[arg(
long = "max-tasks",
short = 'm',
aliases = ["concurrency", "connections"],
default_value = "1000",
value_parser = parse_positive_usize,
help_heading = "Common Options"
)]
pub max_tasks: PositiveUsize,
#[arg(
long = "spawn-rate",
short = 'r',
default_value = "1",
value_parser = parse_positive_usize
)]
pub spawn_rate_per_tick: PositiveUsize,
#[arg(
long = "spawn-interval",
short = 'i',
default_value = "100",
value_parser = parse_positive_u64
)]
pub tick_interval: PositiveU64,
#[arg(long = "rate", short = 'q', value_parser = parse_positive_u64, required = false, help_heading = "Common Options")]
pub rate_limit: Option<PositiveU64>,
#[arg(long = "burst-delay", value_parser = parse_duration_arg)]
pub burst_delay: Option<Duration>,
#[arg(long = "burst-rate", default_value = "1", value_parser = parse_positive_usize)]
pub burst_rate: PositiveUsize,
#[arg(long = "latency-correction")]
pub latency_correction: bool,
#[arg(long = "connect-to", value_parser = parse_connect_to)]
pub connect_to: Vec<ConnectToMapping>,
#[arg(long = "host")]
pub host_header: Option<String>,
#[arg(long = "ipv6")]
pub ipv6_only: bool,
#[arg(long = "ipv4")]
pub ipv4_only: bool,
#[arg(long = "no-pre-lookup")]
pub no_pre_lookup: bool,
#[arg(long = "no-color", env = "NO_COLOR", value_parser = parse_bool_env)]
pub no_color: bool,
#[arg(long = "fps", default_value = "16")]
pub ui_fps: u32,
#[arg(long = "stats-success-breakdown")]
pub stats_success_breakdown: bool,
#[arg(long = "unix-socket")]
pub unix_socket: Option<String>,
#[arg(skip)]
pub load_profile: Option<LoadProfile>,
#[arg(long = "controller-listen")]
pub controller_listen: Option<String>,
#[arg(long = "controller-mode", default_value = "auto", value_enum)]
pub controller_mode: ControllerMode,
#[arg(long = "control-listen")]
pub control_listen: Option<String>,
#[arg(long = "control-auth-token")]
pub control_auth_token: Option<String>,
#[arg(long = "agent-join")]
pub agent_join: Option<String>,
#[arg(long = "auth-token")]
pub auth_token: Option<String>,
#[arg(long = "agent-id")]
pub agent_id: Option<String>,
#[arg(long = "agent-weight", default_value = "1", value_parser = parse_positive_u64)]
pub agent_weight: PositiveU64,
#[arg(long = "min-agents", default_value = "1", value_parser = parse_positive_usize)]
pub min_agents: PositiveUsize,
#[arg(long = "agent-wait-timeout-ms", value_parser = parse_positive_u64)]
pub agent_wait_timeout_ms: Option<PositiveU64>,
#[arg(long = "agent-standby")]
pub agent_standby: bool,
#[arg(long = "agent-reconnect-ms", default_value = "1000", value_parser = parse_positive_u64)]
pub agent_reconnect_ms: PositiveU64,
#[arg(
long = "agent-heartbeat-interval-ms",
default_value = "1000",
value_parser = parse_positive_u64
)]
pub agent_heartbeat_interval_ms: PositiveU64,
#[arg(
long = "agent-heartbeat-timeout-ms",
default_value = "3000",
value_parser = parse_positive_u64
)]
pub agent_heartbeat_timeout_ms: PositiveU64,
#[arg(long = "stream-interval-ms", value_parser = parse_positive_u64)]
pub distributed_stream_interval_ms: Option<PositiveU64>,
#[arg(long = "stream-summaries")]
pub distributed_stream_summaries: bool,
#[arg(long = "http3")]
pub http3: bool,
#[arg(long = "metrics-range", short = 'M', value_parser, required = false)]
pub metrics_range: Option<MetricsRange>,
#[arg(
long = "metrics-max",
default_value = "1000000",
value_parser = parse_positive_usize
)]
pub metrics_max: PositiveUsize,
#[arg(long = "rss-log-ms", value_parser = parse_positive_u64)]
pub rss_log_ms: Option<PositiveU64>,
#[arg(long = "alloc-profiler-ms", value_parser = parse_positive_u64)]
pub alloc_profiler_ms: Option<PositiveU64>,
#[arg(long = "alloc-profiler-dump-ms", value_parser = parse_positive_u64)]
pub alloc_profiler_dump_ms: Option<PositiveU64>,
#[arg(long = "alloc-profiler-dump-path", default_value = "./alloc-prof")]
pub alloc_profiler_dump_path: String,
#[arg(skip)]
pub scenario: Option<Scenario>,
#[arg(long = "script")]
pub script: Option<String>,
#[arg(long = "plugin", help_heading = "Advanced Options")]
pub plugin: Vec<String>,
#[arg(long = "install-service")]
pub install_service: bool,
#[arg(long = "uninstall-service")]
pub uninstall_service: bool,
#[arg(long = "service-name")]
pub service_name: Option<String>,
#[arg(skip)]
pub sinks: Option<SinksConfig>,
#[arg(skip)]
pub distributed_silent: bool,
}