Skip to content

refactor: remove docker requirement of tuic#1345

Merged
Itsusinn merged 25 commits into
masterfrom
test/remove-docker-of-tuic
Jun 4, 2026
Merged

refactor: remove docker requirement of tuic#1345
Itsusinn merged 25 commits into
masterfrom
test/remove-docker-of-tuic

Conversation

@Itsusinn
Copy link
Copy Markdown
Member

@Itsusinn Itsusinn commented Apr 27, 2026

Summary by CodeRabbit

  • Tests

    • Enabled local TUIC tests (no docker gate), added a reusable local TUIC server helper, plus end-to-end echo and authentication-failure tests.
  • Chores

    • Updated test/dev dependencies (some now track upstream main) and added new dev tooling.
    • Removed Docker-based TUIC image reference and simplified CI coverage provisioning (no NASM/Protoc install).

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 27, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds an in-process TUIC test server and test utilities, moves TUIC tests off Docker to local TCP tests, updates tuic-core to track main, adds dev-dependencies moka and tuic-server, removes a TUIC Docker image constant, and removes NASM/Protoc install steps from coverage workflow.

Changes

TUIC tests and dependency updates

Layer / File(s) Summary
Dependency updates
clash-lib/Cargo.toml
tuic-core moved from a pinned git tag to branch = "main"; added dev-dependencies moka = { version = "0.12", features = ["future"] } and tuic-server from git = "https://github.com/Itsusinn/tuic", branch = "main".
TuicServerProcess test helper
clash-lib/src/proxy/tuic/test_utils.rs
New TuicServerProcess that spawns tuic-server in a background Tokio task, signals bound port and readiness via oneshot channels, exposes start() and port(), and aborts the task on Drop.
TUIC test integration
clash-lib/src/proxy/tuic/mod.rs
Expose #[cfg(test)] pub(crate) mod test_utils;, simplify gen_options to use 127.0.0.1, skip_cert_verify = true, SNI "localhost", and add two #[tokio::test] TCP integration tests (echo ping-pong and auth-failure).
Docker utils cleanup
clash-lib/src/proxy/utils/test_utils/docker_utils/consts.rs
Removed the IMAGE_TUIC constant that referenced the TUIC Docker image.
CI coverage workflow
.github/workflows/coverage.yml
Removed NASM and Protoc install steps; coverage tooling and upload steps remain.

Sequence Diagram

sequenceDiagram
  participant Test as Test Code
  participant TSP as TuicServerProcess
  participant Task as Tokio Task
  participant Server as tuic-server
  participant Channel as Oneshot Channel

  Test->>TSP: start()
  TSP->>TSP: bind UDP / build Config
  TSP->>Task: spawn server task
  Task->>Server: Server::init(ctx) -> local_addr
  Server->>Channel: send port & readiness
  Channel-->>TSP: readiness received
  TSP-->>Test: return TuicServerProcess(handle, port)
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Watfaq/clash-rs#1429: Also touches the tuic-core git dependency ref and may overlap with dependency ref updates.

Suggested reviewers

  • ibigbug

Poem

🐰 I hopped a port and spun a server bright,
No Docker shell — just local light.
Echoes bounced and auth was tried,
Tests ran safe with TLS beside.
A happy rabbit, testing tonight.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: removing Docker requirement for tuic testing by replacing Docker-based infrastructure with in-process server utilities.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.
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.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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: 3

🤖 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-lib/src/proxy/tuic/mod.rs`:
- Around line 533-559: The test currently sets session.destination to
"127.0.0.1:9999" (where nothing listens) so failures can come from an
unreachable upstream; instead spawn a real local TcpListener and use its bound
address as the session.destination so the upstream is reachable, then proceed to
call handler.connect_stream(&session, resolver).await, accept the incoming
connection on the listener if any, and assert that the TUIC stream is
rejected/closed (i.e., that stream.write_all or stream.read_exact returns Err)
before any successful proxy I/O; update the code around Session construction and
the connect_stream/assertion to create the listener (e.g.,
tokio::net::TcpListener::bind("127.0.0.1:0").await), set destination from
listener.local_addr(), optionally spawn a task to accept the upstream
connection, and ensure the test cleans up the listener/task after the assertion.

In `@clash-lib/src/proxy/tuic/test_utils.rs`:
- Around line 14-15: The current alloc_port() implementation picks a free port
by creating and immediately dropping a temporary UdpSocket, introducing a TOCTOU
race when tuic-server later binds; change alloc_port() to bind a socket to 0
(e.g., UdpSocket::bind("127.0.0.1:0") or TcpListener::bind("127.0.0.1:0")), read
the actual assigned port from socket.local_addr().port(), and return that port
(keeping the socket alive until the server is spawned if necessary), or
alternatively modify the tuic-server startup path to accept port 0 and read the
bound port from the listener it creates; if keeping the original approach, add a
bounded retry loop around server bind (checking for EADDRINUSE) to retry a few
times before failing to avoid flakiness when alloc_port() selection races with
other processes.
- Around line 73-93: The test helper currently treats Server::init errors as
readiness by always sending on ready_tx and then ignoring the channel result;
change the ready signalling to propagate init failures: make ready_tx/ready_rx
send a Result<(), anyhow::Error> (or equivalent) instead of unit, and on Err(e)
from tuic_server::server::Server::init send Err(e) (or forward the error) rather
than sending Ok(()) so the caller can observe the failure; then when awaiting
the timeout on ready_rx, propagate the received Err to the caller (using ? or
map_err) instead of calling .ok(), so start()/the test returns Err when
initialization failed and does not report readiness for a dead server.
🪄 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: 098d516d-f27a-4929-b891-74be75e6d082

📥 Commits

Reviewing files that changed from the base of the PR and between 499e24e and cababdc.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • clash-lib/Cargo.toml
  • clash-lib/src/proxy/tuic/mod.rs
  • clash-lib/src/proxy/tuic/test_utils.rs
  • clash-lib/src/proxy/utils/test_utils/docker_utils/consts.rs
💤 Files with no reviewable changes (1)
  • clash-lib/src/proxy/utils/test_utils/docker_utils/consts.rs

Comment thread clash-lib/src/proxy/tuic/mod.rs
Comment thread clash-lib/src/proxy/tuic/test_utils.rs Outdated
Comment thread clash-lib/src/proxy/tuic/test_utils.rs Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 27, 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 27, 2026

📊 Proxy Throughput Results

Shadowsocks

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
plain 32 MB 3 13409.4 ±8630.9 13551.1 ±1118.5
obfs-http 32 MB 3 17961.6 ±534.5 17681.4 ±1998.4
obfs-tls 32 MB 3 11752.7 ±2289.7 11375.4 ±472.4
shadow-tls-v3 32 MB 3 14485.8 ±1929.9 13177.4 ±2259.7
v2ray-plugin-ws-tls 32 MB 3 11646.3 ±7998.3 13245.7 ±1971.9

Trojan

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
tcp 32 MB 3 13810.0 ±1669.5 14020.1 ±1152.1
ws 32 MB 3 15881.7 ±1143.7 18084.3 ±1708.4
grpc 32 MB 3 14638.0 ±9509.3 16638.5 ±1292.7

VMess

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
tcp 32 MB 3 15398.8 ±809.9 14655.1 ±467.1
tcp-tls 32 MB 3 15763.3 ±2001.4 15519.3 ±516.3
ws 32 MB 3 15512.9 ±1443.4 18289.9 ±5114.5
h2 32 MB 3 16622.6 ±1028.7 17932.9 ±722.8
grpc 32 MB 3 12543.8 ±7340.9 14453.2 ±2435.8

VLESS

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
tcp 32 MB 3 11038.8 ±6712.1 14539.4 ±805.8
ws 32 MB 3 12909.1 ±327.4 12823.8 ±1255.0
h2 32 MB 3 14370.4 ±830.3 15821.3 ±771.9
grpc 32 MB 3 12870.1 ±3226.7 15508.6 ±3410.0

SOCKS5

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
auth 32 MB 3 17538.0 ±2007.2 18782.2 ±1434.6
noauth 32 MB 3 12866.0 ±7076.2 14286.6 ±1327.0

AnyTLS

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
tls 32 MB 3 15916.6 ±8542.2 15917.2 ±727.8

Hysteria2

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
plain 32 MB 3 13579.4 ±1859.3 12953.8 ±1435.4
salamander 32 MB 3 14293.4 ±1659.1 13321.6 ±1037.0

TUIC

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
bbr 32 MB 3 19574.9 ±267.5 18198.9 ±246.7
cubic 32 MB 3 18655.3 ±2000.3 15504.9 ±1876.6
new_reno 32 MB 3 19146.1 ±2703.0 17826.1 ±1151.7

ShadowQUIC

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
plain 32 MB 3 14389.0 ±2321.1 12854.9 ±2198.3
over-stream 32 MB 3 13618.2 ±3462.4 13176.5 ±8497.5

SSH

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
password 32 MB 3 13646.3 ±1225.4 10891.2 ±6128.7
ed25519 32 MB 3 14818.5 ±1428.0 14352.0 ±1070.3

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

Shadowsocks

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
plain-netem 32 MB 3 17255.0 ±2842.3 12687.2 ±3657.4

Trojan

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
tcp-netem 32 MB 3 16434.8 ±1736.7 15488.7 ±518.6

Hysteria2

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
plain-netem 32 MB 3 15759.8 ±4179.3 16414.5 ±2878.5

TUIC

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
bbr-netem 32 MB 3 16377.7 ±9342.7 15651.2 ±193.2

ShadowQUIC

Transport Payload Runs Upload Mbps (±σ) Download Mbps (±σ)
plain-netem 32 MB 3 15822.9 ±2136.9 14555.2 ±144.8

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

🖥️ Test Environment

OS Linux 6.17.0-1015-azure
Architecture x86_64
Kernel 6.17.0-1015-azure
CPU Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
CPU Cores 4
Memory 15.61 GB
Docker 28.0.4
Rust rustc 1.96.0 (ac68faa20 2026-05-25)

📎 View full workflow run and download artifacts

Full test log

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

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: 1

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

Inline comments:
In @.github/workflows/coverage.yml:
- Around line 36-39: The coverage workflow removed explicit NASM provisioning
but README.md/CLAUDE.md still declare NASM required for Windows builds; restore
an explicit NASM install step in .github/workflows/coverage.yml (near the
"Install cargo-llvm-cov" step) that runs only for the windows-latest job, or
alternatively update the docs to state that GitHub runners now include NASM;
locate the relevant job in coverage.yml around the "Install cargo-llvm-cov" step
and either insert a Windows-only NASM install action (e.g., choco/winget
installation) before build/coverage steps or change README.md/CLAUDE.md to
reflect the runner provisioning so the declared requirements match the workflow.
🪄 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: 7d4d0947-98f7-4d56-8cbd-a1bc2d990bed

📥 Commits

Reviewing files that changed from the base of the PR and between cababdc and 0d8ecde.

📒 Files selected for processing (1)
  • .github/workflows/coverage.yml

Comment thread .github/workflows/coverage.yml
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.

🧹 Nitpick comments (2)
clash-lib/src/proxy/tuic/test_utils.rs (1)

60-74: Consider combining duplicate iteration patterns.

Both online_counter and traffic_stats iterate over cfg.users with identical structure. A single loop would be cleaner.

♻️ Suggested refactor
-        let mut online_counter = HashMap::new();
-        for (user, _) in cfg.users.iter() {
-            online_counter
-                .insert(user.to_owned(), std::sync::atomic::AtomicUsize::new(0));
-        }
-        let mut traffic_stats = HashMap::new();
-        for (user, _) in cfg.users.iter() {
-            traffic_stats.insert(
-                user.to_owned(),
-                (
-                    std::sync::atomic::AtomicUsize::new(0),
-                    std::sync::atomic::AtomicUsize::new(0),
-                ),
-            );
-        }
+        let (online_counter, traffic_stats) = cfg
+            .users
+            .keys()
+            .map(|user| {
+                let counter = (user.to_owned(), std::sync::atomic::AtomicUsize::new(0));
+                let stats = (
+                    user.to_owned(),
+                    (
+                        std::sync::atomic::AtomicUsize::new(0),
+                        std::sync::atomic::AtomicUsize::new(0),
+                    ),
+                );
+                (counter, stats)
+            })
+            .unzip();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clash-lib/src/proxy/tuic/test_utils.rs` around lines 60 - 74, The code
duplicates iteration over cfg.users to populate online_counter and
traffic_stats; refactor by using a single loop over cfg.users and within that
loop insert both online_counter.insert(user.to_owned(), AtomicUsize::new(0)) and
traffic_stats.insert(user.to_owned(), (AtomicUsize::new(0),
AtomicUsize::new(0))); reference the existing symbols online_counter,
traffic_stats, and cfg.users and keep the same to_owned()/AtomicUsize::new(0)
semantics to preserve behavior.
clash-lib/src/proxy/tuic/mod.rs (1)

564-575: Arbitrary sleep makes test potentially slow and flaky.

The 1-second sleep at line 567 is a fixed delay hoping the server processes auth rejection. This could be too short under load or unnecessarily slow in normal conditions.

Consider polling with a short timeout in a loop instead:

♻️ Suggested approach
         if let Ok(mut stream) = result {
             let mut buf = [0u8; 5];
-            // Give the server time to process auth and close
-            tokio::time::sleep(Duration::from_secs(1)).await;
-            let write_result = stream.write_all(b"hello").await;
-            let read_result = stream.read_exact(&mut buf).await;
-            assert!(
-                write_result.is_err() || read_result.is_err(),
-                "expected IO error after auth failure, but both read and write \
-                 succeeded"
-            );
+            // Poll for failure with timeout instead of fixed sleep
+            let io_result = tokio::time::timeout(Duration::from_secs(5), async {
+                loop {
+                    if stream.write_all(b"hello").await.is_err() {
+                        return true; // write failed as expected
+                    }
+                    if stream.read_exact(&mut buf).await.is_err() {
+                        return true; // read failed as expected
+                    }
+                    tokio::time::sleep(Duration::from_millis(50)).await;
+                }
+            })
+            .await;
+            assert!(
+                io_result.is_ok(),
+                "expected IO error after auth failure within timeout"
+            );
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clash-lib/src/proxy/tuic/mod.rs` around lines 564 - 575, The fixed 1s sleep
before testing stream IO makes the test slow and flaky; replace the
tokio::time::sleep(Duration::from_secs(1)).await in the block that handles
Ok(mut stream) (the variable result/stream used with stream.write_all and
stream.read_exact) with a short polling loop that repeatedly attempts a
non-blocking/read-write probe (call the same stream.write_all and
stream.read_exact) until either you observe the expected IO error or a small
overall timeout elapses (use tokio::time::timeout or loop with
tokio::time::sleep(Duration::from_millis(...)) between probes); fail the test if
the timeout elapses without an IO error and keep the existing assert semantics
once an error is observed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@clash-lib/src/proxy/tuic/mod.rs`:
- Around line 564-575: The fixed 1s sleep before testing stream IO makes the
test slow and flaky; replace the
tokio::time::sleep(Duration::from_secs(1)).await in the block that handles
Ok(mut stream) (the variable result/stream used with stream.write_all and
stream.read_exact) with a short polling loop that repeatedly attempts a
non-blocking/read-write probe (call the same stream.write_all and
stream.read_exact) until either you observe the expected IO error or a small
overall timeout elapses (use tokio::time::timeout or loop with
tokio::time::sleep(Duration::from_millis(...)) between probes); fail the test if
the timeout elapses without an IO error and keep the existing assert semantics
once an error is observed.

In `@clash-lib/src/proxy/tuic/test_utils.rs`:
- Around line 60-74: The code duplicates iteration over cfg.users to populate
online_counter and traffic_stats; refactor by using a single loop over cfg.users
and within that loop insert both online_counter.insert(user.to_owned(),
AtomicUsize::new(0)) and traffic_stats.insert(user.to_owned(),
(AtomicUsize::new(0), AtomicUsize::new(0))); reference the existing symbols
online_counter, traffic_stats, and cfg.users and keep the same
to_owned()/AtomicUsize::new(0) semantics to preserve behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 14c9eb89-3b23-424a-aaa9-350e3f6cd16f

📥 Commits

Reviewing files that changed from the base of the PR and between 0d8ecde and 6898057.

📒 Files selected for processing (2)
  • clash-lib/src/proxy/tuic/mod.rs
  • clash-lib/src/proxy/tuic/test_utils.rs

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.

🧹 Nitpick comments (1)
clash-lib/Cargo.toml (1)

176-176: Consider adding explicit rev values to TUIC git dependencies for self-contained manifests.

Line 176 and Line 225 specify tag = "v1.7.2" without explicit rev values. While Cargo.lock already pins the exact commit (18b74bcf11fe33caf9dcfc9e2d6685c5230a2e0a), adding rev directly in Cargo.toml makes the dependency specification more transparent and reduces reliance on Cargo.lock for reproducibility. This is especially valuable for supply-chain clarity in projects with frequent dependency updates.

Also applies to: 225-225

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clash-lib/Cargo.toml` at line 176, The TUIC git dependency entries (e.g., the
tuic-core dependency declaration) currently specify tag = "v1.7.2" without an
explicit rev; update each TUIC git dependency in Cargo.toml (the tuic-core entry
at the shown locations and the other TUIC git entry around the later occurrence)
to include rev = "18b74bcf11fe33caf9dcfc9e2d6685c5230a2e0a" (the commit from
Cargo.lock) alongside tag = "v1.7.2" so the manifest is self-contained and
reproducible.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@clash-lib/Cargo.toml`:
- Line 176: The TUIC git dependency entries (e.g., the tuic-core dependency
declaration) currently specify tag = "v1.7.2" without an explicit rev; update
each TUIC git dependency in Cargo.toml (the tuic-core entry at the shown
locations and the other TUIC git entry around the later occurrence) to include
rev = "18b74bcf11fe33caf9dcfc9e2d6685c5230a2e0a" (the commit from Cargo.lock)
alongside tag = "v1.7.2" so the manifest is self-contained and reproducible.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b936b8f5-8796-4ac1-b55a-af719f3aaeb1

📥 Commits

Reviewing files that changed from the base of the PR and between 6898057 and 0ffaff5.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (1)
  • clash-lib/Cargo.toml

Comment thread clash-lib/src/proxy/tuic/mod.rs Outdated
@ibigbug
Copy link
Copy Markdown
Member

ibigbug commented Apr 28, 2026

is it overall better to run the server like this than using a docker container? i think docker is doing it pretty well to avoid crafting the server logic manually for each outbounds, don't see much benefits here replacing it

@Itsusinn
Copy link
Copy Markdown
Member Author

is it overall better to run the server like this than using a docker container? i think docker is doing it pretty well to avoid crafting the server logic manually for each outbounds, don't see much benefits here replacing it

It doesn't run on all platform, such as windows. I think using dep could test more cases, not just on linux which is the only platform supplies docker

@ibigbug
Copy link
Copy Markdown
Member

ibigbug commented Apr 28, 2026

ok that's a fair point. we should have macOS support after this #1039

maybe we should enable them all and fix Windows support too if not working already

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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@clash-lib/Cargo.toml`:
- Line 185: The TUIC git dependencies in Cargo.toml (tuic-core and tuic-server)
currently track branch="main"; change both entries to use an explicit
rev="COMMIT_SHA" (the same commit SHA for both crates) instead of branch,
preserving existing features and optional flags, to make the dependency
deterministic; after updating the manifest regenerate the lockfile (cargo update
or equivalent) so Cargo.lock records the pinned rev rather than ?branch=main#...
.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0adf3344-5fa2-4567-b049-6aace0449b93

📥 Commits

Reviewing files that changed from the base of the PR and between 0ffaff5 and e4c5d87.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • clash-lib/Cargo.toml
  • clash-lib/src/proxy/tuic/mod.rs
  • clash-lib/src/proxy/tuic/test_utils.rs
  • clash-lib/src/proxy/utils/test_utils/docker_utils/consts.rs
💤 Files with no reviewable changes (3)
  • clash-lib/src/proxy/utils/test_utils/docker_utils/consts.rs
  • clash-lib/src/proxy/tuic/test_utils.rs
  • clash-lib/src/proxy/tuic/mod.rs

Comment thread clash-lib/Cargo.toml Outdated
Itsusinn and others added 9 commits May 25, 2026 08:57
…of-tuic

# Conflicts:
#	Cargo.lock
#	clash-lib/Cargo.toml
The connection-chain test was hitting an external httpbin instance that is
currently returning 502 Bad Gateway on CI (and live as I write this),
causing the shadowsocks-feature api_tests job to fail across all
platforms. Run a tiny local hyper HTTP/1 server bound to 127.0.0.1:0 and
swap the upstream-domain rule for a DST-PORT match against that server's
port — the `["DIRECT", "url-test", "test 🌏"]` chain still fires, but the
test is now hermetic.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`cargo +nightly fmt --all -- --check` flagged three formatting issues in
the previous commit: import ordering in api_tests.rs, a split `use`
inside DripServer::start, and a wrapped `let body = Full::new(...)` line
that fits on a single line.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`cababdcf "remove"` dropped the `IMAGE_TUIC` constant from
`docker_utils/consts.rs`, but `e2e_throughput_tuic_bbr` in
`clash-lib/src/proxy/tuic/mod.rs` (gated on
`cfg(all(test, docker_test, throughput_test))`) still references it.
That breaks the Proxy E2E Throughput job with `cannot find value
IMAGE_TUIC in this scope`. The non-docker unit tests this PR adds do
not use this constant, so re-add it under the same docker+throughput
cfg the consumer is gated on.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Commit 6f7c359 ("feat: silently ignore unknown top-level/dns config
fields; add --strict-config") landed a follow-up "chore: default
--compatibility to false" that reverted clap's `ArgAction::Set` on the
flag, so `--compatibility` is now a plain boolean switch. Passing
`--compatibility=false` to the binary now errors with
"unexpected value 'false' for '--compatibility' found; no more were
expected", failing every clash-rs subprocess spawned by the E2E
throughput tests.

The flag's new default is already `false`, which is what the tests
want, so just drop the arg.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`test_tuic_ping_pong_tcp{,_ipv6,_dual_stack}` reliably fail on cross
targets (aarch64-gnu/musl, armv7-gnu/musl, riscv64gc) with "Error: early
eof" — auth completes, then the QUIC stream gets reset mid-relay. The
same tests pass on every native target we run (Linux x86_64, macOS
aarch64, Windows). QUIC under qemu-user is unreliable: packet timing,
MTU discovery and timers all drift enough to race against TUIC's idle /
request timeouts.

Add `running_under_qemu_user()` to the TUIC test_utils — it asks the
kernel for `utsname.machine` and compares it to the binary's
compile-time `target_arch`. A mismatch means we're a foreign-arch binary
running through qemu-user (which is exactly the `cross test` setup).
Native runs match and proceed normally.

Plumb a `skip_under_qemu_user!` macro into the three failing tests so
they emit a one-line skip notice instead of flaking. `test_tuic_auth_failure`
keeps running everywhere — it doesn't depend on relay timing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Itsusinn and others added 3 commits June 5, 2026 01:40
For environments where the command line is fixed (containers, init
systems, GUI launchers) it's useful to flip on `--compatibility` from
outside. Read `CLASH_RS_COMPATIBILITY_MODE` right after Cli::parse_from
and treat `1` or `true` (case-insensitive, trimmed) as equivalent to
passing `--compatibility`. The CLI flag still takes precedence when
already set, and any other value (including `0`, `false`, empty) is a
no-op.

Add a small `env_truthy` helper with its own unit tests so the accept /
reject sets are pinned down.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous `if !cli.compatibility && env_truthy(...)` form was
semantically OR but read at-a-glance like an AND. Replace with the
direct expression `cli.compatibility = cli.compatibility ||
env_truthy(...)` to make the precedence obvious.

Behaviour unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…rver"

Remove DripServer and restore the test's original
https://httpbin.yba.dev/drip request, per request.

clash-lib/tests/api_tests.rs and clash-lib/tests/common/mod.rs are now
identical to master for the two files touched by the drip work.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Itsusinn Itsusinn enabled auto-merge (squash) June 4, 2026 17:52
Itsusinn and others added 4 commits June 5, 2026 02:08
The previous runtime detector compared the binary's compile-time
target_arch to \`utsname.machine\`, expecting a mismatch under qemu-user.
qemu-user fakes the uname syscall to return the *target* architecture,
so the detector silently returned false and the tests still ran (and
flaked) on aarch64 / armv7 / riscv64 cross builds.

Replace with a much simpler compile-time gate: on non-x86_64 Linux,
mark each ping-pong test \`#[ignore]\`. All such targets in CI are
cross-built and run under qemu-user; the assumption holds until a
native non-x86 Linux runner is added (at which point this can be
revisited). Native Linux x86_64, macOS aarch64, and Windows x86_64
continue to cover the tests.

Also drop the now-unused running_under_qemu_user / arch_matches /
skip_under_qemu_user! macro from test_utils.rs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
A reusable predicate for tests that need to bail out under qemu-user.
The rule: \`target_os = "linux"\` AND \`target_arch\` is neither \`x86_64\`
nor \`x86\` (i686) — every such target in our CI matrix is produced by
\`cross\` and executed under qemu-user, where QUIC and other
timing-sensitive paths drift enough to flake.

Implemented as a \`pub const fn\` so the value folds at compile time and
can be used in \`const\` contexts (e.g. \`const _: () = assert!(...)\`).
Pure \`cfg!\` body — no syscalls, no env lookups, no false negatives from
qemu's faked \`utsname\`.

Add two unit tests:
- \`predicate_matches_target_arch\` pins the truth table.
- \`usable_in_const_context\` confirms it folds at compile time.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
\`cfg_attr\` only accepts cfg-predicate syntax, not function calls — even
a const fn — so the existing helper couldn't shorten the long
\`all(target_os = "linux", not(any(target_arch = "x86_64",
target_arch = "x86")))\` predicate that the three TUIC ping-pong tests
repeated.

Have \`build.rs\` emit \`--cfg likely_qemu_emulated\` when the same
condition is true. Now tests can write
\`#[cfg_attr(likely_qemu_emulated, ignore = "…")]\` directly. Rewrite
\`likely_qemu_emulated()\` as \`cfg!(likely_qemu_emulated)\` so the const
fn and the cfg flag share a single source of truth (build.rs).

Apply the new cfg to all three TUIC tests and update the unit test to
assert the build.rs emit matches the inline predicate.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Per request:
- Shorten the rustc-cfg flag name: \`likely_qemu_emulated\` → \`qemu_emulated\`.
- Drop the \`pub const fn likely_qemu_emulated()\` helper. The cfg flag
  alone covers every call site we have (\`#[cfg_attr(qemu_emulated, …)]\`);
  the const fn was just an alias.

Replace the two helper unit tests with a single sanity check that
\`cfg!(qemu_emulated)\` matches build.rs's emit rule, so the flag and the
docs can't drift.

Also rename the cfg in the three TUIC \`#[cfg_attr]\` sites.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Itsusinn Itsusinn merged commit 73ba858 into master Jun 4, 2026
36 checks passed
@Itsusinn Itsusinn deleted the test/remove-docker-of-tuic branch June 4, 2026 19:06
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