Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Testing

xrat includes a comprehensive testing pipeline that measures connectivity, latency, and throughput for stored proxy configs.

Test Stages

The test command runs up to 5 stages in sequence:

StageMeasuresDefaultImplementation
ICMPPing success and latencyEnabledSpawns system ping command
TCPTCP connect success and latencyEnabledDirect TCP socket connection
Real DelayHTTP round-trip latency through proxyEnabledSpawns proxy, makes HTTP request
DownloadDownload throughput through proxyDisabledDownloads file through proxy
UploadUpload throughput through proxyDisabledPOSTs data through proxy

Stage Configuration

Configure stages in config.toml:

[testing]
concurrency = 0  # 0 = auto-detect
order = ["icmp", "real_delay", "download"]
failure_policy = "continue"

[testing.icmp]
enabled = true
timeout = 3000
attempts = 3

[testing.tcp]
enabled = true
timeout = 5000

[testing.real_delay]
enabled = true
url = "https://www.gstatic.com/generate_204"
timeout = 10_000
# Omit both fields to accept 200-299.
# accepted_status_codes = [200, 204]
# accepted_status_ranges = ["300-399"]
follow_redirects = true

[testing.download]
enabled = false
url = "https://cachefly.cachefly.net/50mb.test"
timeout = 30_000

Stage Order

The order array controls ICMP, TCP, real-delay, and download ordering. Accepted values: icmp, tcp, real_delay, download. When real_delay is present and tcp is not, TCP still runs as an implicit gate before real-delay when [testing.tcp].enabled is true. Listing tcp explicitly makes it a standalone stage and avoids running the same TCP check twice if both tcp and real_delay are present. Upload is optional and runs after download only when --upload-url is provided.

Example: skip ICMP, run only real-delay and download:

order = ["real_delay", "download"]

Failure Policy

Controls behavior when a stage fails:

PolicyBehavior
continueRun all stages regardless of failures
skip_remainingStop testing this config after first failure
mark_failedMark config as failed, skip remaining stages

ICMP Stage

Measures ICMP ping latency by spawning the system ping command.

Configuration

[testing.icmp]
enabled = true
timeout = 3000   # ms per attempt
attempts = 3     # number of ping packets

Output

  • icmp_ok — boolean success
  • icmp_ms — average latency in milliseconds
  • icmp_attempts — number of packets sent

Implementation

xrat spawns the system ping command with platform-specific count and timeout flags, then parses stdout for packet loss and round-trip times.

TCP Stage

Measures TCP connection latency to the proxy’s address:port.

Configuration

[testing.tcp]
enabled = true
timeout = 5000  # ms

Output

  • tcp_ok — boolean success
  • tcp_ms — connection time in milliseconds
  • failure_kind — failure classification (if failed)

Failure Classification

TCP failures are classified into categories:

CategoryDescription
DNSDNS resolution failed
TimeoutConnection timed out
RefusedConnection refused (port closed)
UnreachableNetwork unreachable
PermissionDeniedPermission denied
TLSTLS handshake failed
AuthAuthentication failed
ProcessProxy process failed to start
ProxyProxy returned an error
UnknownUnclassified failure

Real Delay Stage

Measures actual HTTP round-trip latency through the proxy.

How It Works

  1. Generates a temporary Xray probe config with a local SOCKS inbound
  2. Spawns a short-lived Xray process
  3. Waits for the SOCKS port to become ready
  4. Makes an HTTP request through the proxy to the test URL
  5. Measures connect time, TTFB, and total round-trip time
  6. Terminates the Xray process

Configuration

[testing.real_delay]
enabled = true
url = "https://www.gstatic.com/generate_204"
timeout = 10_000  # ms
accepted_status_codes = [204]
accepted_status_ranges = ["300-399"]
follow_redirects = false

When either acceptance field is present, it replaces the default 200-299 range. Exact codes and inclusive START-END ranges are combined with OR semantics, so the example accepts 204 or any status from 300 through 399. Codes and range endpoints must be within 100-599.

With follow_redirects = true, xrat follows up to 10 redirects and checks the terminal response status. A loop or longer chain fails the test. With follow_redirects = false, xrat checks the first response, allowing an initial 3xx response to pass when configured; later redirect behavior, including a possible loop, is intentionally not inspected.

The [dns] settings are applied to the Xray probe configuration used by real-delay, download, and upload tests. This controls how Xray resolves the remote test endpoint through the proxy. The DNS block is omitted when all DNS settings have their defaults. ICMP and TCP stages are direct checks and do not use this configuration.

Output

  • real_delay_ok — boolean success
  • real_delay_ms — total round-trip time
  • connect_ms — TCP connection time
  • ttfb_ms — time to first byte
  • http_status — HTTP response status code

Probe Config

The probe config uses a minimal setup. When [dns] is non-default, the generated JSON also contains the configured Xray dns object:

{
  "log": { "loglevel": "warning" },
  "inbounds": [
    {
      "tag": "probe-in",
      "port": <random>,
      "listen": "127.0.0.1",
      "protocol": "socks",
      "settings": { "udp": false }
    }
  ],
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "<node-protocol>",
      "settings": { ... },
      "stream_settings": { ... }
    }
  ]
}

Download Stage

Measures download throughput by downloading a file through the proxy.

Configuration

[testing.download]
enabled = false
url = "https://cachefly.cachefly.net/50mb.test"
timeout = 30_000  # ms

Output

  • download_mbps — throughput in megabits per second

Implementation

  1. Spawns proxy with the config
  2. Downloads the file through the proxy
  3. Measures bytes transferred and elapsed time
  4. Calculates throughput: (bytes * 8) / (seconds * 1_000_000)

Upload Stage

Measures upload throughput by POSTing data through the proxy.

Invocation

xrat test a1b2 --upload-url https://example.com/upload --upload-timeout 30000

Output

  • upload_mbps — throughput in megabits per second

Bulk Testing

Test multiple configs concurrently:

xrat test --enabled-only --concurrency 4

Concurrency

  • 0 = auto-detect based on CPU cores
  • Positive values set exact worker count

Progress Bar

Bulk tests display an animated progress bar (unless --no-progress is used):

Testing configs ━━━━━━━━━━━━━━━━━━━━ 45/150 30% 2m 15s

Output Formats

FormatDescription
tableAligned human-readable table (default)
tsvTab-separated values for scripts
csvComma-separated values (spreadsheet-friendly)
jsonJSON array with full details

Sorting

Sort results by:

FieldDescription
statusAlive first, then by failure reason
icmpLowest ICMP latency
real-delayLowest real-delay latency
download-speedHighest download throughput
protocolProtocol name alphabetically
addressServer address alphabetically

Ping Loop

Continuous monitoring mode for a single config:

xrat test a1b2 --ping --ping-interval 2000

Runs the test repeatedly until Ctrl+C, printing a live summary:

Ping loop for config a1b2 (vless://example.com:443)
─────────────────────────────────────────────────────
#1  ICMP: 15ms  TCP: 12ms  Real Delay: 145ms  ✓
#2  ICMP: 14ms  TCP: 11ms  Real Delay: 142ms  ✓
#3  ICMP: -     TCP: -     Real Delay: -      ✗ timeout
#4  ICMP: 16ms  TCP: 13ms  Real Delay: 148ms  ✓

GeoIP Enrichment

Optionally enrich test results with GeoIP data (country, city, ASN) using configurable lookup backends.

Backend Types

BackendDescription
mmdbLocal GeoLite2 MMDB files (default)
ipwhoisRemote ipwhois.app API
ip-apiRemote ip-api.com API
chainLocal MMDB with remote fallback

Configuration

[testing.geoip]
enabled = true
backend = "mmdb"             # mmdb | ipwhois | ip-api | chain

mmdb backend

Paths for local GeoLite2 MMDB files. Relative paths are resolved from the config file location, or from XRAT_PATH when set.

[testing.geoip]
country_path = "mmdb/GeoLite2-Country.mmdb"
city_path = "mmdb/GeoLite2-City.mmdb"
asn_path = "mmdb/GeoLite2-ASN.mmdb"

Download MMDB files with the mmdb download command.

Remote backends (ipwhois / ip-api)

[testing.geoip.remote]
provider = "ipwhois"         # ipwhois | ip-api
endpoint = ""                # override API endpoint (empty = provider default)
timeout_ms = 5000
api_key = ""                 # provider-specific (if required)
rate_limit_per_minute = 30

Chain backend

Primary is local MMDB; falls back to a remote service on cache/miss or MMDB absence.

[testing.geoip]
backend = "chain"
fallback = "ipwhois"         # ipwhois | ip-api

Caching

Remote lookups are cached in memory to reduce API calls:

[testing.geoip.cache]
enabled = true
ttl_secs = 86400             # per-entry TTL
max_entries = 10000

Test Result Enrichment

When GeoIP enrichment is enabled, test results describe the dial endpoint — the address xrat actually connected to. For configs that front through a CDN or relay, this is the front door, not necessarily the proxy’s real origin:

  • dial_endpoint_ip — resolved IP address
  • dial_endpoint_country — ISO country code (e.g. NL)
  • dial_endpoint_location — location label such as city/country when available
  • dial_endpoint_asn — Autonomous System Number and organization (e.g. AS15169 Google LLC)
  • dial_endpoint_geoip_source — lookup provenance: literal_ip (the config dialed a literal IP) or dial_dns (a hostname resolved via DNS, where CDN fronting hides)
  • dial_endpoint_fronting — detected CDN/relay provider label (e.g. cloudflare) when the dialed IP belongs to a known fronting network. This is a hint, not proof: the real origin may be elsewhere or hidden. null when no fronting provider is recognized.

Because these fields describe the dial endpoint, the --country/--asn filters on xrat test --latest-run-summary match the fronting/relay provider for fronted configs, not the verified origin.

Test Runs

Tests are grouped into runs for historical analysis:

TablePurpose
connection_test_runsGroups test results (id, kind, created_at)
connection_testsIndividual test results linked to a run

View the latest run summary:

xrat test --latest-run-summary

Filter by country or ASN:

xrat test --latest-run-summary --country US --asn cloudflare

Persistence

All test results are persisted to the database:

FieldDescription
config_idForeign key to configs table
run_idForeign key to connection_test_runs
icmp_ok, icmp_msICMP results
tcp_ok, tcp_msTCP results
real_delay_ok, real_delay_msReal delay results
connect_ms, ttfb_ms, http_statusHTTP details
download_mbps, upload_mbpsThroughput
failure_kind, failure_reasonFailure details
dial_endpoint_ip, dial_endpoint_country, dial_endpoint_asnDial-endpoint GeoIP
dial_endpoint_geoip_sourceLookup provenance
dial_endpoint_frontingDetected CDN/relay provider (hint)
tested_atTimestamp