1#!/usr/bin/env bash 2# Copyright 2016 The TensorFlow Authors. All Rights Reserved. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15# ============================================================================== 16# 17# Common Bash functions used by build scripts 18 19COLOR_NC='\033[0m' 20COLOR_BOLD='\033[1m' 21COLOR_LIGHT_GRAY='\033[0;37m' 22COLOR_GREEN='\033[0;32m' 23COLOR_RED='\033[0;31m' 24 25die() { 26 # Print a message and exit with code 1. 27 # 28 # Usage: die <error_message> 29 # e.g., die "Something bad happened." 30 31 echo $@ 32 exit 1 33} 34 35realpath() { 36 # Get the real path of a file 37 # Usage: realpath <file_path> 38 39 if [[ $# != "1" ]]; then 40 die "realpath: incorrect usage" 41 fi 42 43 [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}" 44} 45 46to_lower () { 47 # Convert string to lower case. 48 # Usage: to_lower <string> 49 50 echo "$1" | tr '[:upper:]' '[:lower:]' 51} 52 53calc_elapsed_time() { 54 # Calculate elapsed time. Takes nanosecond format input of the kind output 55 # by date +'%s%N' 56 # 57 # Usage: calc_elapsed_time <START_TIME> <END_TIME> 58 59 if [[ $# != "2" ]]; then 60 die "calc_elapsed_time: incorrect usage" 61 fi 62 63 START_TIME=$1 64 END_TIME=$2 65 66 if [[ ${START_TIME} == *"N" ]]; then 67 # Nanosecond precision not available 68 START_TIME=$(echo ${START_TIME} | sed -e 's/N//g') 69 END_TIME=$(echo ${END_TIME} | sed -e 's/N//g') 70 ELAPSED="$(expr ${END_TIME} - ${START_TIME}) s" 71 else 72 ELAPSED="$(expr $(expr ${END_TIME} - ${START_TIME}) / 1000000) ms" 73 fi 74 75 echo ${ELAPSED} 76} 77 78run_in_directory() { 79 # Copy the test script to a destination directory and run the test there. 80 # Write test log to a log file. 81 # 82 # Usage: run_in_directory <DEST_DIR> <LOG_FILE> <TEST_SCRIPT> 83 # [ARGS_FOR_TEST_SCRIPT] 84 85 if [[ $# -lt "3" ]]; then 86 die "run_in_directory: incorrect usage" 87 fi 88 89 DEST_DIR="$1" 90 LOG_FILE="$2" 91 TEST_SCRIPT="$3" 92 shift 3 93 SCRIPT_ARGS=("$@") 94 95 # Get the absolute path of the log file 96 LOG_FILE_ABS=$(realpath "${LOG_FILE}") 97 98 cp "${TEST_SCRIPT}" "${DEST_DIR}"/ 99 SCRIPT_BASENAME=$(basename "${TEST_SCRIPT}") 100 101 if [[ ! -f "${DEST_DIR}/${SCRIPT_BASENAME}" ]]; then 102 echo "FAILED to copy script ${TEST_SCRIPT} to temporary directory "\ 103"${DEST_DIR}" 104 return 1 105 fi 106 107 pushd "${DEST_DIR}" > /dev/null 108 109 "${TIMEOUT_BIN}" --preserve-status ${TIMEOUT} \ 110 "${PYTHON_BIN_PATH}" "${SCRIPT_BASENAME}" ${SCRIPT_ARGS[@]} 2>&1 \ 111 > "${LOG_FILE_ABS}" 112 113 rm -f "${SCRIPT_BASENAME}" 114 popd > /dev/null 115 116 if [[ $? != 0 ]]; then 117 echo "Test \"${SCRIPT_BASENAME}\" FAILED" 118 return 1 119 fi 120 121 return 0 122} 123 124 125test_runner() { 126 # Run a suite of tests, print failure logs (if any), wall-time each test, 127 # and show the summary at the end. 128 # 129 # Usage: test_runner <TEST_DESC> <ALL_TESTS> <TEST_BLACKLIST> <LOGS_DIR> 130 # e.g., test_runner "Tutorial test-on-install" \ 131 # "test1 test2 test3" "test2 test3" "/tmp/log_dir" 132 133 if [[ $# != "4" ]]; then 134 die "test_runner: incorrect usage" 135 fi 136 137 TEST_DESC=$1 138 ALL_TESTS_STR=$2 139 TEST_BLACKLIST_SR=$3 140 LOGS_DIR=$4 141 142 NUM_TESTS=$(echo "${ALL_TESTS_STR}" | wc -w) 143 ALL_TESTS=(${ALL_TESTS_STR}) 144 145 COUNTER=0 146 PASSED_COUNTER=0 147 FAILED_COUNTER=0 148 FAILED_TESTS="" 149 FAILED_TEST_LOGS="" 150 SKIPPED_COUNTER=0 151 for CURR_TEST in ${ALL_TESTS[@]}; do 152 ((COUNTER++)) 153 STAT_STR="(${COUNTER} / ${NUM_TESTS})" 154 155 if [[ "${TEST_BLACKLIST_STR}" == *"${CURR_TEST}"* ]]; then 156 ((SKIPPED_COUNTER++)) 157 echo "${STAT_STR} Blacklisted ${TEST_DESC} SKIPPED: ${CURR_TEST}" 158 continue 159 fi 160 161 START_TIME=$(date +'%s%N') 162 163 LOG_FILE="${LOGS_DIR}/${CURR_TEST}.log" 164 rm -rf ${LOG_FILE} || 165 die "Unable to remove existing log file: ${LOG_FILE}" 166 167 "test_${CURR_TEST}" "${LOG_FILE}" 168 TEST_RESULT=$? 169 170 END_TIME=$(date +'%s%N') 171 ELAPSED_TIME=$(calc_elapsed_time "${START_TIME}" "${END_TIME}") 172 173 if [[ ${TEST_RESULT} == 0 ]]; then 174 ((PASSED_COUNTER++)) 175 echo "${STAT_STR} ${TEST_DESC} PASSED: ${CURR_TEST} "\ 176 "(Elapsed time: ${ELAPSED_TIME})" 177 else 178 ((FAILED_COUNTER++)) 179 FAILED_TESTS="${FAILED_TESTS} ${CURR_TEST}" 180 FAILED_TEST_LOGS="${FAILED_TEST_LOGS} ${LOG_FILE}" 181 182 echo "${STAT_STR} ${TEST_DESC} FAILED: ${CURR_TEST} "\ 183 "(Elapsed time: ${ELAPSED_TIME})" 184 185 echo "============== BEGINS failure log content ==============" 186 cat ${LOG_FILE} 187 echo "============== ENDS failure log content ==============" 188 echo "" 189 fi 190 done 191 192 echo "${NUM_TUT_TESTS} ${TEST_DESC} test(s): "\ 193 "${PASSED_COUNTER} passed; ${FAILED_COUNTER} failed; ${SKIPPED_COUNTER} skipped" 194 195 if [[ ${FAILED_COUNTER} -eq 0 ]]; then 196 echo "" 197 echo "${TEST_DESC} SUCCEEDED" 198 199 exit 0 200 else 201 echo "FAILED test(s):" 202 FAILED_TEST_LOGS=($FAILED_TEST_LOGS) 203 FAIL_COUNTER=0 204 for TEST_NAME in ${FAILED_TESTS}; do 205 echo " ${TEST_DESC} (Log @: ${FAILED_TEST_LOGS[${FAIL_COUNTER}]})" 206 ((FAIL_COUNTER++)) 207 done 208 209 echo "" 210 die "${TEST_DESC} FAILED" 211 fi 212} 213 214configure_android_workspace() { 215 # Modify the WORKSPACE file. 216 # Note: This is workaround. This should be done by bazel. 217 if grep -q '^android_sdk_repository' WORKSPACE && grep -q '^android_ndk_repository' WORKSPACE; then 218 echo "You probably have your WORKSPACE file setup for Android." 219 else 220 if [ -z "${ANDROID_API_LEVEL}" -o -z "${ANDROID_BUILD_TOOLS_VERSION}" ] || \ 221 [ -z "${ANDROID_SDK_HOME}" -o -z "${ANDROID_NDK_HOME}" ]; then 222 echo "ERROR: Your WORKSPACE file does not seems to have proper android" 223 echo " configuration and not all the environment variables expected" 224 echo " inside ci_build android docker container are set." 225 echo " Please configure it manually. See: https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/android/README.md" 226 else 227 cat << EOF >> WORKSPACE 228android_sdk_repository( 229 name = "androidsdk", 230 api_level = ${ANDROID_API_LEVEL}, 231 build_tools_version = "${ANDROID_BUILD_TOOLS_VERSION}", 232 path = "${ANDROID_SDK_HOME}", 233) 234 235android_ndk_repository( 236 name="androidndk", 237 path="${ANDROID_NDK_HOME}", 238 api_level=14) 239EOF 240 fi 241 fi 242} 243