blob: 5deb30d1c3f9aad1be2725539e96188f6c757035 [file] [log] [blame]
#!/bin/bash
# Copyright 2019 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
### Test expected behavior of fx test
BT_LINKED_DEPS=(
"third_party"
"prebuilt/third_party/dart"
"scripts/fxtest"
"scripts/fxutils"
)
BT_FILE_DEPS=(
"scripts/fx"
"tools/devshell/tests/subcommands/data/fx_test_test/tests_hashfile"
"tools/devshell/tests/subcommands/data/fx_test_test/tests_multiple_in_package.json"
"tools/devshell/tests/subcommands/data/fx_test_test/tests_package_server_integration.json"
"tools/devshell/lib/fx-cmd-locator.sh"
"tools/devshell/lib/fx-optional-features.sh"
"tools/devshell/lib/vars.sh"
"tools/devshell/lib/platform.sh"
"tools/devshell/test"
)
BT_MOCKED_TOOLS=(
"tools/devshell/build"
"tools/devshell/is-package-server-running"
"tools/devshell/update-if-in-base"
"tools/devshell/shell"
"tools/devshell/symbolize"
"tools/devshell/lib/metrics_custom_report.sh"
)
declare fx DATA_DIR
BT_SET_UP() {
source "${BT_TEMP_DIR}/tools/devshell/tests/lib/fuchsia-mock.sh"
fx="$(btf::setup_fx)"
btf::make_installed_hosttools_mock "ffx" > /dev/null
btf::make_installed_hosttools_mock "symbolizer" > /dev/null
btf::make_installed_hosttools_mock "symbol-index" > /dev/null
DATA_DIR="${BT_TEMP_DIR}/tools/devshell/tests/subcommands/data/fx_test_test"
}
# Test that the "fx test --info" outputs in the format expected by other
# commands, eg `fx run-test`
TEST_fxtest_info() {
cp "${DATA_DIR}/tests_multiple_in_package.json" "${BT_TEMP_DIR}/out/default/tests.json"
local out="${BT_TEMP_DIR}/_fx_test_output"
BT_EXPECT ${fx} test --info --exact > "${out}"
BT_EXPECT_EQ "$(sed -n 's/^package_url: \(.*\)/\1/p' "${out}" | wc -l)" 7
}
# Test that `fx test` calls `fx update-if-in-base` and `fx is-package-server-running` properly
TEST_fxtest_package_server_integration() {
cp "${DATA_DIR}/tests_package_server_integration.json" "${BT_TEMP_DIR}/out/default/tests.json"
local out="${BT_TEMP_DIR}/_fx_test_output"
local testname="overflow_fuzzer_test"
BT_EXPECT ${fx} test --no-use-package-hash ${testname} > ${out}
# ensure that is-package-server-running was called
BT_ASSERT_FILE_EXISTS "${BT_TEMP_DIR}/tools/devshell/is-package-server-running.mock_state"
# ensure that update-if-in-base was called with the proper testname
btf::expect-mock-args "${BT_TEMP_DIR}/tools/devshell/update-if-in-base" "${testname}"
}
# Ensure that `fx build` is called by default
TEST_fxtest_build() {
cp "${DATA_DIR}/tests_package_server_integration.json" "${BT_TEMP_DIR}/out/default/tests.json"
local out="${BT_TEMP_DIR}/_fx_test_output"
local testname="overflow_fuzzer_test"
BT_EXPECT ${fx} test --no-use-package-hash ${testname} > ${out}
# ensure that fx build was called
# TODO: once fx test calls fx build with a specific target, check it here as well
BT_ASSERT_FILE_EXISTS "${BT_TEMP_DIR}/tools/devshell/build.mock_state"
}
# Ensure that `fx test` exits with a non-zero status if `fx build` fails.
TEST_fxtest_build_failure_exits_with_nonzero_status() {
cp "${DATA_DIR}/tests_package_server_integration.json" "${BT_TEMP_DIR}/out/default/tests.json"
local out="${BT_TEMP_DIR}/_fx_test_output"
local testname="overflow_fuzzer_test"
echo 1 > "${BT_TEMP_DIR}/tools/devshell/build.mock_status"
BT_EXPECT_FAIL ${fx} test --no-use-package-hash ${testname} > ${out}
# ensure that fx build was called
# TODO: once fx test calls fx build with a specific target, check it here as well
BT_ASSERT_FILE_EXISTS "${BT_TEMP_DIR}/tools/devshell/build.mock_state"
}
# Ensure that `fx build` is not called when "--no-build" option is given
TEST_fxtest_nobuild() {
cp "${DATA_DIR}/tests_package_server_integration.json" "${BT_TEMP_DIR}/out/default/tests.json"
local out="${BT_TEMP_DIR}/_fx_test_output"
local testname="overflow_fuzzer_test"
BT_EXPECT ${fx} test --no-use-package-hash --no-build ${testname} > ${out}
# ensure that fx build was called
# TODO: once fx test calls fx build with a specific target, check it here as well
BT_ASSERT_FILE_DOES_NOT_EXIST "${BT_TEMP_DIR}/tools/devshell/build.mock_state"
}
# Ensure that `fx test` exits with a non-zero status if
# `fx # is-package-server-running` fails.
TEST_fxtest_fails_with_no_package_server() {
cp "${DATA_DIR}/tests_package_server_integration.json" "${BT_TEMP_DIR}/out/default/tests.json"
local out="${BT_TEMP_DIR}/_fx_test_output"
local testname1="overflow_fuzzer_test"
echo 1 > "${BT_TEMP_DIR}/tools/devshell/is-package-server-running.mock_status"
BT_EXPECT_FAIL ${fx} test --no-use-package-hash --no-build ${testname} > ${out}
# ensure that fx is-package-server-running was called
BT_ASSERT_FILE_EXISTS "${BT_TEMP_DIR}/tools/devshell/is-package-server-running.mock_state"
}
# Test that "fx test" runs a component test pinning it to the hash (merkleroot) of
# the component package, so that the user has confidence that if a test runs, it is
# running the exact same version that has been built
TEST_fxtest_hashpinnning() {
cp -R "${DATA_DIR}/tests_hashfile/out" "${BT_TEMP_DIR}"
local out="${BT_TEMP_DIR}/_fx_test_output"
local testname1="overflow_fuzzer_test"
local hash1="913cdd63ab4aa794694448450505efaa2a8fe27fb33888e5156da9db60ac0a29"
local testname2="hello_world_cpp_unittests"
local hash2="7a604498e05fa012391b6b51da9cc74ff6a6a9d25b1376de98125c194232bfa1"
# expect that "fx shell run-test-component URL-WITH-HASH" was executed
BT_EXPECT ${fx} test --no-build ${testname1} >> "${out}"
local packageUrl1="fuchsia-pkg://fuchsia.com/example-fuzzers?hash=${hash1}#meta/overflow_fuzzer_test.cmx"
btf::expect-mock-args "${BT_TEMP_DIR}/tools/devshell/shell" "run-test-component" "${packageUrl1}"
# expect that "fx shell run-test-component URL-WITH-HASH" was executed
BT_EXPECT ${fx} test --no-build ${testname2} >> "${out}"
local packageUrl2="fuchsia-pkg://fuchsia.com/hello_world_cpp_tests?hash=${hash2}#meta/hello_world_cpp_unittests.cmx"
btf::expect-mock-args "${BT_TEMP_DIR}/tools/devshell/shell.mock_state.2" "run-test-component" "${packageUrl2}"
}
# Test that when the merkle root of a package is changed as a result of the
# 'fx build' executed by fx test, the new hash is used when pinning the
# package in fx shell run-test-component
TEST_fxtest_updated_hash() {
cp -R "${DATA_DIR}/tests_hashfile/out" "${BT_TEMP_DIR}"
local out="${BT_TEMP_DIR}/_fx_test_output"
local testname1="overflow_fuzzer_test"
local hash_old="913cdd63ab4aa794694448450505efaa2a8fe27fb33888e5156da9db60ac0a29"
local hash_new="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
# create a build script that, when called, changes hash_old to hash_new in the
# package repository
cat > "${BT_TEMP_DIR}/tools/devshell/build.mock_side_effects" <<EOF
sed -i 's/${hash_old}/${hash_new}/g' ${BT_TEMP_DIR}/out/default/amber-files/repository/targets.json
EOF
# expect that "fx shell run-test-component URL-WITH-HASH" executes with the new hash, not the old one
BT_EXPECT ${fx} test ${testname1} >> "${out}"
local packageUrl="fuchsia-pkg://fuchsia.com/example-fuzzers?hash=${hash_new}#meta/overflow_fuzzer_test.cmx"
btf::expect-mock-args "${BT_TEMP_DIR}/tools/devshell/shell" "run-test-component" "${packageUrl}"
}
# Test that "fx test" fails if a component test doesn't have an entry in the
# package repository
TEST_fxtest_no_hashfile() {
cp -R "${DATA_DIR}/tests_hashfile/out" "${BT_TEMP_DIR}"
cat > "${BT_TEMP_DIR}/out/default/tests.json" <<EOF
[{"environments": [],
"test": {
"cpu": "arm64",
"label": "//examples/fuzzer:fuzzing-examples_pkg(//build/toolchain/fuchsia:arm64)",
"name": "overflow_fuzzer_test",
"os": "fuchsia",
"package_url": "fuchsia-pkg://fuchsia.com/example_not_in_repository#meta/overflow_fuzzer_test.cmx",
"path": ""
}
}]
EOF
local out="${BT_TEMP_DIR}/_fx_test_output"
# expect that fx test fails because the repository doesn't have an entry for
# this test's package (example_not_in_repository)
BT_EXPECT_FAIL ${fx} test --no-build overflow_fuzzer_test >> "${out}"
}
# Test that "fx test" builds only the minimal target for device tests
TEST_fxtest_build_device_only_package() {
mkdir -p "${BT_TEMP_DIR}/out/default"
cat > "${BT_TEMP_DIR}/out/default/tests.json" <<EOF
[{"environments": [],
"test": {
"cpu": "arm64",
"label": "//examples/fuzzer:fuzzing-examples_pkg(//build/toolchain/fuchsia:arm64)",
"package_label": "//examples/fuzzer:fuzzing_pkg(//build/toolchain/fuchsia:arm64)",
"name": "overflow_fuzzer_test",
"os": "fuchsia",
"package_url": "fuchsia-pkg://fuchsia.com/example-fuzzers#meta/overflow_fuzzer_test.cmx",
"path": ""
}
}]
EOF
local out="${BT_TEMP_DIR}/_fx_test_output"
# with incremental enabled, expect "fx shell build <test_package>"
BT_EXPECT ${fx} --enable=incremental test --no-use-package-hash overflow_fuzzer_test >> "${out}"
btf::expect-mock-args "${BT_TEMP_DIR}/tools/devshell/build" "examples/fuzzer:fuzzing_pkg"
# with incremental disabled, expect "fx shell build updates"
BT_EXPECT ${fx} --disable=incremental test --no-use-package-hash overflow_fuzzer_test >> "${out}"
btf::expect-mock-args "${BT_TEMP_DIR}/tools/devshell/build.mock_state.2" "updates"
}
# Test that "fx test" builds the default target for an e2e test
TEST_fxtest_build_e2e() {
mkdir -p "${BT_TEMP_DIR}/out/default"
cat > "${BT_TEMP_DIR}/out/default/tests.json" <<EOF
[{"environments": [{"dimensions": {"device_type": "qemu_x64"}}],
"test": {
"cpu": "x64",
"label": "//examples/example_host_test:host_tools_example_pkg(//build/toolchain/host_x64)",
"name": "example_host_test",
"os": "linux",
"path": "host_x64/example_host_test"
}
}]
EOF
local out="${BT_TEMP_DIR}/_fx_test_output"
btf::make_hosttools_mock "example_host_test" > /dev/null
# expect "fx shell build"
BT_EXPECT ${fx} test --e2e example_host_test >> "${out}"
btf::expect-mock-args "${BT_TEMP_DIR}/tools/devshell/build"
}
# Test that "fx test" only builds the host tool for a host test
TEST_fxtest_build_host() {
mkdir -p "${BT_TEMP_DIR}/out/default"
cat > "${BT_TEMP_DIR}/out/default/tests.json" <<EOF
[{"environments": [],
"test": {
"cpu": "x64",
"label": "//examples/example_host_test:host_tools_example_pkg(//build/toolchain/host_x64)",
"name": "example_host_test",
"os": "linux",
"path": "host_x64/example_host_test"
}
}]
EOF
local out="${BT_TEMP_DIR}/_fx_test_output"
btf::make_hosttools_mock "example_host_test" > /dev/null
# expect "fx shell build"
BT_EXPECT ${fx} test example_host_test >> "${out}"
btf::expect-mock-args "${BT_TEMP_DIR}/tools/devshell/build" "host_x64/example_host_test"
}
# Test that "fx test" executes an e2e test with the proper env variables set
TEST_fxtest_e2e_env() {
mkdir -p "${BT_TEMP_DIR}/out/default"
cat > "${BT_TEMP_DIR}/out/default/tests.json" <<EOF
[{"environments": [{"dimensions": {"device_type": "qemu_x64"}}],
"test": {
"cpu": "x64",
"label": "//examples/example_host_test:host_tools_example_pkg(//build/toolchain/host_x64)",
"name": "example_host_test",
"os": "linux",
"path": "host_x64/example_host_test"
}
}]
EOF
local out="${BT_TEMP_DIR}/_fx_test_output"
local test_exec="$(btf::make_hosttools_mock "example_host_test")"
# some 'fx test' features call this function to track test execution if the
# user has metrics enabled.
function track-subcommand-custom-event {
:
}
export -f track-subcommand-custom-event
# when the test is executed, print out the e2e variables as they are given to the test
cat > "${test_exec}.mock_side_effects" <<'EOF'
printVar() {
local n="$1"
# print var if it's set, even if it's empty
[[ -n ${!n+x} ]] && echo "TESTING_E2E_VARS: $n=${!n}" > /dev/stderr
}
printVar FUCHSIA_DEVICE_ADDR
printVar FUCHSIA_SSH_KEY
printVar FUCHSIA_SSH_PORT
printVar FUCHSIA_TEST_OUTDIR
printVar SL4F_HTTP_PORT
printVar FUCHSIA_IPV4_ADDR
exit 0
EOF
# check if environemnt is as expected for a user-defined IPV4 device and SSH port
BT_EXPECT ${fx} -d 1.1.1.1:8123 test -o --e2e example_host_test | grep "TESTING_E2E_VARS" > "${out}"
BT_EXPECT_FILE_CONTAINS_SUBSTRING "${out}" "FUCHSIA_DEVICE_ADDR=1.1.1.1"
BT_EXPECT_FILE_CONTAINS_SUBSTRING "${out}" "FUCHSIA_SSH_PORT=8123"
BT_EXPECT_FILE_CONTAINS_SUBSTRING "${out}" "FUCHSIA_SSH_KEY=..*" # ensures no empty definition
BT_EXPECT_FILE_CONTAINS_SUBSTRING "${out}" "FUCHSIA_TEST_OUTDIR=..*" # ensures no empty definition
# check if environemnt is as expected for a user-defined IPV6 device and SSH port
BT_EXPECT ${fx} -d '[::1]:1111' test -o --e2e example_host_test | grep "TESTING_E2E_VARS" > "${out}"
BT_EXPECT_FILE_CONTAINS_SUBSTRING "${out}" "FUCHSIA_DEVICE_ADDR=[::1]"
BT_EXPECT_FILE_CONTAINS_SUBSTRING "${out}" "FUCHSIA_SSH_PORT=1111"
BT_EXPECT_FILE_CONTAINS_SUBSTRING "${out}" "FUCHSIA_SSH_KEY=..*" # ensures no empty definition
BT_EXPECT_FILE_CONTAINS_SUBSTRING "${out}" "FUCHSIA_TEST_OUTDIR=..*" # ensures no empty definition
# no device set, test should not be given a fuchsia_ssh_port, and fuchsia_device_addr must be defined as empty
BT_EXPECT ${fx} test -o --e2e example_host_test | grep "TESTING_E2E_VARS" > "${out}"
BT_EXPECT_FILE_CONTAINS_SUBSTRING "${out}" 'FUCHSIA_DEVICE_ADDR=$' # ensures empty definition
BT_EXPECT_EMPTY "$(grep FUCHSIA_SSH_PORT "${out}")" "unexpected FUCHSIA_SSH_PORT"
# if defined in the caller's environment, sl4f_http_port is passed as is
BT_EXPECT SL4F_HTTP_PORT=9099 ${fx} test -o --e2e example_host_test | grep "TESTING_E2E_VARS" > "${out}"
BT_EXPECT_FILE_CONTAINS_SUBSTRING "${out}" "SL4F_HTTP_PORT=9099"
# fuchsia_test_outdir must be a valid and writable directory
BT_EXPECT ${fx} test -o --e2e example_host_test > "${out}"
local test_out_dir="$(sed -n "s/.* FUCHSIA_TEST_OUTDIR=\(.*\)/\1/p" "${out}")"
BT_EXPECT touch "${test_out_dir}/test_file"
}
# Ensure that if `fx build` changes `tests.json`, `fx test` loads the updated
# tests.json before running the test.
TEST_fxtest_build_changes_testsjson() {
mkdir -p "${BT_TEMP_DIR}/out/default"
local out="${BT_TEMP_DIR}/_fx_test_output"
local test_exec="$(btf::make_hosttools_mock "example_host_test")"
cat > "${BT_TEMP_DIR}/out/default/tests.json" <<EOF
[{"environments": [],
"test": {
"command": [
"host_x64/example_host_test",
"beforefxbuild"
],
"cpu": "x64",
"label": "//examples/example_host_test:host_tools_example_pkg(//build/toolchain/host_x64)",
"name": "example_host_test",
"os": "linux",
"path": "host_x64/example_host_test"
}
}]
EOF
# make 'fx build' change the command argument in tests.json from "beforefxbuild"
# to "afterfxbuild"
cat > "${BT_TEMP_DIR}/tools/devshell/build.mock_side_effects" <<EOF
sed -i 's/beforefxbuild/afterfxbuild/' "${BT_TEMP_DIR}/out/default/tests.json"
EOF
BT_EXPECT ${fx} test example_host_test > ${out}
btf::expect-mock-args "${test_exec}.mock_state" "afterfxbuild"
}
BT_RUN_TESTS "$@"