2016-12-21 21:45:01 +01:00
|
|
|
#!/bin/sh
|
|
|
|
|
2018-05-07 17:13:32 +02:00
|
|
|
: ${TEST_BOARDS_AVAILABLE:="nrf52dk samr21-xpro"}
|
2018-06-22 10:31:44 +02:00
|
|
|
: ${TEST_BOARDS_LLVM_COMPILE:="iotlab-m3 native nrf52dk mulle nucleo-f401re samr21-xpro slstk3402a"}
|
2018-06-22 10:31:44 +02:00
|
|
|
|
2016-12-21 21:45:01 +01:00
|
|
|
export RIOT_CI_BUILD=1
|
|
|
|
export STATIC_TESTS=${STATIC_TESTS:-1}
|
|
|
|
export CFLAGS_DBG=""
|
2017-06-17 18:19:05 +02:00
|
|
|
export DLCACHE_DIR=${DLCACHE_DIR:-~/.dlcache}
|
2018-12-08 23:12:37 +01:00
|
|
|
export ENABLE_TEST_CACHE=${ENABLE_TEST_CACHE:-1}
|
2016-12-21 21:45:01 +01:00
|
|
|
|
2017-03-24 14:40:38 +01:00
|
|
|
NIGHTLY=${NIGHTLY:-0}
|
|
|
|
RUN_TESTS=${RUN_TESTS:-${NIGHTLY}}
|
|
|
|
|
2018-12-08 23:12:37 +01:00
|
|
|
DWQ_ENV="-E BOARDS -E APPS -E NIGHTLY -E RUN_TESTS -E ENABLE_TEST_CACHE -E TEST_HASH"
|
2018-04-11 09:57:18 +02:00
|
|
|
|
2017-03-24 14:40:38 +01:00
|
|
|
check_label() {
|
|
|
|
local label="${1}"
|
|
|
|
[ -z "${CI_PULL_LABELS}" ] && return 1
|
|
|
|
echo "${CI_PULL_LABELS}" | grep -q "${label}"
|
|
|
|
return $?
|
|
|
|
}
|
|
|
|
|
|
|
|
[ "$RUN_TESTS" != "1" ] && {
|
|
|
|
check_label "CI: run tests" && RUN_TESTS=1
|
|
|
|
}
|
|
|
|
|
2018-12-08 23:12:37 +01:00
|
|
|
[ "$ENABLE_TEST_CACHE" = "1" ] && {
|
|
|
|
check_label "CI: disable test cache" && export ENABLE_TEST_CACHE=0
|
|
|
|
}
|
|
|
|
|
2017-01-30 16:59:18 +01:00
|
|
|
error() {
|
|
|
|
echo "$@"
|
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
|
2018-07-23 09:33:35 +02:00
|
|
|
# if MURDOCK_HOOK is set, this function will execute it and pass on all it's
|
|
|
|
# parameters. should the hook script exit with negative exit code, hook() makes
|
|
|
|
# this script exit with error, too.
|
|
|
|
# hook() will be called from different locations of this script.
|
|
|
|
# currently, the only caller is "run_test", which calls "hook run_test_pre".
|
|
|
|
# More hooks will be added as needed.
|
|
|
|
hook() {
|
|
|
|
if [ -n "${MURDOCK_HOOK}" ]; then
|
|
|
|
echo "- executing hook $1"
|
|
|
|
"${MURDOCK_HOOK}" "$@" || {
|
|
|
|
error "$0: hook \"${MURDOCK_HOOK} $@\" failed!"
|
|
|
|
}
|
|
|
|
echo "- hook $1 finished"
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2017-03-24 14:40:38 +01:00
|
|
|
# true if word "$1" is in list of words "$2", false otherwise
|
|
|
|
# uses grep -w, thus only alphanum and "_" count as word bounderies
|
|
|
|
# (word "def" matches "abc-def")
|
|
|
|
is_in_list() {
|
|
|
|
[ $# -ne 2 ] && return 1
|
|
|
|
|
|
|
|
local needle="$1"
|
|
|
|
local haystack="$2"
|
|
|
|
|
|
|
|
echo "$haystack" | grep -q -w "$needle"
|
|
|
|
}
|
|
|
|
|
2019-07-02 10:24:28 +02:00
|
|
|
# grep that doesn't return error on empty input
|
|
|
|
_grep() {
|
|
|
|
grep "$@"
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
2016-12-21 21:45:01 +01:00
|
|
|
_greplist() {
|
|
|
|
if [ $# -eq 0 ]; then
|
|
|
|
echo cat
|
|
|
|
else
|
2019-07-02 10:24:28 +02:00
|
|
|
echo -n "_grep -E ($1"
|
2016-12-21 21:45:01 +01:00
|
|
|
shift
|
|
|
|
for i in $*; do
|
|
|
|
echo -n "|$i"
|
|
|
|
done
|
|
|
|
echo ")"
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
# get list of all app directories
|
|
|
|
get_apps() {
|
2018-08-30 23:09:56 +02:00
|
|
|
make -f makefiles/app_dirs.inc.mk info-applications \
|
|
|
|
| $(_greplist $APPS) | sort
|
2016-12-21 21:45:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# take app dir as parameter, print all boards that are supported
|
|
|
|
# Only print for boards in $BOARDS.
|
|
|
|
get_supported_boards() {
|
|
|
|
local appdir=$1
|
2017-10-17 18:09:10 +02:00
|
|
|
local boards="$(make --no-print-directory -C$appdir info-boards-supported 2>/dev/null || echo broken)"
|
|
|
|
|
|
|
|
if [ "$boards" = broken ]; then
|
|
|
|
echo "makefile_broken"
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
|
|
|
|
for board in $boards
|
2016-12-21 21:45:01 +01:00
|
|
|
do
|
|
|
|
echo $board
|
|
|
|
done | $(_greplist $BOARDS)
|
|
|
|
}
|
|
|
|
|
2018-06-22 10:31:44 +02:00
|
|
|
get_supported_toolchains() {
|
|
|
|
local appdir=$1
|
|
|
|
local board=$2
|
|
|
|
local toolchains="gnu"
|
|
|
|
|
|
|
|
if is_in_list "${board}" "${TEST_BOARDS_LLVM_COMPILE}"; then
|
|
|
|
toolchains="$(make -s --no-print-directory -C${appdir} BOARD=${board} \
|
|
|
|
info-toolchains-supported 2> /dev/null | grep -o -e "llvm" -e "gnu")"
|
|
|
|
fi
|
|
|
|
echo "${toolchains}"
|
|
|
|
}
|
|
|
|
|
|
|
|
# given an app dir as parameter, print "$appdir $board:$toolchain" for each
|
|
|
|
# supported board and toolchain. Only print for boards in $BOARDS.
|
2019-07-02 10:27:48 +02:00
|
|
|
# if extra args are given, they will be prepended to each output line.
|
2018-06-22 10:31:44 +02:00
|
|
|
get_app_board_toolchain_pairs() {
|
2016-12-21 21:45:01 +01:00
|
|
|
local appdir=$1
|
2019-03-12 11:18:44 +01:00
|
|
|
local boards="$(get_supported_boards $appdir)"
|
|
|
|
|
2019-07-02 10:27:48 +02:00
|
|
|
# collect extra arguments into prefix variable
|
|
|
|
shift
|
|
|
|
local prefix="$*"
|
|
|
|
|
2019-03-12 11:18:44 +01:00
|
|
|
if [ "$boards" = makefile_broken ]; then
|
|
|
|
echo "$appdir makefile_broken"
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
|
|
|
|
for board in ${boards}
|
2016-12-21 21:45:01 +01:00
|
|
|
do
|
2018-06-22 10:31:44 +02:00
|
|
|
for toolchain in $(get_supported_toolchains $appdir $board)
|
|
|
|
do
|
2019-07-02 10:27:48 +02:00
|
|
|
echo $prefix $appdir $board:$toolchain
|
2018-06-22 10:31:44 +02:00
|
|
|
done
|
2016-12-21 21:45:01 +01:00
|
|
|
done | $(_greplist $BOARDS)
|
|
|
|
}
|
|
|
|
|
2018-06-22 10:31:44 +02:00
|
|
|
# use dwqc to create full "appdir board toolchain" compile job list
|
2016-12-21 21:45:01 +01:00
|
|
|
get_compile_jobs() {
|
|
|
|
get_apps | \
|
2018-04-11 09:57:18 +02:00
|
|
|
dwqc ${DWQ_ENV} -s \
|
2019-07-02 10:31:29 +02:00
|
|
|
${DWQ_JOBID:+--subjob} \
|
2019-07-02 10:27:48 +02:00
|
|
|
"$0 get_app_board_toolchain_pairs \${1} $0 compile"
|
2016-12-21 21:45:01 +01:00
|
|
|
}
|
|
|
|
|
2018-01-22 14:19:52 +01:00
|
|
|
print_worker() {
|
|
|
|
[ -n "$DWQ_WORKER" ] && \
|
|
|
|
echo "-- running on worker ${DWQ_WORKER} thread ${DWQ_WORKER_THREAD}, build number $DWQ_WORKER_BUILDNUM."
|
|
|
|
}
|
|
|
|
|
2018-12-08 23:12:37 +01:00
|
|
|
test_hash_calc() {
|
|
|
|
local bindir=$1
|
|
|
|
|
|
|
|
# Why two times cut?
|
|
|
|
# "test-input-hash.sha1" contains a list of lines containing
|
|
|
|
# "<hash> <filename>" on each line.
|
|
|
|
# We need to filter out the filename, as it contains the full path name,
|
|
|
|
# which differs depending on the build machine.
|
|
|
|
#
|
|
|
|
# After piping through sha1sum, we get "<hash> -". " -" has to go so we save the
|
|
|
|
# hassle of escaping the resulting hash.
|
|
|
|
|
|
|
|
cat ${bindir}/test-input-hash.sha1 | cut -f1 -d' ' | sha1sum | cut -f1 -d' '
|
|
|
|
}
|
|
|
|
|
|
|
|
test_cache_get() {
|
|
|
|
test "${ENABLE_TEST_CACHE}" = "1" || return 1
|
|
|
|
test -n "$(redis-cli get $1)" > /dev/null
|
|
|
|
}
|
|
|
|
|
|
|
|
test_cache_put() {
|
|
|
|
redis-cli set "$1" ok
|
|
|
|
}
|
|
|
|
|
2018-06-22 10:31:44 +02:00
|
|
|
# compile one app for one board with one toolchain. delete intermediates.
|
2016-12-21 21:45:01 +01:00
|
|
|
compile() {
|
|
|
|
local appdir=$1
|
2018-06-22 10:31:44 +02:00
|
|
|
local board=$(echo $2 | cut -f 1 -d':')
|
|
|
|
local toolchain=$(echo $2 | cut -f 2 -d':')
|
2016-12-21 21:45:01 +01:00
|
|
|
|
2019-03-12 11:28:14 +01:00
|
|
|
[ "$board" = "makefile_broken" ] && {
|
|
|
|
echo "$0: There seems to be a problem in \"$appdir\" while getting supported boards!"
|
|
|
|
echo "$0: testing \"make -C$appdir info-boards-supported\"..."
|
|
|
|
make -C$appdir info-boards-supported && echo "$0: success. no idea what's wrong." || echo "$0: failed!"
|
|
|
|
exit 1
|
|
|
|
}
|
2017-10-17 18:09:10 +02:00
|
|
|
|
2017-02-23 18:45:41 +01:00
|
|
|
# set build directory. CI ensures only one build at a time in $(pwd).
|
|
|
|
export BINDIR="$(pwd)/build"
|
|
|
|
export PKGDIRBASE="${BINDIR}/pkg"
|
|
|
|
|
2017-12-01 12:11:27 +01:00
|
|
|
# Pre-build cleanup
|
|
|
|
rm -rf ${BINDIR}
|
|
|
|
|
2018-01-22 14:19:52 +01:00
|
|
|
print_worker
|
2017-01-30 16:59:18 +01:00
|
|
|
|
|
|
|
# sanity checks
|
2018-06-22 10:31:44 +02:00
|
|
|
[ $# -ne 2 ] && error "$0: compile: invalid parameters (expected \$appdir \$board:\$toolchain)"
|
2017-01-30 16:59:18 +01:00
|
|
|
[ ! -d "$appdir" ] && error "$0: compile: error: application directory \"$appdir\" doesn't exist"
|
|
|
|
[ ! -d "boards/$board" ] && error "$0: compile: error: board directory \"boards/$board\" doesn't exist"
|
|
|
|
|
2017-03-24 14:40:38 +01:00
|
|
|
# compile
|
2018-06-22 10:31:44 +02:00
|
|
|
CCACHE_BASEDIR="$(pwd)" BOARD=$board TOOLCHAIN=$toolchain RIOT_CI_BUILD=1 \
|
2018-12-08 23:12:37 +01:00
|
|
|
make -C${appdir} clean all test-input-hash -j${JOBS:-4}
|
2016-12-21 21:45:01 +01:00
|
|
|
RES=$?
|
|
|
|
|
2017-03-24 14:40:38 +01:00
|
|
|
# run tests
|
2016-12-21 21:45:01 +01:00
|
|
|
if [ $RES -eq 0 ]; then
|
2017-03-24 14:40:38 +01:00
|
|
|
if [ $RUN_TESTS -eq 1 -o "$board" = "native" ]; then
|
|
|
|
if [ -f "${BINDIR}/.test" ]; then
|
|
|
|
if [ "$board" = "native" ]; then
|
|
|
|
BOARD=$board make -C${appdir} test
|
|
|
|
RES=$?
|
|
|
|
elif is_in_list "$board" "$TEST_BOARDS_AVAILABLE"; then
|
2018-12-08 23:12:37 +01:00
|
|
|
test_hash=$(test_hash_calc "$BINDIR")
|
|
|
|
echo "-- test_hash=$test_hash"
|
|
|
|
if test_cache_get $test_hash; then
|
|
|
|
echo "-- skipping test due to positive cache hit"
|
|
|
|
else
|
|
|
|
BOARD=$board TOOLCHAIN=$toolchain TEST_HASH=$test_hash \
|
|
|
|
make -C${appdir} test-murdock
|
|
|
|
RES=$?
|
|
|
|
fi
|
2017-03-24 14:40:38 +01:00
|
|
|
fi
|
|
|
|
fi
|
2016-12-21 21:45:01 +01:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
2017-12-01 12:11:27 +01:00
|
|
|
if [ -d ${BINDIR} ]
|
|
|
|
then
|
|
|
|
echo "-- build directory size: $(du -sh ${BINDIR} | cut -f1)"
|
2017-02-23 18:45:41 +01:00
|
|
|
|
2017-12-01 12:11:27 +01:00
|
|
|
# cleanup
|
|
|
|
rm -rf ${BINDIR}
|
|
|
|
fi
|
2016-12-21 21:45:01 +01:00
|
|
|
|
|
|
|
return $RES
|
|
|
|
}
|
|
|
|
|
2017-03-24 14:40:38 +01:00
|
|
|
test_job() {
|
|
|
|
local appdir=$1
|
2018-06-22 10:31:44 +02:00
|
|
|
local board=$(echo $2 | cut -f 1 -d':')
|
|
|
|
local toolchain=$(echo $2 | cut -f 2 -d':')
|
2017-03-24 14:40:38 +01:00
|
|
|
local flashfile="$3"
|
|
|
|
|
|
|
|
[ ! -f "$flashfile" ] && {
|
|
|
|
echo "$0: _test(): flashfile \"$flashfile\" doesn't exist!"
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
dwqc \
|
2018-04-11 09:57:18 +02:00
|
|
|
${DWQ_ENV} \
|
2017-03-24 14:40:38 +01:00
|
|
|
${DWQ_JOBID:+--subjob} \
|
|
|
|
--file $flashfile:$appdir/bin/${board}/$(basename $flashfile) \
|
|
|
|
--queue ${TEST_QUEUE:-$board} \
|
|
|
|
--maxfail 1 \
|
2018-06-22 10:31:44 +02:00
|
|
|
"./.murdock run_test $appdir $board:$toolchain"
|
2017-03-24 14:40:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
run_test() {
|
|
|
|
local appdir=$1
|
2018-06-22 10:31:44 +02:00
|
|
|
local board=$(echo $2 | cut -f 1 -d':')
|
|
|
|
local toolchain=$(echo $2 | cut -f 2 -d':')
|
2017-03-24 14:40:38 +01:00
|
|
|
print_worker
|
2018-06-22 10:31:44 +02:00
|
|
|
echo "-- executing tests for $appdir on $board (compiled with $toolchain toolchain):"
|
2018-07-23 09:33:35 +02:00
|
|
|
hook run_test_pre
|
2019-06-28 13:18:38 +02:00
|
|
|
|
|
|
|
# do flashing and building of termdeps simultaneously
|
|
|
|
BOARD=$board TOOLCHAIN=${toolchain} make -C$appdir flash-only termdeps -j2
|
|
|
|
|
|
|
|
# now run the actual test
|
|
|
|
BOARD=$board TOOLCHAIN=${toolchain} make -C$appdir test
|
2018-12-08 23:12:37 +01:00
|
|
|
RES=$?
|
|
|
|
|
|
|
|
if [ $RES -eq 0 -a -n "$TEST_HASH" ]; then
|
|
|
|
echo -n "-- saving test result to cache: "
|
|
|
|
test_cache_put $TEST_HASH
|
|
|
|
fi
|
|
|
|
|
|
|
|
return $RES
|
2017-03-24 14:40:38 +01:00
|
|
|
}
|
|
|
|
|
2016-12-21 21:45:01 +01:00
|
|
|
# execute static tests
|
|
|
|
static_tests() {
|
|
|
|
local repo=${CI_BASE_REPO:-https://github.com/RIOT-OS/RIOT}
|
|
|
|
local branch=${CI_BASE_BRANCH:-master}
|
|
|
|
|
2018-01-22 14:19:52 +01:00
|
|
|
print_worker
|
|
|
|
|
2016-12-21 21:45:01 +01:00
|
|
|
OUT="$(git remote add upstream $repo 2>&1 && git fetch upstream ${branch}:${branch} 2>&1)"
|
|
|
|
RES=$?
|
|
|
|
if [ $RES -ne 0 ]; then
|
|
|
|
echo "$OUT"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
BUILDTEST_MCU_GROUP=static-tests ./dist/tools/ci/build_and_test.sh
|
|
|
|
}
|
|
|
|
|
2019-06-28 15:49:27 +02:00
|
|
|
get_non_compile_jobs() {
|
2016-12-21 21:45:01 +01:00
|
|
|
[ "$STATIC_TESTS" = "1" ] && \
|
|
|
|
echo "$0 static_tests###{ \"jobdir\" : \"exclusive\" }"
|
2019-06-28 15:49:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
get_jobs() {
|
|
|
|
get_non_compile_jobs
|
2016-12-21 21:45:01 +01:00
|
|
|
get_compile_jobs
|
|
|
|
}
|
|
|
|
|
|
|
|
$*
|