-
Notifications
You must be signed in to change notification settings - Fork 4.1k
/
collect_coverage.sh
executable file
·174 lines (145 loc) · 5.71 KB
/
collect_coverage.sh
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
#!/bin/bash -x
# 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
#
# Script expects that it will be started in the execution root directory and
# not in the test's runfiles directory.
if [[ -z "$LCOV_MERGER" ]]; then
echo --
echo "Coverage collection running in legacy mode."
echo "Legacy mode only supports C++ and even then, it's very brittle."
COVERAGE_LEGACY_MODE=1
else
COVERAGE_LEGACY_MODE=
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.
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
# Only check if file exists when LCOV_MERGER is set
if [[ ! "$COVERAGE_LEGACY_MODE" ]]; then
for name in "$LCOV_MERGER"; do
if [[ ! -e $name ]]; then
echo --
echo Coverage runner: cannot locate file $name
exit 1
fi
done
fi
if [[ "$COVERAGE_LEGACY_MODE" ]]; then
export GCOV_PREFIX_STRIP=3
export GCOV_PREFIX="${COVERAGE_DIR}"
export LLVM_PROFILE_FILE="${COVERAGE_DIR}/%h-%p-%m.profraw"
fi
cd "$TEST_SRCDIR/$TEST_WORKSPACE"
"$@"
TEST_STATUS=$?
# always create output files
touch $COVERAGE_OUTPUT_FILE
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
cd $ROOT
USES_LLVM_COV=
if stat --printf='' "${COVERAGE_DIR}"/*.profraw 2>/dev/null; then
USES_LLVM_COV=1
fi
if [[ "$USES_LLVM_COV" ]]; then
"${COVERAGE_GCOV_PATH}" merge -output "${COVERAGE_OUTPUT_FILE}" "${COVERAGE_DIR}"/*.profraw
exit $TEST_STATUS
# If LCOV_MERGER is not set, use the legacy C++-only method to convert coverage files.
elif [[ "$COVERAGE_LEGACY_MODE" ]]; then
cat "${COVERAGE_MANIFEST}" | grep ".gcno$" | while read path; do
mkdir -p "${COVERAGE_DIR}/$(dirname ${path})"
cp "${ROOT}/${path}" "${COVERAGE_DIR}/${path}"
done
# Unfortunately, lcov messes up the source file names if it can't find the
# files at their relative paths. Workaround by creating empty source files
# according to the manifest (i.e., only for files that are supposed to be
# instrumented).
cat "${COVERAGE_MANIFEST}" | egrep ".(cc|h)$" | while read path; do
mkdir -p "${COVERAGE_DIR}/$(dirname ${path})"
touch "${COVERAGE_DIR}/${path}"
done
# Symlink the gcov tool such with a link called gcov. Clang comes with a tool
# called llvm-cov, which behaves like gcov if symlinked in this way (otherwise
# we would need to invoke it with "llvm-cov gcov").
GCOV="${COVERAGE_DIR}/gcov"
ln -s "${COVERAGE_GCOV_PATH}" "${GCOV}"
# Run lcov over the .gcno and .gcda files to generate the lcov tracefile.
# -c - Collect coverage data
# --no-external - Do not collect coverage data for system files
# --ignore-errors graph - Ignore missing .gcno files; Bazel only instruments some files
# --gcov-tool "${GCOV}" - Pass the local symlink to be uses as gcov by lcov
# -d "${COVERAGE_DIR}" - Directory to search for .gcda files
# -o "${COVERAGE_OUTPUT_FILE}" - Output file
/usr/bin/lcov -c --no-external --ignore-errors graph \
--gcov-tool "${GCOV}" \
-d "${COVERAGE_DIR}" -o "${COVERAGE_OUTPUT_FILE}"
# The paths are all wrong, because they point to /tmp. Fix up the paths to
# point to the exec root instead (${ROOT}).
# This does not work with sandboxing, because ${ROOT} points to the sandbox dir.
sed -i -e "s*${COVERAGE_DIR}*${ROOT}*g" "${COVERAGE_OUTPUT_FILE}"
exit $TEST_STATUS
fi
export LCOV_MERGER_CMD="${LCOV_MERGER} --coverage_dir=${COVERAGE_DIR} \
--output_file=${COVERAGE_OUTPUT_FILE}"
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