Skip to content

fix(tests): skip config_input_test in cross env, fix Windows path in log#1348

Closed
ibigbug wants to merge 8 commits intomasterfrom
pr-1331-fix-tests
Closed

fix(tests): skip config_input_test in cross env, fix Windows path in log#1348
ibigbug wants to merge 8 commits intomasterfrom
pr-1331-fix-tests

Conversation

@ibigbug
Copy link
Copy Markdown
Member

@ibigbug ibigbug commented Apr 28, 2026

Context

Fixes the failing tests from PR #1331 (feat/mirage-to-mihomo).

Root causes

1. Cross-compiled targets (arm, aarch64, riscv, etc.)

All 9 config_input_test tests failed with exit code 127 or empty stdout. In cross/QEMU test environments the test binary runs inside an emulator, but when it spawns a child process (the clash-rs binary), execve of the foreign-arch ELF is not intercepted by QEMU. glibc falls back to running it through /bin/sh, which exits with code 127.

Fix: Add a binary_can_be_spawned() probe (cached via OnceLock) that runs the binary with -v and checks for exit code 127. Each test calls skip_on_cross!() at the top to bail out early.

2. Windows (empty_file_reports_empty_file_error only)

escape_logrus_text() doubles backslashes in log lines (C:\\Users\\...), but the test checked stdout.contains("configuration file C:\\Users\\...\\empty.yaml is empty") (single backslashes). The path in the log line didn't match.

Fix: Restructure the test to check lines individually, mirroring file_failure_logs_error_then_summary_on_stdout: verify the first line contains "is empty" (no path comparison), and check the unescaped summary line for the exact path.

Changes

  • clash-bin/tests/config_input_test.rs: adds binary_can_be_spawned()/skip_on_cross!() guard to all 9 tests; fixes empty_file_reports_empty_file_error for Windows

Summary by CodeRabbit

Release Notes

  • New Features

    • Added alternative config input methods: base64-encoded strings and stdin support alongside file paths.
    • Restored backward compatibility with mihomo CLI flag syntax.
  • Improvements

    • Enhanced error reporting with timestamped structured logging.
    • Refined health-check configuration defaults for proxy providers.
  • Tests

    • Added comprehensive integration tests for config input handling across multiple input sources.

Tunglies and others added 8 commits April 25, 2026 13:43
- accept mihomo-style config sources in test mode, including -config, -f -, and CLASH_* environment inputs

- print validation errors and summaries on stdout with mihomo-compatible exit codes

- create the mihomo default config for missing file-mode configs and cover the CLI behavior with integration tests
- allow proxy providers to omit health-check and apply mihomo-compatible defaults

- default enabled health checks to interval 300 and lazy=true

- return provider parse errors instead of panicking during config validation
… for HealthCheck

Co-authored-by: Copilot <copilot@github.com>
In cross-compilation test runs (arm, aarch64, riscv, etc.) the clash-rs
binary cannot be spawned as a child process from within a QEMU-emulated
test runner -- glibc falls back to execing the foreign-arch ELF through
/bin/sh, which exits 127. All nine config_input_test tests failed with
exit code 127 or empty stdout.

Fix: add a OnceLock-cached binary_can_be_spawned() probe that runs the
binary with -v and checks for exit code 127.  Each test calls
skip_on_cross!() at the top to bail out early in such environments.

On Windows, escape_logrus_text() doubles backslashes in log lines, so
'configuration file C:\Users\...' appears in stdout but the test was
checking for 'C:\...' with single backslashes, causing
empty_file_reports_empty_file_error to fail.

Fix: restructure that test to check lines individually, mirroring
file_failure_logs_error_then_summary_on_stdout: verify the first line
contains 'is empty' (no path comparison) and check the unescaped
summary line for the exact path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 28, 2026

📝 Walkthrough

Walkthrough

The changes refactor CLI config input handling to support filesystem paths, base64-encoded strings, and stdin sources; improve health-check configuration with proper defaults and helper methods; add comprehensive integration tests; and strengthen error handling by converting panic-prone code to Result-based propagation across config conversion routines.

Changes

Cohort / File(s) Summary
Runtime Dependencies
clash-bin/Cargo.toml
Added runtime dependencies on base64 and time (with formatting/local time offset/macros), plus tempfile as dev-only dependency.
CLI Configuration Input Refactoring
clash-bin/src/main.rs
Introduced ConfigInput abstraction supporting three sources: filesystem paths, base64-decoded strings (via --config-string or CLASH_CONFIG_STRING), and stdin. Rewrites mihomo-compatible flags (-f, -config=...) into new option names. Centralized default config handling with directory creation. Enhanced logging with timestamps for errors and test failures.
CLI Integration Tests
clash-bin/tests/config_input_test.rs
Comprehensive test suite validating config input handling across file paths, base64 encoding, stdin, and various argument formats. Includes environment variable suppression, cross-compilation detection, and exit code/stderr assertions.
Health-Check Configuration Defaults
clash-lib/src/config/internal/proxy.rs
Added Clone derive and explicit Default implementation to HealthCheck. Introduced #[serde(default)] on fields for graceful missing-field deserialization. New helper methods: effective_interval() (returns 300 when enabled but unconfigured, 0 when disabled) and effective_lazy() (returns lazy with true fallback). Includes unit tests for default and override behavior.
Health-Check Integration in Manager
clash-lib/src/app/outbound/manager.rs
Refactored HealthCheck::new initialization to use effective_interval() and effective_lazy() instead of raw config fields, ensuring consistent defaults across proxy providers.
Error Handling Refactoring
clash-lib/src/config/internal/convert/mod.rs, clash-lib/src/config/internal/convert/rule_provider.rs
Converted panic-prone expect() calls to Result-based error propagation. rule_provider::convert() now returns Result<HashMap<String, RuleProviderDef>, Error>, with transposition pattern used to cleanly handle Option<Result<...>> cases while preserving empty-map defaults.

Sequence Diagram(s)

sequenceDiagram
    participant User as User/CLI
    participant Parser as Argument Parser
    participant ConfigInput as ConfigInput
    participant Source as Config Source<br/>(File/Base64/Stdin)
    participant Logger as Logger
    participant App as Application

    User->>Parser: clash-rs -f config.yaml<br/>(or --config-string=... or -)
    Parser->>Parser: Normalize mihomo flags<br/>(-f, -config, etc.)
    Parser->>ConfigInput: Create ConfigInput<br/>(path/base64/stdin)
    ConfigInput->>Source: Resolve input source
    Source-->>ConfigInput: Config bytes
    ConfigInput->>ConfigInput: Parse and validate
    alt Validation Success
        ConfigInput-->>Logger: Timestamped success log
        Logger->>App: Proceed with config
    else Validation Failure
        ConfigInput-->>Logger: Timestamped error log<br/>(decode/parse error)
        Logger-->>User: "configuration file ... test failed"<br/>(stdout)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Poem

🐰 A rabbit hops through config streams,
With base64 and filesystem dreams,
Health checks tick with proper grace,
And errors caught in their place!
No more panics, just clean Result flows,
Where every input path now knows. 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main purpose of the pull request, which is to fix failing tests by skipping config_input_test in cross-compilation environments and fixing Windows path escaping in logs.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pr-1331-fix-tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@clash-bin/src/main.rs`:
- Around line 329-356: The fallback for "-f -" currently returns
DEFAULT_CONFIG_FILE in the process CWD; change resolve_config_file and its
caller so the configured home directory is preserved: update resolve_config_file
to accept an extra directory: &Path parameter and, when stdin is empty, return
ConfigInput::from_file_path(directory.join(DEFAULT_CONFIG_FILE)) instead of
PathBuf::from(DEFAULT_CONFIG_FILE); then update resolve_config_path to call
resolve_config_file(config, directory) when config == Path::new("-"). Use the
existing symbols resolve_config_path, resolve_config_file, DEFAULT_CONFIG_FILE,
and ConfigInput::from_file_path to locate and implement the changes.
- Around line 321-326: The function decode_config currently uses
String::from_utf8_lossy which silently replaces invalid UTF-8 bytes; change
decode_config to validate UTF-8 strictly (e.g., use String::from_utf8 or
std::str::from_utf8 on the decoded byte Vec) and return an error via anyhow!
when UTF-8 validation fails so that ConfigInput::Bytes { content } only receives
valid UTF-8 content and invalid base64 payloads are rejected instead of being
repaired.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: be79ee31-f660-49cf-b289-b5851343efeb

📥 Commits

Reviewing files that changed from the base of the PR and between 4b5fd03 and ab9a96f.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • clash-bin/Cargo.toml
  • clash-bin/src/main.rs
  • clash-bin/tests/config_input_test.rs
  • clash-lib/src/app/outbound/manager.rs
  • clash-lib/src/config/internal/convert/mod.rs
  • clash-lib/src/config/internal/convert/rule_provider.rs
  • clash-lib/src/config/internal/proxy.rs

Comment thread clash-bin/src/main.rs
Comment on lines +321 to +326
fn decode_config(config: &str) -> anyhow::Result<ConfigInput> {
let content = STANDARD
.decode(config)
.map_err(|err| anyhow!("decode config: {err}"))?;
let content = String::from_utf8_lossy(&content).into_owned();
Ok(ConfigInput::Bytes { content })
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cd clash-bin && find . -name "main.rs" -type f

Repository: Watfaq/clash-rs

Length of output: 73


🏁 Script executed:

cat -n clash-bin/src/main.rs | sed -n '310,340p'

Repository: Watfaq/clash-rs

Length of output: 1254


🏁 Script executed:

# Let's check the full context of decode_config and how ConfigInput is used
rg -A 20 "fn decode_config" clash-bin/src/main.rs

Repository: Watfaq/clash-rs

Length of output: 701


🏁 Script executed:

# Check how ConfigInput is used in the codebase
rg "ConfigInput" clash-bin/src/main.rs | head -20

Repository: Watfaq/clash-rs

Length of output: 932


🏁 Script executed:

# Check if there are any tests for decode_config
rg -B 5 -A 10 "decode_config\|ConfigInput" clash-bin/src/main.rs

Repository: Watfaq/clash-rs

Length of output: 41


🏁 Script executed:

# Check ConfigInput enum definition to understand the structure better
rg -B 5 -A 15 "enum ConfigInput" clash-bin/src/main.rs

Repository: Watfaq/clash-rs

Length of output: 653


🏁 Script executed:

# Check how STANDARD is defined (base64 standard)
rg "STANDARD" clash-bin/src/main.rs | head -10

Repository: Watfaq/clash-rs

Length of output: 143


🏁 Script executed:

# Look for any tests or usages of decode_config
rg -B 3 -A 5 "decode_config" clash-bin/src/ --type rs

Repository: Watfaq/clash-rs

Length of output: 86


🏁 Script executed:

# Check if there's documentation or examples showing what inputs are expected
rg -B 5 -A 5 "config-string\|config_string" clash-bin/src/main.rs

Repository: Watfaq/clash-rs

Length of output: 41


🏁 Script executed:

# Check the full ConfigInput implementation to understand how the content is used
rg -A 30 "impl ConfigInput" clash-bin/src/main.rs

Repository: Watfaq/clash-rs

Length of output: 1167


🏁 Script executed:

# Check if there are any validation or parsing steps after ConfigInput::Bytes is created
rg -B 5 -A 10 "config_input.load\|config_input\.load\|ConfigInput::" clash-bin/src/main.rs | head -40

Repository: Watfaq/clash-rs

Length of output: 41


🏁 Script executed:

# Look at how the config content is parsed after being read
rg -B 3 -A 3 "Bytes.*content" clash-bin/src/main.rs

Repository: Watfaq/clash-rs

Length of output: 940


🏁 Script executed:

# Check if there's a reason for using lossy conversion by looking at git history or comments
rg -B 10 "from_utf8_lossy" clash-bin/src/main.rs

Repository: Watfaq/clash-rs

Length of output: 367


🏁 Script executed:

# Check how clash::Config::Str handles the content parsing
rg -B 5 -A 5 "try_parse\|Config::Str" clash-bin/src/ | head -40

Repository: Watfaq/clash-rs

Length of output: 41


🏁 Script executed:

# Look for any documentation or comments about expected input format
rg -B 5 "config_string\|CLASH_CONFIG_STRING" clash-bin/src/main.rs

Repository: Watfaq/clash-rs

Length of output: 41


🏁 Script executed:

# Check if there are integration tests or examples showing expected behavior
find clash-bin -name "*.rs" -type f | xargs rg -l "decode_config\|config_string" | head -5

Repository: Watfaq/clash-rs

Length of output: 41


🏁 Script executed:

# Check if there are comments in the codebase about UTF-8 handling
rg "utf.?8\|UTF.?8" clash-bin/src/main.rs

Repository: Watfaq/clash-rs

Length of output: 41


🏁 Script executed:

# Verify the base64 crate version to understand decode behavior
cat clash-bin/Cargo.toml | grep -A 5 "base64"

Repository: Watfaq/clash-rs

Length of output: 265


Reject non-UTF-8 base64 configs instead of silently repairing them.

String::from_utf8_lossy replaces invalid bytes with U+FFFD, so the parsed YAML can differ from the caller's payload. This should fail fast with a UTF-8 error instead of continuing with modified content.

🩹 Proposed fix
 fn decode_config(config: &str) -> anyhow::Result<ConfigInput> {
     let content = STANDARD
         .decode(config)
         .map_err(|err| anyhow!("decode config: {err}"))?;
-    let content = String::from_utf8_lossy(&content).into_owned();
+    let content =
+        String::from_utf8(content).map_err(|err| anyhow!("decode config as UTF-8: {err}"))?;
     Ok(ConfigInput::Bytes { content })
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clash-bin/src/main.rs` around lines 321 - 326, The function decode_config
currently uses String::from_utf8_lossy which silently replaces invalid UTF-8
bytes; change decode_config to validate UTF-8 strictly (e.g., use
String::from_utf8 or std::str::from_utf8 on the decoded byte Vec) and return an
error via anyhow! when UTF-8 validation fails so that ConfigInput::Bytes {
content } only receives valid UTF-8 content and invalid base64 payloads are
rejected instead of being repaired.

Comment thread clash-bin/src/main.rs
Comment on lines +329 to +356
fn resolve_config_path(
config: &Path,
directory: &Path,
) -> anyhow::Result<ConfigInput> {
if config == Path::new("-") {
return resolve_config_file(config);
}
if config.is_absolute() {
Ok(ConfigInput::from_file_path(config.to_path_buf()))
} else {
Ok(ConfigInput::from_file_path(directory.join(config)))
}
}

fn resolve_config_file(file: &Path) -> anyhow::Result<ConfigInput> {
if file == Path::new("-") {
let mut content = String::new();
std::io::stdin()
.read_to_string(&mut content)
.context("read configuration from stdin")?;
if !content.is_empty() {
return Ok(ConfigInput::Bytes { content });
}
return Ok(ConfigInput::from_file_path(PathBuf::from(
DEFAULT_CONFIG_FILE,
)));
}
Ok(ConfigInput::from_file_path(file.to_path_buf()))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Keep the configured home directory when -f - receives no stdin.

When stdin is empty, the fallback path becomes plain config.yaml, so --directory <dir> -f - (and CLASH_HOME_DIR with CLASH_CONFIG_FILE=-) creates the default file in the process cwd instead of the resolved config directory.

🩹 Proposed fix
 fn resolve_config_path(
     config: &Path,
     directory: &Path,
 ) -> anyhow::Result<ConfigInput> {
     if config == Path::new("-") {
-        return resolve_config_file(config);
+        return resolve_config_file(config, Some(directory));
     }
     if config.is_absolute() {
         Ok(ConfigInput::from_file_path(config.to_path_buf()))
     } else {
         Ok(ConfigInput::from_file_path(directory.join(config)))
@@
         if let Some(file) = std::env::var_os("CLASH_CONFIG_FILE") {
-            return resolve_config_file(&PathBuf::from(file));
+            return resolve_config_file(&PathBuf::from(file), Some(&directory));
         }
@@
-fn resolve_config_file(file: &Path) -> anyhow::Result<ConfigInput> {
+fn resolve_config_file(
+    file: &Path,
+    directory: Option<&Path>,
+) -> anyhow::Result<ConfigInput> {
     if file == Path::new("-") {
         let mut content = String::new();
         std::io::stdin()
             .read_to_string(&mut content)
             .context("read configuration from stdin")?;
         if !content.is_empty() {
             return Ok(ConfigInput::Bytes { content });
         }
-        return Ok(ConfigInput::from_file_path(PathBuf::from(
-            DEFAULT_CONFIG_FILE,
-        )));
+        let fallback = directory
+            .map(|dir| dir.join(DEFAULT_CONFIG_FILE))
+            .unwrap_or_else(|| PathBuf::from(DEFAULT_CONFIG_FILE));
+        return Ok(ConfigInput::from_file_path(fallback));
     }
     Ok(ConfigInput::from_file_path(file.to_path_buf()))
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clash-bin/src/main.rs` around lines 329 - 356, The fallback for "-f -"
currently returns DEFAULT_CONFIG_FILE in the process CWD; change
resolve_config_file and its caller so the configured home directory is
preserved: update resolve_config_file to accept an extra directory: &Path
parameter and, when stdin is empty, return
ConfigInput::from_file_path(directory.join(DEFAULT_CONFIG_FILE)) instead of
PathBuf::from(DEFAULT_CONFIG_FILE); then update resolve_config_path to call
resolve_config_file(config, directory) when config == Path::new("-"). Use the
existing symbols resolve_config_path, resolve_config_file, DEFAULT_CONFIG_FILE,
and ConfigInput::from_file_path to locate and implement the changes.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 28, 2026

@ibigbug
Copy link
Copy Markdown
Member Author

ibigbug commented Apr 28, 2026

Closing — the fix was pushed directly to the contributor's PR branch (feat/mirage-to-mihomo) since maintainer edits are enabled.

@ibigbug ibigbug closed this Apr 28, 2026
@github-actions
Copy link
Copy Markdown
Contributor

📊 Proxy Throughput Results

Shadowsocks

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
plain 32 MB 3 11922.9 ±1472.7 11408.5 ±1564.6
obfs-http 32 MB 3 12976.3 ±2338.4 12549.2 ±4180.9
obfs-tls 32 MB 3 14777.3 ±1963.4 13728.1 ±2408.4
shadow-tls-v3 32 MB 3 10960.1 ±1175.5 11608.6 ±711.7
v2ray-plugin-ws-tls 32 MB 3 10645.6 ±491.4 10259.0 ±1037.8

Trojan

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
tcp 32 MB 3 11886.6 ±6384.4 9350.9 ±1374.7
ws 32 MB 3 9784.3 ±1958.2 13084.3 ±2114.4
grpc 32 MB 3 11118.1 ±5955.7 12343.7 ±2040.3

VMess

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
tcp 32 MB 3 12783.1 ±1395.5 11475.7 ±6106.3
tcp-tls 32 MB 3 9933.3 ±817.5 11687.1 ±4044.8
ws 32 MB 3 16735.5 ±230.4 16444.8 ±543.5
h2 32 MB 3 11141.0 ±845.5 12219.6 ±1903.1
grpc 32 MB 3 10794.2 ±3378.8 12317.1 ±2993.1

VLESS

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
tcp 32 MB 3 9999.0 ±1031.4 10125.8 ±2136.3
ws 32 MB 3 13596.7 ±1338.5 12057.2 ±1903.5
h2 32 MB 3 17001.7 ±847.8 17064.8 ±1645.5
grpc 32 MB 3 1158.4 ±4947.4 11147.2 ±742.7

SOCKS5

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
auth 32 MB 3 13300.8 ±781.7 12001.9 ±997.6
noauth 32 MB 3 9340.1 ±5285.5 12818.7 ±1990.3

AnyTLS

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
tls 32 MB 3 9528.7 ±6977.9 12094.4 ±6880.1

Hysteria2

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
plain 32 MB 3 15059.4 ±2445.2 13196.3 ±929.9
salamander 32 MB 3 10281.0 ±3110.3 13525.1 ±3117.5

TUIC

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
bbr 32 MB 3 13548.4 ±2433.9 13704.7 ±2477.9
cubic 32 MB 3 12246.7 ±2574.7 12267.3 ±459.6
new_reno 32 MB 3 10911.7 ±3867.2 10821.1 ±7782.7

ShadowQUIC

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
plain 32 MB 3 10566.2 ±1920.7 11239.8 ±3224.7
over-stream 32 MB 3 12593.7 ±1935.4 12302.2 ±1861.9

SSH

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
password 32 MB 3 7681.6 ±2504.0 9444.5 ±2984.3
ed25519 32 MB 3 8896.2 ±1492.2 9839.7 ±1404.6

Netem Tests (50 ms delay, 1% packet loss)

Shadowsocks

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
plain-netem 32 MB 3 11807.7 ±2357.5 11546.3 ±2467.5

Trojan

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
tcp-netem 32 MB 3 14209.4 ±3959.4 11947.9 ±1392.9

Hysteria2

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
plain-netem 32 MB 3 13711.0 ±1313.9 13101.2 ±2465.9

TUIC

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
bbr-netem 32 MB 3 13064.4 ±2800.5 12407.8 ±1120.1

ShadowQUIC

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
plain-netem 32 MB 3 14703.5 ±963.2 13345.9 ±545.7

Ran 34 variant(s) in parallel; each direction transfers the full payload.

🖥️ Test Environment

OS Linux 6.17.0-1010-azure
Architecture x86_64
Kernel 6.17.0-1010-azure
CPU AMD EPYC 9V74 80-Core Processor
CPU Cores 4
Memory 15.61 GB
Docker 28.0.4
Rust rustc 1.95.0 (59807616e 2026-04-14)

📎 View full workflow run and download artifacts

Full test log

Download the throughput-results artifact from the workflow run for the full log.

@ibigbug ibigbug deleted the pr-1331-fix-tests branch May 2, 2026 06:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants