blob: 5bfdccc0f3ba27bb478553ab3244028acec78d40 [file] [log] [blame]
# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
# Distributed under the terms of the GNU General Public License v2
#
# Original Author: The Chromium OS Authors <chromium-os-dev@chromium.org>
# Purpose: Eclass for handling autotest test packages
#
RDEPEND="( autotest? ( >=chromeos-base/autotest-0.0.1-r3 ) )"
IUSE="+buildcheck autotest opengles"
# Ensure the configures run by autotest pick up the right config.site
export CONFIG_SITE="/usr/share/config.site"
export AUTOTEST_WORKDIR="${WORKDIR}/autotest-work"
# @ECLASS-VARIABLE: AUTOTEST_CLIENT_*
# @DESCRIPTION:
# Location of the appropriate test directory inside ${S}
: ${AUTOTEST_CLIENT_TESTS:=client/tests}
: ${AUTOTEST_CLIENT_SITE_TESTS:=client/site_tests}
: ${AUTOTEST_SERVER_TESTS:=server/tests}
: ${AUTOTEST_SERVER_SITE_TESTS:=server/site_tests}
: ${AUTOTEST_CONFIG:=client/config}
: ${AUTOTEST_DEPS:=client/deps}
: ${AUTOTEST_PROFILERS:=client/profilers}
# @ECLASS-VARIABLE: AUTOTEST_*_LIST
# @DESCRIPTION:
# The list of deps/configs/profilers provided with this package
: ${AUTOTEST_CONFIG_LIST:=*}
: ${AUTOTEST_DEPS_LIST:=*}
: ${AUTOTEST_PROFILERS_LIST:=*}
# @ECLASS-VARIABLE: AUTOTEST_FORCE_LIST
# @DESCRIPTION:
# Sometimes we just want to forget about useflags and build what's inside
: ${AUTOTEST_FORCE_TEST_LIST:=}
# @ECLASS-VARIABLE: AUTOTEST_FILE_MASK
# @DESCRIPTION:
# The list of 'find' expressions to find in the resulting image and delete
: ${AUTOTEST_FILE_MASK:=}
function fast_cp() {
cp -l "$@" || cp "$@"
}
function get_test_list() {
if [ -n "${AUTOTEST_FORCE_TEST_LIST}" ]; then
# list forced
echo "${AUTOTEST_FORCE_TEST_LIST}"
return
fi
# we cache the result of this operation in AUTOTEST_TESTS,
# because it's expensive and does not change over the course of one ebuild run
local result="${IUSE_TESTS//[+-]tests_/}"
result="${result//tests_/}"
result=$(for test in ${result}; do use tests_${test} && echo -n "${test} "; done)
echo "${result}"
}
# Pythonify the list of packages
function pythonify_test_list() {
local result
result=$(for test in $*; do echo -n "${test},"; done)
echo ${result}
}
# Create python package init files for top level test case dirs.
function touch_init_py() {
local dirs=${1}
for base_dir in $dirs
do
local sub_dirs="$(find ${base_dir} -maxdepth 1 -type d)"
for sub_dir in ${sub_dirs}
do
touch ${sub_dir}/__init__.py
done
touch ${base_dir}/__init__.py
done
}
function setup_cross_toolchain() {
if tc-is-cross-compiler ; then
tc-export CC CXX AR RANLIB LD NM STRIP
export PKG_CONFIG_PATH="${ROOT}/usr/lib/pkgconfig/"
export CCFLAGS="$CFLAGS"
fi
# TODO(fes): Check for /etc/hardened for now instead of the hardened
# use flag because we aren't enabling hardened on the target board.
# Rather, right now we're using hardened only during toolchain compile.
# Various tests/etc. use %ebx in here, so we have to turn off PIE when
# using the hardened compiler
if use x86 ; then
if use hardened ; then
#CC="${CC} -nopie"
append-flags -nopie
fi
fi
}
function create_autotest_workdir() {
local dst=${1}
# create a working enviroment for pre-building
ln -sf "${SYSROOT}"/usr/local/autotest/{conmux,tko,global_config.ini,shadow_config.ini} "${dst}"/
# NOTE: in order to make autotest not notice it's running from /usr/local/, we need
# to make sure the binaries are real, because they do the path magic
local root_path base_path
for base_path in utils server; do
root_path="${SYSROOT}/usr/local/autotest/${base_path}"
mkdir -p "${dst}/${base_path}"
for entry in $(ls "${root_path}"); do
if [ -d ${entry} ]; then
ln -sf "${root_path}/${entry}" "${dst}/${base_path}/"
else
cp -f ${root_path}/${entry} ${dst}/${base_path}/
fi
done
done
for base_path in client client/bin; do
root_path="${SYSROOT}/usr/local/autotest/${base_path}"
mkdir -p "${dst}/${base_path}"
# Skip bin, because it is processed separately, and test-provided dirs
# Also don't symlink to packages, because that kills the build
for entry in $(ls "${root_path}" | \
grep -v "\(bin\|tests\|site_tests\|config\|deps\|profilers\|packages\)$"); do
ln -sf "${root_path}/${entry}" "${dst}/${base_path}/"
done
done
# replace the important binaries with real copies
for base_path in autotest autotest_client; do
root_path="${SYSROOT}/usr/local/autotest/client/bin/${base_path}"
rm "${dst}/client/bin/${base_path}"
cp -f ${root_path} "${dst}/client/bin/${base_path}"
done
# Selectively pull in deps that are not provided by the current test package
for base_path in config deps profilers; do
for dir in "${SYSROOT}/usr/local/autotest/client/${base_path}"/*; do
if [ -d "${dir}" ] && \
! [ -d "${AUTOTEST_WORKDIR}/client/${base_path}/$(basename ${dir})" ]; then
# directory does not exist, create a symlink
ln -sf "${dir}" "${AUTOTEST_WORKDIR}/client/${base_path}/$(basename ${dir})"
fi
done
done
}
function print_test_dirs() {
local testroot="${1}"
pushd "${testroot}" 1> /dev/null
for test in *; do
if [ -d "${test}" ] && [ -f "${test}/${test}".py ]; then
echo "${test}"
fi
done
popd 1> /dev/null
}
# checks IUSE_TESTS and sees if at least one of these is enabled
function are_we_used() {
if ! use autotest; then
# unused
return 1
fi
[ -n "$(get_test_list)" ] && return 0
# unused
return 1
}
function autotest_src_prepare() {
are_we_used || return 0
einfo "Preparing tests"
# FIXME: These directories are needed, autotest quietly dies if
# they don't even exist. They may, however, stay empty.
mkdir -p "${AUTOTEST_WORKDIR}"/client/tests
mkdir -p "${AUTOTEST_WORKDIR}"/client/site_tests
mkdir -p "${AUTOTEST_WORKDIR}"/client/config
mkdir -p "${AUTOTEST_WORKDIR}"/client/deps
mkdir -p "${AUTOTEST_WORKDIR}"/client/profilers
mkdir -p "${AUTOTEST_WORKDIR}"/server/tests
mkdir -p "${AUTOTEST_WORKDIR}"/server/site_tests
TEST_LIST=$(get_test_list)
# Pull in the individual test cases.
for l1 in client server; do
for l2 in site_tests tests; do
# pick up the indicated location of test sources
eval srcdir=${WORKDIR}/${P}/\${AUTOTEST_${l1^^*}_${l2^^*}}
# test does have this directory
for test in ${TEST_LIST}; do
if [ -d "${srcdir}/${test}" ]; then
fast_cp -fpr "${srcdir}/${test}" "${AUTOTEST_WORKDIR}/${l1}/${l2}"/ || die
fi
done
done
done
# Pull in all the deps provided by this package, selectively.
for l2 in config deps profilers; do
# pick up the indicated location of test sources
eval srcdir=${WORKDIR}/${P}/\${AUTOTEST_${l2^^*}}
if [ -d "${srcdir}" ]; then # test does have this directory
pushd "${srcdir}" 1> /dev/null
eval deplist=\${AUTOTEST_${l2^^*}_LIST}
if [ "${deplist}" = "*" ]; then
fast_cp -fpr * "${AUTOTEST_WORKDIR}/client/${l2}"
else
for dir in ${deplist}; do
fast_cp -fpr "${dir}" "${AUTOTEST_WORKDIR}/client/${l2}"/ || die
done
fi
popd 1> /dev/null
fi
done
# FIXME: We'd like if this were not necessary, and autotest supported out-of-tree build
create_autotest_workdir "${AUTOTEST_WORKDIR}"
# Each test directory needs to be visited and have an __init__.py created.
# However, that only applies to the directories which have a main .py file.
pushd "${AUTOTEST_WORKDIR}" > /dev/null || die "AUTOTEST_WORKDIR does not exist?!"
for dir in client/tests client/site_tests server/tests server/site_tests; do
pushd "${dir}" > /dev/null || continue
for sub in *; do
[ -f "${sub}/${sub}.py" ] || continue
touch_init_py ${sub}
done
popd > /dev/null
done
popd > /dev/null
# Cleanup checked-in binaries that don't support the target architecture
[[ ${E_MACHINE} == "" ]] && return 0;
rm -fv $( scanelf -RmyBF%a "${AUTOTEST_WORKDIR}" | grep -v -e ^${E_MACHINE} )
}
function autotest_src_compile() {
if ! are_we_used; then
ewarn "***************************************************************"
ewarn "* Not building any tests, because the requested list is empty *"
ewarn "***************************************************************"
return 0
fi
einfo "Compiling tests"
pushd "${AUTOTEST_WORKDIR}" 1> /dev/null
setup_cross_toolchain
if use opengles ; then
graphics_backend=OPENGLES
else
graphics_backend=OPENGL
fi
# HACK: Some of the autotests depend on SYSROOT being defined, and die
# a gruesome death if it isn't. But SYSROOT does not need to exist, for
# example on the host, it doesn't. Let's define a compatible variable
# here in case we have none.
export SYSROOT=${SYSROOT:-"/"}
# This only prints the tests that have the associated .py
# (and therefore a setup function)
local prebuild_test_dirs="
client/tests client/site_tests
server/tests server/site_tests"
TESTS=$(\
for dir in ${prebuild_test_dirs}; do
print_test_dirs "${AUTOTEST_WORKDIR}/${dir}"
done | sort | uniq
)
NR_TESTS=$(echo ${TESTS}|wc -w)
if ! [ "${NR_TESTS}" = "0" ]; then
einfo "Building tests (${NR_TESTS}):"
einfo "${TESTS}"
NORMAL=$(echo -e "\e[0m")
GREEN=$(echo -e "\e[1;32m")
RED=$(echo -e "\e[1;31m")
# Call autotest to prebuild all test cases.
# Parse output through a colorifying sed script
( GRAPHICS_BACKEND="$graphics_backend" LOGNAME=${SUDO_USER} \
client/bin/autotest_client --quiet \
--client_test_setup=$(pythonify_test_list ${TESTS}) \
|| ! use buildcheck || die "Tests failed to build."
) | sed -e "s/\(INFO:root:setup\)/${GREEN}* \1${NORMAL}/" \
-e "s/\(ERROR:root:\[.*\]\)/${RED}\1${NORMAL}/"
else
einfo "No tests to prebuild, skipping"
fi
# Cleanup some temp files after compiling
for mask in '*.[do]' ${AUTOTEST_FILE_MASK}; do
einfo "Purging ${mask}"
find . -name "${mask}" -delete
done
popd 1> /dev/null
}
function autotest_src_install() {
are_we_used || return 0
einfo "Installing tests"
# Install all test cases, after setup has been called on them.
# We install everything, because nothing else is copied into the
# testcase directories besides what this package provides.
local instdirs="
client/tests
client/site_tests
server/tests
server/site_tests"
for dir in ${instdirs}; do
[ -d "${AUTOTEST_WORKDIR}/${dir}" ] || continue
insinto /usr/local/autotest/$(dirname ${dir})
doins -r "${AUTOTEST_WORKDIR}/${dir}"
done
# Install the deps, configs, profilers.
# Difference from above is, we don't install the whole thing, just
# the stuff provided by this package, by looking at AUTOTEST_*_LIST.
instdirs="
config
deps
profilers"
for dir in ${instdirs}; do
[ -d "${AUTOTEST_WORKDIR}/client/${dir}" ] || continue
insinto /usr/local/autotest/client/${dir}
eval provided=\${AUTOTEST_${dir^^*}_LIST}
# * means provided all, figure out the list from ${S}
if [ "${provided}" = "*" ]; then
if eval pushd "${WORKDIR}/${P}/\${AUTOTEST_${dir^^*}}" &> /dev/null; then
provided=$(ls)
popd 1> /dev/null
else
provided=""
fi
fi
for item in ${provided}; do
doins -r "${AUTOTEST_WORKDIR}/client/${dir}/${item}"
done
done
# TODO: Not all needs to be executable, but it's hard to pick selectively.
# The source repo should already contain stuff with the right permissions.
chmod -R a+x "${D}"/usr/local/autotest/*
}
function autotest_prepackage() {
are_we_used || return 0
TEST_DEP="${1}"
einfo "Pre-packaging test dep ${TEST_DEP}"
dodir /usr/local/autotest-pkgs
"${AUTOTEST_WORKDIR}"/utils/packager.py -d "${TEST_DEP}" \
-r "${D}"/usr/local/autotest-pkgs upload \
|| die "Can't preinstall ${1}"
}
EXPORT_FUNCTIONS src_compile src_prepare src_install