blob: a85df0cf6258f5be575f52ab0e4baf5d16bdb081 [file] [log] [blame]
#!/bin/bash
#
# Copyright 2017 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.
#
# Tests remote execution and caching.
#
# 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; }
function set_up() {
work_path=$(mktemp -d "${TEST_TMPDIR}/remote.XXXXXXXX")
cas_path=$(mktemp -d "${TEST_TMPDIR}/remote.XXXXXXXX")
pid_file=$(mktemp -u "${TEST_TMPDIR}/remote.XXXXXXXX")
attempts=1
while [ $attempts -le 5 ]; do
(( attempts++ ))
worker_port=$(pick_random_unused_tcp_port) || fail "no port found"
http_port=$(pick_random_unused_tcp_port) || fail "no port found"
"${BAZEL_RUNFILES}/src/tools/remote/worker" \
--work_path="${work_path}" \
--cas_path="${cas_path}" \
--listen_port=${worker_port} \
--http_listen_port=${http_port} \
--pid_file="${pid_file}" &
local wait_seconds=0
until [ -s "${pid_file}" ] || [ "$wait_seconds" -eq 15 ]; do
sleep 1
((wait_seconds++)) || true
done
if [ -s "${pid_file}" ]; then
break
fi
done
if [ ! -s "${pid_file}" ]; then
fail "Timed out waiting for remote worker to start."
fi
}
function tear_down() {
bazel clean >& $TEST_log
if [ -s "${pid_file}" ]; then
local pid=$(cat "${pid_file}")
kill "${pid}" || true
fi
rm -rf "${pid_file}"
rm -rf "${work_path}"
rm -rf "${cas_path}"
}
function test_remote_http_cache_flag() {
# Test that the deprecated --remote_http_cache flag still works.
mkdir -p a
cat > a/BUILD <<EOF
genrule(
name = 'foo',
outs = ["foo.txt"],
cmd = "echo \"foo bar\" > \$@",
)
EOF
bazel build \
--remote_http_cache=http://localhost:${http_port} \
//a:foo \
|| fail "Failed to build //a:foo with remote cache"
}
function test_cc_binary_http_cache() {
mkdir -p a
cat > a/BUILD <<EOF
package(default_visibility = ["//visibility:public"])
cc_binary(
name = 'test',
srcs = [ 'test.cc' ],
)
EOF
cat > a/test.cc <<EOF
#include <iostream>
int main() { std::cout << "Hello world!" << std::endl; return 0; }
EOF
bazel build //a:test \
|| fail "Failed to build //a:test without remote cache"
cp -f bazel-bin/a/test ${TEST_TMPDIR}/test_expected
bazel clean
bazel build \
--remote_cache=http://localhost:${http_port} \
//a:test \
|| fail "Failed to build //a:test with remote HTTP cache service"
diff bazel-bin/a/test ${TEST_TMPDIR}/test_expected \
|| fail "Remote cache generated different result"
# Check that persistent connections are closed after the build. Is there a good cross-platform way
# to check this?
if [[ "$PLATFORM" = "linux" ]]; then
if netstat -tn | grep -qE ":${http_port}\\s+ESTABLISHED$"; then
fail "connections to to cache not closed"
fi
fi
}
function test_cc_binary_http_cache_bad_server() {
mkdir -p a
cat > a/BUILD <<EOF
package(default_visibility = ["//visibility:public"])
cc_binary(
name = 'test',
srcs = [ 'test.cc' ],
)
EOF
cat > a/test.cc <<EOF
#include <iostream>
int main() { std::cout << "Hello world!" << std::endl; return 0; }
EOF
bazel build //a:test >& $TEST_log \
|| fail "Failed to build //a:test without remote cache"
cp -f bazel-bin/a/test ${TEST_TMPDIR}/test_expected
bazel clean >& $TEST_log
bazel build \
--remote_cache=http://bad.hostname/bad/cache \
//a:test >& $TEST_log \
|| fail "Failed to build //a:test with remote HTTP cache service"
diff bazel-bin/a/test ${TEST_TMPDIR}/test_expected \
|| fail "Remote cache generated different result"
# Check that persistent connections are closed after the build. Is there a good cross-platform way
# to check this?
if [[ "$PLATFORM" = "linux" ]]; then
if netstat -tn | grep -qE ":${http_port}\\s+ESTABLISHED$"; then
fail "connections to to cache not closed"
fi
fi
}
function test_refuse_to_upload_symlink() {
cat > BUILD <<'EOF'
genrule(
name = 'make-link',
outs = ['l', 't'],
cmd = 'touch $(location t) && ln -s t $(location l)',
)
EOF
bazel build \
--noremote_allow_symlink_upload \
--remote_cache=http://localhost:${http_port} \
//:make-link &> $TEST_log \
&& fail "should have failed" || true
expect_log "/l is a symbolic link"
}
function test_refuse_to_upload_symlink_in_directory() {
cat > BUILD <<'EOF'
genrule(
name = 'make-link',
outs = ['dir'],
cmd = 'mkdir $(location dir) && touch $(location dir)/t && ln -s t $(location dir)/l',
)
EOF
bazel build \
--noremote_allow_symlink_upload \
--remote_cache=http://localhost:${http_port} \
//:make-link &> $TEST_log \
&& fail "should have failed" || true
expect_log "dir/l is a symbolic link"
}
function set_directory_artifact_skylark_testfixtures() {
mkdir -p a
cat > a/rule.bzl <<'EOF'
def _gen_output_dir_impl(ctx):
output_dir = ctx.actions.declare_directory(ctx.attr.outdir)
ctx.actions.run_shell(
outputs = [output_dir],
inputs = [],
command = """
mkdir -p $1/sub1; \
echo "Hello, world!" > $1/foo.txt; \
echo "Shuffle, duffle, muzzle, muff" > $1/sub1/bar.txt
""",
arguments = [output_dir.path],
)
return [
DefaultInfo(
files=depset(direct=[output_dir]),
data_runfiles=ctx.runfiles(files=[output_dir]),
),
]
gen_output_dir = rule(
implementation = _gen_output_dir_impl,
attrs = {
"outdir": attr.string(mandatory = True),
},
)
EOF
cat > a/BUILD <<'EOF'
package(default_visibility = ["//visibility:public"])
load("//a:rule.bzl", "gen_output_dir")
gen_output_dir(
name = "output_dir",
outdir = "dir",
)
genrule(
name = "test",
srcs = [":output_dir"],
outs = ["qux"],
cmd = "mkdir $@ && paste -d\"\n\" $(location :output_dir)/foo.txt $(location :output_dir)/sub1/bar.txt > $@/out.txt",
)
sh_binary(
name = "a-tool",
srcs = ["a-tool.sh"],
data = [":output_dir"],
)
genrule(
name = "test2",
outs = ["test2-out.txt"],
cmd = "$(location :a-tool) > $@",
tools = [":a-tool"],
)
EOF
cat > a/a-tool.sh <<'EOF'
#!/bin/sh -eu
cat "$0".runfiles/main/a/dir/foo.txt "$0".runfiles/main/a/dir/sub1/bar.txt
EOF
chmod u+x a/a-tool.sh
cat > a/test_expected <<EOF
Hello, world!
Shuffle, duffle, muzzle, muff
EOF
}
function test_directory_artifact_skylark_local() {
set_directory_artifact_skylark_testfixtures
bazel build //a:test >& $TEST_log \
|| fail "Failed to build //a:test without remote execution"
diff bazel-genfiles/a/qux/out.txt a/test_expected \
|| fail "Local execution generated different result"
}
function test_directory_artifact_skylark() {
set_directory_artifact_skylark_testfixtures
bazel build \
--spawn_strategy=remote \
--remote_executor=grpc://localhost:${worker_port} \
//a:test >& $TEST_log \
|| fail "Failed to build //a:test with remote execution"
diff bazel-genfiles/a/qux/out.txt a/test_expected \
|| fail "Remote execution generated different result"
bazel clean
bazel build \
--spawn_strategy=remote \
--remote_executor=grpc://localhost:${worker_port} \
//a:test >& $TEST_log \
|| fail "Failed to build //a:test with remote execution"
expect_log "remote cache hit"
diff bazel-genfiles/a/qux/out.txt a/test_expected \
|| fail "Remote cache hit generated different result"
}
function test_directory_artifact_skylark_grpc_cache() {
set_directory_artifact_skylark_testfixtures
bazel build \
--remote_cache=grpc://localhost:${worker_port} \
//a:test >& $TEST_log \
|| fail "Failed to build //a:test with remote gRPC cache"
diff bazel-genfiles/a/qux/out.txt a/test_expected \
|| fail "Remote cache miss generated different result"
bazel clean
bazel build \
--remote_cache=grpc://localhost:${worker_port} \
//a:test >& $TEST_log \
|| fail "Failed to build //a:test with remote gRPC cache"
expect_log "remote cache hit"
diff bazel-genfiles/a/qux/out.txt a/test_expected \
|| fail "Remote cache hit generated different result"
}
function test_directory_artifact_skylark_http_cache() {
set_directory_artifact_skylark_testfixtures
bazel build \
--remote_cache=http://localhost:${http_port} \
//a:test >& $TEST_log \
|| fail "Failed to build //a:test with remote HTTP cache"
diff bazel-genfiles/a/qux/out.txt a/test_expected \
|| fail "Remote cache miss generated different result"
bazel clean
bazel build \
--remote_cache=http://localhost:${http_port} \
//a:test >& $TEST_log \
|| fail "Failed to build //a:test with remote HTTP cache"
expect_log "remote cache hit"
diff bazel-genfiles/a/qux/out.txt a/test_expected \
|| fail "Remote cache hit generated different result"
}
function test_directory_artifact_in_runfiles_skylark_http_cache() {
set_directory_artifact_skylark_testfixtures
bazel build \
--remote_cache=http://localhost:${http_port} \
//a:test2 >& $TEST_log \
|| fail "Failed to build //a:test2 with remote HTTP cache"
diff bazel-genfiles/a/test2-out.txt a/test_expected \
|| fail "Remote cache miss generated different result"
bazel clean
bazel build \
--remote_cache=http://localhost:${http_port} \
//a:test2 >& $TEST_log \
|| fail "Failed to build //a:test2 with remote HTTP cache"
expect_log "remote cache hit"
diff bazel-genfiles/a/test2-out.txt a/test_expected \
|| fail "Remote cache hit generated different result"
}
function test_remote_state_cleared() {
# Regression test for https://github.com/bazelbuild/bazel/issues/7555
# Test that the remote cache state is properly reset, so that building without
# a remote cache works after previously building with a remote cache.
mkdir -p a
cat > a/BUILD <<'EOF'
genrule(
name = "gen1",
outs = ["out1"],
cmd = "touch $@",
)
EOF
bazel build \
--remote_cache=http://localhost:${http_port} \
//a:gen1 \
|| fail "Failed to build //a:gen1 with remote cache"
bazel clean
bazel build //a:gen1 \
|| fail "Failed to build //a:gen1 without remote cache"
}
function test_genrule_combined_disk_http_cache() {
# Test for the combined disk and http cache.
# Built items should be pushed to both the disk and http cache.
# If an item is missing on disk cache, but present on http cache,
# then bazel should copy it from http cache to disk cache on fetch.
local cache="${TEST_TMPDIR}/cache"
local disk_flags="--disk_cache=$cache"
local http_flags="--remote_cache=http://localhost:${http_port}"
mkdir -p a
cat > a/BUILD <<EOF
package(default_visibility = ["//visibility:public"])
genrule(
name = 'test',
cmd = 'echo "Hello world" > \$@',
outs = [ 'test.txt' ],
)
EOF
rm -rf $cache
mkdir $cache
# Build and push to disk and http cache
bazel build $disk_flags $http_flags //a:test \
|| fail "Failed to build //a:test with combined disk http cache"
cp -f bazel-genfiles/a/test.txt ${TEST_TMPDIR}/test_expected
# Fetch from disk cache
bazel clean
bazel build $disk_flags //a:test &> $TEST_log \
|| fail "Failed to fetch //a:test from disk cache"
expect_log "1 remote cache hit" "Fetch from disk cache failed"
diff bazel-genfiles/a/test.txt ${TEST_TMPDIR}/test_expected \
|| fail "Disk cache generated different result"
# Fetch from http cache
bazel clean
bazel build $http_flags //a:test &> $TEST_log \
|| fail "Failed to fetch //a:test from http cache"
expect_log "1 remote cache hit" "Fetch from http cache failed"
diff bazel-genfiles/a/test.txt ${TEST_TMPDIR}/test_expected \
|| fail "HTTP cache generated different result"
rm -rf $cache
mkdir $cache
# Copy from http cache to disk cache
bazel clean
bazel build $disk_flags $http_flags //a:test &> $TEST_log \
|| fail "Failed to copy //a:test from http cache to disk cache"
expect_log "1 remote cache hit" "Copy from http cache to disk cache failed"
diff bazel-genfiles/a/test.txt ${TEST_TMPDIR}/test_expected \
|| fail "HTTP cache generated different result"
# Fetch from disk cache
bazel clean
bazel build $disk_flags //a:test &> $TEST_log \
|| fail "Failed to fetch //a:test from disk cache"
expect_log "1 remote cache hit" "Fetch from disk cache after copy from http cache failed"
diff bazel-genfiles/a/test.txt ${TEST_TMPDIR}/test_expected \
|| fail "Disk cache generated different result"
rm -rf $cache
}
run_suite "Remote execution and remote cache tests"