blob: 9d480ba8484e6c8c052de5439dd76817de1df98e [file] [log] [blame]
Keith Smiley615e1b12021-04-20 02:10:23 -07001#!/bin/bash
Yue Ganaf1e3c22016-12-05 14:05:15 +00002
3# Copyright 2016 The Bazel Authors. All rights reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17# Wrapper script for collecting code coverage during test execution.
18#
19# Expected environment:
20# COVERAGE_MANIFEST - mandatory, location of the instrumented file manifest
21# LCOV_MERGER - mandatory, location of the LcovMerger
22# COVERAGE_DIR - optional, location of the coverage temp directory
23# COVERAGE_OUTPUT_FILE - optional, location of the final lcov file
Keith Smiley615e1b12021-04-20 02:10:23 -070024# VERBOSE_COVERAGE - optional, print debug info from the coverage scripts
Yue Ganaf1e3c22016-12-05 14:05:15 +000025#
26# Script expects that it will be started in the execution root directory and
27# not in the test's runfiles directory.
28
Keith Smiley615e1b12021-04-20 02:10:23 -070029if [[ -n "$VERBOSE_COVERAGE" ]]; then
30 set -x
31fi
32
plfa445cda2020-10-29 10:39:30 -070033function resolve_links() {
34 local name="$1"
35
36 if [ -e "$name" ]; then
37 # resolve all links, keep path absolute
38 while [ -L "$name" ]; do
39 local target=$(readlink "$name")
40 if [ "$(echo "$target" | head -c1)" = "/" ]; then
41 name="$target"
42 else
43 name="$(dirname "$name")/$target"
44 fi
45 done
46 echo "$name"
47 else
48 false # fail the function
49 fi
50}
51
Yue Ganaf1e3c22016-12-05 14:05:15 +000052if [[ -z "$COVERAGE_MANIFEST" ]]; then
53 echo --
54 echo Coverage runner: \$COVERAGE_MANIFEST is not set
55 echo Current environment:
56 env | sort
57 exit 1
58fi
Yue Ganaf1e3c22016-12-05 14:05:15 +000059# When collect_coverage.sh is used, test runner must be instructed not to cd
60# to the test's runfiles directory.
iirina190d4f82018-08-23 06:05:34 -070061export ROOT="$PWD"
Yue Ganaf1e3c22016-12-05 14:05:15 +000062
63if [[ "$COVERAGE_MANIFEST" != /* ]]; then
64 # Canonicalize the path to coverage manifest so that tests can find it.
65 export COVERAGE_MANIFEST="$ROOT/$COVERAGE_MANIFEST"
66fi
67
68# write coverage data outside of the runfiles tree
69export COVERAGE_DIR=${COVERAGE_DIR:-"$ROOT/coverage"}
70# make COVERAGE_DIR an absolute path
71if ! [[ $COVERAGE_DIR == $ROOT* ]]; then
72 COVERAGE_DIR=$ROOT/$COVERAGE_DIR
73fi
74
75mkdir -p "$COVERAGE_DIR"
76COVERAGE_OUTPUT_FILE=${COVERAGE_OUTPUT_FILE:-"$COVERAGE_DIR/_coverage.dat"}
77# make COVERAGE_OUTPUT_FILE an absolute path
78if ! [[ $COVERAGE_OUTPUT_FILE == $ROOT* ]]; then
79 COVERAGE_OUTPUT_FILE=$ROOT/$COVERAGE_OUTPUT_FILE
80fi
81
Yue Ganaf1e3c22016-12-05 14:05:15 +000082# Java
83# --------------------------------------
84export JAVA_COVERAGE_FILE=$COVERAGE_DIR/jvcov.dat
85# Let tests know that it is a coverage run
86export COVERAGE=1
87export BULK_COVERAGE_RUN=1
88
iirinaeb3e07d2018-09-20 05:58:31 -070089# Setting up the environment for executing the C++ tests.
ulfjackb3763e92020-01-27 05:09:37 -080090if [[ -z "$GCOV_PREFIX_STRIP" ]]; then
91 # TODO: GCOV_PREFIX_STRIP=3 is incorrect on MacOS in the default setup
92 export GCOV_PREFIX_STRIP=3
93fi
iirinaeb3e07d2018-09-20 05:58:31 -070094export GCOV_PREFIX="${COVERAGE_DIR}"
95export LLVM_PROFILE_FILE="${COVERAGE_DIR}/%h-%p-%m.profraw"
Yue Ganaf1e3c22016-12-05 14:05:15 +000096
elenairina2b36cd32019-01-11 10:53:50 -080097# In coverage mode for Java, we need to merge the runtime classpath before
98# running the tests. JacocoCoverageRunner uses this merged jar in order
99# to get coverage data.
100#
101# Merge the classpath using SingleJar and save it in the environment
102# variable JACOCO_METADATA_JAR. The jars on the runtime classpath are listed
103# in the file $JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE.
104#
105# We need to merge the jars here because the merged jar can be an input
106# too large (the combined merged jars for several big tests in a run
107# can go over 10G). Not merging the jars and making
108# JacocoCoverageRunner read every individual jar goes over the shutdown hook
109# time limit in the coverage runner (~few seconds).
110#
111# SINGLE_JAR_TOOL Exec path of SingleJar.
112#
113# JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE Exec path of a file that contains the
114# relative paths of the jars on the runtime
115# classpath delimited by newline.
116if [[ ! -z "${JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE}" ]]; then
117 JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE="${PWD}/${JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE}"
118 SINGLE_JAR_TOOL="${PWD}/${SINGLE_JAR_TOOL}"
119
120 # Create a paramsfile for invoking SingleJar.
121 mkdir -p "${COVERAGE_DIR}"
122 single_jar_params_file="${COVERAGE_DIR}/runtime_classpath.paramsfile"
123 touch "$single_jar_params_file"
124
125 # Export JACOCO_METADATA_JAR in order for JacocoCoverageRunner to be able
126 # to read it.
127 export JACOCO_METADATA_JAR="${COVERAGE_DIR}/coverage-runtime_merged_instr.jar"
128
129 echo -e "--output ${JACOCO_METADATA_JAR}\n--sources" >> "$single_jar_params_file"
130
131 # Append the runfiles prefix to all the relative paths found in
132 # JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE, to invoke SingleJar with the
133 # absolute paths.
Ulf Adams8ba48ad2021-04-21 10:44:09 -0700134 RUNFILES_PREFIX="$TEST_SRCDIR/"
elenairina2b36cd32019-01-11 10:53:50 -0800135 cat "$JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE" | sed "s@^@$RUNFILES_PREFIX@" >> "$single_jar_params_file"
136
137 # Invoke SingleJar. This will create JACOCO_METADATA_JAR.
138 "${SINGLE_JAR_TOOL}" "@$single_jar_params_file"
139fi
140
plfa445cda2020-10-29 10:39:30 -0700141if [[ "$IS_COVERAGE_SPAWN" == "0" ]]; then
142 # TODO(bazel-team): cd should be avoided.
143 cd "$TEST_SRCDIR/$TEST_WORKSPACE"
Yue Ganaf1e3c22016-12-05 14:05:15 +0000144
plfa445cda2020-10-29 10:39:30 -0700145 # Always create the coverage report.
146 if [[ "$SPLIT_COVERAGE_POST_PROCESSING" == "0" ]]; then
147 touch $COVERAGE_OUTPUT_FILE
148 fi
149
Garrett Holmstrom2793e5a2021-04-06 02:23:01 -0700150 # Execute the test.
151 "$@"
152 TEST_STATUS=$?
153
plfa445cda2020-10-29 10:39:30 -0700154 if [[ $TEST_STATUS -ne 0 ]]; then
155 echo --
156 echo Coverage runner: Not collecting coverage for failed test.
157 echo The following commands failed with status $TEST_STATUS
158 echo "$@"
159 exit $TEST_STATUS
160 fi
Yue Ganaf1e3c22016-12-05 14:05:15 +0000161fi
162
plfa445cda2020-10-29 10:39:30 -0700163
164# ------------------EXPERIMENTAL---------------------
165# After this point we can run the code necessary for the coverage spawn
166
167if [[ "$SPLIT_COVERAGE_POST_PROCESSING" == "1" && "$IS_COVERAGE_SPAWN" == "0" ]]; then
168 exit 0
169fi
170
171if [[ "$SPLIT_COVERAGE_POST_PROCESSING" == "1" && "$IS_COVERAGE_SPAWN" == "1" ]]; then
172 touch $COVERAGE_OUTPUT_FILE
173fi
iirina9e183ca2018-09-27 04:23:29 -0700174# TODO(bazel-team): cd should be avoided.
Yue Ganaf1e3c22016-12-05 14:05:15 +0000175cd $ROOT
iirina9e183ca2018-09-27 04:23:29 -0700176# Call the C++ code coverage collection script.
iirina190d4f82018-08-23 06:05:34 -0700177if [[ "$CC_CODE_COVERAGE_SCRIPT" ]]; then
178 eval "${CC_CODE_COVERAGE_SCRIPT}"
lberki8a5752d2017-05-23 17:48:14 +0200179fi
180
Keith Smileya570f5f2022-03-15 04:33:09 -0700181if [[ -z "$LCOV_MERGER" ]]; then
182 # this can happen if a rule returns an InstrumentedFilesInfo (which all do
183 # following 5b216b2) but does not define an _lcov_merger attribute.
184 # Unfortunately, we cannot simply stop this script being called in this case
185 # due to conflicts with how things work within Google.
186 # The file creation is required because TestActionBuilder has already declared
187 # it.
188 exit 0
189fi
190
191for name in "$LCOV_MERGER"; do
192 if [[ ! -e $name ]]; then
193 echo --
194 echo Coverage runner: cannot locate file $name
195 exit 1
196 fi
197done
198
iirinaeb3e07d2018-09-20 05:58:31 -0700199# Export the command line that invokes LcovMerger with the flags:
iirina0d693712018-09-24 09:58:50 -0700200# --coverage_dir The absolute path of the directory where the
201# intermediate coverage reports are located.
202# CoverageOutputGenerator will search for files with
203# the .dat and .gcov extension under this directory and
204# will merge everything it found in the output report.
205#
206# --output_file The absolute path of the merged coverage report.
207#
208# --filter_sources Filters out the sources that match the given regexes
209# from the final coverage report. This is needed
210# because some coverage tools (e.g. gcov) do not have
211# any way of specifying what sources to exclude when
212# generating the code coverage report (in this case the
213# syslib sources).
214#
215# --source_file_manifest The absolute path of the coverage source file
216# manifest. CoverageOutputGenerator uses this file to
Googlerf38e2932020-11-30 06:04:16 -0800217# keep only the sources found in the manifest (that is,
218# only the sources of targets matched by
219# --instrumentation_filter, excluding test targets
220# unless --instrument_test_targets).
plfa445cda2020-10-29 10:39:30 -0700221
222if [[ "$IS_COVERAGE_SPAWN" == "1" ]]; then
223 COVERAGE_DIR=$(resolve_links $COVERAGE_DIR)
224 COVERAGE_MANIFEST=$(resolve_links $COVERAGE_MANIFEST)
225fi
226
iirina81efc3f2018-10-29 05:23:09 -0700227LCOV_MERGER_CMD="${LCOV_MERGER} --coverage_dir=${COVERAGE_DIR} \
iirinaeb3e07d2018-09-20 05:58:31 -0700228 --output_file=${COVERAGE_OUTPUT_FILE} \
229 --filter_sources=/usr/bin/.+ \
230 --filter_sources=/usr/lib/.+ \
iirinaa4a76592018-10-12 10:43:37 -0700231 --filter_sources=/usr/include.+ \
Philipp Stephani71747cc2022-03-10 07:58:27 -0800232 --filter_sources=/Applications/.+ \
iirina0d693712018-09-24 09:58:50 -0700233 --filter_sources=.*external/.+ \
234 --source_file_manifest=${COVERAGE_MANIFEST}"
Yue Ganaf1e3c22016-12-05 14:05:15 +0000235
iirina81efc3f2018-10-29 05:23:09 -0700236if [[ $COVERAGE_REPORTED_TO_ACTUAL_SOURCES_FILE ]]; then
237 LCOV_MERGER_CMD="$LCOV_MERGER_CMD\
238 --sources_to_replace_file=$ROOT/$COVERAGE_REPORTED_TO_ACTUAL_SOURCES_FILE"
239fi
Yue Ganaf1e3c22016-12-05 14:05:15 +0000240
241if [[ $DISPLAY_LCOV_CMD ]] ; then
242 echo "Running lcov_merger"
243 echo $LCOV_MERGER_CMD
244 echo "-----------------"
245fi
246
lberki913478d2017-06-09 10:31:39 -0400247# JAVA_RUNFILES is set to the runfiles of the test, which does not necessarily
248# contain a JVM (it does only if the test has a Java binary somewhere). So let
249# the LCOV merger discover where its own runfiles tree is.
Googlerf38e2932020-11-30 06:04:16 -0800250JAVA_RUNFILES= exec $LCOV_MERGER_CMD