Skip to content

Commit

Permalink
Add integration test for python coverage.
Browse files Browse the repository at this point in the history
  • Loading branch information
adam-azarchs committed Jun 7, 2022
1 parent 9a63281 commit 54421e5
Show file tree
Hide file tree
Showing 2 changed files with 192 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/test/shell/bazel/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,15 @@ sh_test(
],
)

sh_test(
name = "bazel_coverage_hermetic_py_test",
srcs = ["bazel_coverage_hermetic_py_test.sh"],
data = [":test-deps"],
tags = [
"no_windows",
],
)

sh_test(
name = "bazel_coverage_sh_test",
srcs = ["bazel_coverage_sh_test.sh"],
Expand Down
183 changes: 183 additions & 0 deletions src/test/shell/bazel/bazel_coverage_hermetic_py_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#!/bin/bash
#
# Copyright 2015 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.

set -eu

# Load the test setup defined in the parent directory
CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${CURRENT_DIR}/../integration_test_setup.sh" \
|| { echo "integration_test_setup.sh not found!" >&2; exit 1; }

# Fetch hermetic python and register toolchain.
function set_up() {
cat >>WORKSPACE <<EOF
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "rules_python",
sha256 = "cdf6b84084aad8f10bf20b46b77cb48d83c319ebe6458a18e9d2cebf57807cdd",
strip_prefix = "rules_python-0.8.1",
url = "https://github.com/bazelbuild/rules_python/archive/refs/tags/0.8.1.tar.gz",
)
load("@rules_python//python:repositories.bzl", "python_register_toolchains")
# Load hermetic python toolchain.
python_register_toolchains(
name = "python3_9",
python_version = "3.9",
# Don't register it, though, because we need to set up coverage support.
register_toolchains = False,
)
http_archive(
name = "coverage_linux_x64",
build_file_content = """
filegroup(
name = "coverage",
srcs = ["coverage/__main__.py"],
data = glob(["coverage/*", "coverage/**/*.py"]),
visibility = ["//visibility:public"],
)
""",
sha256 = "84631e81dd053e8a0d4967cedab6db94345f1c36107c71698f746cb2636c63e3",
type = "zip",
urls = [
"https://files.pythonhosted.org/packages/74/0d/0f3c522312fd27c32e1abe2fb5c323b583a5c108daf2c26d6e8dfdd5a105/coverage-6.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
],
)
register_toolchains(
"//:python_toolchain",
)
EOF
}

# Asserts if the given expected coverage result is included in the given output
# file.
#
# - expected_coverage The expected result that must be included in the output.
# - output_file The location of the coverage output file.
function assert_coverage_result() {
local expected_coverage="${1}"; shift
local output_file="${1}"; shift

# Replace newlines with commas to facilitate the assertion.
local expected_coverage_no_newlines="$( echo "$expected_coverage" | tr '\n' ',' )"
local output_file_no_newlines="$( cat "$output_file" | tr '\n' ',' )"

(echo "$output_file_no_newlines" \
| grep -F "$expected_coverage_no_newlines") \
|| fail "Expected coverage result
<$expected_coverage>
was not found in actual coverage report:
<$( cat "$output_file" )>"
}

# Returns the path of the code coverage report that was generated by Bazel by
# looking at the current $TEST_log. The method fails if TEST_log does not
# contain any coverage report for a passed test.
function get_coverage_file_path_from_test_log() {
local ending_part="$(sed -n -e '/PASSED/,$p' "$TEST_log")"

local coverage_file_path=$(grep -Eo "/[/a-zA-Z0-9\.\_\-]+\.dat$" <<< "$ending_part")
[[ -e "$coverage_file_path" ]] || fail "Coverage output file does not exist!"
echo "$coverage_file_path"
}

function set_up_py_test_coverage() {
# Set up python toolchain.
cat <<EOF > BUILD
load("@bazel_tools//tools/python:toolchain.bzl", "py_runtime_pair")
py_runtime(
name = "py3_runtime",
coverage_tool = "@coverage_linux_x64//:coverage",
files = ["@python3_9_x86_64-unknown-linux-gnu//:files"],
interpreter = "@python3_9_x86_64-unknown-linux-gnu//:bin/python3",
python_version = "PY3",
)
py_runtime_pair(
name = "python_runtimes",
py2_runtime = None,
py3_runtime = ":py3_runtime",
)
toolchain(
name = "python_toolchain",
exec_compatible_with = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
],
toolchain = ":python_runtimes",
toolchain_type = "@bazel_tools//tools/python:toolchain_type",
)
EOF
# Add a py_library and test.
cat <<EOF >> BUILD
py_library(
name = "hello",
srcs = ["hello.py"],
)
py_test(
name = "hello_test",
srcs = ["hello_test.py"],
deps = [":hello"],
)
EOF
cat <<EOF > hello.py
def Hello():
print("Hello, world!")
def Goodbye():
print("Goodbye, world!")
EOF
cat <<EOF > hello_test.py
import unittest
import hello
class Tests(unittest.TestCase):
def testHello(self):
hello.Hello()
if __name__ == "__main__":
unittest.main()
EOF
cat <<EOF > expected.dat
SF:hello.py
FNF:0
FNH:0
DA:1,1,fi+A0ud2xABMExsbhdW38w
DA:2,1,3qA2I6CcUyJmcd1vpeVcRA
DA:4,1,nFnrj5CwYCqkvbVhPUFVVw
DA:5,0,RmWioilSA3bI5NbLlwiuSA
LH:3
LF:4
end_of_record
EOF
}

function test_py_test_coverage() {
set_up_py_test_coverage
bazel coverage --test_output=all //:hello_test &>$TEST_log || fail "Coverage for //:hello_test failed"
local coverage_file_path="$( get_coverage_file_path_from_test_log )"
diff expected.dat "$coverage_file_path" >> $TEST_log
cmp expected.dat "$coverage_file_path" || fail "Coverage output file is different than the expected file for py_library."
}

run_suite "test tests"

0 comments on commit 54421e5

Please sign in to comment.