diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile.am | 12 | ||||
-rw-r--r-- | contrib/ci/README.md | 62 | ||||
-rwxr-xr-x | contrib/ci/clean | 25 | ||||
-rw-r--r-- | contrib/ci/configure.sh | 50 | ||||
-rw-r--r-- | contrib/ci/deps.sh | 119 | ||||
-rw-r--r-- | contrib/ci/distro.sh | 86 | ||||
-rwxr-xr-x | contrib/ci/make-check-wrap | 52 | ||||
-rw-r--r-- | contrib/ci/misc.sh | 116 | ||||
-rwxr-xr-x | contrib/ci/rpm-spec-builddeps | 35 | ||||
-rwxr-xr-x | contrib/ci/run | 371 | ||||
-rwxr-xr-x | contrib/ci/valgrind-condense | 128 |
12 files changed, 1056 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore index f935a3592..82432e181 100644 --- a/.gitignore +++ b/.gitignore @@ -111,3 +111,4 @@ sss_ssh_authorizedkeys sss_ssh_knownhostsproxy sssd_ssh test-authtok +/ci-build-* diff --git a/Makefile.am b/Makefile.am index 1b183d023..869ebb182 100644 --- a/Makefile.am +++ b/Makefile.am @@ -318,6 +318,11 @@ dist_noinst_SCRIPTS = \ contrib/rhel/update_debug_levels.py \ contrib/fedora/bashrc_sssd \ contrib/fedora/make_srpm.sh \ + contrib/ci/clean \ + contrib/ci/make-check-wrap \ + contrib/ci/rpm-spec-builddeps \ + contrib/ci/run \ + contrib/ci/valgrind-condense \ src/tests/pyhbac-test.py \ src/tests/pysss_murmur-test.py @@ -328,7 +333,12 @@ dist_noinst_DATA = \ src/config/testconfigs/sssd-badversion.conf \ src/config/testconfigs/sssd-invalid.conf \ src/config/testconfigs/sssd-invalid-badbool.conf \ - src/config/etc/sssd.api.d/crash_test_dummy + src/config/etc/sssd.api.d/crash_test_dummy \ + contrib/ci/README.md \ + contrib/ci/configure.sh \ + contrib/ci/deps.sh \ + contrib/ci/distro.sh \ + contrib/ci/misc.sh ############################### # Global compilation settings # diff --git a/contrib/ci/README.md b/contrib/ci/README.md new file mode 100644 index 000000000..6c87200db --- /dev/null +++ b/contrib/ci/README.md @@ -0,0 +1,62 @@ +Continuous integration +====================== + +The executables and modules in this directory implement continuous integration +(CI) tests, which can be run to verify SSSD code quality and validity. + +Supported host distros are Fedora 20 and later, RHEL 6.5 and later, and Debian +Testing. + +The tests are executed by running `contrib/ci/run` from the source tree root. +It accepts options to choose from three test sets: "essential", "moderate" and +"rigorous" (-e/-m/-r), with the essential set selected by default. + +Essential tests include building everything and running the built-in test +suite under Valgrind, completing in under 5 minutes. Valgrind failures are +ignored for now. + +Moderate tests include essential tests, plus a distcheck target build and mock +package builds for Fedora and RHEL on Red Hat distros. They complete in about +15 minutes. + +Rigorous tests include moderate tests, plus a pass with Clang static analyzer +over the whole build and test execution with code coverage collection and +verification, completing in 30 minutes. Static analyzer failures are ignored +for now. + +Use `contrib/ci/clean` to remove test results from the source tree. + + +Setup +----- + +CI requires `lsb_release` command to be available in order to determine host +distro version. On Red Hat distros it is contained in the `redhat-lsb-core` +package and on Debian in `lsb-release`. + +The rest of the required packages CI will attempt to install itself, using +the distribution's package manager invoked through sudo. + +A sudo rule can be employed to selectively avoid password prompts on Red Hat +distros: + + <USER> ALL=(ALL:ALL) NOPASSWD: /usr/bin/yum --assumeyes install -- * + +and Debian-based distros: + + <USER> ALL=(ALL:ALL) NOPASSWD: /usr/bin/apt-get --yes install -- * + +Where `<USER>` is the user invoking CI. + +On Red Hat distros a repository carrying dependencies missing from some +distros needs to be added to yum configuration. See instructions on the +[Copr project page](http://copr-fe.cloud.fedoraproject.org/coprs/lslebodn/sssd-deps/). +That repository is also automatically used by CI during mock builds. + +Package installation can be disabled with the -n/--no-deps option, e.g. for +manual dependency management, or for shaving off a few seconds of execution +time, when dependency changes are not expected. + +On Red Hat distros, where mock builds are ran, it is better to have the +invoking user added to the `mock` group. Otherwise mock builds will be +executed through sudo. diff --git a/contrib/ci/clean b/contrib/ci/clean new file mode 100755 index 000000000..ee18c1070 --- /dev/null +++ b/contrib/ci/clean @@ -0,0 +1,25 @@ +#!/bin/bash +# +# Clean source tree after a run of integration tests. +# +# Copyright (C) 2014 Red Hat +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +set -o nounset -o pipefail -o errexit +export PATH=`dirname "\`readlink -f \"\$0\"\`"`:$PATH + +. misc.sh + +rm_rf_ro ci-* diff --git a/contrib/ci/configure.sh b/contrib/ci/configure.sh new file mode 100644 index 000000000..b92b09441 --- /dev/null +++ b/contrib/ci/configure.sh @@ -0,0 +1,50 @@ +# +# Configure argument management. +# +# Copyright (C) 2014 Red Hat +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +if [ -z ${_CONFIGURE_SH+set} ]; then +declare -r _CONFIGURE_SH= + +. distro.sh + +# List of "configure" arguments. +declare -a CONFIGURE_ARG_LIST=( + "--disable-dependency-tracking" + "--disable-rpath" + "--disable-static" + "--enable-ldb-version-check" + "--with-syslog=journald" +) + + +if [[ "$DISTRO_BRANCH" == -redhat-redhatenterprise*-6.*- ]]; then + CONFIGURE_ARG_LIST+=( + "--disable-cifs-idmap-plugin" + "--with-syslog=syslog" + ) +fi + +if [[ "$DISTRO_BRANCH" == -debian-* ]]; then + CONFIGURE_ARG_LIST+=( + # TODO Remove once libini_config >= 1.1.0 becomes available + "--without-samba" + ) +fi + +declare -r -a CONFIGURE_ARG_LIST + +fi # _CONFIGURE_SH diff --git a/contrib/ci/deps.sh b/contrib/ci/deps.sh new file mode 100644 index 000000000..ba59f7848 --- /dev/null +++ b/contrib/ci/deps.sh @@ -0,0 +1,119 @@ +# +# Dependency management. +# +# Copyright (C) 2014 Red Hat +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +if [ -z ${_DEPS_SH+set} ]; then +declare -r _DEPS_SH= + +. distro.sh + +# Dependency list +declare -a DEPS_LIST=( + lcov + valgrind + xqilla +) + +# True, if all test dependencies are satisfied by the package list +declare DEPS_TESTS_SATISFIED=true + +if [[ "$DISTRO_BRANCH" == -redhat-* ]]; then + declare _DEPS_LIST_SPEC + DEPS_LIST+=( + clang-analyzer + mock + rpm-build + ) + _DEPS_LIST_SPEC=` + sed -e 's/@PACKAGE_VERSION@/0/g' \ + -e 's/@PACKAGE_NAME@/package-name/g' \ + -e 's/@PRERELEASE_VERSION@//g' contrib/sssd.spec.in | + rpm-spec-builddeps /dev/stdin` + readarray -t -O "${#DEPS_LIST[@]}" DEPS_LIST <<<"$_DEPS_LIST_SPEC" + if [[ "$DISTRO_BRANCH" == *-redhatenterprise*-6.*- ]]; then + DEPS_TESTS_SATISFIED=false + fi +fi + +if [[ "$DISTRO_BRANCH" == -debian-* ]]; then + DEPS_LIST+=( + autoconf + automake + autopoint + check + cifs-utils + clang + dh-apparmor + dnsutils + docbook-xml + docbook-xsl + gettext + krb5-config + libaugeas-dev + libc-ares-dev + libcmocka-dev + libcollection-dev + libdbus-1-dev + libdhash-dev + libglib2.0-dev + libini-config-dev + libkeyutils-dev + libkrb5-dev + libldap2-dev + libldb-dev + libltdl-dev + libnl-3-dev + libnl-route-3-dev + libnspr4-dev + libnss3-dev + libpam0g-dev + libpcre3-dev + libpopt-dev + libsasl2-dev + libselinux1-dev + libsemanage1-dev + libsmbclient-dev + libsystemd-journal-dev + libtalloc-dev + libtdb-dev + libtevent-dev + libtool + libxml2-utils + python-dev + samba-dev + systemd + xml-core + xsltproc + ) +fi + +declare -a -r DEPS_LIST +declare -r DEPS_TESTS_SATISFIED + +# Install dependencies. +function deps_install() +{ + distro_pkg_install "${DEPS_LIST[@]}" +} + +# Remove dependencies. +function deps_remove() +{ + distro_pkg_remove "${DEPS_LIST[@]}" +} + +fi # _DEPS_SH diff --git a/contrib/ci/distro.sh b/contrib/ci/distro.sh new file mode 100644 index 000000000..5416bfff3 --- /dev/null +++ b/contrib/ci/distro.sh @@ -0,0 +1,86 @@ +# +# Distribution version discovery +# +# Copyright (C) 2014 Red Hat +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +if [ -z ${_DISTRO_SH+set} ]; then +declare -r _DISTRO_SH= + +# Distribution family (lowercase) +declare DISTRO_FAMILY= +# Distribution ID (lowercase) +declare DISTRO_ID= +# Distribution release (lowercase) +declare DISTRO_RELEASE= + +if [ -e /etc/redhat-release ]; then + DISTRO_FAMILY=redhat +elif [ -e /etc/debian_version ]; then + DISTRO_FAMILY=debian +else + DISTRO_FAMILY=unknown +fi +declare -r DISTRO_FAMILY + +DISTRO_ID=`lsb_release --id | sed -e 's/^[^:]*:\s*\(.*\)$/\L\1\E/'` +declare -r DISTRO_ID +DISTRO_RELEASE=`lsb_release --release | sed -e 's/^[^:]*:\s*\(.*\)$/\L\1\E/'` +declare -r DISTRO_RELEASE + +# Distribution branch (lowercase) +declare -r DISTRO_BRANCH="-$DISTRO_FAMILY-$DISTRO_ID-$DISTRO_RELEASE-" + + +# Install packages. +# Args: [pkg_name...] +function distro_pkg_install() +{ + declare prompt=$'Need root permissions to install packages.\n' + prompt+="Enter sudo password for $USER: " + if [[ "$DISTRO_BRANCH" == -redhat-* ]]; then + [ $# != 0 ] && sudo -p "$prompt" yum --assumeyes install -- "$@" |& + # Pass input to output, fail if a missing package is reported + # TODO Remove and switch to DNF once + # https://bugzilla.redhat.com/show_bug.cgi?id=1128139 is fixed + awk 'BEGIN {s=0} + /^No package .* available.$/ {s=1} + {print} + END {exit s}' + elif [[ "$DISTRO_BRANCH" == -debian-* ]]; then + [ $# != 0 ] && sudo -p "$prompt" apt-get --yes install -- "$@" + else + echo "Cannot install packages on $DISTRO_BRANCH" >&2 + exit 1 + fi +} + +# Remove packages. +# Args: [pkg_name...] +function distro_pkg_remove() +{ + declare prompt=$'Need root permissions to remove packages.\n' + prompt+="Enter sudo password for $USER: " + if [[ "$DISTRO_BRANCH" == -redhat-* ]]; then + [ $# != 0 ] && sudo -p "$prompt" yum --assumeyes remove -- "$@" + elif [[ "$DISTRO_BRANCH" == -debian-* ]]; then + [ $# != 0 ] && sudo -p "$prompt" apt-get --yes remove -- "$@" + else + echo "Cannot remove packages on $DISTRO_BRANCH" >&2 + exit 1 + fi +} + +fi # _DISTRO_SH diff --git a/contrib/ci/make-check-wrap b/contrib/ci/make-check-wrap new file mode 100755 index 000000000..4ad323e5f --- /dev/null +++ b/contrib/ci/make-check-wrap @@ -0,0 +1,52 @@ +#!/bin/bash +# +# Build a make check target, prepending test commands with specified command +# and arguments. +# Args: [make_arg...] [-- wrap_cmd wrap_arg...] +# +# Copyright (C) 2014 Red Hat +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +set -o nounset -o pipefail -o errexit + +declare -a argv=("make") +declare arg + +while [ $# != 0 ]; do + arg="$1" + shift + if [ "$arg" == "--" ]; then + break + fi + argv+=("$arg") +done + +if [ $# != 0 ]; then + # If Makefile supports LOG_COMPILER + if grep -q -w LOG_COMPILER Makefile; then + printf -v arg 'LOG_COMPILER=%q' $1 + argv+=("$arg") + shift + if [ $# != 0 ]; then + printf -v arg ' %q' "$@" + argv+=("LOG_FLAGS=$arg") + fi + else + printf -v arg ' %q' "$@" + argv+=("AUX_TESTS_ENVIRONMENT=$arg") + fi +fi + +"${argv[@]}" diff --git a/contrib/ci/misc.sh b/contrib/ci/misc.sh new file mode 100644 index 000000000..9af848c76 --- /dev/null +++ b/contrib/ci/misc.sh @@ -0,0 +1,116 @@ +# +# Miscellaneous routines. +# +# Copyright (C) 2014 Red Hat +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +if [ -z ${_MISC_SH+set} ]; then +declare -r _MISC_SH= + +# Remove files and directories recursively, forcing write permissions on +# directories. +# Args: path... +function rm_rf_ro() +{ + chmod -Rf u+w -- "$@" || true + rm -Rf -- "$@" +} + +# Run "scan-build" with output to a single specified directory, instead of +# a subdirectory. +# Args: dir [scan_build_arg...] +function scan_build_single() +{ + declare -r dir="$1"; shift + declare entry + declare subdir + declare status + + set +o errexit + scan-build -o "$dir" "$@" + status="$?" + set -o errexit + + for entry in "$dir/"*; do + if [ -n "${subdir+set}" ] || ! [ -d "$entry" ]; then + echo 'Unexpected entries in scan-build output directory' >&2 + exit 1 + fi + subdir="$entry" + done + + mv "$subdir/"* "$dir" + rmdir "$subdir" + return "$status" +} + +# Check if a scan-build result directory has any non-empty .plist files. +# Args: dir +function scan_check() +{ + declare -r dir="$1" + declare f + for f in "$dir"/*.plist; do + if [ "`xqilla -i \"\$f\" /dev/stdin \ + <<<'count(/plist/dict/array[count(*) > 0])'`" != 0 ]; then + return 1 + fi + done + return 0 +} + +# Extract line and function coverage percentage from a "genhtml" or "lcov +# --summary" output. +# Input: "genhtml" or "lcov --summary" output +# Output: lines funcs +function lcov_summary() +{ + sed -ne 's/^ *\(lines\|functions\)\.*: \([0-9]\+\).*$/ \2/p' | + tr -d '\n' + echo +} + +# Check if a "genhtml" or "lcov --summary" output has a minimum coverage +# percentage of lines and functions. +# Input: "genhtml" or "lcov --summary" output +# Args: min_lines min_funcs +function lcov_check() +{ + declare -r min_lines="$1"; shift + declare -r min_funcs="$1"; shift + declare lines + declare funcs + + read -r lines funcs < <(lcov_summary) + ((lines >= min_lines && funcs >= min_funcs)) && return 0 || return 1 +} + +# Check if the current user belongs to a group. +# Args: group_name +function memberof() +{ + declare -r group_name="$1" + declare group_id + declare id + group_id=`getent group "$group_name" | cut -d: -f3` || return 1 + for id in "${GROUPS[@]}"; do + if [ "$id" == "$group_id" ]; then + return 0 + fi + done + return 1 +} + +fi # _MISC_SH diff --git a/contrib/ci/rpm-spec-builddeps b/contrib/ci/rpm-spec-builddeps new file mode 100755 index 000000000..b73ed2083 --- /dev/null +++ b/contrib/ci/rpm-spec-builddeps @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# +# Extract build dependencies from an RPM .spec file. +# +# Copyright (C) 2014 Red Hat +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import sys +import re +import rpm + +def usage(file): + file.write(("Usage: %s SPEC\n" + + "Extract build dependencies from an RPM .spec file.\n") % + re.match(".*?([^/]+)$", sys.argv[0]).group(1)) + +if len(sys.argv) != 2: + usage(sys.stderr) + sys.exit(1) + +spec = rpm.spec(sys.argv[1]) +for d in rpm.ds(spec.sourceHeader, 'requires'): + print d.DNEVR()[2:] diff --git a/contrib/ci/run b/contrib/ci/run new file mode 100755 index 000000000..b8a296aea --- /dev/null +++ b/contrib/ci/run @@ -0,0 +1,371 @@ +#!/bin/bash +# +# Run continuous integration tests. +# +# Copyright (C) 2014 Red Hat +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +set -o nounset -o pipefail -o errexit +export PATH=`dirname "\`readlink -f \"\$0\"\`"`:$PATH +export LC_ALL=C + +. deps.sh +. distro.sh +. configure.sh +. misc.sh + +declare -r DEBUG_CFLAGS="-g3 -O2" +declare -r COVERAGE_CFLAGS="-g3 -O0 --coverage" +declare -r ARCH=`uname -m` +declare -r CPU_NUM=`getconf _NPROCESSORS_ONLN` +declare -r TITLE_WIDTH=24 +declare -r RESULT_WIDTH=18 + +# Minimum percentage of code lines covered by tests +declare -r COVERAGE_MIN_LINES=15 +# Minimum percentage of code functions covered by tests +declare -r COVERAGE_MIN_FUNCS=0 + +declare BASE_PFX="" +declare DEPS=true +declare BASE_DIR=`pwd` +declare MODERATE=false +declare RIGOROUS=false + +# Output program usage information. +function usage() +{ + cat <<EOF +Usage: `basename "$0"` [OPTION...] +Run continuous integration tests. + +Options: + -h, --help Output this help message and exit. + -p, --prefix=STRING Use STRING as the prefix to prepend to file and + directory paths in output. + -n, --no-deps Don't attempt to install dependencies. + -e, --essential Run the essential subset of tests. + -m, --moderate Run the moderate subset of tests. + -r, --rigorous, + -f, --full Run the rigorous (full) set of tests. + +Default options: --essential +EOF +} + +# Output a file display path: a path relocated from base directory (BASE_DIR) +# to base prefix (BASE_PFX). +# Args: path +function disppath() +{ + declare -r path=`readlink -f "$1"` + printf "%s" "$BASE_PFX${path:${#BASE_DIR}+1}" +} + +# Run a stage. +# Args: id cmd [arg...] +function stage() +{ + declare -r id="$1"; shift + declare -r log="ci-$id.log" + declare status + declare start + declare end + declare duration + + printf "%-${TITLE_WIDTH}s" "$id:" + + { + printf "Start: " + start=`date +%s` + date --date="@$start" + set +o errexit + ( + set -o errexit -o xtrace + "$@" + ) + status=$? + set -o errexit + printf "End: " + end=`date +%s` + date --date="@$end" + } &> "$log" + + duration=$((end - start)) + + if [ "$status" == 0 ]; then + printf 'success ' + else + printf 'failure ' + fi + printf "%02u:%02u:%02u " \ + $((duration / (60 * 60))) \ + $((duration / 60 % 60)) \ + $((duration % 60)) + disppath "$log" + printf "\n" + + return "$status" +} + +# Execute mock as is, or, if the user is not in the "mock" group, under sudo, +# which has password prompt/input on the console, instead of stderr/stdin. +# Args: [mock_arg...] +function mock_privileged() +{ + if memberof mock; then + mock "$@" + else + declare prompt=$'Not a "mock" group member.\n' + prompt+="To run mock enter sudo password for $USER: " + sudo -p "$prompt" mock "$@" + fi +} + +# Execute mock_privileged with extra chroot configuration added. +# Args: chroot [mock_arg...] +# Input: extra configuration +function mock_privileged_conf() +{ + declare -r chroot="$1"; shift + declare conf_dir + + conf_dir=`mktemp --tmpdir --directory mock-config.XXXXXXXX` + trap 'trap - RETURN; rm -R "$conf_dir";' RETURN + cp -r /etc/mock/* "$conf_dir"/ + cat >> "${conf_dir}/${chroot}.cfg" + mock_privileged --configdir="$conf_dir" --root="$chroot" "$@" +} + +# Execute mock_privileged with dependency package source configuration added. +# Args: chroot [mock_arg...] +function mock_privileged_deps() +{ + declare -r chroot="$1"; shift + declare repo + + if [[ "$chroot" == fedora-* ]]; then + repo='fedora-$releasever-$basearch' + elif [[ "$chroot" =~ epel-([0-9]+) ]]; then + repo="epel-${BASH_REMATCH[1]}-\$basearch" + else + echo "Unknown chroot config: $chroot" >&2 + exit 1 + fi + + mock_privileged_conf "$chroot" "$@" <<<" +config_opts['yum.conf'] += ''' +[sssd-deps] +name=Extra SSSD dependencies +baseurl=http://copr-be.cloud.fedoraproject.org/results/lslebodn/sssd-deps/$repo/ +skip_if_unavailable=true +gpgcheck=0 +enabled=1 +''' +" +} + +# Run debug build checks. +function build_debug() +{ + export CFLAGS="$DEBUG_CFLAGS" + declare test_dir + declare test_dir_distcheck + declare distcheck_configure_args + declare status + + test_dir=`mktemp --directory /dev/shm/ci-test-dir.XXXXXXXX` + stage configure "$BASE_DIR/configure" \ + "${CONFIGURE_ARG_LIST[@]}" \ + --with-test-dir="$test_dir" + + # Not building "tests" due to https://fedorahosted.org/sssd/ticket/2350 + stage make-tests make-check-wrap -j $CPU_NUM check -- true + + # Ignored until issues found by Valgrind are fixed + status=0 + CK_FORK=no \ + stage make-check-valgrind \ + make-check-wrap -j $CPU_NUM check -- \ + libtool --mode=execute \ + valgrind-condense 99 '!(*.py)' -- \ + --vgdb=no \ + --trace-children=yes \ + --trace-children-skip='*/bin/*,*/sbin/*' \ + --leak-check=full || + status=$? + mv "$test_dir" ci-test-dir + + if "$MODERATE"; then + test_dir_distcheck=`mktemp --directory /dev/shm/ci-test-dir.XXXXXXXX` + # Single thread due to https://fedorahosted.org/sssd/ticket/2354 + status=0 + printf -v distcheck_configure_args " %q" \ + "${CONFIGURE_ARG_LIST[@]}" \ + "--with-test-dir=$test_dir_distcheck" + stage make-distcheck make distcheck \ + AUX_DISTCHECK_CONFIGURE_FLAGS=" \ + $distcheck_configure_args" || + status=$? + mv "$test_dir_distcheck" ci-test-dir-distcheck + ((status == 0)) + + if [[ "$DISTRO_BRANCH" == -redhat-* ]]; then + stage make-srpm env -u CFLAGS -- make srpm + stage mock-epel6 mock_privileged_deps "epel-6-$ARCH" \ + --resultdir ci-mock-result-epel6 \ + rpmbuild/SRPMS/*.src.rpm + stage mock-fedora20 mock_privileged_deps "fedora-20-$ARCH" \ + --resultdir ci-mock-result-fedora20 \ + rpmbuild/SRPMS/*.src.rpm + fi + fi + + unset CFLAGS +} + +# Run coverage build checks. +function build_coverage() +{ + declare -r scan_report_dir="ci-report-scan" + declare -r coverage_report_dir="ci-report-coverage" + declare test_dir + + export CFLAGS="$COVERAGE_CFLAGS" + + test_dir=`mktemp --directory /dev/shm/ci-test-dir.XXXXXXXX` + stage configure scan-build "$BASE_DIR/configure" \ + "${CONFIGURE_ARG_LIST[@]}" \ + --with-test-dir="$test_dir" + + # Build everything, including tests + # Not building "tests" due to https://fedorahosted.org/sssd/ticket/2350 + stage scan-make-tests scan_build_single \ + "$scan_report_dir" \ + -plist-html \ + --html-title="sssd - scan-build report" \ + make-check-wrap -j $CPU_NUM check -- true + printf "%-$((TITLE_WIDTH + RESULT_WIDTH))s%s\n" \ + "scan report:" \ + "`disppath \"\$scan_report_dir/index.html\"`" + # Ignored until issues found by the scanner are fixed + stage scan-check scan_check "$scan_report_dir" || + true + + stage lcov-pre lcov --capture --initial --directory . \ + --base-directory "$BASE_DIR" \ + --output-file ci-base.info + # Run tests + stage make-check scan-build make -j $CPU_NUM check || true + mv "$test_dir" ci-test-dir + + stage lcov-post lcov --capture --directory . \ + --base-directory "$BASE_DIR" \ + --output-file ci-check.info + stage lcov-merge lcov --add-tracefile ci-base.info \ + --add-tracefile ci-check.info \ + --output-file ci-dirty.info + stage lcov-clean lcov --remove ci-dirty.info \ + "/usr/*" "src/tests/*" \ + --output-file ci.info + stage genhtml eval 'genhtml --output-directory \ + "$coverage_report_dir" \ + --title "sssd" --show-details \ + --legend --prefix "$BASE_DIR" \ + ci.info |& tee ci-genhtml.out' + printf "%-$((TITLE_WIDTH + RESULT_WIDTH))s%s\n" \ + "coverage report:" \ + "`disppath \"\$coverage_report_dir/index.html\"`" + + # If dependencies for all tests are satisfied + # and so all the tests should have been built and ran. + if "$DEPS_TESTS_SATISFIED"; then + stage lcov-check eval 'lcov_check "$COVERAGE_MIN_LINES" \ + "$COVERAGE_MIN_FUNCS" \ + < ci-genhtml.out' + fi + + unset CFLAGS +} + +# Run a build inside a sub-directory. +# Args: id cmd [arg...] +function run_build() +{ + declare -r id="$1"; shift + declare -r dir="ci-build-$id" + + mkdir "$dir" + printf "%-$((TITLE_WIDTH + RESULT_WIDTH))s%s\n" \ + "${id^^} BUILD:" "`disppath \"\$dir\"`" + + cd "$dir" + "$@" + cd .. +} + +# +# Main routine +# +declare args_expr +args_expr=`getopt --name \`basename "\$0"\` \ + --options hp:nemrf \ + --longoptions help,prefix:,no-deps \ + --longoptions essential,moderate,rigorous,full \ + -- "$@"` +eval set -- "$args_expr" + +while true; do + case "$1" in + -h|--help) + usage; exit 0;; + -p|--prefix) + BASE_PFX="$2"; shift 2;; + -n|--no-deps) + DEPS=false; shift;; + -e|--essential) + MODERATE=false; RIGOROUS=false; shift;; + -m|--moderate) + MODERATE=true; RIGOROUS=false; shift;; + -r|--rigorous|-f|--full) + MODERATE=true; RIGOROUS=true; shift;; + --) + shift; break;; + *) + echo "Unknown option: $1" >&2 + exit 1;; + esac +done + +if [ $# != 0 ]; then + echo "Positional arguments are not accepted." >&2 + usage >&2 + exit 1 +fi + +trap 'echo FAILURE' EXIT +rm_rf_ro ci-* +export V=1 +if "$DEPS"; then + stage install-deps deps_install +fi +stage autoreconf autoreconf --install --force +run_build debug build_debug +if "$RIGOROUS"; then + run_build coverage build_coverage +fi +unset V +trap - EXIT +echo SUCCESS diff --git a/contrib/ci/valgrind-condense b/contrib/ci/valgrind-condense new file mode 100755 index 000000000..b838039e2 --- /dev/null +++ b/contrib/ci/valgrind-condense @@ -0,0 +1,128 @@ +#!/bin/bash +# +# Run Valgrind, condensing logged reports into an exit code. +# +# Copyright (C) 2014 Red Hat +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +set -o nounset -o pipefail -o errexit +shopt -s extglob + +function usage() +{ + cat <<EOF +Usage: `basename "$0"` ERROR_EXITCODE [PATH_PATTERN...] [-- VALGRIND_ARG...] +Run Valgrind, condensing logged reports into an exit code. + +Arguments: + ERROR_EXITCODE An exit code to return if at least one error is found in + Valgrind log files. + PATH_PATTERN An extended glob pattern matching (original) paths to + programs to execute under Valgrind. Execution is skipped + and success is returned for non-matching programs. Without + patterns, all programs match. + VALGRIND_ARG An argument to pass to Valgrind after the arguments + specified by `basename "$0"`. + +The first non-option VALGRIND_ARG will be considered the path to the program +to execute under Valgrind and will be used in naming Valgrind log files as +such: + + PROGRAM_NAME.PID.valgrind.log + +where PROGRAM_NAME is the filename portion of the program path and PID is the +executed process ID. If the last directory of the program path is ".libs" and +the filename begins with "lt-", both are removed to match the name of libtool +frontend script. All files matching PROGRAM_NAME.*.valgrind.log are removed +before invoking Valgrind. + +If an error is found in Valgrind log files, ERROR_EXITCODE is returned, +otherwise Valgrind exit code is returned. +EOF +} + + +if [[ $# == 0 ]]; then + echo "Invalid number of arguments." >&2 + usage >&2 + exit 1 +fi + +declare error_exitcode="$1"; shift +declare -a path_pattern_list=() +declare arg +declare got_dash_dash +declare program_path +declare path_pattern +declare match +declare program_name +declare status=0 + +# Extract path patterns +while [[ $# != 0 ]]; do + arg="$1" + shift + if [[ "$arg" == "--" ]]; then + break + else + path_pattern_list+=("$arg") + fi +done + +# Find program path argument +got_dash_dash=false +for arg in "$@"; do + if [[ "$arg" == "--" ]]; then + got_dash_dash=true + elif "$got_dash_dash" || [[ "$arg" != -* ]]; then + program_path="$arg" + break + fi +done + +if [[ -z "${program_path+set}" ]]; then + echo "Program path not specified." >&2 + usage >&2 + exit 1 +fi + +# Match against path patterns, if any +if [[ ${#path_pattern_list[@]} != 0 ]]; then + match=false + for path_pattern in "${path_pattern_list[@]}"; do + if [[ "$program_path" == $path_pattern ]]; then + match=true + fi + done + if ! $match; then + exit 0 + fi +fi + +# Generate original path from libtool path +program_path=`sed -e 's/^\(.*\/\)\?\.libs\/lt-\([^\/]\+\)$/\1\2/' \ + <<<"$program_path"` + +program_name=`basename "$program_path"` + +rm -f "$program_name".*.valgrind.log +valgrind --log-file="$program_name.%p.valgrind.log" "$@" || status=$? + +if grep -q '^==[0-9]\+== *ERROR SUMMARY: *[1-9]' \ + "$program_name".*.valgrind.log; then + exit "$error_exitcode" +else + exit "$status" +fi |