blob: 6785d8147f15c398d122e74e2a602832d697b985 [file] [edit]
#!/usr/bin/env fuchsia-vendored-python
# Copyright 2023 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.
"""Simple FFX host tool E2E test."""
import json
import logging
import ffxtestcase
from honeydew.transports.ffx.types import MachineFormat
from mobly import asserts, test_runner
_LOGGER: logging.Logger = logging.getLogger(__name__)
class FfxTest(ffxtestcase.FfxTestCase):
"""FFX host tool E2E test."""
async def setup_class(self) -> None:
await super().setup_class()
self.isolate_dir = self.dut.ffx.config.isolate_dir.directory()
def test_component_list(self) -> None:
"""Test `ffx component list` output returns as expected."""
output = self.dut.ffx.run(["component", "list"])
asserts.assert_true(
len(output.splitlines()) > 0,
f"stdout is unexpectedly empty: {output}",
)
def test_target_list_includes_port(self) -> None:
"""Test `ffx target list` output returns as expected."""
# NOTE: This test fails if the device under test is an user-mode networking emulator.
output = self.dut.ffx.run(
["target", "list", "--format", "a"], machine=MachineFormat.RAW
)
asserts.assert_true(
":22" in output, f"expected stdout to contain ':22',got {output}"
)
def test_target_show(self) -> None:
"""Test `ffx target show` output returns as expected."""
output = self.dut.ffx.get_target_information()
got_device_name = output.target.name
# Assert FFX's target show device name matches Honeydew's.
asserts.assert_equal(got_device_name, self.dut.device_name)
# TODO(b/493680962): re-enable this test when we have a mechanism for disconnecting
# from RCS.
# async def test_target_echo_repeat(self) -> None:
# """Test `ffx target echo --repeat` is resilient to target disconnection."""
# with self.dut.ffx.popen(
# ["target", "echo", "--repeat"],
# stdout=subprocess.PIPE,
# text=False,
# ) as process:
# try:
# line = process.stdout.readline()
# asserts.assert_true(
# line.startswith(b"SUCCESS"),
# f"First ping didn't succeed: {line}",
# )
# # XXX somehow disconnect from RCS.
# # We used to stop the daemon, but these days the daemon doesn't
# # run in Lacewing. We could reboot the device, but that doesn't
# # play well with Infra. Maybe a Fuchsia Controller request of
# # some sort?
# while True:
# line = process.stdout.readline()
# if not line.startswith(b"ERROR") and not line.startswith(
# b"Waiting for"
# ):
# break
# _LOGGER.debug(f"echo output: {line}")
# asserts.assert_true(
# line.startswith(b"SUCCESS"),
# f"Success didn't resume after error: {line}",
# )
# finally:
# process.kill()
def test_machine_errors(self) -> None:
"""Test machine formattable errors."""
cmd = [
"--machine",
"json",
"-t",
"this-should-not-exist",
"-c",
"proxy.timeout_secs=5",
"target",
"show",
]
(code, stdout, stderr) = self.run_ffx_unchecked(cmd)
output_json = json.loads(stdout)
asserts.assert_equal(stderr, "")
asserts.assert_equal(output_json["type"], "user")
asserts.assert_equal(
output_json["message"],
(
"Failed to create remote control proxy: "
'Timeout attempting to reach target "this-should-not-exist". '
"Please check the connection to the target; "
"`ffx doctor -v` may help diagnose the issue."
),
)
asserts.assert_equal(output_json["code"], 1)
def test_machine_user_error(self) -> None:
"""Test machine formattable errors for a user error kind."""
cmd = [
"--machine",
"json",
"repository",
"server",
"start",
"--background",
"--foreground",
]
(code, stdout, stderr) = self.run_ffx_unchecked(cmd)
try:
output_json = json.loads(stdout)
except json.JSONDecodeError as e:
raise ValueError(f"could not parse string as JSON: {e}. {stdout}")
# This is an expected message on stderr. The log file is changed for package servers.
asserts.assert_in("Switching log file to", stderr)
asserts.assert_equal(output_json["type"], "user")
asserts.assert_equal(
output_json["message"],
"--background and --foreground are mutually exclusive",
)
asserts.assert_equal(output_json["code"], 1)
def test_machine_config_error(self) -> None:
"""Test machine formattable errors for a user error kind."""
cmd = [
"--machine",
"json",
"-t",
"foo",
"-t",
"bar",
"target",
"show",
]
(code, stdout, stderr) = self.run_ffx_unchecked(cmd)
output_json = json.loads(stdout)
asserts.assert_equal(stderr, "")
asserts.assert_equal(output_json["type"], "config")
asserts.assert_equal(
output_json["message"],
"Error parsing option '-t' with value 'bar': duplicate values provided\n",
)
asserts.assert_equal(output_json["code"], 1)
def test_arg_parse_error_formats(self) -> None:
"""Test machine formattable errors for a user error kind."""
cmd = [
"-t",
"foo",
"-t",
"bar",
"target",
"show",
]
(code, stdout, stderr) = self.run_ffx_unchecked(cmd)
output_json = json.loads(stdout)
asserts.assert_equal(stderr, "")
asserts.assert_equal(output_json["type"], "config")
asserts.assert_equal(
output_json["message"],
"Error parsing option '-t' with value 'bar': duplicate values provided\n",
)
asserts.assert_equal(output_json["code"], 1)
def test_machine_unexpected_error(self) -> None:
"""Test machine formattable errors for a user error kind."""
cmd = [
"--machine",
"json",
"-t",
"foo,bar",
"target",
"show",
]
(code, stdout, stderr) = self.run_ffx_unchecked(cmd)
output_json = json.loads(stdout)
asserts.assert_equal(stderr, "")
asserts.assert_equal(output_json["type"], "unexpected")
asserts.assert_equal(
output_json["message"],
"--config must either be a file path, /\n a valid JSON object, or comma separated key=value pairs.",
)
asserts.assert_equal(output_json["code"], 1)
def test_machine_help(self) -> None:
"""Test machine formattable help."""
cmd = [
"--machine",
"json",
"--help",
]
(code, stdout, stderr) = self.run_ffx_unchecked(cmd)
json.loads(stdout)
asserts.assert_equal(stderr, "")
asserts.assert_equal(code, 0)
def test_daemon_start_background_works_with_autostart_false(self) -> None:
"""Test that `ffx daemon start --background` works even if daemon.autostart=false"""
self.run_ffx(["--isolate-dir", self.isolate_dir, "daemon", "stop"])
# We're validating that this command doesn't throw an exception
self.run_ffx(
[
"--isolate-dir",
self.isolate_dir,
"--machine",
"raw",
"-c",
"daemon.autostart=false",
"daemon",
"start",
"--background",
]
)
def test_shared_data(self) -> None:
"""Test `ffx -c shared_dir=<dir>` will use the value passed in for $SHARED_DATA"""
(_code, stdout, _stderr) = self.run_ffx_unchecked(
["-c", "shared_data=foo", "config", "get", "monitor.pid_file"]
)
asserts.assert_true(
"foo/monitor" in stdout,
"Expected SHARED_DATA to be correctly set",
stdout,
)
if __name__ == "__main__":
test_runner.main()