|  | #!/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. | 
|  | # | 
|  | # Tests as much of femu as possible for OSX but running on a Linux machine, using | 
|  | # fake uname output to test these code paths. We do not actually run the binaries, | 
|  | # but just make sure that the arguments and dependencies are as correct as possible. | 
|  |  | 
|  | set -e | 
|  |  | 
|  | # Initialize variables that need to be set before BT_SET_UP() | 
|  |  | 
|  | # Specify a simulated CIPD instance id for prebuilts | 
|  | AEMU_VERSION="git_revision:unknown" | 
|  | AEMU_LABEL="$(echo "${AEMU_VERSION}" | tr ':/' '_')" | 
|  | GRPCWEBPROXY_VERSION="git_revision:unknown" | 
|  | # Force mac-amd64 to test OSX on Linux | 
|  | PLATFORM="mac-amd64" | 
|  |  | 
|  | # Create fake "uname -s" to pretend we are on OSX | 
|  | set_up_uname() { | 
|  | cat >"${PATH_DIR_FOR_TEST}/uname.mock_side_effects" <<"INPUT" | 
|  | if [[ "$1" == "-m" ]]; then | 
|  | echo "x86_64" | 
|  | elif [[ "$1" == "-s" ]]; then | 
|  | echo "Darwin" | 
|  | elif [[ "$1" == "" ]]; then | 
|  | echo "Darwin" | 
|  | else | 
|  | echo "Unexpected uname option: $1" | 
|  | exit 1 | 
|  | fi | 
|  | INPUT | 
|  | } | 
|  |  | 
|  | # The tools/devshell/lib/fvm.sh script adds -x for Darwin, so we need to | 
|  | # remove it here so it runs on Linux. Create a fake "stat" command that | 
|  | # ignores the -x, and then calls the local Linux stat command. Make sure | 
|  | # this continues to work on OSX as well with IS_MAC. | 
|  | set_up_stat() { | 
|  | cat >"${PATH_DIR_FOR_TEST}/stat.mock_side_effects" <<"INPUT" | 
|  | if (( ! IS_MAC )); then | 
|  | if [[ "$1" != "-x" ]]; then | 
|  | echo "Error: Expected -x argument to ignore" | 
|  | exit 1 | 
|  | fi | 
|  | shift | 
|  | fi | 
|  | "${STAT_PATH}" $@ | 
|  | INPUT | 
|  | } | 
|  |  | 
|  | # Create fake ZIP file download so femu.sh doesn't try to download it, and | 
|  | # later on provide a mocked emulator script so it doesn't try to unzip it. | 
|  | set_up_cipd() { | 
|  | touch "${FUCHSIA_WORK_DIR}/emulator/aemu-${PLATFORM}-${AEMU_LABEL}.zip" | 
|  | } | 
|  |  | 
|  | function run_femu_wrapper() { | 
|  | # femu.sh will run "fvm decompress" to convert the given fvm image format into | 
|  | # an intermediate raw image suffixed by ".decompress". The image is then used for | 
|  | # extension. Since the fvm tool is faked and does nothing in the test, we need | 
|  | # to fake the intermediate decompressed image. | 
|  | cp "${FUCHSIA_WORK_DIR}/image/storage-full.blk" \ | 
|  | "${FUCHSIA_WORK_DIR}/image/storage-full.blk.decompressed" | 
|  | gn-test-run-bash-script "${BT_TEMP_DIR}/scripts/sdk/gn/base/bin/femu.sh" "$@" | 
|  | } | 
|  |  | 
|  |  | 
|  | TEST_femu_osx_networking() { | 
|  | PATH_DIR_FOR_TEST="${BT_TEMP_DIR}/_isolated_path_for" | 
|  | export PATH="${PATH_DIR_FOR_TEST}:${PATH}" | 
|  |  | 
|  | set_up_uname | 
|  | set_up_stat | 
|  | set_up_cipd | 
|  |  | 
|  | # Run command. | 
|  | BT_EXPECT run_femu_wrapper \ | 
|  | -N \ | 
|  | -I fakenetwork \ | 
|  | --unknown-arg1-to-qemu \ | 
|  | --authorized-keys "${BT_TEMP_DIR}/scripts/sdk/gn/base/testdata/authorized_keys" \ | 
|  | --unknown-arg2-to-qemu | 
|  |  | 
|  | # Verify that the image first goes through a decompress process by fvm | 
|  | # shellcheck disable=SC1090 | 
|  | source "${MOCKED_FVM}.mock_state.1" | 
|  | gn-test-check-mock-args _ANY_ _ANY_ decompress --default _ANY_ | 
|  |  | 
|  | # Verify that the image will be extended to double the size | 
|  | # shellcheck disable=SC1090 | 
|  | source "${MOCKED_FVM}.mock_state.2" | 
|  | gn-test-check-mock-args _ANY_ _ANY_ extend --length 2048 --length-is-lowerbound | 
|  |  | 
|  | # Check that fpave.sh was called to download the needed system images | 
|  | # shellcheck disable=SC1090 | 
|  | source "${BT_TEMP_DIR}/scripts/sdk/gn/base/bin/fpave.sh.mock_state" | 
|  | gn-test-check-mock-args _ANY_ --prepare --image qemu-x64 --bucket fuchsia --work-dir "${FUCHSIA_WORK_DIR}" | 
|  |  | 
|  | # Check that fserve.sh was called to download the needed system images | 
|  | # shellcheck disable=SC1090 | 
|  | source "${BT_TEMP_DIR}/scripts/sdk/gn/base/bin/fserve.sh.mock_state" | 
|  | gn-test-check-mock-args _ANY_ --prepare --image qemu-x64 --bucket fuchsia --work-dir "${FUCHSIA_WORK_DIR}" | 
|  |  | 
|  | # Verify that zbi was called to add the authorized_keys | 
|  | # shellcheck disable=SC1090 | 
|  | source "${MOCKED_ZBI}.mock_state" | 
|  | gn-test-check-mock-args _ANY_ -o _ANY_ "${FUCHSIA_WORK_DIR}/image/zircon-a.zbi" --entry "data/ssh/authorized_keys=${BT_TEMP_DIR}/scripts/sdk/gn/base/testdata/authorized_keys" | 
|  |  | 
|  | # Verify some of the arguments passed to the emulator binary | 
|  | # shellcheck disable=SC1090 | 
|  | source "${FUCHSIA_WORK_DIR}/emulator/aemu-${PLATFORM}-${AEMU_LABEL}/emulator.mock_state" | 
|  | # The mac address is computed with a hash function in fx emu based on the device name. | 
|  | # We test the generated mac address since other scripts hard code this to SSH into the device. | 
|  | gn-test-check-mock-partial -fuchsia | 
|  | gn-test-check-mock-partial -netdev type=tap,ifname=fakenetwork,id=net0,script="${BT_TEMP_DIR}/scripts/sdk/gn/base/bin/devshell/lib/emu-ifup-macos.sh" | 
|  | gn-test-check-mock-partial -device virtio-net-pci,vectors=8,netdev=net0,mac=52:54:00:95:03:66 | 
|  | gn-test-check-mock-partial --unknown-arg1-to-qemu | 
|  | gn-test-check-mock-partial --unknown-arg2-to-qemu | 
|  |  | 
|  | # Check that the default OSX ifup script actually exists | 
|  | BT_EXPECT_FILE_EXISTS "${BT_TEMP_DIR}/scripts/sdk/gn/base/bin/devshell/lib/emu-ifup-macos.sh" | 
|  | } | 
|  |  | 
|  | TEST_femu_osx_fail_tuntap() { | 
|  | PATH_DIR_FOR_TEST="${BT_TEMP_DIR}/_isolated_path_for" | 
|  | export PATH="${PATH_DIR_FOR_TEST}:${PATH}" | 
|  |  | 
|  | set_up_uname | 
|  | set_up_stat | 
|  | set_up_cipd | 
|  |  | 
|  | if [[ -c /dev/tap0 && -w /dev/tap0 ]]; then | 
|  | # Run command, which should work because the tun/tap driver is installed and writable by the user | 
|  | BT_EXPECT run_femu_wrapper \ | 
|  | -N | 
|  |  | 
|  | # Verify some of the arguments passed to the emulator binary | 
|  | # shellcheck disable=SC1090 | 
|  | source "${FUCHSIA_WORK_DIR}/emulator/aemu-${PLATFORM}-${AEMU_LABEL}/emulator.mock_state" | 
|  | # The mac address is computed with a hash function in fx emu based on the device name. | 
|  | # We test the generated mac address since other scripts hard code this to SSH into the device. | 
|  | gn-test-check-mock-partial -fuchsia | 
|  | gn-test-check-mock-partial -netdev type=tap,ifname=tap0,id=net0,script="${BT_TEMP_DIR}/scripts/sdk/gn/base/bin/devshell/lib/emu-ifup-macos.sh" | 
|  | gn-test-check-mock-partial -device virtio-net-pci,vectors=8,netdev=net0,mac=52:54:00:4d:27:96 | 
|  | else | 
|  | # The tun/tap driver is not installed, so test if the execution fails the way we expect | 
|  | BT_EXPECT_FAIL run_femu_wrapper \ | 
|  | -N \ | 
|  | > femu_error_output.txt 2>&1 | 
|  |  | 
|  | if [[ ! -c /dev/tap0 ]]; then | 
|  | BT_EXPECT_FILE_CONTAINS_SUBSTRING femu_error_output.txt "To use emu with networking on macOS, install the tun/tap driver" | 
|  | else | 
|  | BT_EXPECT_FILE_CONTAINS_SUBSTRING femu_error_output.txt "For networking /dev/tap0 must be owned by ${USER}. Please run:" | 
|  | fi | 
|  | fi | 
|  | } | 
|  |  | 
|  | # Test initialization. Note that we copy various tools/devshell files and need to replicate the | 
|  | # behavior of generate.py by copying these files into scripts/sdk/gn/base/bin/devshell | 
|  | # shellcheck disable=SC2034 | 
|  | BT_FILE_DEPS=( | 
|  | scripts/sdk/gn/base/bin/femu.sh | 
|  | scripts/sdk/gn/base/bin/devshell/lib/image_build_vars.sh | 
|  | scripts/sdk/gn/base/bin/fuchsia-common.sh | 
|  | scripts/sdk/gn/bash_tests/gn-bash-test-lib.sh | 
|  | tools/devshell/emu | 
|  | tools/devshell/lib/fvm.sh | 
|  | tools/devshell/lib/emu-ifup-macos.sh | 
|  | ) | 
|  | # shellcheck disable=SC2034 | 
|  | BT_MOCKED_TOOLS=( | 
|  | test-home/.fuchsia/emulator/aemu-linux-amd64-"${AEMU_LABEL}"/emulator | 
|  | test-home/.fuchsia/emulator/aemu-mac-amd64-"${AEMU_LABEL}"/emulator | 
|  | scripts/sdk/gn/base/bin/fpave.sh | 
|  | scripts/sdk/gn/base/bin/fserve.sh | 
|  | scripts/sdk/gn/base/tools/x64/zbi | 
|  | scripts/sdk/gn/base/tools/x64/fvm | 
|  | scripts/sdk/gn/base/tools/arm64/zbi | 
|  | scripts/sdk/gn/base/tools/arm64/fvm | 
|  | _isolated_path_for/ip | 
|  | # Create fake "stty sane" command so that fx emu test succeeds when < /dev/null is being used | 
|  | _isolated_path_for/stty | 
|  | # Create fake "uname" command to pretend we are on OSX | 
|  | _isolated_path_for/uname | 
|  | # Create fake "stat" command that eats up the -x argument for OSX which doesn't work on Linux | 
|  | _isolated_path_for/stat | 
|  | ) | 
|  |  | 
|  | BT_SET_UP() { | 
|  |  | 
|  | # shellcheck disable=SC1090 | 
|  | source "${BT_TEMP_DIR}/scripts/sdk/gn/bash_tests/gn-bash-test-lib.sh" | 
|  |  | 
|  | # Make "home" directory in the test dir so the paths are stable." | 
|  | mkdir -p "${BT_TEMP_DIR}/test-home" | 
|  | export HOME="${BT_TEMP_DIR}/test-home" | 
|  | FUCHSIA_WORK_DIR="${HOME}/.fuchsia" | 
|  |  | 
|  | # We change the PATH to override the stat command, but need a reference to it | 
|  | if ! STAT_PATH="$(type -p stat)"; then | 
|  | echo "Error: Could not type -p stat" | 
|  | exit 1 | 
|  | fi | 
|  | export STAT_PATH | 
|  |  | 
|  | # Detect if we are on a Mac and store it, because once we override uname | 
|  | # then is-mac will always return 1 | 
|  | if is-mac; then | 
|  | export IS_MAC=1 | 
|  | else | 
|  | export IS_MAC=0 | 
|  | fi | 
|  |  | 
|  | # Create a small disk image to avoid downloading, and test if it is doubled in size as expected | 
|  | mkdir -p "${FUCHSIA_WORK_DIR}/image" | 
|  | dd if=/dev/zero of="${FUCHSIA_WORK_DIR}/image/storage-full.blk" bs=1024 count=1  > /dev/null 2>/dev/null | 
|  |  | 
|  | MOCKED_FVM="${BT_TEMP_DIR}/scripts/sdk/gn/base/$(gn-test-tools-subdir)/fvm" | 
|  | MOCKED_ZBI="${BT_TEMP_DIR}/scripts/sdk/gn/base/$(gn-test-tools-subdir)/zbi" | 
|  |  | 
|  | } | 
|  |  | 
|  | BT_INIT_TEMP_DIR() { | 
|  |  | 
|  | # Generate the prebuilt version file based on the simulated version string | 
|  | echo "${AEMU_VERSION}" > "${BT_TEMP_DIR}/scripts/sdk/gn/base/bin/aemu.version" | 
|  | echo "${GRPCWEBPROXY_VERSION}" > "${BT_TEMP_DIR}/scripts/sdk/gn/base/bin/grpcwebproxy.version" | 
|  |  | 
|  | # Create empty authorized_keys file to add to the system image, but the contents are not used. | 
|  | mkdir -p "${BT_TEMP_DIR}/scripts/sdk/gn/base/testdata" | 
|  | echo ssh-ed25519 00000000000000000000000000000000000000000000000000000000000000000000 \ | 
|  | >"${BT_TEMP_DIR}/scripts/sdk/gn/base/testdata/authorized_keys" | 
|  |  | 
|  | # Stage the files we copy from the fx emu implementation, replicating behavior of generate.py | 
|  | cp -r "${BT_TEMP_DIR}/tools/devshell" "${BT_TEMP_DIR}/scripts/sdk/gn/base/bin/" | 
|  | } | 
|  |  | 
|  | BT_RUN_TESTS "$@" |