Files
shadowsocks-libev/tests/test_deb_build.sh
Max LvandClaude Opus 4.6 6423c8e496 Add Debian package build test and statically link bundled submodules
Add tests/test_deb_build.sh with four phases:
1. Build .deb packages via dpkg-buildpackage
2. Verify all three packages contain expected files (binaries, man
   pages, shared library, headers, pkg-config)
3. Install packages and resolve dependencies
4. Smoke-test installed binaries, ldconfig, and headers

Add a Linux-only CI step in build.yml to run the test.

Statically link the bundled submodule libraries (libcork, libipset,
libbloom) into all targets instead of building them as shared libs.
These are vendored code built from git submodules, not system
libraries, so static linking is correct and eliminates
dpkg-shlibdeps warnings about missing .so files.

Pass -DWITH_STATIC=OFF in debian/rules since debian build-depends
only provide shared library dev packages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 11:32:13 +08:00

191 lines
5.2 KiB
Bash

#!/bin/bash
#
# Test that Debian packages build, contain expected files, install, and work.
#
# Usage: bash tests/test_deb_build.sh
#
# Requirements (Linux only):
# - dpkg-buildpackage, debhelper, fakeroot
# - Build dependencies listed in debian/control
# - sudo (for install phase)
#
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
# --- helpers ----------------------------------------------------------------
PASS_COUNT=0
FAIL_COUNT=0
FAILURES=""
log() {
echo "=== [test_deb_build] $* ==="
}
check_pass() {
PASS_COUNT=$((PASS_COUNT + 1))
echo " PASS: $*"
}
check_fail() {
FAIL_COUNT=$((FAIL_COUNT + 1))
FAILURES="${FAILURES} FAIL: $*"$'\n'
echo " FAIL: $*"
}
# check_file_in_deb DEB_FILE PATTERN DESCRIPTION
# Verifies that at least one file matching PATTERN exists in the .deb
check_file_in_deb() {
local deb="$1" pattern="$2" desc="$3"
# Avoid grep -q: with pipefail, early grep exit causes SIGPIPE on dpkg-deb
if dpkg-deb -c "$deb" | grep -E "$pattern" >/dev/null; then
check_pass "$desc"
else
check_fail "$desc"
fi
}
# check_command CMD DESCRIPTION
# Verifies that a command runs successfully (exit 0)
check_command() {
local desc="$2"
if eval "$1" >/dev/null 2>&1; then
check_pass "$desc"
else
check_fail "$desc"
fi
}
summary() {
echo ""
log "Results: $PASS_COUNT passed, $FAIL_COUNT failed"
if [ "$FAIL_COUNT" -gt 0 ]; then
echo ""
echo "Failures:"
printf '%s' "$FAILURES"
exit 1
fi
}
# --- phase 1: build --------------------------------------------------------
log "Phase 1: Build Debian packages"
cd "$PROJECT_DIR"
# dpkg-buildpackage -b builds binary-only packages (no .orig.tar.gz needed)
dpkg-buildpackage -b -us -uc -j"$(nproc)"
# .deb files are placed in the parent directory
PARENT_DIR="$(dirname "$PROJECT_DIR")"
DEB_MAIN=""
DEB_LIB=""
DEB_DEV=""
for f in "$PARENT_DIR"/shadowsocks-libev_*.deb; do
[ -f "$f" ] && DEB_MAIN="$f" && break
done
for f in "$PARENT_DIR"/libshadowsocks-libev2_*.deb; do
[ -f "$f" ] && DEB_LIB="$f" && break
done
for f in "$PARENT_DIR"/libshadowsocks-libev-dev_*.deb; do
[ -f "$f" ] && DEB_DEV="$f" && break
done
# --- phase 2: verify contents ----------------------------------------------
log "Phase 2: Verify package contents"
# Check all three .deb files exist
if [ -n "$DEB_MAIN" ] && [ -f "$DEB_MAIN" ]; then
check_pass "shadowsocks-libev .deb exists: $(basename "$DEB_MAIN")"
else
check_fail "shadowsocks-libev .deb not found"
fi
if [ -n "$DEB_LIB" ] && [ -f "$DEB_LIB" ]; then
check_pass "libshadowsocks-libev2 .deb exists: $(basename "$DEB_LIB")"
else
check_fail "libshadowsocks-libev2 .deb not found"
fi
if [ -n "$DEB_DEV" ] && [ -f "$DEB_DEV" ]; then
check_pass "libshadowsocks-libev-dev .deb exists: $(basename "$DEB_DEV")"
else
check_fail "libshadowsocks-libev-dev .deb not found"
fi
# Bail early if any .deb is missing - remaining checks would all fail
if [ "$FAIL_COUNT" -gt 0 ]; then
summary
fi
# Main package: binaries
for bin in ss-local ss-server ss-redir ss-tunnel ss-manager; do
check_file_in_deb "$DEB_MAIN" "usr/bin/${bin}" "$bin binary in main package"
done
# Main package: man pages
for bin in ss-local ss-server ss-redir ss-tunnel ss-manager; do
check_file_in_deb "$DEB_MAIN" "usr/share/man/man1/$bin\\.1" "$bin man page in main package"
done
# Shared library package
check_file_in_deb "$DEB_LIB" "usr/lib/.*/libshadowsocks-libev\\.so\\." "shared library in lib package"
# Dev package: header
check_file_in_deb "$DEB_DEV" "usr/include/shadowsocks\\.h" "shadowsocks.h header in dev package"
# Dev package: pkg-config
check_file_in_deb "$DEB_DEV" "usr/lib/.*/pkgconfig/shadowsocks-libev\\.pc" "pkg-config file in dev package"
# Dev package: unversioned .so symlink
check_file_in_deb "$DEB_DEV" "usr/lib/.*/libshadowsocks-libev\\.so[^.]" "unversioned .so symlink in dev package"
# --- phase 3: install -------------------------------------------------------
log "Phase 3: Install packages"
sudo dpkg -i "$DEB_LIB" "$DEB_DEV" "$DEB_MAIN" || true
sudo apt-get -f install -y
# Verify dpkg thinks they are installed
for pkg in shadowsocks-libev libshadowsocks-libev2 libshadowsocks-libev-dev; do
if dpkg -s "$pkg" >/dev/null 2>&1; then
check_pass "$pkg installed"
else
check_fail "$pkg not installed"
fi
done
# --- phase 4: smoke-test ----------------------------------------------------
log "Phase 4: Smoke-test installed binaries"
# Each binary should respond to --help
for bin in ss-local ss-server ss-redir ss-tunnel ss-manager; do
check_command "$bin --help" "$bin --help runs"
done
# Shared library should be findable by ldconfig
sudo ldconfig
if ldconfig -p | grep -q libshadowsocks-libev; then
check_pass "libshadowsocks-libev found by ldconfig"
else
check_fail "libshadowsocks-libev not found by ldconfig"
fi
# Header should be in the include path
if [ -f /usr/include/shadowsocks.h ]; then
check_pass "shadowsocks.h installed in /usr/include"
else
check_fail "shadowsocks.h not installed in /usr/include"
fi
# --- summary ----------------------------------------------------------------
summary