1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
|
#!/bin/bash
# Copyright 2016 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Wrapper script for collecting code coverage during test execution.
#
# Expected environment:
# COVERAGE_MANIFEST - mandatory, location of the instrumented file manifest
# LCOV_MERGER - mandatory, location of the LcovMerger
# COVERAGE_DIR - optional, location of the coverage temp directory
# COVERAGE_OUTPUT_FILE - optional, location of the final lcov file
# VERBOSE_COVERAGE - optional, print debug info from the coverage scripts
#
# Script expects that it will be started in the execution root directory and
# not in the test's runfiles directory.
if [[ -n "$VERBOSE_COVERAGE" ]]; then
set -x
fi
function resolve_links() {
local name="$1"
if [ -e "$name" ]; then
# resolve all links, keep path absolute
while [ -L "$name" ]; do
local target=$(readlink "$name")
if [ "$(echo "$target" | head -c1)" = "/" ]; then
name="$target"
else
name="$(dirname "$name")/$target"
fi
done
echo "$name"
else
false # fail the function
fi
}
if [[ -z "$COVERAGE_MANIFEST" ]]; then
echo --
echo Coverage runner: \$COVERAGE_MANIFEST is not set
echo Current environment:
env | sort
exit 1
fi
# When collect_coverage.sh is used, test runner must be instructed not to cd
# to the test's runfiles directory.
export ROOT="$PWD"
if [[ "$COVERAGE_MANIFEST" != /* ]]; then
# Canonicalize the path to coverage manifest so that tests can find it.
export COVERAGE_MANIFEST="$ROOT/$COVERAGE_MANIFEST"
fi
# write coverage data outside of the runfiles tree
export COVERAGE_DIR=${COVERAGE_DIR:-"$ROOT/coverage"}
# make COVERAGE_DIR an absolute path
if ! [[ $COVERAGE_DIR == $ROOT* ]]; then
COVERAGE_DIR=$ROOT/$COVERAGE_DIR
fi
mkdir -p "$COVERAGE_DIR"
COVERAGE_OUTPUT_FILE=${COVERAGE_OUTPUT_FILE:-"$COVERAGE_DIR/_coverage.dat"}
# make COVERAGE_OUTPUT_FILE an absolute path
if ! [[ $COVERAGE_OUTPUT_FILE == $ROOT* ]]; then
COVERAGE_OUTPUT_FILE=$ROOT/$COVERAGE_OUTPUT_FILE
fi
# Java
# --------------------------------------
export JAVA_COVERAGE_FILE=$COVERAGE_DIR/jvcov.dat
# Let tests know that it is a coverage run
export COVERAGE=1
export BULK_COVERAGE_RUN=1
for name in "$LCOV_MERGER"; do
if [[ ! -e $name ]]; then
echo --
echo Coverage runner: cannot locate file $name
exit 1
fi
done
# Setting up the environment for executing the C++ tests.
if [[ -z "$GCOV_PREFIX_STRIP" ]]; then
# TODO: GCOV_PREFIX_STRIP=3 is incorrect on MacOS in the default setup
export GCOV_PREFIX_STRIP=3
fi
export GCOV_PREFIX="${COVERAGE_DIR}"
export LLVM_PROFILE_FILE="${COVERAGE_DIR}/%h-%p-%m.profraw"
# In coverage mode for Java, we need to merge the runtime classpath before
# running the tests. JacocoCoverageRunner uses this merged jar in order
# to get coverage data.
#
# Merge the classpath using SingleJar and save it in the environment
# variable JACOCO_METADATA_JAR. The jars on the runtime classpath are listed
# in the file $JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE.
#
# We need to merge the jars here because the merged jar can be an input
# too large (the combined merged jars for several big tests in a run
# can go over 10G). Not merging the jars and making
# JacocoCoverageRunner read every individual jar goes over the shutdown hook
# time limit in the coverage runner (~few seconds).
#
# SINGLE_JAR_TOOL Exec path of SingleJar.
#
# JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE Exec path of a file that contains the
# relative paths of the jars on the runtime
# classpath delimited by newline.
if [[ ! -z "${JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE}" ]]; then
JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE="${PWD}/${JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE}"
SINGLE_JAR_TOOL="${PWD}/${SINGLE_JAR_TOOL}"
# Create a paramsfile for invoking SingleJar.
mkdir -p "${COVERAGE_DIR}"
single_jar_params_file="${COVERAGE_DIR}/runtime_classpath.paramsfile"
touch "$single_jar_params_file"
# Export JACOCO_METADATA_JAR in order for JacocoCoverageRunner to be able
# to read it.
export JACOCO_METADATA_JAR="${COVERAGE_DIR}/coverage-runtime_merged_instr.jar"
echo -e "--output ${JACOCO_METADATA_JAR}\n--sources" >> "$single_jar_params_file"
# Append the runfiles prefix to all the relative paths found in
# JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE, to invoke SingleJar with the
# absolute paths.
RUNFILES_PREFIX="$TEST_SRCDIR/"
cat "$JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE" | sed "s@^@$RUNFILES_PREFIX@" >> "$single_jar_params_file"
# Invoke SingleJar. This will create JACOCO_METADATA_JAR.
"${SINGLE_JAR_TOOL}" "@$single_jar_params_file"
fi
if [[ "$IS_COVERAGE_SPAWN" == "0" ]]; then
# TODO(bazel-team): cd should be avoided.
cd "$TEST_SRCDIR/$TEST_WORKSPACE"
# Execute the test.
"$@"
TEST_STATUS=$?
# Always create the coverage report.
if [[ "$SPLIT_COVERAGE_POST_PROCESSING" == "0" ]]; then
touch $COVERAGE_OUTPUT_FILE
fi
if [[ $TEST_STATUS -ne 0 ]]; then
echo --
echo Coverage runner: Not collecting coverage for failed test.
echo The following commands failed with status $TEST_STATUS
echo "$@"
exit $TEST_STATUS
fi
fi
# ------------------EXPERIMENTAL---------------------
# After this point we can run the code necessary for the coverage spawn
if [[ "$SPLIT_COVERAGE_POST_PROCESSING" == "1" && "$IS_COVERAGE_SPAWN" == "0" ]]; then
exit 0
fi
if [[ "$SPLIT_COVERAGE_POST_PROCESSING" == "1" && "$IS_COVERAGE_SPAWN" == "1" ]]; then
touch $COVERAGE_OUTPUT_FILE
fi
# TODO(bazel-team): cd should be avoided.
cd $ROOT
# Call the C++ code coverage collection script.
if [[ "$CC_CODE_COVERAGE_SCRIPT" ]]; then
eval "${CC_CODE_COVERAGE_SCRIPT}"
fi
# Export the command line that invokes LcovMerger with the flags:
# --coverage_dir The absolute path of the directory where the
# intermediate coverage reports are located.
# CoverageOutputGenerator will search for files with
# the .dat and .gcov extension under this directory and
# will merge everything it found in the output report.
#
# --output_file The absolute path of the merged coverage report.
#
# --filter_sources Filters out the sources that match the given regexes
# from the final coverage report. This is needed
# because some coverage tools (e.g. gcov) do not have
# any way of specifying what sources to exclude when
# generating the code coverage report (in this case the
# syslib sources).
#
# --source_file_manifest The absolute path of the coverage source file
# manifest. CoverageOutputGenerator uses this file to
# keep only the C++ sources found in the manifest.
# For other languages the sources in the manifest are
# ignored.
if [[ "$IS_COVERAGE_SPAWN" == "1" ]]; then
COVERAGE_DIR=$(resolve_links $COVERAGE_DIR)
COVERAGE_MANIFEST=$(resolve_links $COVERAGE_MANIFEST)
fi
LCOV_MERGER_CMD="${LCOV_MERGER} --coverage_dir=${COVERAGE_DIR} \
--output_file=${COVERAGE_OUTPUT_FILE} \
--filter_sources=/usr/bin/.+ \
--filter_sources=/usr/lib/.+ \
--filter_sources=/usr/include.+ \
--filter_sources=.*external/.+ \
--source_file_manifest=${COVERAGE_MANIFEST}"
if [[ $COVERAGE_REPORTED_TO_ACTUAL_SOURCES_FILE ]]; then
LCOV_MERGER_CMD="$LCOV_MERGER_CMD\
--sources_to_replace_file=$ROOT/$COVERAGE_REPORTED_TO_ACTUAL_SOURCES_FILE"
fi
if [[ $DISPLAY_LCOV_CMD ]] ; then
echo "Running lcov_merger"
echo $LCOV_MERGER_CMD
echo "-----------------"
fi
# JAVA_RUNFILES is set to the runfiles of the test, which does not necessarily
# contain a JVM (it does only if the test has a Java binary somewhere). So let
# the LCOV merger discover where its own runfiles tree is.
JAVA_RUNFILES= exec $LCOV_MERGER_CMD
|