Files
shoes/.github/workflows/test.yml
cfal b586e8c654 Fix stream byte loss and expand lifecycle coverage (#206)
Preserve payload bytes across fragmented VLESS response headers, nonempty WebSocket Ping frames, and ShadowTLS authentication fallback. Expand authentication, buffering, half-close, flow-control, and TUN reload coverage; harden isolated test selection, enable macOS process-watcher tests, and document suite boundaries and remaining gaps.
2026-10-22 02:20:03 -04:00

410 lines
15 KiB
YAML

name: Test
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
SING_BOX_VERSION: 1.14.1
SING_BOX_SHA256: 12cb2816b52febb356f6a885b740cc8758c3f30b8ae0ca8edba80f0d2d35343f
MIHOMO_VERSION: 1.19.31
MIHOMO_SHA256: 04cf9f09671704f839ddbee2e93069dc831a4123a75281e725d1d96ab9ac1afc
XRAY_VERSION: 26.10.21
XRAY_SHA256: 0eec3ed4163c273d8c8bf821f7d219e257921cf584aa3fb970715e458e631978
XRAY_COMMIT: 1b1647cd9ddf0abc34b981d4611fc03bcac1ca74
MIHOMO_ALPHA_COMMIT: 94b13aed49b8dc41973e4bb3f721c5fa2c5c5c1f
NAIVE_CADDY_VERSION: 2.11.7-naive
NAIVE_CADDY_SHA256: ac97057c925bb098eb575e7b0cb8bd547d4c5f845b09a3dedfbe34444aa7ae88
jobs:
dependency-notices:
name: Dependency notices
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- uses: taiki-e/install-action@v2
with:
tool: cargo-about@0.9.2
- name: Verify generated dependency licenses and artifact checks
run: |
python3 scripts/generate-release-notices.py
git diff --exit-code -- licenses/dependencies.txt
cargo fetch --locked
python3 scripts/test-release-notices.py
wireguard-interop:
name: WireGuard interoperability
runs-on: ubuntu-latest
timeout-minutes: 60
env:
GOMAXPROCS: 1
WG_SING_BOX_COMMIT: 7054cac5124465ffdb145870d7c01885566711b1
WG_XRAY_COMMIT: 1b1647cd9ddf0abc34b981d4611fc03bcac1ca74
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- name: Restore pinned WireGuard peers
id: wireguard-peers
uses: actions/cache/restore@v6
with:
path: ~/.cache/shoes-wireguard
key: ${{ runner.os }}-${{ runner.arch }}-wireguard-peers-go1.27.3-${{ env.WG_SING_BOX_COMMIT }}-${{ env.WG_XRAY_COMMIT }}
- uses: actions/setup-go@v7
if: steps.wireguard-peers.outputs.cache-hit != 'true'
with:
go-version: '1.27.3'
cache: false
- uses: actions/cache@v6
with:
path: |
~/.cargo/registry
~/.cargo/git
target
~/go/pkg/mod
~/.cache/go-build
key: ${{ runner.os }}-wireguard-${{ hashFiles('**/Cargo.lock') }}-${{ env.WG_SING_BOX_COMMIT }}-${{ env.WG_XRAY_COMMIT }}
- name: Build pinned independent WireGuard peers
if: steps.wireguard-peers.outputs.cache-hit != 'true'
run: |
mkdir -p "$HOME/.cache/shoes-wireguard"
git clone --filter=blob:none --no-checkout https://github.com/SagerNet/sing-box.git "$HOME/wg-sing-box"
git -C "$HOME/wg-sing-box" checkout --detach "$WG_SING_BOX_COMMIT"
test "$(git -C "$HOME/wg-sing-box" rev-parse HEAD)" = "$WG_SING_BOX_COMMIT"
git clone --filter=blob:none --no-checkout https://github.com/XTLS/Xray-core.git "$HOME/wg-xray"
git -C "$HOME/wg-xray" checkout --detach "$WG_XRAY_COMMIT"
test "$(git -C "$HOME/wg-xray" rev-parse HEAD)" = "$WG_XRAY_COMMIT"
cd "$HOME/wg-sing-box"
go build -mod=readonly -p 1 -tags with_gvisor,with_wireguard -o "$HOME/.cache/shoes-wireguard/sing-box" ./cmd/sing-box
cd "$HOME/wg-xray"
go build -mod=readonly -p 1 -o "$HOME/.cache/shoes-wireguard/xray" ./main
- name: Save pinned WireGuard peers
if: steps.wireguard-peers.outputs.cache-hit != 'true'
uses: actions/cache/save@v6
with:
path: ~/.cache/shoes-wireguard
key: ${{ steps.wireguard-peers.outputs.cache-primary-key }}
- name: Select WireGuard peers
run: |
echo "SHOES_TEST_SING_BOX_BIN=$HOME/.cache/shoes-wireguard/sing-box" >> "$GITHUB_ENV"
echo "SHOES_TEST_XRAY_BIN=$HOME/.cache/shoes-wireguard/xray" >> "$GITHUB_ENV"
"$HOME/.cache/shoes-wireguard/sing-box" version
"$HOME/.cache/shoes-wireguard/xray" version
- name: Test both roles, inner address families, and real rekey
env:
RUST_LOG: warn
run: >-
cargo test -p shoes --locked --features optional-peer-tests
--test optional_peer wireguard -- --ignored --test-threads=1
unit-tests:
name: Unit tests
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/checkout@v7
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry
uses: actions/cache@v6
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo index
uses: actions/cache@v6
with:
path: ~/.cargo/git
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo build
uses: actions/cache@v6
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
- name: Build
run: cargo build --workspace --locked --verbose
- name: Run local tests
run: cargo test --workspace --locked --lib --bins --verbose
- name: Run process contract tests
run: cargo test -p shoes --locked --test process_contract --verbose -- --test-threads=1
- name: Run rule compilation allocation regression
run: cargo test -p shoes --locked --test rule_allocation --verbose
- name: Run host FFI tests
run: cargo test -p shoes --locked --lib --features ffi -- --test-threads=1
benchmark-tooling:
name: Benchmark tooling
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: '24'
package-manager-cache: false
- name: Test benchmark harness and manifests
run: node --test benches/*.test.mjs
tun-macos:
name: Rootless TUN (macOS)
runs-on: macos-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust build
uses: actions/cache@v6
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-tun-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Run raw-FD and packet tests without a TUN device
run: >-
cargo test -p shoes --locked --lib --features ffi tun:: -- --test-threads=1
- name: Run rootless WireGuard, FFI, and process lifecycle tests
run: >-
cargo test -p shoes --locked --lib --test process_contract --features ffi wireguard -- --test-threads=1
- name: Run FFI rule-source startup and packet tests
run: >-
cargo test -p shoes --locked --lib --features ffi ffi::common::rule_source_tests -- --test-threads=1
- name: Run rule-source routing and filesystem reload tests
run: >-
cargo test -p shoes --locked --test process_contract --features ffi rule_sets:: -- --test-threads=1
- name: Run process filesystem watcher unit tests
run: >-
cargo test -p shoes --locked --bin shoes process:: -- --test-threads=1
integration-tests:
name: Integration (${{ matrix.name }})
needs: unit-tests
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
- name: local protocols
features: integration-tests
target: integration
filters: ""
peer: sing-box
- name: optional peer interoperability
features: optional-peer-tests
target: optional_peer
filters: ""
peer: mihomo
- name: XHTTP interoperability
features: integration-tests
target: xhttp_interop
filters: ""
peer: xhttp
- name: external DNS
features: external-network-tests
target: external_network
filters: dns resolver vless_doh vless_dot
peer: sing-box
- name: external proxies
features: external-network-tests
target: external_network
filters: portforward shadowtls
peer: sing-box
- name: external REALITY
features: external-network-tests
target: external_network
filters: reality
peer: sing-box
- name: kernel WireGuard
features: privileged-tests
target: privileged
filters: wireguard_kernel
peer: kernel-wireguard
steps:
- uses: actions/checkout@v7
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry
uses: actions/cache@v6
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo index
uses: actions/cache@v6
with:
path: ~/.cargo/git
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo build
uses: actions/cache@v6
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
- name: Install kernel WireGuard test tools
if: matrix.peer == 'kernel-wireguard'
run: |
sudo apt-get update
sudo apt-get install --yes --no-install-recommends wireguard-tools iproute2
uname -r
wg --version
- name: Install sing-box test peer
if: matrix.peer == 'sing-box' || matrix.target == 'optional_peer'
run: |
archive="$RUNNER_TEMP/sing-box.tar.gz"
curl --fail --location --retry 3 \
--output "$archive" \
"https://github.com/SagerNet/sing-box/releases/download/v${SING_BOX_VERSION}/sing-box-${SING_BOX_VERSION}-linux-amd64.tar.gz"
echo "${SING_BOX_SHA256} ${archive}" | sha256sum --check --strict
tar --extract --gzip --file "$archive" --directory "$RUNNER_TEMP"
binary="$RUNNER_TEMP/sing-box-${SING_BOX_VERSION}-linux-amd64/sing-box"
chmod +x "$binary"
echo "SHOES_TEST_SING_BOX_BIN=$binary" >> "$GITHUB_ENV"
- name: Install Mihomo test peer
if: matrix.peer == 'mihomo'
run: |
archive="$RUNNER_TEMP/mihomo.gz"
binary="$RUNNER_TEMP/mihomo"
curl --fail --location --retry 3 \
--output "$archive" \
"https://github.com/MetaCubeX/mihomo/releases/download/v${MIHOMO_VERSION}/mihomo-linux-amd64-compatible-v${MIHOMO_VERSION}.gz"
echo "${MIHOMO_SHA256} ${archive}" | sha256sum --check --strict
gzip --decompress --stdout "$archive" > "$binary"
chmod +x "$binary"
echo "SHOES_TEST_MIHOMO_BIN=$binary" >> "$GITHUB_ENV"
- name: Install Xray test peer
if: matrix.target == 'optional_peer'
run: |
archive="$RUNNER_TEMP/xray.zip"
curl --fail --location --retry 3 \
--output "$archive" \
"https://github.com/XTLS/Xray-core/releases/download/v${XRAY_VERSION}/Xray-linux-64.zip"
echo "${XRAY_SHA256} ${archive}" | sha256sum --check --strict
unzip "$archive" xray -d "$RUNNER_TEMP/xray-peer"
binary="$RUNNER_TEMP/xray-peer/xray"
chmod +x "$binary"
echo "SHOES_TEST_XRAY_BIN=$binary" >> "$GITHUB_ENV"
- name: Install native Naive Caddy test peer
if: matrix.target == 'optional_peer'
run: |
archive="$RUNNER_TEMP/caddy-forwardproxy-naive.tar.xz"
curl --fail --location --retry 3 \
--output "$archive" \
"https://github.com/klzgrad/forwardproxy/releases/download/v${NAIVE_CADDY_VERSION}/caddy-forwardproxy-naive.tar.xz"
echo "${NAIVE_CADDY_SHA256} ${archive}" | sha256sum --check --strict
tar --extract --xz --file "$archive" --directory "$RUNNER_TEMP"
binary="$RUNNER_TEMP/caddy-forwardproxy-naive/caddy"
chmod +x "$binary"
echo "SHOES_TEST_NAIVE_CADDY_BIN=$binary" >> "$GITHUB_ENV"
- name: Run sing-box mux lifecycle tests
if: matrix.name == 'local protocols'
run: >-
cargo test -p shoes --locked --lib --features integration-tests
h2mux::h2mux_server_session::singbox_interop_tests:: -- --test-threads=1
- name: Restore pinned XHTTP peers
if: matrix.target == 'xhttp_interop'
id: xhttp-peers
uses: actions/cache/restore@v6
with:
path: |
~/.cache/shoes-xray/xray
~/.cache/shoes-mihomo/mihomo
key: ${{ runner.os }}-xhttp-peers-go1.27.3-${{ env.XRAY_COMMIT }}-${{ env.MIHOMO_ALPHA_COMMIT }}
- name: Install Go for XHTTP peers
if: matrix.target == 'xhttp_interop' && steps.xhttp-peers.outputs.cache-hit != 'true'
uses: actions/setup-go@v7
with:
go-version: '1.27.3'
cache: false
- name: Build pinned Xray test peer
if: matrix.target == 'xhttp_interop' && steps.xhttp-peers.outputs.cache-hit != 'true'
run: |
source="$HOME/.cache/shoes-xray"
git clone --filter=blob:none --no-checkout https://github.com/XTLS/Xray-core.git "$source"
git -C "$source" checkout --detach "$XRAY_COMMIT"
test "$(git -C "$source" rev-parse HEAD)" = "$XRAY_COMMIT"
cd "$source"
GOMAXPROCS=1 go build -p 1 -o "$source/xray" ./main
- name: Build pinned Mihomo Alpha test peer
if: matrix.target == 'xhttp_interop' && steps.xhttp-peers.outputs.cache-hit != 'true'
run: |
source="$HOME/.cache/shoes-mihomo"
git clone --filter=blob:none --no-checkout https://github.com/MetaCubeX/mihomo.git "$source"
git -C "$source" checkout --detach "$MIHOMO_ALPHA_COMMIT"
test "$(git -C "$source" rev-parse HEAD)" = "$MIHOMO_ALPHA_COMMIT"
cd "$source"
GOMAXPROCS=1 CGO_ENABLED=0 go build -p 1 \
-ldflags "-X github.com/metacubex/mihomo/constant.Version=alpha-${MIHOMO_ALPHA_COMMIT:0:8}" \
-o "$source/mihomo" .
- name: Save pinned XHTTP peers
if: matrix.target == 'xhttp_interop' && steps.xhttp-peers.outputs.cache-hit != 'true'
uses: actions/cache/save@v6
with:
path: |
~/.cache/shoes-xray/xray
~/.cache/shoes-mihomo/mihomo
key: ${{ steps.xhttp-peers.outputs.cache-primary-key }}
- name: Select XHTTP peers
if: matrix.target == 'xhttp_interop'
run: |
echo "SHOES_TEST_XRAY_BIN=$HOME/.cache/shoes-xray/xray" >> "$GITHUB_ENV"
echo "SHOES_TEST_MIHOMO_BIN=$HOME/.cache/shoes-mihomo/mihomo" >> "$GITHUB_ENV"
"$HOME/.cache/shoes-xray/xray" version
"$HOME/.cache/shoes-mihomo/mihomo" -v
- name: Run integration tests
env:
TEST_FILTERS: ${{ matrix.filters }}
RUST_LOG: warn
run: |
if [ -z "$TEST_FILTERS" ]; then
cargo test -p shoes --locked \
--features "${{ matrix.features }}" \
--test "${{ matrix.target }}" \
--verbose -- --test-threads=1
else
for filter in $TEST_FILTERS; do
cargo test -p shoes --locked \
--features "${{ matrix.features }}" \
--test "${{ matrix.target }}" \
--verbose "$filter::" -- --test-threads=1
done
fi