| #!/bin/bash |
| # Copyright 2020 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. |
| # |
| # Common helpers specific for Fuchsia in-tree testing. |
| |
| btf::setup_fx() { |
| if [[ -z "${BT_TEMP_DIR}" ]]; then |
| echo "Cannot proceed, BT_TEMP_DIR is unset" 1>&2 |
| exit 1 |
| fi |
| local with_metrics=0 |
| if [[ $# -gt 0 && "$1" == "1" ]]; then |
| with_metrics=1 |
| fi |
| |
| local _HOST_OUT_DIR="host_x64" |
| local _REL_BUILD_DIR="out/default" |
| local _FUCHSIA_DIR="${BT_TEMP_DIR}" |
| local _FUCHSIA_BUILD_DIR="${_FUCHSIA_DIR}/${_REL_BUILD_DIR}" |
| |
| # Fake fuchsia dir configuration. |
| local _FX="${_FUCHSIA_DIR}/scripts/fx" |
| BT_ASSERT_FILE_EXISTS "${_FX}" |
| BT_ASSERT_FILE_EXISTS "${_FUCHSIA_DIR}/tools/devshell/lib/vars.sh" |
| BT_ASSERT_FILE_EXISTS "${_FUCHSIA_DIR}/tools/devshell/lib/platform.sh" |
| BT_ASSERT_FILE_EXISTS "${_FUCHSIA_DIR}/tools/devshell/lib/fx-optional-features.sh" |
| |
| # Fake a build directory with the minimal content so that fx work |
| mkdir -p "${_FUCHSIA_BUILD_DIR}" "${_FUCHSIA_BUILD_DIR}/${_HOST_OUT_DIR}" \ |
| "${_FUCHSIA_DIR}/.jiri_root/bin" "${_FUCHSIA_DIR}/.ssh" |
| ln -s "${_FX}" "${_FUCHSIA_DIR}/.jiri_root/bin/fx" |
| echo "${_REL_BUILD_DIR}" > "${_FUCHSIA_DIR}/.fx-build-dir" |
| touch "${_FUCHSIA_BUILD_DIR}/args.gn" |
| touch "${_FUCHSIA_DIR}/.ssh/fuchsia_ed25519" "${_FUCHSIA_DIR}/.ssh/fuchsia_authorized_keys" |
| echo -e "${_FUCHSIA_DIR}/.ssh/fuchsia_ed25519\n${_FUCHSIA_DIR}/.ssh/fuchsia_authorized_keys" > "${_FUCHSIA_DIR}/.fx-ssh-path" |
| |
| cat > "${_FUCHSIA_BUILD_DIR}/fx.config" << EOF |
| # Generated by fuchsia-mock.sh. |
| FUCHSIA_BUILD_DIR='${_REL_BUILD_DIR}' |
| FUCHSIA_ARCH='x64' |
| FUCHSIA_BOARD_NAME=pc |
| FUCHSIA_ZBI_COMPRESSION=zstd |
| HOST_OUT_DIR='${_HOST_OUT_DIR}' |
| EOF |
| if (( with_metrics )); then |
| BT_ASSERT_FILE_EXISTS "${_FUCHSIA_DIR}/tools/devshell/lib/metrics.sh" |
| else |
| btf::make_mock "${_FUCHSIA_DIR}/tools/devshell/lib/metrics.sh" |
| cat > "${_FUCHSIA_DIR}/tools/devshell/lib/metrics.sh.mock_side_effects" <<EOF |
| function track-command-execution { |
| : |
| } |
| function track-command-finished { |
| : |
| } |
| EOF |
| fi |
| # If the host-tool command is not mocked, some code in vars.sh will |
| # not work well. If a custom mock of 'fx host-tool' is needed, mock it |
| # before calling 'setup_fx' |
| btf::_make_fx_host_tool_mock |
| |
| echo "${_FX}" |
| } |
| |
| btf::setup_fx_with_metrics() { |
| btf::setup_fx 1 |
| } |
| |
| btf::_make_buildtool_mock() { |
| local rel_path="$1" |
| local path="${BT_TEMP_DIR}/${rel_path}" |
| btf::make_mock "${path}" |
| |
| echo "${path}" >> "${BT_TEMP_DIR}/.mocked_tools" |
| echo "${path}" |
| } |
| |
| btf::make_installed_hosttools_mock() { |
| local hosttool_name="$1" |
| btf::_make_buildtool_mock "out/default/host-tools/${hosttool_name}" |
| } |
| |
| btf::make_hosttools_mock() { |
| local hosttool_name="$1" |
| btf::_make_buildtool_mock "out/default/host_x64/${hosttool_name}" |
| } |
| |
| btf::make_mock_binary() { |
| local -r _BIN_PATH="$(mktemp -d "${BT_TEMP_DIR}/binpath.XXXXXX")" |
| local tool_name="$1" |
| local tool_path="${_BIN_PATH}/${tool_name}" |
| btf::make_mock "${tool_path}" |
| echo "${tool_path}" |
| } |
| |
| btf::add_binary_to_path() { |
| local tool_path="$(dirname "$1")" |
| export PATH="${tool_path}:$PATH" |
| } |
| |
| btf::_make_fx_host_tool_mock() { |
| local tool="${BT_TEMP_DIR}/tools/devshell/host-tool" |
| if [[ -f "${tool}" ]]; then |
| return 0 |
| fi |
| |
| btf::make_mock "${tool}" |
| cat > "${tool}.mock_side_effects" <<EOF |
| # remove host-tool args (like --check-firewall) |
| print=false |
| while [[ \$# -gt 0 && \$1 =~ ^- ]]; do |
| if [[ \$1 == "--print" ]]; then |
| print=true |
| fi |
| shift |
| done |
| if [[ \$# == 0 ]]; then |
| echo >&2 "Invalid state, cannot find host tool name" |
| return 1 |
| fi |
| tool="\$1" |
| p="\$(grep "/\${tool}$" "${BT_TEMP_DIR}/.mocked_tools")" |
| if [[ -z "\$p" ]]; then |
| echo >&2 "Invalid state, cannot find path for \$tool." \ |
| "Use a btf::make_*_mock() method from fuchsia-mock.sh to mock it." |
| return 1 |
| fi |
| if [[ ! -x "\$p" ]]; then |
| echo >&2 "Invalid state, \$p is not executable." |
| return 1 |
| fi |
| if \$print; then |
| echo "\$p" |
| else |
| "\$p" "\$@" |
| fi |
| EOF |
| } |
| |
| # Verifies that the arguments in BT_MOCK_ARGS match the arguments to this function. |
| # The number and order of arguments must match, or non-zero is returned. |
| # If a value of an argument is un-important it can be marked with the string |
| # _ANY_. This allows for matching arguments that may have unique values, such as temp |
| # filenames. |
| # Args: toolname|mock_state_file arg [arg] [arg] ... |
| # Returns: 0 if found; 1 if not found. |
| btf::expect-mock-args() { |
| local tool="$1" |
| if [[ ! "${tool}" =~ \.mock_state(\.[0-9]+)?$ ]]; then |
| tool="${tool}.mock_state" |
| fi |
| BT_ASSERT_FILE_EXISTS "${tool}" |
| shift |
| source "${tool}" |
| local expected=("$@") |
| local actual=("${BT_MOCK_ARGS[@]:1}") # ignore the first arg, the mocked command |
| if [[ ${#actual[@]} -ne ${#expected[@]} ]]; then |
| btf::_fail 1 "Unexpected number of arguments to ${tool}.\n Expected ${#expected[@]}: ${expected[*]}\n Actual ${#actual[@]}: ${actual[*]}" |
| return |
| fi |
| for (( i=0; i<"${#expected[@]}"; i++ )); do |
| if [[ "${expected[$i]}" != "_ANY_" ]]; then |
| if [[ "${actual[$i]}" != "${expected[$i]}" ]]; then |
| btf::_fail 1 "Unexpected arguments to ${tool}.\n Expected: ${expected[*]}\n Actual: ${actual[*]}" |
| return |
| fi |
| fi |
| done |
| return 0 |
| } |
| |
| btf::does-mock-args-contain() { |
| local state_file="$1" |
| BT_ASSERT_FILE_EXISTS "${state_file}" |
| shift |
| source "${state_file}" |
| local expected=("$@") |
| local actual=("${BT_MOCK_ARGS[@]}") |
| local al=${#actual[@]} |
| local el=${#expected[@]} |
| if [[ $el -gt $al ]]; then |
| return 1 |
| fi |
| for (( a=1; a<"$(( al - el + 1 ))"; a++ )); do |
| for (( e=0; e<"${el}"; e++ )); do |
| local shifted="$((a + e))" |
| if [[ "${expected[$e]}" != "_ANY_" && "${actual[$shifted]}" != "${expected[$e]}" ]]; then |
| continue 2 # continue the outer loop |
| fi |
| done |
| # if we got here, we went through all the expected arguments, so success |
| return 0 |
| done |
| return 1 |
| } |
| |
| btf::does-mock-args-not-contain() { |
| local state_file="$1" |
| BT_ASSERT_FILE_EXISTS "${state_file}" |
| shift |
| source "${state_file}" |
| local expected=("$@") |
| local actual=("${BT_MOCK_ARGS[@]}") |
| local al=${#actual[@]} |
| local el=${#expected[@]} |
| if [[ $el -gt $al ]]; then |
| return 0 |
| fi |
| for (( a=1; a<"$(( al - el + 1 ))"; a++ )); do |
| for (( e=0; e<"${el}"; e++ )); do |
| local shifted="$((a + e))" |
| if [[ "${expected[$e]}" != "_ANY_" && "${actual[$shifted]}" != "${expected[$e]}" ]]; then |
| continue 2 # continue the outer loop |
| fi |
| done |
| # if we got here, we went through all the expected arguments, so we found it |
| return 1 |
| done |
| } |