#!/bin/bash set -euo pipefail IFS=$'\n\t' # # Test harness for the atomic CLI. # export PYTHONPATH=${PYTHONPATH:-$(pwd)} export WORK_DIR=$(mktemp -p $(pwd) -d -t .tmp.XXXXXXXXXX) export DOCKER=${DOCKER:-"/usr/bin/docker"} export SECRET=`dd if=/dev/urandom bs=4096 count=1 2> /dev/null | sha256sum` export ATOMIC_LIBEXEC="$(pwd)" export ATOMIC_CLIENT="$(pwd)/atomic_dbus_client.py" mkdir $WORK_DIR/ostree-repo ostree --repo=$WORK_DIR/ostree-repo init --mode=bare-user export ATOMIC_OSTREE_REPO=$WORK_DIR/ostree-repo # This image contains the secret, so it needs to be rebuilt each time. cat > tests/test-images/Dockerfile.secret < ${LOG} cleanup () { rm -rf ${WORK_DIR} } trap cleanup EXIT _checksum () { if [[ -d "${1}" ]]; then CHK=`find "${1}" -type f -exec sha256sum {} \; | sha256sum` echo "${CHK}" return 0 fi if [[ -e "${1}" ]]; then echo "$(sha256sum ${1})" fi } # Ensure the test-environment has a standard set of images. # This function will not rebuild images if the dockerfile # is the same as its last build. make_docker_images () { echo "${SECRET}" > ${WORK_DIR}/secret echo "Pulling standard images from Docker Hub..." | tee -a ${LOG} ${DOCKER} pull centos>> ${LOG} echo "Building images from tests/test-images..." | tee -a ${LOG} for df in `find ./tests/test-images/ -name 'Dockerfile.*' | sort`; do # Don't include directories for dockerfile data if [[ -d "${df}" ]]; then continue fi BASE_NAME="$(basename ${df})" chksum=$(_checksum ${df}) IFS=$'.' read -a split <<< "${BASE_NAME}" iname="atomic-test-${split[1]}" # If there is a matching Dockerfile.X.d, then include its contents # in the checksum data. chksum="${chksum}$(_checksum ${df}.d)" set +e i_chksum=`${DOCKER} inspect -f '{{ .Config.Labels.Checksum }}' \ ${iname} 2> /dev/null` if [[ ${i_chksum} = "" ]] || \ [[ "${i_chksum}" = "${chksum}" ]]; then printf "\tSkipped : ${iname}\n" continue fi set -e # Copy the dockerfile into the build directory, then label the image # with the original Dockerfile's checksum. This allows us to prevent # rebuilding images df_cp=${WORK_DIR}/${BASE_NAME} cp ${df} ${df_cp} printf "\nLABEL \"Checksum\"=\"${chksum}" >> ${df_cp} # Copy help.1 into atomic-test-1 if [[ ${iname} = "atomic-test-1" ]]; then cp ./tests/test-images/help.1 ${WORK_DIR} fi # Copy help.sh into atomic-test-3 if [ ${iname} = "atomic-test-3" -o ${iname} = "atomic-test-4" ]; then cp ./tests/test-images/help.sh ${WORK_DIR} fi # Copy install.sh into atomic-test-6 if [[ ${iname} = "atomic-test-6" ]]; then cp ./tests/test-images/install.sh ${WORK_DIR} cp ./tests/test-images/show-hostname.sh ${WORK_DIR} fi # Copy needed files into atomic-test-system if [[ ${iname} = "atomic-test-system" ]]; then cp ./tests/test-images/system-container-files/* ${WORK_DIR} fi # Copy needed files into atomic-test-system-update if [[ ${iname} = "atomic-test-system-update" ]]; then cp ./tests/test-images/system-container-update-files/* ${WORK_DIR} fi # Copy needed files atomic-test-system-hostfs if [[ ${iname} = "atomic-test-system-hostfs" ]]; then cp ./tests/test-images/system-container-files-hostfs/* ${WORK_DIR} fi # Copy runonce files into into atomic-test-runonce-system if [[ ${iname} = "atomic-test-runonce" ]]; then cp ./tests/test-images/system-container-runonce-files/* ${WORK_DIR} fi # Remove the old image... Though there may not be one. set +e ${DOCKER} rmi ${iname} &>> ${LOG} set -e if [[ -d "${df}.d" ]]; then cp -r "${df}.d" "${WORK_DIR}/${BASE_NAME}.d" fi SECONDS=0 ${DOCKER} build -t ${iname} -f ${df_cp} ${WORK_DIR} >> ${LOG} DURATION=$SECONDS # Clean up build files. rm "${df_cp}" if [[ -d "${WORK_DIR}/${BASE_NAME}.d" ]]; then rm -r "${WORK_DIR}/${BASE_NAME}.d" fi printf "\tBuilt : ${iname} in $DURATION seconds\n" done } make_docker_images if ! skopeo copy docker-daemon://atomic-test-system:latest ostree:test@$ATOMIC_OSTREE_REPO; then export SKOPEO_NO_OSTREE=1 fi if [ ! -n "${PYTHON+ }" ]; then if hash python3 > /dev/null 2>&1 /dev/null; then PYTHON=$(hash -t python3) elif type python3 > /dev/null 2>&1; then PYTHON=$(type python3 | awk '{print $3}') elif hash python2 > /dev/null 2>&1; then PYTHON=$(hash -t python2) elif type python2 > /dev/null 2>&1; then PYTHON=$(type python2 | awk '{print $3}') else PYTHON='/usr/bin/python' fi fi export PYTHON=$PYTHON # Add images with INSTALL labels to /var/lib/atomic/install.json INSTALL_DATA_FILE="$(pwd)/install.json" INSTALL_DATA=`docker images --no-trunc | awk '/atomic-test-/ {printf "\"%s\": {\"install_id\": \"%s\"},\n", $1, $3}' | sed 's/sha256://g' | sed '$ s/,$//'` echo "{$INSTALL_DATA}" > ${INSTALL_DATA_FILE} export ATOMIC_INSTALL_JSON=$INSTALL_DATA_FILE echo "UNIT TESTS:" COVERAGE_BIN=${COVERAGE_BIN-"/usr/bin/coverage"} if [[ ! -x "${COVERAGE_BIN}" ]]; then # Check to see if it is in local instead. COVERAGE_BIN="/usr/local/bin/coverage" fi if [[ ! -x "${COVERAGE_BIN}" ]]; then # The executable is "coverage2" on systems with default python3 and no # python3 install. COVERAGE_BIN="/usr/bin/coverage2" fi if [[ ! -x "${COVERAGE_BIN}" ]]; then COVERAGE_BIN="/usr/bin/coverage3" fi if [[ -x "${COVERAGE_BIN}" ]]; then COVERAGE="${COVERAGE_BIN} run --source=./Atomic/ --branch" else COVERAGE="${PYTHON:-/usr/bin/python}" fi if [ ! -n "${TEST_INTEGRATION+ }" ]; then set +e # Was a single test requested? if [ -n "${TEST_UNIT+ }" ]; then UTEST=tests/unit/test_${TEST_UNIT}.py # Make sure the test actually exists if [ ! -e ${UTEST} ]; then echo "Failed to find the unittest ${UTEST}" exit 1 fi ${COVERAGE} ${UTEST} | tee -a ${LOG} else ${COVERAGE} -m unittest discover ./tests/unit/ | tee -a ${LOG} fi _UNIT_FAIL="$?" set -e else echo " SKIPPING UNIT TESTS..." _UNIT_FAIL=0 fi # CLI integration tests. let failures=0 || true printf "\nINTEGRATION TESTS:\n" | tee -a ${LOG} export ATOMIC_NO_DEBUG="atomic" export ATOMIC="atomic --debug" if [[ -x "${COVERAGE_BIN}" ]]; then export ATOMIC="${COVERAGE} --append $ATOMIC" fi if [ ! -n "${TEST_UNIT+ }" ]; then for tf in `find ./tests/integration/ -name 'test_*.sh'`; do bn=$(basename "$tf") extension="${bn##*.}" if [ -n "${TEST_INTEGRATION+ }" ]; then tfbn="${bn%.*}" tfbn="${tfbn#test_}" if [[ " $TEST_INTEGRATION " != *" $tfbn "* ]]; then continue fi fi # If it is not running with ENABLE_DESTRUCTIVE and the test has # not the :test-destructive tag, skip it silently. if test -z "${ENABLE_DESTRUCTIVE-}" && grep ":destructive-test" ${tf} &> /dev/null; then continue fi printf "Running %-40.40s" "$(basename ${tf})...." printf "\n==== ${tf} ====\n" >> ${LOG} if [ "${extension}" == "py" ]; then tf="$PYTHON ${tf}" fi if ${tf} &>> ${LOG}; then printf "PASS\n"; else if test $? = 77; then printf "SKIP\n"; else printf "FAIL\n"; let "failures += 1" fi fi done else echo " SKIPPING INTEGRATION TESTS..." fi if [[ -x "${COVERAGE_BIN}" ]]; then echo "Coverage report:" | tee -a ${LOG} ${COVERAGE_BIN} report | tee -a ${LOG} fi if [[ "${failures}" -eq "0" ]]; then if [[ $_UNIT_FAIL -eq 0 ]]; then echo "ALL TESTS PASSED" exit 0 else echo "Unit tests failed." fi else if [[ $_UNIT_FAIL -ne 0 ]]; then echo "Unit tests failed." fi echo "Integration test failures: ${failures}" echo "See ${LOG} for more information." fi exit 1