Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ci/test/00_setup_env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export BASE_OUTDIR=${BASE_OUTDIR:-$BASE_SCRATCH_DIR/out}
# The folder for previous release binaries.
# This folder exists only on the ci guest, and on the ci host as a volume.
export PREVIOUS_RELEASES_DIR=${PREVIOUS_RELEASES_DIR:-$BASE_ROOT_DIR/prev_releases}
export CI_BASE_PACKAGES=${CI_BASE_PACKAGES:-build-essential pkgconf curl ca-certificates ccache python3-dev rsync git procps bison e2fsprogs cmake ninja-build}
export CI_BASE_PACKAGES=${CI_BASE_PACKAGES:-build-essential pkgconf curl ca-certificates ccache python3-dev rsync git procps bison e2fsprogs cmake ninja-build net-tools tcpdump}
export GOAL=${GOAL:-install}
export DIR_QA_ASSETS=${DIR_QA_ASSETS:-${BASE_SCRATCH_DIR}/qa-assets}
export CI_RETRY_EXE=${CI_RETRY_EXE:-"retry"}
Expand Down
2 changes: 2 additions & 0 deletions ci/test/00_setup_env_mac_native.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ export BITCOIN_CONFIG="\
-DCMAKE_EXE_LINKER_FLAGS='-Wl,-stack_size -Wl,0x80000' \
"
export BITCOIN_CMD="bitcoin -m" # Used in functional tests
# Can't run tcpdump: tcpdump: en0: You don't have permission to capture on that device
export CI_TCPDUMP_OK_TO_FAIL=1
2 changes: 2 additions & 0 deletions ci/test/00_setup_env_mac_native_fuzz.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
export RUN_FUZZ_TESTS=true
export GOAL="all"
# Can't run tcpdump: tcpdump: en0: You don't have permission to capture on that device
export CI_TCPDUMP_OK_TO_FAIL=1
2 changes: 1 addition & 1 deletion ci/test/00_setup_env_native_alpine_musl.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export LC_ALL=C.UTF-8

export CONTAINER_NAME=ci_native_alpine_musl
export CI_IMAGE_NAME_TAG="mirror.gcr.io/alpine:3.23"
export CI_BASE_PACKAGES="build-base musl-dev pkgconf curl ccache make ninja git python3-dev py3-pip which patch xz procps rsync util-linux bison e2fsprogs cmake dash linux-headers"
export CI_BASE_PACKAGES="build-base musl-dev pkgconf curl ccache make ninja git python3-dev py3-pip which patch xz procps rsync util-linux bison e2fsprogs cmake dash linux-headers net-tools tcpdump"
export PIP_PACKAGES="--break-system-packages pyzmq pycapnp"
export DEP_OPTS="DEBUG=1"
export GOAL="install"
Expand Down
1 change: 1 addition & 0 deletions ci/test/02_run_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ def main():
cmd_run = ["docker", "run", "--rm", "--interactive", "--detach", "--tty"]
cmd_run += [
"--cap-add=LINUX_IMMUTABLE",
"--cap-add=NET_RAW",
*shlex.split(os.getenv("CI_CONTAINER_CAP", "")),
f"--mount=type=bind,src={os.environ['BASE_READ_ONLY_DIR']},dst={os.environ['BASE_READ_ONLY_DIR']},readonly",
f"--mount={CI_CCACHE_MOUNT}",
Expand Down
67 changes: 67 additions & 0 deletions ci/test/03_test_script.sh
Original file line number Diff line number Diff line change
Expand Up @@ -163,17 +163,77 @@ if [[ "$CI_OS_NAME" == "macos" && "${GOAL}" = "install deploy" ]]; then
fi
fi

# Return a list of the network interfaces on the machine, for example: docker0 lo enp3s0 wlp2s0
function get_interfaces()
{
set -o pipefail
ifconfig | awk -F ':| ' '/^[^[:space:]]/ { print $1 }'
set +o pipefail
}

# Generate a file name for storing raw packets captured by tcpdump.
function tcpdump_file()
{
local test_name="$1"
local interface_name="$2"
echo "/tmp/tcpdump_${test_name}_$interface_name"
}

# Start tcpdump on each interface in the background.
function traffic_monitor_begin()
{
test_name="$1"
for ifname in $(get_interfaces) ; do
if [[ "$ifname" == lo* ]] ; then
# Only report as unwanted traffic to local interfaces to port 53 (DNS)
# because that is usually proxied to upstream resolvers on the internet.
filter="port 53"
fi
tcpdump -nU -i "$ifname" -w "$(tcpdump_file "$test_name" "$ifname")" "$filter" &
done
}

# Read tcpdump raw packet files that are generated by traffic_monitor_begin() and if any of them contain
# data, then print the packets and exit with an error.
function traffic_monitor_end()
{
test_name="$1"

for ifname in $(get_interfaces) ; do
f=$(tcpdump_file "$test_name" "$ifname")
if [ ! -e "$f" ] && [ "$CI_TCPDUMP_OK_TO_FAIL" = "1" ] ; then
# In some CI environments this script is not running as root and so the
# tcpdump errors and does not create $f. Those would set
# CI_TCPDUMP_OK_TO_FAIL=1 and we skip them silently here.
continue
fi
# We are running as root and those files are created with owner:group =
# tcpdump:tcpdump and then `tcpdump -r` refuses to read them with an error
# "permission denied" if they are not owned by root:root.
chown root:root "$f"
out="$(tcpdump -n -r "$f" --direction=out tcp or udp)"
if [ -n "$out" ] ; then
echo "Error: detected outbound TCP or UDP packets on a non loopback interface or DNS queries during $test_name tests:" >&2
tcpdump -n -r "$f" tcp or udp
exit 1
fi
done
}

if [ "$RUN_UNIT_TESTS" = "true" ]; then
traffic_monitor_begin "unit"
DIR_UNIT_TEST_DATA="${DIR_UNIT_TEST_DATA}" \
LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" \
CTEST_OUTPUT_ON_FAILURE=ON \
ctest --test-dir "${BASE_BUILD_DIR}" \
--stop-on-failure \
"${MAKEJOBS}" \
--timeout $(( TEST_RUNNER_TIMEOUT_FACTOR * 60 ))
traffic_monitor_end "unit"
fi

if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then
traffic_monitor_begin "functional"
# parses TEST_RUNNER_EXTRA as an array which allows for multiple arguments such as TEST_RUNNER_EXTRA='--exclude "rpc_bind.py --ipv6"'
eval "TEST_RUNNER_EXTRA=($TEST_RUNNER_EXTRA)"
LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" \
Expand All @@ -186,9 +246,11 @@ if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then
"${TEST_RUNNER_EXTRA[@]}" \
--quiet \
--failfast
traffic_monitor_end "functional"
fi

if [ "${RUN_TIDY}" = "true" ]; then
traffic_monitor_begin "tidy"
cmake -B /tidy-build -DLLVM_DIR=/usr/lib/llvm-"${TIDY_LLVM_V}"/cmake -DCMAKE_BUILD_TYPE=Release -S "${BASE_ROOT_DIR}"/contrib/devtools/bitcoin-tidy
cmake --build /tidy-build "$MAKEJOBS"
cmake --build /tidy-build --target bitcoin-tidy-tests "$MAKEJOBS"
Expand All @@ -205,9 +267,11 @@ if [ "${RUN_TIDY}" = "true" ]; then
echo "^^^ ⚠️ Failure generated from clang-tidy"
false
fi
traffic_monitor_end "tidy"
fi

if [[ "${RUN_IWYU}" == true ]]; then
traffic_monitor_begin "iwyu"
# TODO: Consider enforcing IWYU across the entire codebase.
FILES_WITH_ENFORCED_IWYU="/src/(((crypto|index|kernel|primitives|univalue/(lib|test)|util|zmq)/.*|common/license_info|node/blockstorage|node/utxo_snapshot|clientversion|core_io|signet)\\.cpp)"
jq --arg patterns "$FILES_WITH_ENFORCED_IWYU" 'map(select(.file | test($patterns)))' "${BASE_BUILD_DIR}/compile_commands.json" > "${BASE_BUILD_DIR}/compile_commands_iwyu_errors.json"
Expand Down Expand Up @@ -235,9 +299,11 @@ if [[ "${RUN_IWYU}" == true ]]; then

run_iwyu "compile_commands_iwyu_warnings.json"
git --no-pager diff
traffic_monitor_end "iwyu"
fi

if [ "$RUN_FUZZ_TESTS" = "true" ]; then
traffic_monitor_begin "fuzz"
# shellcheck disable=SC2086
LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" \
"${BASE_BUILD_DIR}/test/fuzz/test_runner.py" \
Expand All @@ -246,4 +312,5 @@ if [ "$RUN_FUZZ_TESTS" = "true" ]; then
-l DEBUG \
"${DIR_FUZZ_IN}" \
--empty_min_time=60
traffic_monitor_end "fuzz"
fi
2 changes: 2 additions & 0 deletions src/test/util/setup_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ BasicTestingSetup::BasicTestingSetup(const ChainType chainType, TestOpts opts)
m_args.ForceSetArg("-datadir", fs::PathToString(m_path_root));
gArgs.ForceSetArg("-datadir", fs::PathToString(m_path_root));

gArgs.ForceSetArg("-natpmp", "0"); // Avoid non-loopback network traffic during tests.

SelectParams(chainType);
InitLogging(*m_node.args);
AppInitParameterInteraction(*m_node.args);
Expand Down
2 changes: 1 addition & 1 deletion test/functional/test_framework/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ def write_config(config_path, *, n, chain, extra_config="", disable_autoconnect=
# in tests.
f.write("peertimeout=999999999\n")
f.write("printtoconsole=0\n")
f.write("natpmp=0\n")
f.write("natpmp=0\n") # Avoid non-loopback network traffic during tests.
f.write("shrinkdebugfile=0\n")
# To improve SQLite wallet performance so that the tests don't timeout, use -unsafesqlitesync
f.write("unsafesqlitesync=1\n")
Expand Down
Loading