sccache/scripts/freebsd-ci-test.sh

351 строка
9.2 KiB
Bash
Executable File

#!/bin/sh
# This script contains CI tests for FreeBSD, testing
#
# - cargo build & cargo test
# - configure and start sccache-dist and scheduler
# - test distributed compile
# - test that the cache is used
#
# It creates a temporary test pool backed by a
# file (using mdconfig) and does a full configuration
# of pot.
#
# After running it copies the sccache log file into
# the repo's root directory. It also does a full
# cleanup (removal of all temporary files, test pool
# etc.) after each run. This can be prevented by
# setting FREEBSD_CI_NOCLEAN in the environment:
#
# FREEBSD_CI_NOCLEAN=1 scripts/freebsd-ci-test.sh
#
# When running in a loop, time and bandwidth can be
# saved by placing FreeBSD distribution files in
# $HOME/.potcache
#
# mkdir $HOME/.potcache
# fetch -o $HOME/.potcache/14.1-RELEASE_base.txz \
# https://ftp.freebsd.org/pub/FreeBSD/releases/amd64/14.1-RELEASE/base.txz
#
# This script can be run from a github action. When run locally, make
# sure to install the required packages:
#
# pkg install -y ca-root-nss curl gmake gtar pot sudo
#
# shellcheck disable=SC3040
set -eo pipefail
init()
{
base=$(realpath "$(dirname "$0")"/..)
OS_VERSION="$(freebsd-version | awk -F- '{print $1}')"
PUB_INTF="$(netstat -4rn | grep default | awk '{ print $4}')"
TEST_TMPDIR=$(mktemp -d "/tmp/sccache_freebsd.XXXXXXX") || exit 1
chmod g+r "$TEST_TMPDIR"
export XDG_CONFIG_HOME="$TEST_TMPDIR/.config"
mkdir -p "$XDG_CONFIG_HOME"
export SCCACHE_DIR="$TEST_TMPDIR/.cache"
killall sccache 2>/dev/null || true
killall sccache-dist 2>/dev/null || true
export RUST_LOG_STYLE=never
}
output_env_info()
{
echo "## user"
whoami
echo "## environment"
env | sort
echo "## network"
ifconfig
echo "## tooling info"
cargo -V
rustc -V
curl --version
# See https://github.com/bsdpot/pot/pull/253
pot version || true
gtar --version
echo "## installed packages"
pkg info
}
build_and_test_project()
{
echo "#### building sccache (cargo)"
cd "$base"
FAULT=0
export RUSTFLAGS="-C debuginfo=0"
cargo build --features "dist-client,dist-server" || FAULT=1
echo "#### testing sccache (cargo)"
cargo test --features "dist-client,dist-server" -- \
--test-threads 1 || FAULT=1
unset RUSTFLAGS
if [ "$FAULT" -eq 0 ]; then
# save build time by avoiding "cargo install"
cp -a target/debug/sccache target/debug/sccache-dist \
"$HOME/.cargo/bin/."
fi
if [ $FAULT -ne 0 ]; then return 1; fi
}
prepare_and_run_sccache_dist()
{
echo "#### preparing sccache-dist"
SECRET_KEY="$(sccache-dist auth generate-jwt-hs256-key)"
CLIENT_AUTH_KEY="$(sccache-dist auth generate-jwt-hs256-key)"
# create scheduler.conf
cat >"$TEST_TMPDIR"/scheduler.conf <<-EOF
public_addr = "127.0.0.1:10600"
[client_auth]
type = "token"
token = "$CLIENT_AUTH_KEY"
[server_auth]
type = "jwt_hs256"
secret_key = "$SECRET_KEY"
EOF
SERVER_TOKEN="$(sccache-dist auth generate-jwt-hs256-server-token \
--config="$TEST_TMPDIR"/scheduler.conf \
--server="127.0.0.1:10501")"
# Create server.conf
cat >"$TEST_TMPDIR"/server.conf <<-EOF
cache_dir = "$TEST_TMPDIR/toolchains"
public_addr = "127.0.0.1:10501"
scheduler_url = "http://127.0.0.1:10600"
[builder]
type = "pot"
pot_fs_root = "$TEST_TMPDIR/pot"
[scheduler_auth]
type = "jwt_token"
token = "$SERVER_TOKEN"
EOF
# create sccache client config
TC="$(rustup toolchain list | grep default | awk '{ print $1 }')"
RUSTC_PATH="$HOME/.rustup/toolchains/$TC/bin/rustc"
mkdir -p "$XDG_CONFIG_HOME/sccache"
cat >"$XDG_CONFIG_HOME/sccache/config" <<-EOF
[dist]
scheduler_url = "http://127.0.0.1:10600"
toolchain_cache_size = 5368709120
cache_dir = "$HOME/.cache/sccache-dist-client"
[dist.auth]
type = "token"
token = "$CLIENT_AUTH_KEY"
[[dist.toolchains]]
type = "path_override"
compiler_executable = "/usr/bin/cc"
archive = "$TEST_TMPDIR/empty.tar.gz"
archive_compiler_executable = "/usr/bin/cc"
[[dist.toolchains]]
type = "path_override"
compiler_executable = "$RUSTC_PATH"
archive = "$TEST_TMPDIR/rust-toolchain.tgz"
archive_compiler_executable = "$RUSTC_PATH"
EOF
echo "Creating toolchain tarballs"
gtar cvf - --files-from /dev/null | \
gzip -n >"$TEST_TMPDIR/empty.tar.gz"
gtar cf - --sort=name --mtime='2022-06-28 17:35Z' "$HOME/.rustup" | \
gzip -n >"$TEST_TMPDIR/rust-toolchain.tgz"
echo "Starting scheduler"
sccache-dist scheduler --config "$TEST_TMPDIR"/scheduler.conf
}
prepare_zpool()
{
echo "#### preparing zpool"
sudo dd if=/dev/zero of="$TEST_TMPDIR/zfs1" bs=1 count=1 seek=3G
MDUNIT=$(sudo mdconfig -a -n -t vnode -S 4096 -f "$TEST_TMPDIR/zfs1")
zdev="/dev/md$MDUNIT"
sudo zpool create -f potpool "$zdev"
}
prepare_pot()
{
echo "#### preparing pot"
sudo sysrc -f /usr/local/etc/pot/pot.conf POT_ZFS_ROOT=potpool/pot
sudo sysrc -f /usr/local/etc/pot/pot.conf POT_EXTIF="$PUB_INTF"
sudo sysrc -f /usr/local/etc/pot/pot.conf POT_TMP="$TEST_TMPDIR"
sudo sysrc -f /usr/local/etc/pot/pot.conf \
POT_FS_ROOT="$TEST_TMPDIR/pot"
sudo sysrc -f /usr/local/etc/pot/pot.conf POT_GROUP=wheel
sudo pot init -f ""
sudo pot version
sudo cp "$HOME"/.potcache/*.txz /var/cache/pot 2>/dev/null || true
sudo pot create -p sccache-template -N alias -i "lo0|127.0.0.2" \
-t single -b "$OS_VERSION"
sudo pot set-cmd -p sccache-template -c /usr/bin/true
sudo pot set-attr -p sccache-template -A no-rc-script -V YES
sudo pot snapshot -p sccache-template
}
start_build_server()
{
echo "#### starting build-server (as root)"
SCCACHE_DIST_LOG=debug RUST_LOG=info sudo \
"$HOME"/.cargo/bin/sccache-dist server \
--config "$TEST_TMPDIR"/server.conf &
}
wait_for_build_server()
{
echo "#### waiting for build server to become available"
count=0
while [ "$(sockstat -q4l -p 10501 | wc -l | xargs)" -eq "0" ]; do
count=$(( count + 1 ))
if [ $count -gt 60 ]; then
2>&1 echo "Build server did not become available"
return 1
fi
sleep 5
done
}
create_build_test_project()
{
echo "#### create and build test project"
cd "$TEST_TMPDIR"
cargo init buildtest
cd buildtest
echo 'chrono = "0.4"' >>Cargo.toml
}
start_sccache_server()
{
echo "#### starting sccache-server"
killall sccache 2>/dev/null || true
SCCACHE_ERROR_LOG="$TEST_TMPDIR"/sccache_log.txt SCCACHE_LOG=info \
RUST_LOG=info sccache --start-server
sleep 10
}
test_sccache_dist_01()
{
echo "#### running scache_dist test 01"
cd "$TEST_TMPDIR/buildtest"
RUSTC_WRAPPER=sccache cargo build
STATS="$(sccache -s)"
echo "Statistics of first buildtest"
echo "$STATS"
CACHE_HITS="$(echo "$STATS" | \
grep "Cache hits" | grep -v Rust | \awk '{ print $3 }')"
FAILED_DIST="$(echo "$STATS" | \
grep "Failed distributed compilations" | awk '{ print $4 }')"
SUCCEEDED_DIST="$(echo "$STATS" | \
(grep -F "127.0.0.1:10501" || echo 0 0) | awk '{ print $2 }')"
if [ "$CACHE_HITS" -ne 0 ]; then
2>&1 echo "Unexpected cache hits"
return 1
fi
# We sometimes get "connection closed before message completed"
# on the first remote build (which will make sccache fall-back
# to building locally). Until this has been resolved, accept
# one failed remote build.
if [ "$FAILED_DIST" -gt 1 ]; then
2>&1 echo "More than one distributed compilations failed"
cat "$TEST_TMPDIR"/sccache_log.txt
return 1
fi
if [ "$SUCCEEDED_DIST" -eq 0 ]; then
2>&1 echo "No distributed compilations succeeded"
return 1
fi
}
test_sccache_dist_02()
{
echo "#### running scache_dist test 02"
cd "$TEST_TMPDIR/buildtest"
sccache -z
cargo clean
RUSTC_WRAPPER=sccache cargo build
STATS="$(sccache -s)"
echo "Statistics of second buildtest"
echo "$STATS"
CACHE_HITS="$(echo "$STATS" | \
grep "Cache hits" | grep -v Rust | \awk '{ print $3 }')"
FAILED_DIST="$(echo "$STATS" | \
grep "Failed distributed compilations" | awk '{ print $4 }')"
SUCCEEDED_DIST="$(echo "$STATS" | \
(grep -F "127.0.0.1:10501" || echo 0 0) | awk '{ print $2 }')"
if [ "$CACHE_HITS" -eq 0 ]; then
2>&1 echo "No cache hits when there should be some"
return 1
fi
# We sometimes get "connection closed before message completed"
# on the first remote build (which will make sccache fall-back
# to building locally). Until this has been resolved, accept
# one failed remote build.
if [ "$FAILED_DIST" -gt 1 ]; then
2>&1 echo "More than one distributed compilations failed"
return 1
fi
if [ "$SUCCEEDED_DIST" -ne 0 ]; then
2>&1 echo "Unexpected distributed compilations happened"
return 1
fi
}
cleanup()
{
echo "#### cleaning up"
set +e
sccache --stop-server
killall sccache
killall sccache-dist && sleep 3
sudo killall sccache-dist && sleep 3
sudo killall -9 sccache-dist
killall sccache
cp "$TEST_TMPDIR/sccache_log.txt" "$base/sccache_log_$(date +%s).txt"
if [ -z "$FREEBSD_CI_NOCLEAN" ]; then
for name in $(pot ls -q); do
sudo pot stop -p "$name"
done
sudo pot de-init
sudo zpool destroy -f potpool
if [ -n "$MDUNIT" ]; then
sudo mdconfig -d -u "$MDUNIT"
fi
sudo rm -rf "$TEST_TMPDIR"
fi
set -e
}
install_signal_handler()
{
trap 'remove_signal_handler; cleanup; exit' EXIT INT HUP
}
remove_signal_handler()
{
trap - EXIT INT HUP
}
main()
{
install_signal_handler
init
output_env_info
build_and_test_project
prepare_and_run_sccache_dist
prepare_zpool
prepare_pot
start_build_server
wait_for_build_server
create_build_test_project
start_sccache_server
test_sccache_dist_01
test_sccache_dist_02
remove_signal_handler
cleanup
}
# run main function
main