| #!/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; } |
| |
| disable_bzlmod |
| |
| # Fetch hermetic python and register toolchain. |
| function set_up() { |
| cat >>WORKSPACE <<EOF |
| register_toolchains( |
| "//:python_toolchain", |
| ) |
| EOF |
| } |
| |
| # 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 |
| ending_part="$(sed -n -e '/PASSED/,$p' "$TEST_log")" |
| |
| local coverage_file_path |
| 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") |
| |
| package(default_visibility = ["//visibility:public"]) |
| |
| py_runtime( |
| name = "py3_runtime", |
| coverage_tool = ":mock_coverage", |
| interpreter_path = "$(which python3)", |
| python_version = "PY3", |
| ) |
| |
| py_runtime_pair( |
| name = "python_runtimes", |
| py2_runtime = None, |
| py3_runtime = ":py3_runtime", |
| ) |
| |
| toolchain( |
| name = "python_toolchain", |
| 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_library( |
| name = "mock_coverage", |
| srcs = ["mock_coverage.py"], |
| deps = [":coverage_support"], |
| ) |
| |
| py_library( |
| name = "coverage_support", |
| srcs = ["coverage_support.py"], |
| ) |
| |
| py_test( |
| name = "hello_test", |
| srcs = ["hello_test.py"], |
| deps = [":hello"], |
| ) |
| EOF |
| echo "# fake dependency" > coverage_support.py |
| cat <<EOF > mock_coverage.py |
| #!/usr/bin/env python3 |
| import argparse |
| import os |
| import subprocess |
| import sys |
| import coverage_support |
| parser = argparse.ArgumentParser() |
| mode = sys.argv[1] |
| del(sys.argv[1]) |
| parser.add_argument("--rcfile", type=str) |
| parser.add_argument("--append", action="store_true") |
| parser.add_argument("--branch", action="store_true") |
| parser.add_argument("--output", "-o", type=str) |
| parser.add_argument("target", nargs="*") |
| args = parser.parse_args() |
| tmp_cov_file = os.path.join(os.environ["COVERAGE_DIR"], "tmp.out") |
| if mode == "run": |
| subprocess.check_call([sys.executable]+args.target) |
| with open(tmp_cov_file, "a") as tmp: |
| tmp.write("TN:\nSF:") |
| tmp.write(os.path.join(os.path.dirname(os.path.realpath(args.target[0])), "hello.py")) |
| tmp.write(""" |
| 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 |
| """) |
| else: |
| with open(args.output, "w") as out_file: |
| with open(tmp_cov_file, "r") as in_file: |
| out_file.write(in_file.read()) |
| 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 |
| 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" |