|  | #!/bin/bash | 
|  | # Copyright 2018 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. | 
|  |  | 
|  | 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; } | 
|  |  | 
|  | # Bazel build arguments to disable the use of the sandbox.  We have tests below | 
|  | # that configure a fake sandboxfs and they would fail if they were to use it. | 
|  | DISABLE_SANDBOX_ARGS=( | 
|  | --genrule_strategy=local | 
|  | --spawn_strategy=local | 
|  | ) | 
|  |  | 
|  | # Creates a fake sandboxfs process in "path" that logs interactions with it in | 
|  | # the given "log" file and reports the given "version". | 
|  | function create_fake_sandboxfs() { | 
|  | local path="${1}"; shift | 
|  | local log="${1}"; shift | 
|  | local version="${1}"; shift | 
|  |  | 
|  | cat >"${path}" <<EOF | 
|  | #! /bin/sh | 
|  |  | 
|  | rm -f "${log}" | 
|  | trap 'echo "Terminated" >>"${log}"' EXIT TERM | 
|  |  | 
|  | echo "PID: \${$}" >>"${log}" | 
|  | echo "ARGS: \${*}" >>"${log}" | 
|  |  | 
|  | if [ "\${1}" = --version ]; then | 
|  | echo "${version}" | 
|  | exit 0 | 
|  | fi | 
|  |  | 
|  | while read line; do | 
|  | echo "Received: \${line}" >>"${log}" | 
|  | if [ -z "\${line}" ]; then | 
|  | echo "Done" | 
|  | fi | 
|  | done | 
|  | EOF | 
|  | chmod +x "${path}" | 
|  | } | 
|  |  | 
|  | function create_hello_package() { | 
|  | mkdir -p hello | 
|  |  | 
|  | cat >hello/BUILD <<EOF | 
|  | cc_binary(name = "hello", srcs = ["hello.cc"]) | 
|  | EOF | 
|  |  | 
|  | cat >hello/hello.cc <<EOF | 
|  | #include <stdio.h> | 
|  | int main(void) { printf("Hello, world!\n"); return 0; } | 
|  | EOF | 
|  | } | 
|  |  | 
|  | function test_default_sandboxfs_from_path() { | 
|  | mkdir -p fake-tools | 
|  | create_fake_sandboxfs fake-tools/sandboxfs "$(pwd)/log" "sandboxfs 0.0.0" | 
|  | PATH="$(pwd)/fake-tools:${PATH}"; export PATH | 
|  |  | 
|  | create_hello_package | 
|  |  | 
|  | # This test relies on a PATH change that is only recognized when the server | 
|  | # first starts up, so ensure there are no Bazel servers left behind. | 
|  | # | 
|  | # TODO(philwo): This is awful.  The testing infrastructure should ensure | 
|  | # that tests cannot pollute each other's state, but at the moment that's not | 
|  | # the case. | 
|  | bazel shutdown | 
|  |  | 
|  | bazel build \ | 
|  | "${DISABLE_SANDBOX_ARGS[@]}" \ | 
|  | --experimental_use_sandboxfs \ | 
|  | //hello >"${TEST_log}" 2>&1 || fail "Build should have succeeded" | 
|  |  | 
|  | # Dump fake sandboxfs' log for debugging. | 
|  | sed -e 's,^,SANDBOXFS: ,' log >>"${TEST_log}" | 
|  |  | 
|  | grep -q "Terminated" log \ | 
|  | || fail "sandboxfs process was not terminated (not executed?)" | 
|  | } | 
|  |  | 
|  | function test_explicit_sandboxfs_not_found() { | 
|  | create_hello_package | 
|  |  | 
|  | bazel build \ | 
|  | --experimental_use_sandboxfs \ | 
|  | --experimental_sandboxfs_path="/non-existent/sandboxfs" \ | 
|  | //hello >"${TEST_log}" 2>&1 && fail "Build succeeded but should have failed" | 
|  |  | 
|  | expect_log "/non-existent/sandboxfs.*not be found" | 
|  | } | 
|  |  | 
|  | function test_explicit_sandboxfs_is_invalid() { | 
|  | mkdir -p fake-tools | 
|  | create_hello_package | 
|  | do_build() { | 
|  | bazel build \ | 
|  | "${DISABLE_SANDBOX_ARGS[@]}" \ | 
|  | --experimental_use_sandboxfs=yes \ | 
|  | --experimental_sandboxfs_path="$(pwd)/fake-tools/sandboxfs" \ | 
|  | //hello | 
|  | } | 
|  |  | 
|  | # Try with a binary that prints an invalid version string. | 
|  | create_fake_sandboxfs fake-tools/sandboxfs "$(pwd)/log" "not-sandboxfs 0.0.0" | 
|  | do_build >"${TEST_log}" 2>&1 && fail "Build should have failed" | 
|  |  | 
|  | # Now try with a valid binary just to ensure our test scenario works. | 
|  | create_fake_sandboxfs fake-tools/sandboxfs "$(pwd)/log" "sandboxfs 0.0.0" | 
|  | do_build >"${TEST_log}" 2>&1 || fail "Build should have succeeded" | 
|  | sed -e 's,^,SANDBOXFS: ,' log >>"${TEST_log}" | 
|  |  | 
|  | grep -q "Terminated" log \ | 
|  | || fail "sandboxfs process was not terminated (not executed?)" | 
|  | } | 
|  |  | 
|  | function test_use_sandboxfs_if_present() { | 
|  | # This test relies on a PATH change that is only recognized when the server | 
|  | # first starts up, so ensure there are no Bazel servers left behind. | 
|  | # | 
|  | # TODO(philwo): This is awful.  The testing infrastructure should ensure | 
|  | # that tests cannot pollute each other's state, but at the moment that's not | 
|  | # the case. | 
|  | bazel shutdown | 
|  |  | 
|  | mkdir -p fake-tools | 
|  | PATH="$(pwd)/fake-tools:${PATH}"; export PATH | 
|  | create_hello_package | 
|  | do_build() { | 
|  | bazel build \ | 
|  | "${DISABLE_SANDBOX_ARGS[@]}" \ | 
|  | --experimental_use_sandboxfs=auto \ | 
|  | //hello | 
|  | } | 
|  |  | 
|  | # Try with sandboxfs not in the PATH. | 
|  | do_build >"${TEST_log}" 2>&1 || fail "Build should have succeeded" | 
|  | [[ ! -f log ]] || echo "sandboxfs was used but should not have" | 
|  |  | 
|  | # Now try with sandboxfs in the PATH to ensure our test scenario works. | 
|  | create_fake_sandboxfs fake-tools/sandboxfs "$(pwd)/log" "sandboxfs 0.0.0" | 
|  | do_build >"${TEST_log}" 2>&1 || fail "Build should have succeeded" | 
|  | sed -e 's,^,SANDBOXFS: ,' log >>"${TEST_log}" | 
|  | grep -q "Terminated" log \ | 
|  | || fail "sandboxfs process was not terminated (not executed?)" | 
|  | } | 
|  |  | 
|  | # Runs a build of the given target using a fake sandboxfs that captures its | 
|  | # activity and dumps it to the given log file. | 
|  | function build_with_fake_sandboxfs() { | 
|  | local log="${1}"; shift | 
|  |  | 
|  | create_fake_sandboxfs fake-sandboxfs.sh "${log}" "sandboxfs 0.0.0" | 
|  |  | 
|  | local ret=0 | 
|  | bazel build \ | 
|  | "${DISABLE_SANDBOX_ARGS[@]}" \ | 
|  | --experimental_use_sandboxfs \ | 
|  | --experimental_sandboxfs_path="$(pwd)/fake-sandboxfs.sh" \ | 
|  | "${@}" >"${TEST_log}" 2>&1 || ret="${?}" | 
|  |  | 
|  | # Dump fake sandboxfs' log for debugging. | 
|  | sed -e 's,^,SANDBOXFS: ,' log >>"${TEST_log}" | 
|  |  | 
|  | return "${ret}" | 
|  | } | 
|  |  | 
|  | function test_mount_unmount() { | 
|  | create_hello_package | 
|  |  | 
|  | local output_base="$(bazel info output_base)" | 
|  | local sandbox_base="${output_base}/sandbox" | 
|  |  | 
|  | build_with_fake_sandboxfs "$(pwd)/log" //hello \ | 
|  | || fail "Build should have succeeded" | 
|  |  | 
|  | grep -q "ARGS: .*${sandbox_base}/sandboxfs" log \ | 
|  | || fail "Cannot find expected mount point in sandboxfs mount call" | 
|  | grep -q "Terminated" log \ | 
|  | || fail "sandboxfs process was not terminated (not unmounted?)" | 
|  | } | 
|  |  | 
|  | function test_debug_lifecycle() { | 
|  | create_hello_package | 
|  |  | 
|  | function sandboxfs_pid() { | 
|  | case "$(uname)" in | 
|  | Darwin) | 
|  | # We cannot use ps to look for the sandbox process because this is | 
|  | # not allowed when running with macOS's App Sandboxing. | 
|  | grep -q "Terminated" log && return | 
|  | grep "^PID:" log | awk '{print $2}' | 
|  | ;; | 
|  |  | 
|  | *) | 
|  | # We could use the same approach we follow on Darwin to look for the | 
|  | # PID of the subprocess, but it's better if we look at the real | 
|  | # process table if we are able to. | 
|  | ps ax | grep [f]ake-sandboxfs | awk '{print $1}' | 
|  | ;; | 
|  | esac | 
|  | } | 
|  |  | 
|  | # Want sandboxfs to be left mounted after a build with debugging on. | 
|  | build_with_fake_sandboxfs "$(pwd)/log" --sandbox_debug //hello | 
|  | grep -q "ARGS:" log || fail "sandboxfs was not run" | 
|  | grep -q "Terminated" log \ | 
|  | && fail "sandboxfs process was terminated but should not have been" | 
|  | local pid1="$(sandboxfs_pid)" | 
|  | [[ -n "${pid1}" ]] || fail "sandboxfs process not found in process table" | 
|  |  | 
|  | # Want sandboxfs to be restarted if the previous build had debugging on. | 
|  | build_with_fake_sandboxfs "$(pwd)/log" --sandbox_debug //hello | 
|  | local pid2="$(sandboxfs_pid)" | 
|  | [[ -n "${pid2}" ]] || fail "sandboxfs process not found in process table" | 
|  | [[ "${pid1}" -ne "${pid2}" ]] || fail "sandboxfs was not restarted" | 
|  |  | 
|  | # Want build to finish successfully and to clear the mount point. | 
|  | build_with_fake_sandboxfs "$(pwd)/log" --nosandbox_debug //hello | 
|  | local pid3="$(sandboxfs_pid)" | 
|  | [[ -z "${pid3}" ]] || fail "sandboxfs was not terminated" | 
|  | } | 
|  |  | 
|  | function test_always_unmounted_on_exit() { | 
|  | create_hello_package | 
|  |  | 
|  | # Want sandboxfs to be left mounted after a build with debugging on. | 
|  | build_with_fake_sandboxfs "$(pwd)/log" --sandbox_debug //hello | 
|  | grep -q "ARGS:" log || fail "sandboxfs was not run" | 
|  | grep -q "Terminated" log \ | 
|  | && fail "sandboxfs process was terminated but should not have been" | 
|  |  | 
|  | # Want Bazel to unmount the sandboxfs instance on exit no matter what. | 
|  | # | 
|  | # Note that we do not even tell Bazel where the sandboxfs binary lives | 
|  | # but we expect changes to the log of the currently-running sandboxfs | 
|  | # binary.  This is intentional to verify that the already-mounted | 
|  | # instance is the one shut down. | 
|  | bazel shutdown | 
|  | grep -q "Terminated" log \ | 
|  | || fail "sandboxfs process was not terminated but should have been" | 
|  | } | 
|  |  | 
|  | run_suite "sandboxfs-based sandboxing tests" |