blob: 7b594f7b3f87216c4dcdf76e8e690c2757a66b31 [file] [log] [blame]
# 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.
import json
import os
import tempfile
import typing
import unittest
import unittest.mock as mock
import async_utils.command as command
from parameterized import parameterized
import args
import environment
import event
import execution
import test_list_file
import tests_json_file
def _make_exec_env(
fuchsia_dir: str, out_dir: str, gemini_api_key: typing.Optional[str] = None
) -> environment.ExecutionEnvironment:
"""Create an execution environment for test."""
return environment.ExecutionEnvironment(
fuchsia_dir=fuchsia_dir,
out_dir=out_dir,
test_json_file="",
disabled_ctf_tests_file="",
log_file=None,
test_list_file="",
gemini_api_key=gemini_api_key,
)
class TestExecution(unittest.IsolatedAsyncioTestCase):
def assertContainsSublist(
self, target: list[typing.Any], data: list[typing.Any]
) -> None:
"""Helper method to assert that one list is contained in the other, in order.
Args:
target (list[typing.Any]): The sublist to search for.
data (list[typing.Any]): The list to search in.
"""
self.assertNotEqual(len(target), 0, "Target list cannot be empty")
starts = [i for i, v in enumerate(data) if v == target[0]]
for start_index in starts:
if data[start_index : start_index + len(target)] == target:
return
self.assertTrue(False, f"List {target} is not a sublist of {data}")
async def test_run_command(self) -> None:
"""Test that run_command works with and without events"""
with tempfile.TemporaryDirectory() as tmp:
open(os.path.join(tmp, "temp-file.txt"), "w").close()
output = await execution.run_command(
"ls", "temp-file.txt", env={"CWD": tmp}
)
assert output is not None
self.assertEqual(output.return_code, 0)
recorder = event.EventRecorder()
recorder.emit_init()
output = await execution.run_command(
"ls", "temp-file.txt", env={"CWD": tmp}, recorder=recorder
)
assert output is not None
self.assertEqual(output.return_code, 0)
recorder.emit_end()
events = [e async for e in recorder.iter()]
# Ensure we got init, end, and at least one sub-event start/stop
self.assertGreater(len(events), 4)
async def test_run_command_failure(self) -> None:
"""Test that running an invalid command emits an error event"""
recorder = event.EventRecorder()
recorder.emit_init()
output = await execution.run_command(
"___invalid_command_name___", recorder=recorder
)
recorder.emit_end()
events = [e async for e in recorder.iter()]
# Ensure we get no output and that at least one event is an error.
self.assertIsNone(output)
self.assertTrue(any([e.error is not None for e in events]))
@parameterized.expand(
[
(
"with default log severity",
[],
[["--max-severity-logs", "INFO"]],
[],
),
(
"with min log severity override",
["--min-severity-logs", "DEBUG"],
[["--min-severity-logs", "DEBUG"]],
[],
),
(
"without log restriction",
["--no-restrict-logs"],
[["--min-severity-logs", "TRACE"]],
["--max-severity-logs"],
),
(
"with default to not run disabled tests",
[],
[["--min-severity-logs", "TRACE"]],
["--run-disabled"],
),
(
"with disabled tests running",
["--also-run-disabled-tests"],
[["--run-disabled"], ["--min-severity-logs", "TRACE"]],
[],
),
(
"with full moniker in logs",
["--show-full-moniker-in-logs"],
[["--show-full-moniker-in-logs"]],
[],
),
(
"without full moniker in logs",
["--no-show-full-moniker-in-logs"],
[],
["--show-full-moniker-in-logs"],
),
(
"without ffx output directory",
[],
[],
["--output-directory"],
),
(
"with ffx output directory",
["--ffx-output-directory", "foo"],
[["--output-directory", "foo/0"]],
[],
),
(
"with extra args",
["--", "--foo"],
[["--", "--foo"]],
[],
),
]
)
async def test_test_execution_component(
self,
_unused_name: str,
flag_list: list[str],
expected_present_flag_lists: list[list[str]],
expected_not_present_flags: list[str],
) -> None:
"""Test the usage of the TestExecution wrapper on a component test"""
exec_env = _make_exec_env("/fuchsia", "/out/fuchsia")
test = execution.TestExecution(
test_list_file.Test(
tests_json_file.TestEntry(
tests_json_file.TestSection("foo", "//foo", "fuchsia")
),
test_list_file.TestListEntry(
"foo",
[],
test_list_file.TestListExecutionEntry(
"fuchsia-pkg://fuchsia.com/foo#meta/foo_test.cm",
realm="foo_tests",
max_severity_logs="INFO",
min_severity_logs="TRACE",
test_filters=["-foo", "-bar"],
),
),
),
exec_env,
args.parse_args(["--no-use-package-hash"] + flag_list),
)
command_line = test.command_line()
self.assertContainsSublist(
[
"fx",
"--dir",
"/out/fuchsia",
"ffx",
"test",
"run",
"--realm",
"foo_tests",
],
command_line,
)
self.assertContainsSublist(
[
"--test-filter",
"-foo",
"--test-filter",
"-bar",
],
command_line,
)
self.assertContainsSublist(
["fuchsia-pkg://fuchsia.com/foo#meta/foo_test.cm"], command_line
)
for expected_flag_list in expected_present_flag_lists:
self.assertContainsSublist(expected_flag_list, command_line)
for not_present_flag in expected_not_present_flags:
self.assertFalse(
not_present_flag in command_line,
f"Expected {not_present_flag} to not be in {command_line}",
)
self.assertFalse(test.is_hermetic())
self.assertIsNone(test.environment())
self.assertTrue(test.should_symbolize())
@parameterized.expand(
[
(
"test execution does not pass a --parallel by default",
None,
None,
[],
),
(
"test execution respects parallel overrides in test specs",
1,
None,
["--parallel", "1"],
),
(
"test execution flag overrides test spec",
4,
2,
["--parallel", "2"],
),
]
)
async def test_test_execution_parallel_cases(
self,
_unused_name: str,
spec_parallel: int | None,
flag_parallel: int | None,
expected_args: list[str],
) -> None:
"""Test the usage of the TestExecution wrapper on a component test"""
exec_env = _make_exec_env("/fuchsia", "/out/fuchsia")
test = execution.TestExecution(
test_list_file.Test(
tests_json_file.TestEntry(
tests_json_file.TestSection(
"foo", "//foo", "fuchsia", parallel=spec_parallel
)
),
test_list_file.TestListEntry(
"foo",
[],
test_list_file.TestListExecutionEntry(
"fuchsia-pkg://fuchsia.com/foo#meta/foo_test.cm",
realm="foo_tests",
max_severity_logs="INFO",
min_severity_logs="TRACE",
),
),
),
exec_env,
args.parse_args(
["--no-use-package-hash"]
+ (
[]
if not flag_parallel
else ["--parallel-cases", str(flag_parallel)]
)
),
)
self.assertListEqual(
test.command_line(),
[
"fx",
"--dir",
"/out/fuchsia",
"ffx",
"test",
"run",
"--realm",
"foo_tests",
"--max-severity-logs",
"INFO",
"--min-severity-logs",
"TRACE",
]
+ expected_args
+ [
"--timeout",
"300",
"fuchsia-pkg://fuchsia.com/foo#meta/foo_test.cm",
],
)
self.assertFalse(test.is_hermetic())
self.assertIsNone(test.environment())
self.assertTrue(test.should_symbolize())
@parameterized.expand(
[
(
"test execution does not pass a --no-exception-channel by default",
None,
[],
),
(
"test execution respects create_no_exception_channel in test specs",
True,
["--no-exception-channel"],
),
]
)
async def test_test_execution_create_no_exception_channel(
self,
_unused_name: str,
spec_create_no_exception_channel: bool | None,
expected_args: list[str],
) -> None:
"""Test the usage of the TestExecution wrapper on a component test"""
exec_env = _make_exec_env("/fuchsia", "/out/fuchsia")
test = execution.TestExecution(
test_list_file.Test(
tests_json_file.TestEntry(
tests_json_file.TestSection(
"foo",
"//foo",
"fuchsia",
create_no_exception_channel=spec_create_no_exception_channel,
)
),
test_list_file.TestListEntry(
"foo",
[],
test_list_file.TestListExecutionEntry(
"fuchsia-pkg://fuchsia.com/foo#meta/foo_test.cm",
realm="foo_tests",
max_severity_logs="INFO",
min_severity_logs="TRACE",
),
),
),
exec_env,
args.parse_args(["--no-use-package-hash"]),
)
self.assertListEqual(
test.command_line(),
[
"fx",
"--dir",
"/out/fuchsia",
"ffx",
"test",
"run",
"--realm",
"foo_tests",
"--max-severity-logs",
"INFO",
"--min-severity-logs",
"TRACE",
]
+ expected_args
+ [
"--timeout",
"300",
"fuchsia-pkg://fuchsia.com/foo#meta/foo_test.cm",
],
)
self.assertFalse(test.is_hermetic())
self.assertIsNone(test.environment())
self.assertTrue(test.should_symbolize())
async def test_test_execution_component_with_experimental_new_path(
self,
) -> None:
"""Test the usage of the TestExecution wrapper on a component test while using test interface"""
exec_env = _make_exec_env("/fuchsia", "/out/fuchsia")
test = execution.TestExecution(
test_list_file.Test(
tests_json_file.TestEntry(
tests_json_file.TestSection(
"foo",
"//foo",
"fuchsia",
new_path="bin/test_component_wrapper.sh",
)
),
test_list_file.TestListEntry(
"foo",
[],
test_list_file.TestListExecutionEntry(
"fuchsia-pkg://fuchsia.com/foo#meta/foo_test.cm",
realm="foo_tests",
max_severity_logs="INFO",
min_severity_logs="TRACE",
),
),
),
exec_env,
args.parse_args(["--use-test-pilot", "--", "--some_extra_arg"]),
)
command_line = test.command_line()
self.assertEquals(
[
"/out/fuchsia/bin/test_component_wrapper.sh",
"--realm=foo_tests",
"--max-severity-logs=INFO",
"--min-severity-logs=TRACE",
"--target-test-args=--some_extra_arg",
"--timeout=300",
],
command_line,
)
env = test.environment()
assert env is not None
# TODO: Add environment checking when added.
self.assertDictContainsSubset(
{
"CWD": "/out/fuchsia",
"FUCHSIA_CUSTOM_TEST_ARGS": "--some_extra_arg",
},
env,
)
# without --use-test-pilot flag
test = execution.TestExecution(
test_list_file.Test(
tests_json_file.TestEntry(
tests_json_file.TestSection(
"foo",
"//foo",
"fuchsia",
new_path="bin/test_component_wrapper.sh",
)
),
test_list_file.TestListEntry(
"foo",
[],
test_list_file.TestListExecutionEntry(
"fuchsia-pkg://fuchsia.com/foo#meta/foo_test.cm",
realm="foo_tests",
max_severity_logs="INFO",
min_severity_logs="TRACE",
),
),
),
exec_env,
args.parse_args(
["--no-use-package-hash", "--", "--some_extra_arg"]
),
)
command_line = test.command_line()
self.assertContainsSublist(
[
"fx",
"--dir",
"/out/fuchsia",
"ffx",
"test",
"run",
"--realm",
"foo_tests",
],
command_line,
)
self.assertContainsSublist(
["fuchsia-pkg://fuchsia.com/foo#meta/foo_test.cm"], command_line
)
self.assertContainsSublist(["--", "--some_extra_arg"], command_line)
self.assertIsNone(test.environment())
# TODO(b/444203259): Failing on debian 12 Linux. Re-enable once a fix is implemented.
# async def test_test_execution_host(self) -> None:
# """Test the usage of the TestExecution wrapper on a host test, and actually run it"""
# with tempfile.TemporaryDirectory() as tmp:
# # We will run ls, but it needs to be relative to the output directory.
# # Find the actual path to the ls binary and symlink it into the
# # output directory.
# env_path = (
# subprocess.check_output(["which", "env"]).decode().strip()
# )
# self.assertTrue(os.path.isfile, f"{env_path} is not a file")
# os.symlink(env_path, os.path.join(tmp, "env"))
# exec_env = _make_exec_env("/fuchsia", tmp)
# flags = args.parse_args([])
# test = execution.TestExecution(
# test_list_file.Test(
# tests_json_file.TestEntry(
# tests_json_file.TestSection(
# "foo", "//foo", "linux", path="env"
# )
# ),
# test_list_file.TestListEntry("foo", [], execution=None),
# ),
# exec_env,
# flags,
# )
# self.assertFalse(test.is_hermetic())
# env = test.environment()
# assert env is not None
# self.assertDictEqual(env, {"CWD": tmp})
# self.assertFalse(test.should_symbolize())
# recorder = event.EventRecorder()
# recorder.emit_init()
# output = await test.run(recorder, flags, event.GLOBAL_RUN_ID)
# recorder.emit_end()
# assert output is not None
# lines = output.stdout.splitlines()
# outdir: None | str = None
# for line in lines:
# l = line.split("=")
# if len(l) > 1 and l[0] == "FUCHSIA_TEST_OUTDIR":
# outdir = l[1]
# assert outdir is not None
# self.assertEqual(
# outdir[:4],
# "/tmp",
# f"Expecting that the output directory is an absolute path into /tmp. Found {outdir}",
# )
# self.assertFalse(
# any([e.error is not None async for e in recorder.iter()])
# )
@parameterized.expand(
[
("without --e2e enabled", ["--no-e2e"], execution.TestSkipped),
("with --e2e enabled", ["--e2e"], execution.TestFailed),
]
)
@mock.patch("execution.run_command", return_value=None)
async def test_test_execution_e2e(
self,
_unused_name: str,
extra_flags: list[str],
expected_exception: type,
command_mock: mock.MagicMock,
) -> None:
"""Test that execution of e2e depends on the --e2e flag"""
exec_env = _make_exec_env("/fuchsia", "/out/fuchsia")
flags = args.parse_args(extra_flags)
test = execution.TestExecution(
test_list_file.Test(
tests_json_file.TestEntry(
tests_json_file.TestSection(
"foo", "//foo", "linux", path="ls"
),
environments=[
tests_json_file.EnvironmentEntry(
dimensions=tests_json_file.DimensionsEntry(
device_type="AEMU"
)
)
],
),
test_list_file.TestListEntry("foo", [], execution=None),
),
exec_env,
flags,
)
self.assertTrue(test._test.is_e2e_test())
self.assertFalse(test.is_hermetic())
env = test.environment()
assert env is not None
self.assertDictEqual(env, {"CWD": "/out/fuchsia"})
self.assertFalse(test.should_symbolize())
recorder = event.EventRecorder()
recorder.emit_init()
try:
await test.run(recorder, flags, event.GLOBAL_RUN_ID)
self.assertTrue(False, "No exception was raised")
except Exception as e:
self.assertIsInstance(e, expected_exception)
recorder.emit_end()
@mock.patch("execution.run_command", return_value=None)
async def test_test_execution_skip_boot_tests(
self, command_mock: mock.MagicMock
) -> None:
"""Test that boot tests are skipped"""
exec_env = _make_exec_env("/fuchsia", "/out/fuchsia")
flags = args.parse_args([])
test = execution.TestExecution(
test_list_file.Test(
tests_json_file.TestEntry(
tests_json_file.TestSection(
"foo", "//foo", "linux", path="ls"
),
environments=[
tests_json_file.EnvironmentEntry(
dimensions=tests_json_file.DimensionsEntry(
device_type="AEMU"
)
)
],
is_boot_test=True,
),
test_list_file.TestListEntry("foo", [], execution=None),
),
exec_env,
flags,
)
self.assertTrue(test._test.is_e2e_test())
self.assertFalse(test.is_hermetic())
env = test.environment()
assert env is not None
self.assertDictEqual(env, {"CWD": "/out/fuchsia"})
self.assertFalse(test.should_symbolize())
recorder = event.EventRecorder()
recorder.emit_init()
try:
await test.run(recorder, flags, event.GLOBAL_RUN_ID)
self.assertTrue(False, "No exception was raised")
except Exception as e:
self.assertIsInstance(e, execution.TestSkipped)
recorder.emit_end()
async def test_test_execution_with_package_hash(self) -> None:
"""Ensure that test execution respects --use-package-hash"""
with tempfile.TemporaryDirectory() as tmp:
with open(os.path.join(tmp, "package-repositories.json"), "w") as f:
json.dump(
[
{
"targets": "targets.json",
}
],
f,
)
with open(os.path.join(tmp, "targets.json"), "w") as f:
json.dump(
{
"signed": {
"targets": {
"foo_test/0": {
"custom": {
"merkle": "f00",
}
},
"bar_test/0": {},
}
}
},
f,
)
def make_test(name: str) -> test_list_file.Test:
name = f"fuchsia-pkg://fuchsia.com/{name}#meta/test.cm"
return test_list_file.Test(
tests_json_file.TestEntry(
tests_json_file.TestSection(name, "//foo", "linux")
),
test_list_file.TestListEntry(
name,
[],
execution=test_list_file.TestListExecutionEntry(name),
),
)
def assertTestExecutionFailsUsingMerkleHash(
error_regex: str,
test: test_list_file.Test,
exec_env: environment.ExecutionEnvironment,
) -> None:
self.assertRaisesRegex(
execution.TestCouldNotRun,
error_regex,
lambda: execution.TestExecution(
test, exec_env, args.parse_args([])
).command_line(),
)
self.assertIsNotNone(
execution.TestExecution(
test,
exec_env,
args.parse_args(["--no-use-package-hash"]),
).command_line()
)
# This environment is missing a package-repository.json file, so attempts
# to match a merkle root will fail.
missing_exec_env = environment.ExecutionEnvironment(
fuchsia_dir="/fuchsia",
out_dir="",
test_json_file="",
disabled_ctf_tests_file="",
)
assertTestExecutionFailsUsingMerkleHash(
"Could not load a Merkle hash",
make_test("foo_test"),
missing_exec_env,
)
# This environment contains a package repository, so we need to
# ensure the merkle hash argument is respected.
exec_env = environment.ExecutionEnvironment(
fuchsia_dir="/fuchsia",
out_dir="",
test_json_file="",
disabled_ctf_tests_file="",
package_repositories_file=os.path.join(
tmp, "package-repositories.json"
),
)
# Hash is present only when use_merkle_hash is True, absent otherwise.
self.assertIn(
"fuchsia-pkg://fuchsia.com/foo_test?hash=f00#meta/test.cm",
execution.TestExecution(
make_test("foo_test"), exec_env, args.parse_args([])
).command_line(),
)
self.assertIn(
"fuchsia-pkg://fuchsia.com/foo_test#meta/test.cm",
execution.TestExecution(
make_test("foo_test"),
exec_env,
args.parse_args(["--no-use-package-hash"]),
).command_line(),
)
# Mangle the component URL such that a name cannot be extracted,
# and expect an error.
broken_test = make_test("foo_test")
assert broken_test.info is not None
assert broken_test.info.execution is not None
broken_test.info.execution.component_url = "foo_test"
assertTestExecutionFailsUsingMerkleHash(
"Failed to parse package name", broken_test, exec_env
)
# This test has an entry, but no merkle.
assertTestExecutionFailsUsingMerkleHash(
"Could not find a Merkle hash for this test",
make_test("bar_test"),
exec_env,
)
# This test has no entry.
assertTestExecutionFailsUsingMerkleHash(
"Could not find a Merkle hash for this test",
make_test("baz_test"),
exec_env,
)
def _make_command_output(
self, stdout: str, return_code: int = 0
) -> command.CommandOutput:
return command.CommandOutput(stdout, "", return_code, 0.2, None)
@mock.patch("execution.run_command")
async def test_gemini_analysis_not_called_on_success(
self, command_mock: mock.AsyncMock
) -> None:
"""test that gemini analysis is not called on a successful run."""
exec_env = _make_exec_env("/fuchsia", "/out/fuchsia")
flags = args.parse_args(["--gemini-analysis"])
test = execution.TestExecution(
test_list_file.Test(
tests_json_file.TestEntry(
tests_json_file.TestSection(
"foo", "//foo", "linux", path="ls"
)
),
test_list_file.TestListEntry("foo", [], execution=None),
),
exec_env,
flags,
)
# Simulate a successful command
command_mock.return_value = self._make_command_output(
"success", return_code=0
)
recorder = event.EventRecorder()
recorder.emit_init()
await test.run(recorder, flags, event.GLOBAL_RUN_ID)
# The command should only be called once for the test itself.
command_mock.assert_called_once()
@mock.patch("execution.run_command")
async def test_gemini_analysis_verbosity_level_passed(
self, command_mock: mock.AsyncMock
) -> None:
"""test that the verbosity level is correctly passed to the gemini analysis script."""
exec_env = _make_exec_env(
"/fuchsia", "/out_dir", gemini_api_key="fake_key"
)
flags = args.parse_args(
["--gemini-analysis=3", "--env", "GEMINI_API_KEY=fake_key"]
)
test = execution.TestExecution(
test_list_file.Test(
tests_json_file.TestEntry(
tests_json_file.TestSection(
"foo", "//foo", "linux", path="ls"
)
),
test_list_file.TestListEntry("foo", [], execution=None),
),
exec_env,
flags,
)
# Simulate a failing command
command_mock.return_value = self._make_command_output(
"some error", return_code=1
)
recorder = event.EventRecorder()
recorder.emit_init()
with self.assertRaises(execution.TestFailed):
await test.run(recorder, flags, event.GLOBAL_RUN_ID)
# The first call is to the test itself, the second is to gemini_analysis.py
self.assertEqual(command_mock.call_count, 2)
gemini_call = command_mock.call_args_list[1]
self.assertIn("gemini_analysis.py", gemini_call.args[0])
self.assertIn("--verbosity", gemini_call.args)
self.assertIn("3", gemini_call.args)
self.assertEqual(gemini_call.kwargs["input_bytes"], b"some error\n")
@mock.patch("execution.run_command")
async def test_gemini_analysis_with_no_api_key(
self, command_mock: mock.AsyncMock
) -> None:
"""test that gemini analysis prints an error if no api key is provided."""
exec_env = _make_exec_env("/fuchsia", "/out/fuchsia")
flags = args.parse_args(["--gemini-analysis"])
test = execution.TestExecution(
test_list_file.Test(
tests_json_file.TestEntry(
tests_json_file.TestSection(
"foo", "//foo", "linux", path="ls"
)
),
test_list_file.TestListEntry("foo", [], execution=None),
),
exec_env,
flags,
)
# Simulate a failing command
command_mock.return_value = self._make_command_output(
"some error", return_code=1
)
recorder = event.EventRecorder()
recorder.emit_init()
with self.assertRaises(execution.TestFailed):
await test.run(recorder, flags, event.GLOBAL_RUN_ID)
# The command should only be called once for the test itself, as gemini analysis should be skipped.
command_mock.assert_called_once()
class TestExecutionUtils(unittest.IsolatedAsyncioTestCase):
def _make_command_output(
self, stdout: str, return_code: int = 0
) -> command.CommandOutput:
return command.CommandOutput(stdout, "", return_code, 0.2, None)
def setUp(self) -> None:
self._temp_dir = tempfile.TemporaryDirectory()
self._env = _make_exec_env(self._temp_dir.name, "")
return super().setUp()
def tearDown(self) -> None:
self._temp_dir.cleanup()
return super().tearDown()
@mock.patch("execution.run_command")
async def test_get_device_environment_success(
self, command_patch: mock.AsyncMock
) -> None:
command_patch.side_effect = [
self._make_command_output("127.0.0.1:6000"),
self._make_command_output("foo-bar"),
# config get ssh.priv
self._make_command_output("/foo/path"),
]
device_env = await execution.get_device_environment_from_exec_env(
self._env
)
self.assertDictContainsSubset(
{
"address": "127.0.0.1",
"port": "6000",
"name": "foo-bar",
"private_key_path": "/foo/path",
},
vars(device_env),
)
@mock.patch("execution.run_command")
async def test_get_device_environment_ipv6(
self, command_patch: mock.AsyncMock
) -> None:
command_patch.side_effect = [
self._make_command_output("[::1]:6000"),
self._make_command_output("foo-bar"),
# config get ssh.priv
self._make_command_output("/foo/path"),
]
device_env = await execution.get_device_environment_from_exec_env(
self._env
)
self.assertDictContainsSubset(
{
"address": "[::1]",
"port": "6000",
"name": "foo-bar",
"private_key_path": "/foo/path",
},
vars(device_env),
)
@mock.patch("execution.run_command")
async def test_get_device_environment_ssh_error(
self, command_patch: mock.AsyncMock
) -> None:
command_patch.side_effect = [
self._make_command_output("", return_code=1),
]
try:
device_env = await execution.get_device_environment_from_exec_env(
self._env
)
self.assertTrue(False, f"Should have failed, got {device_env}")
except execution.DeviceConfigError as e:
self.assertRegex(str(e), "Failed to get the ssh address")
@mock.patch("execution.run_command")
async def test_get_device_environment_bad_ip_format(
self, command_patch: mock.AsyncMock
) -> None:
command_patch.side_effect = [
self._make_command_output("foo"),
]
try:
device_env = await execution.get_device_environment_from_exec_env(
self._env
)
self.assertTrue(False, f"Should have failed, got {device_env}")
except execution.DeviceConfigError as e:
self.assertRegex(str(e), "Could not parse")
@mock.patch("execution.run_command")
async def test_get_device_environment_no_target_name(
self, command_patch: mock.AsyncMock
) -> None:
command_patch.side_effect = [
self._make_command_output("127.0.0.1:6000"),
self._make_command_output("", return_code=1),
]
try:
device_env = await execution.get_device_environment_from_exec_env(
self._env
)
self.assertTrue(False, f"Should have failed, got {device_env}")
except execution.DeviceConfigError as e:
self.assertRegex(str(e), "Failed to get the target name")
async def test_test_execution_gets_env_from_flags(self) -> None:
"""Test TestExecution wrapper uses the environment provided by flags"""
with tempfile.TemporaryDirectory() as tmp:
exec_env = _make_exec_env("/fuchsia", tmp)
flags = args.parse_args(
["-e", "foo=bar", "--env", "my_setting=baz"]
)
test = execution.TestExecution(
test_list_file.Test(
tests_json_file.TestEntry(
tests_json_file.TestSection(
"foo", "//foo", "linux", path="wont_exist"
)
),
test_list_file.TestListEntry("foo", [], execution=None),
),
exec_env,
flags,
)
e = test.environment()
assert e is not None
self.assertDictEqual(
e,
{"CWD": tmp, "foo": "bar", "my_setting": "baz"},
)
@parameterized.expand(
[
(
None,
None,
300,
),
(
None,
1234,
1234,
),
(
1234,
None,
1234,
),
(
0,
None,
None,
),
(
0,
1234,
None,
),
]
)
def test_calculate_timeout(
self,
arg: float | None,
config: int | None,
result: float | None,
) -> None:
"""Test _calculate_timeout function works properly"""
exec_env = _make_exec_env("/fuchsia", "/out/fuchsia")
test = execution.TestExecution(
test_list_file.Test(
tests_json_file.TestEntry(
tests_json_file.TestSection(
"foo",
"//foo",
"fuchsia",
timeout_secs=config,
)
),
test_list_file.TestListEntry(
"foo",
[],
test_list_file.TestListExecutionEntry(
"fuchsia-pkg://fuchsia.com/foo#meta/foo_test.cm",
realm="foo_tests",
max_severity_logs="INFO",
min_severity_logs="TRACE",
),
),
),
exec_env,
args.parse_args(["--timeout", str(arg)] if arg is not None else []),
)
self.assertEqual(test._calculate_timeout(), result)