Skip to content

Releases: tsenart/trunks

trunks v0.2.0

16 Feb 15:46
ec8df2c

Choose a tag to compare

What's new

Comprehensive code quality overhaul from a Jon Gjengset-style review — 14 issues fixed across the entire codebase, with a cleaner public API.

cargo install trunks-cli   # or: brew upgrade tsenart/tap/trunks

Breaking changes ⚠️

  • Attack fields are now private. Use the new builder API:

    // Before (0.1.x)
    let atk = Attack { name: "test".into(), client, pacer, targets, workers: 4, ... };
    
    // After (0.2.0)
    let atk = Attack::builder("test", client, pacer, targets)
        .workers(4)
        .max_workers(16)
        .duration(Duration::from_secs(10))
        .build();

    Optional fields have sensible defaults (workers=num_cpus, timeout=30s, max_body=-1, redirects=10).

  • Codec trait removed. JsonCodec, CsvCodec, MsgpackCodec now have inherent async methods. Remove use trunks::Codec from imports — call .encode()/.decode() directly.

  • Targets and Attack are no longer generic over R. Targets<R> is now just Targets. Attack<C, P, R> is now Attack<C, P>. For lazy targets, wrap the reader: Targets::Lazy(Box::new(target_reader)).

Improvements

  • DNS: fully async resolution using tokio::net::UdpSocket — no more spawn_blocking per query, no thread pool exhaustion under load
  • DNS: transaction ID validation prevents accepting spoofed responses
  • Memory: response bodies stream chunk-by-chunk up to max_body bytes instead of buffering the entire response before truncating
  • Memory: @body_path file reads are cached — read once, reused across all targets referencing the same file
  • Performance: status codes use BTreeMap<u16, u64> instead of allocating String keys per request
  • Performance: proxy CONNECT response uses 512-byte buffered reads instead of byte-by-byte syscalls
  • Performance: codec encode/decode no longer boxes futures via async_trait

Bug fixes

  • Fixed panic when request count exceeds u32::MAX — mean latency used as u32 truncation causing divide-by-zero
  • Fixed Metrics::close() not being idempotent — second call destroyed percentile data
  • Fixed duration_as_nanos silently wrapping durations > 584 years — now saturates to u64::MAX
  • Msgpack decoder rejects frames > 64MB before allocating (prevents OOM from malicious input)

Internal

  • 90 tests covering all fixes
  • AGENTS.md with project guidelines, architecture, CI/release process
  • REVIEW.md tracking all 17 review issues and resolutions

trunks v0.1.1

16 Feb 13:43
8c6123d

Choose a tag to compare

🧪 Comprehensive Test Suite & Library Modules

This release adds 75 tests across 9 modules — taking the codebase from 2 tests to thorough coverage — and extracts three new public library modules from the CLI.

New Library Modules

Three modules that previously lived as inline code in the CLI are now part of the trunks library crate, making them available to anyone building on trunks:

  • trunks::lttbLargest Triangle Three Buckets downsampling for efficient time-series visualization
  • trunks::plot — Self-contained HTML latency scatter plots with LTTB downsampling, dark theme, log scale toggle, and multi-series support
  • trunks::PrometheusMetrics — Prometheus exposition format renderer with per-label histograms, byte counters, and failure tracking

Test Coverage

75 tests across all core modules, covering both happy paths and edge cases:

Module Tests What's covered
Pacers 14 ConstantPacer (pacing, behind/ahead, zero freq/per, rate), LinearPacer (hits, rate growth, pacing), SinePacer (invalid configs, rate oscillation, peak/trough)
Hit Codecs 8 JSON, CSV, MessagePack round-trips; headers; error fields; special characters; empty bodies
LTTB 8 Threshold edge cases; first/last preservation; correct output size; known downsampling verification
Metrics 7 Empty/single/multi-hit accumulation; status code bucketing; error deduplication; rate/throughput; byte means
Reporters 7 Text section presence; JSON serde round-trip; histogram bucketing; HDR percentile format; Go-style duration formatting; bucket string parsing
Prometheus 6 Empty render; single hit exposition; histogram bucket counting; failure labels; multi-label; cumulative buckets
Plot 5 Empty input error; HTML structure; multi-attack series; error labeler; custom titles
Targets 8 HTTP format (method+URL, headers, comments); JSON format; static round-robin cycling; empty/invalid errors
Resolver 12 Address normalization (IPv4, IPv6, brackets, ports); DNS query packet structure (A/AAAA); DNS response parsing with crafted packets; name compression

Install

cargo install trunks-cli

Or use as a library:

cargo add trunks

Platforms

Pre-compiled binaries for 7 targets:

Platform Architecture File
Linux (glibc) x86_64 trunks_0.1.1_x86_64-unknown-linux-gnu.tar.gz
Linux (musl) x86_64 trunks_0.1.1_x86_64-unknown-linux-musl.tar.gz
Linux (glibc) aarch64 trunks_0.1.1_aarch64-unknown-linux-gnu.tar.gz
Linux (musl) aarch64 trunks_0.1.1_aarch64-unknown-linux-musl.tar.gz
macOS x86_64 trunks_0.1.1_x86_64-apple-darwin.tar.gz
macOS aarch64 (Apple Silicon) trunks_0.1.1_aarch64-apple-darwin.tar.gz
Windows x86_64 trunks_0.1.1_x86_64-pc-windows-msvc.zip

Verify downloads with the SHA256SUMS file.

trunks v0.1.0

16 Feb 12:56
1187030

Choose a tag to compare

🎉 First Release

Trunks is a versatile HTTP load testing tool written in Rust — the son of Vegeta, reborn in Rust for maximum performance. It's over 90,000!

Highlights

Rust performance — zero-cost async I/O with Tokio and Hyper, designed to saturate targets without saturating itself

🎯 Avoids Coordinated Omission — clock-based pacing, not response-driven, so your latency measurements are honest

🔄 Vegeta compatible — drop-in replacement for vegeta's CLI, target formats, and JSON output encoding. Your existing pipelines just work.

📊 Rich reporting — text summaries, JSON, bucketed histograms, HDR percentile plots, and interactive HTML latency scatter plots with LTTB downsampling

🔧 Usable as a librarytrunks is both a Rust crate and a CLI (trunks-cli)

Features

  • Pacers: constant rate, linear ramp, sine wave
  • Dynamic worker scaling — auto-spawns workers when the attack falls behind
  • HTTP/2, h2c (HTTP/2 cleartext), TLS (rustls), mTLS
  • Unix domain socket support
  • Custom DNS resolution with configurable caching TTL
  • HTTP/HTTPS proxy support with CONNECT tunneling
  • Prometheus metrics exporter (/metrics endpoint)
  • Three output encodings: JSON, CSV, MessagePack
  • Graceful two-phase shutdown — Ctrl+C drains in-flight requests, second Ctrl+C force exits
  • Redirect following with cross-origin credential stripping

Quick Start

# Install
cargo install trunks-cli

# Run a load test
echo "GET http://localhost:8080/" | trunks attack --name test --rate 100/1s --duration 10s | trunks report

Platforms

Pre-compiled binaries for 7 targets:

Platform Architecture File
Linux (glibc) x86_64 trunks_0.1.0_x86_64-unknown-linux-gnu.tar.gz
Linux (musl) x86_64 trunks_0.1.0_x86_64-unknown-linux-musl.tar.gz
Linux (glibc) aarch64 trunks_0.1.0_aarch64-unknown-linux-gnu.tar.gz
Linux (musl) aarch64 trunks_0.1.0_aarch64-unknown-linux-musl.tar.gz
macOS x86_64 trunks_0.1.0_x86_64-apple-darwin.tar.gz
macOS aarch64 (Apple Silicon) trunks_0.1.0_aarch64-apple-darwin.tar.gz
Windows x86_64 trunks_0.1.0_x86_64-pc-windows-msvc.zip

Verify downloads with the SHA256SUMS file.