Merge #282: Improve tests

9977fa69af ci: use run-tests.sh (Erik Arvstedt)
a82f0f5f48 add test 'pkgsUnstable' (Erik Arvstedt)
95bc1237e2 run-tests: rename testDir -> scriptDir (Erik Arvstedt)
466d23deaa ci: extract build-to-cachix.sh (Erik Arvstedt)
a70c3bf210 make-test-vm: remove unneeded leftover arg attrs (Erik Arvstedt)
ed65e78a2b make-test: expose test config (Erik Arvstedt)
7265742655 run-tests: add 'instantiate' command (Erik Arvstedt)
8cbdef8bf6 run-tests: fix CLI (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    Very nice! ACK 9977fa69af

Tree-SHA512: bb7f97096cc6e21f053c7db72a584a25ad62bca28af99e51fa83c15d2f75a198ada801428657821fc35f2cf01831176af8a9cd471e21dd0a7f5185f9d58efea1
This commit is contained in:
Jonas Nick 2020-12-11 21:25:02 +00:00
commit 7928495e45
No known key found for this signature in database
GPG Key ID: 4861DBF262123605
7 changed files with 147 additions and 115 deletions

50
ci/build-to-cachix.sh Executable file
View File

@ -0,0 +1,50 @@
#!/usr/bin/env bash
# Build a single-output derivation and store it in 'cachixCache'.
# Skip the build if it is already cached.
# Accepts the same arguments as nix-instantiate.
set -euo pipefail
CACHIX_SIGNING_KEY=${CACHIX_SIGNING_KEY:-}
cachixCache=nix-bitcoin
trap 'echo Error at line $LINENO' ERR
atExit() {
rm -rf $tmpDir
if [[ -v cachixPid ]]; then kill $cachixPid; fi
}
tmpDir=$(mktemp -d -p /tmp)
trap atExit EXIT
## Instantiate
time nix-instantiate "$@" --add-root $tmpDir/drv --indirect > /dev/null
printf "instantiated "; realpath $tmpDir/drv
outPath=$(nix-store --query $tmpDir/drv)
if nix path-info --store https://$cachixCache.cachix.org $outPath &>/dev/null; then
echo "$outPath has already been built successfully."
exit 0
fi
## Build
if [[ -v CIRRUS_CI ]]; then
cachix use $cachixCache
fi
if [[ $CACHIX_SIGNING_KEY ]]; then
# Speed up task by uploading store paths as soon as they are created
cachix push $cachixCache --watch-store &
cachixPid=$!
fi
nix-build --out-link $tmpDir/result $tmpDir/drv >/dev/null
if [[ $CACHIX_SIGNING_KEY ]]; then
cachix push $cachixCache $outPath
fi
echo $outPath

View File

@ -1,12 +0,0 @@
let
pkgs = import <nixpkgs> {};
nbPkgs = import ../pkgs { inherit pkgs; };
ciPkgs = with nbPkgs; [
electrs
elementsd
hwi
joinmarket
lightning-loop
];
in
pkgs.writeText "ci-pkgs" (pkgs.lib.concatMapStringsSep "\n" toString ciPkgs)

View File

@ -3,73 +3,27 @@
# This script can also be run locally for testing: # This script can also be run locally for testing:
# scenario=default ./build.sh # scenario=default ./build.sh
# #
# WARNING: This script fetches contents from an untrusted $cachixCache to your local nix-store.
#
# When variable CIRRUS_CI is unset, this script leaves no persistent traces on the host system. # When variable CIRRUS_CI is unset, this script leaves no persistent traces on the host system.
set -euo pipefail set -euo pipefail
scenario=${scenario:-} scenario=${scenario:-}
CACHIX_SIGNING_KEY=${CACHIX_SIGNING_KEY:-}
cachixCache=nix-bitcoin
trap 'echo Error at line $LINENO' ERR if [[ -v CIRRUS_CI && $scenario ]]; then
if [[ ! -e /dev/kvm ]]; then
if [[ -v CIRRUS_CI ]]; then >&2 echo "No KVM available on VM host."
tmpDir=/tmp exit 1
if [[ $scenario ]]; then
if [[ ! -e /dev/kvm ]]; then
>&2 echo "No KVM available on VM host."
exit 1
fi
# Enable KVM access for nixbld users
chmod o+rw /dev/kvm
fi fi
else # Enable KVM access for nixbld users
atExit() { chmod o+rw /dev/kvm
rm -rf $tmpDir
if [[ -v cachixPid ]]; then kill $cachixPid; fi
}
tmpDir=$(mktemp -d -p /tmp)
trap atExit EXIT
# Prevent cachix from writing to HOME
export HOME=$tmpDir
fi fi
cachix use $cachixCache
cd "${BASH_SOURCE[0]%/*}"
## Build
echo "$NIX_PATH ($(nix eval --raw nixpkgs.lib.version))" echo "$NIX_PATH ($(nix eval --raw nixpkgs.lib.version))"
if [[ $scenario ]]; then if [[ $scenario ]]; then
buildExpr=$(../test/run-tests.sh --scenario $scenario exprForCI) testArgs="--scenario $scenario"
else else
buildExpr="import ./build.nix" testArgs=pkgsUnstable
fi fi
time nix-instantiate -E "$buildExpr" --add-root $tmpDir/drv --indirect > /dev/null "${BASH_SOURCE[0]%/*}/../test/run-tests.sh" --ci $testArgs
printf "instantiated "; realpath $tmpDir/drv
outPath=$(nix-store --query $tmpDir/drv)
if nix path-info --store https://$cachixCache.cachix.org $outPath &>/dev/null; then
echo "$outPath" has already been built successfully.
exit 0
fi
# Cirrus doesn't expose secrets to pull-request builds,
# so skip cache uploading in this case
if [[ $CACHIX_SIGNING_KEY ]]; then
# Speed up task by uploading store paths as soon as they are created
cachix push $cachixCache --watch-store &
cachixPid=$!
fi
nix-build --out-link $tmpDir/result $tmpDir/drv >/dev/null
if [[ $CACHIX_SIGNING_KEY ]]; then
cachix push $cachixCache $outPath
fi
echo $outPath

View File

@ -5,7 +5,7 @@ let
test = (import "${pkgs.path}/nixos/tests/make-test-python.nix") (testArgs pkgs); test = (import "${pkgs.path}/nixos/tests/make-test-python.nix") (testArgs pkgs);
fixedTest = { system ? builtins.currentSystem, ... }@args: fixedTest = { ... }@args:
let let
pkgsFixed = pkgs // { pkgsFixed = pkgs // {
# Fix the black Python code formatter that's used in the test to allow the test # Fix the black Python code formatter that's used in the test to allow the test

View File

@ -41,11 +41,13 @@ scenario: testConfig:
container = { container = {
# The container name has a 11 char length limit # The container name has a 11 char length limit
containers.nb-test = { config, ...}: { containers.nb-test = { config, ... }: {
config = { config = {
extra = config.config.test.container; extra = config.config.test.container;
config = testConfig; config = testConfig;
}; };
}; };
}; };
config = testConfig;
} }

13
test/pkgs-unstable.nix Normal file
View File

@ -0,0 +1,13 @@
let
pinned = import ../pkgs/nixpkgs-pinned.nix;
pkgs = import pinned.nixpkgs-unstable {};
nbPkgs = import ../pkgs { inherit pkgs; };
pkgsUnstable = with nbPkgs; [
electrs
elementsd
hwi
joinmarket
lightning-loop
];
in
pkgs.writeText "pkgs-unstable" (pkgs.lib.concatMapStringsSep "\n" toString pkgsUnstable)

View File

@ -40,8 +40,11 @@
set -eo pipefail set -eo pipefail
scriptDir=$(cd "${BASH_SOURCE[0]%/*}" && pwd)
scenario= scenario=
outLinkPrefix= outLinkPrefix=
ciBuild=
while :; do while :; do
case $1 in case $1 in
--scenario|-s) --scenario|-s)
@ -64,6 +67,10 @@ while :; do
exit 1 exit 1
fi fi
;; ;;
--ci)
shift
ciBuild=1
;;
*) *)
break break
esac esac
@ -73,9 +80,7 @@ numCPUs=${numCPUs:-$(nproc)}
# Min. 800 MiB needed to avoid 'out of memory' errors # Min. 800 MiB needed to avoid 'out of memory' errors
memoryMiB=${memoryMiB:-2048} memoryMiB=${memoryMiB:-2048}
testDir=$(cd "${BASH_SOURCE[0]%/*}" && pwd) export NIX_PATH=nixpkgs=$(nix eval --raw -f "$scriptDir/../pkgs/nixpkgs-pinned.nix" nixpkgs)
export NIX_PATH=nixpkgs=$(nix eval --raw -f "$testDir/../pkgs/nixpkgs-pinned.nix" nixpkgs)
# Run the test. No temporary files are left on the host system. # Run the test. No temporary files are left on the host system.
run() { run() {
@ -83,7 +88,7 @@ run() {
export TMPDIR=$(mktemp -d /tmp/nix-bitcoin-test.XXX) export TMPDIR=$(mktemp -d /tmp/nix-bitcoin-test.XXX)
trap "rm -rf $TMPDIR" EXIT trap "rm -rf $TMPDIR" EXIT
nix-build --out-link $TMPDIR/driver -E "(import \"$testDir/tests.nix\" { scenario = \"$scenario\"; }).vm" -A driver nix-build --out-link $TMPDIR/driver -E "(import \"$scriptDir/tests.nix\" { scenario = \"$scenario\"; }).vm" -A driver
# Variable 'tests' contains the Python code that is executed by the driver on startup # Variable 'tests' contains the Python code that is executed by the driver on startup
if [[ $1 == --interactive ]]; then if [[ $1 == --interactive ]]; then
@ -124,42 +129,57 @@ evalTest() {
echo # nix eval doesn't print a newline echo # nix eval doesn't print a newline
} }
instantiate() {
nix-instantiate -E "$(vmTestNixExpr)" "$@"
}
container() { container() {
. "$testDir/lib/make-container.sh" "$@" . "$scriptDir/lib/make-container.sh" "$@"
}
doBuild() {
name=$1
shift
if [[ $ciBuild ]]; then
"$scriptDir/../ci/build-to-cachix.sh" "$@"
else
if [[ $outLinkPrefix ]]; then
outLink="--out-link $outLinkPrefix-$name"
else
outLink=--no-out-link
fi
nix-build $outLink "$@"
fi
} }
# Run the test by building the test derivation # Run the test by building the test derivation
buildTest() { buildTest() {
if [[ $outLinkPrefix ]]; then vmTestNixExpr | doBuild $scenario $outLinkArg "$@" -
buildArgs="--out-link $outLinkPrefix-$scenario"
else
buildArgs=--no-out-link
fi
vmTestNixExpr | nix-build $buildArgs "$@" -
}
# On continuous integration nodes there are few other processes running alongside the
# test, so use more memory here for maximum performance.
exprForCI() {
memoryMiB=4096
memTotalKiB=$(awk '/MemTotal/ { print $2 }' /proc/meminfo)
memAvailableKiB=$(awk '/MemAvailable/ { print $2 }' /proc/meminfo)
# Round down to nearest multiple of 50 MiB for improved test build caching
((memAvailableMiB = memAvailableKiB / (1024 * 50) * 50))
((memAvailableMiB < memoryMiB)) && memoryMiB=$memAvailableMiB
>&2 echo "VM stats: CPUs: $numCPUs, memory: $memoryMiB MiB"
>&2 echo "Host memory total: $((memTotalKiB / 1024)) MiB, available: $memAvailableMiB MiB"
# VMX is usually not available on CI nodes due to recursive virtualisation.
# Explicitly disable VMX, otherwise QEMU 4.20 fails with message
# "error: failed to set MSR 0x48b to 0x159ff00000000"
vmTestNixExpr "-cpu host,-vmx"
} }
vmTestNixExpr() { vmTestNixExpr() {
extraQEMUOpts="$1" extraQEMUOpts=
cat <<EOF
((import "$testDir/tests.nix" { scenario = "$scenario"; }).vm {}).overrideAttrs (old: rec { if [[ $ciBuild ]]; then
# On continuous integration nodes there are few other processes running alongside the
# test, so use more memory here for maximum performance.
memoryMiB=4096
memTotalKiB=$(awk '/MemTotal/ { print $2 }' /proc/meminfo)
memAvailableKiB=$(awk '/MemAvailable/ { print $2 }' /proc/meminfo)
# Round down to nearest multiple of 50 MiB for improved test build caching
((memAvailableMiB = memAvailableKiB / (1024 * 50) * 50))
((memAvailableMiB < memoryMiB)) && memoryMiB=$memAvailableMiB
>&2 echo "VM stats: CPUs: $numCPUs, memory: $memoryMiB MiB"
>&2 echo "Host memory total: $((memTotalKiB / 1024)) MiB, available: $memAvailableMiB MiB"
# VMX is usually not available on CI nodes due to recursive virtualisation.
# Explicitly disable VMX, otherwise QEMU 4.20 fails with message
# "error: failed to set MSR 0x48b to 0x159ff00000000"
extraQEMUOpts="-cpu host,-vmx"
fi
cat <<EOF
((import "$scriptDir/tests.nix" { scenario = "$scenario"; }).vm {}).overrideAttrs (old: rec {
buildCommand = '' buildCommand = ''
export QEMU_OPTS="-smp $numCPUs -m $memoryMiB $extraQEMUOpts" export QEMU_OPTS="-smp $numCPUs -m $memoryMiB $extraQEMUOpts"
echo "VM stats: CPUs: $numCPUs, memory: $memoryMiB MiB" echo "VM stats: CPUs: $numCPUs, memory: $memoryMiB MiB"
@ -168,6 +188,10 @@ vmTestNixExpr() {
EOF EOF
} }
pkgsUnstable() {
doBuild pkgs-unstable "$scriptDir/pkgs-unstable.nix"
}
# A basic subset of tests to keep the total runtime within # A basic subset of tests to keep the total runtime within
# manageable bounds (<4 min on desktop systems). # manageable bounds (<4 min on desktop systems).
# These are also run on the CI server. # These are also run on the CI server.
@ -175,30 +199,31 @@ basic() {
scenario=default buildTest "$@" scenario=default buildTest "$@"
scenario=netns buildTest "$@" scenario=netns buildTest "$@"
scenario=netnsRegtest buildTest "$@" scenario=netnsRegtest buildTest "$@"
pkgsUnstable
} }
all() { all() {
scenario=default buildTest "$@" basic
scenario=netns buildTest "$@"
scenario=full buildTest "$@" scenario=full buildTest "$@"
scenario=regtest buildTest "$@" scenario=regtest buildTest "$@"
scenario=netnsRegtest buildTest "$@"
} }
# An alias for buildTest
build() { build() {
if [[ $scenario ]]; then buildTest "$@"
buildTest "$@"
else
basic "$@"
fi
} }
command="${1:-build}" if [[ $# > 0 && $1 != -* ]]; then
shift || true # An explicit command was provided
if [[ $command != build ]]; then command=$1
shift
if [[ $command == eval ]]; then
command=evalTest
fi
: ${scenario:=default} : ${scenario:=default}
fi elif [[ $scenario ]]; then
if [[ $command == eval ]]; then command=buildTest
command=evalTest else
command=basic
fi fi
$command "$@" $command "$@"